Commit graph

13517 commits

Author SHA1 Message Date
Cody Kickertz
c07e5a697d
fix(frontend): use ref to avoid stale movies closure in search (#103)
Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 12:27:41 -06:00
Cody Kickertz
80912b7d43
fix(security): prevent path traversal and command injection (#102)
Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 12:21:31 -06:00
Cody Kickertz
9d7b5b5298
fix: avoid redundant First() calls in BasicRepository (#101)
Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 12:00:29 -06:00
Cody Kickertz
2b0f9ad03a
fix: add null safety to QualityProfile First/Last methods (#100)
Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 12:00:19 -06:00
Cody Kickertz
b843e777de
fix: add empty catch comment and SingleOrDefault safety (#99)
Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 11:59:59 -06:00
Cody Kickertz
1a5ca83f4f
fix: resolve thread safety issues in ConfigService cache (#98)
Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 11:58:46 -06:00
Cody Kickertz
d8c69e87e2
fix(security): add regex timeouts for ReDoS prevention (#97)
Add TimeSpan.FromSeconds(1) timeout to remaining regex patterns:
- FileNameBuilder.cs: EditionOrdinalRegex, EditionUppercaseRegex
- Parser.cs: SlugSpaceRegex, SlugInvalidCharsRegex, SlugDuplicateDefaultRegex

Clears final 5 SonarCloud security hotspots for 100% review coverage

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 11:50:11 -06:00
Cody Kickertz
9bf299c196
fix: add empty checks before First() in MovieFileController (#96)
Add guard clauses to prevent InvalidOperationException when
movieFiles list is empty in bulk update/delete operations

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 11:44:49 -06:00
Cody Kickertz
0081ec2aa1
fix: use SingleOrDefault() with null check in UserService (#95)
Replace .Single() with .SingleOrDefault() when reading Config element
from XML to prevent InvalidOperationException on malformed config files

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 11:39:41 -06:00
Cody Kickertz
c249c20eb2
fix: add null/empty checks before First() in download clients (#94)
- FileStationProxy: throw if no file info returned from API
- NzbVortex: return outputPath if no files in response
- RTorrent: use FirstOrDefault() for validation errors

Prevents InvalidOperationException on empty collections

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 11:36:28 -06:00
Cody Kickertz
67a4720ed3
perf: fix remaining regex caching and add timeouts (#93)
- XbmcNfoDetector: convert instance regex to static readonly with timeout
- Parser: add RegexOptions.Compiled and timeout to ReportMovieTitleFolderRegex

Addresses Issue #36

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 11:15:46 -06:00
Cody Kickertz
739a672637
perf: replace List.Contains() with HashSet for O(1) lookups (#92)
- ReleaseSearchService: wrap wantedLanguages in HashSet<Language>
- FileNameBuilder: convert splitFilter array to HashSet<string>
- NewznabCategoryFieldOptionsConverter: use HashSet<int> for category filters

Addresses Issue #35

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 11:15:37 -06:00
Cody Kickertz
f4f7253165
chore(ci): standardize branch naming to use main instead of master (#91)
- Update workflow triggers to use main instead of master
- Update CONTRIBUTING.md to reference main branch
- Aligns with documentation in CLAUDE.md

Closes #52

Note: Actual branch rename (master → main) must be done on GitHub.

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 11:11:39 -06:00
Cody Kickertz
168ea24266
perf(backend): cache additional regex patterns (#89)
* perf(backend): cache regex patterns for better performance

- TransmissionBase: add static VersionRegex, share with Transmission
- SearchCriteriaBase: cache RepeatingPlusRegex
- SearchMovieComparer: cache QueryYearRegex
- XbmcMetadata: cache WatchedRegex

Avoids regex compilation on each method call.

Partially addresses #36

* fix(security): add regex timeout to prevent ReDoS vulnerabilities

All cached regex patterns now include TimeSpan.FromSeconds(1) timeout
to prevent potential denial of service from malicious input patterns.

---------

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 10:38:37 -06:00
Cody Kickertz
b17381f53f
fix(frontend): replace any types with proper TypeScript types (#88)
* fix(frontend): replace any types with proper TypeScript types

- AutoSuggestInput: use Data type from popper.js for modifier callback
- Tooltip: use Data type from popper.js for computeMaxSize callback
- OverlayScroller: use ComponentPropsWithoutRef<'div'> for renderView
- index.ts: use unknown[] instead of any[] for logError parameters

Improves type safety and removes eslint-disable comments.

Partially addresses #37

* fix(frontend): use ModifierFn type and string values for Popper styles

- Use ModifierFn type from popper.js for modifier callbacks
- Calculate bottom/right from offset properties (top+height, left+width)
- Convert numeric style values to strings with 'px' suffix
- Fix typo: 'botton' -> 'bottom' in AutoSuggestInput

---------

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-21 10:38:16 -06:00
Cody Kickertz
c89ee01b63
chore(ci): standardize branch naming to use main instead of master (#90)
- Update workflow triggers to use main instead of master
- Update CONTRIBUTING.md to reference main branch
- Aligns with documentation in CLAUDE.md

Closes #52

Note: Actual branch rename (master → main) must be done on GitHub.

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-20 09:00:25 -06:00
Cody Kickertz
1230212df8
fix(frontend): memoize inline JSX objects for performance (#87)
- MovieIndexTable: memoize itemData, move row flex styles to CSS
- MovieIndexOverviews: memoize itemData, extract listStyle constant
- MovieIndexOverview: memoize elementStyle and infoStyle
- CircularProgressBar: memoize containerStyle and circleStyle

Reduces unnecessary re-renders in virtualized lists and frequently
rendered components.

Closes #41

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-19 20:01:07 -06:00
Cody Kickertz
80c364110c
fix(ui): update user-facing links to Aletheia resources (#86)
- MoreInfo: point to Aletheia GitHub instead of Radarr resources
- UpdateChanges: link issue numbers to Aletheia repo
- Add "Upstream" translation key for Radarr reference link

Closes #53

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-19 20:00:39 -06:00
Cody Kickertz
b6b1df9dfe
chore: update GitHub Actions and consolidate .editorconfig rules (#85)
Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-19 20:00:23 -06:00
Cody Kickertz
a73b82d40c
fix(frontend): remove index from React keys in dynamic lists (#84)
Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-19 19:35:56 -06:00
Cody Kickertz
c4dae9a279
fix: add null safety to LINQ First/Single calls (#83)
Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-19 19:35:45 -06:00
Cody Kickertz
934a18e9a5
perf: cache regex patterns in Parser.ToUrlSlug and FileNameBuilder.GetEditionToken (#82)
Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-19 19:35:29 -06:00
Cody Kickertz
f2fff6419d
refactor: notification provider deduplication + docs (#81)
* fix: SonarCloud null safety and struct comparison issues

- OsPath.cs: Remove ReferenceEquals checks on struct (always false)
- SkyHookProxy.cs: Add null-conditional operators for Credits.Cast/Crew

* fix: remaining React index-as-key issues and backend null safety

Frontend:
- Fix 8 remaining index-as-key violations using content-based keys
- ImportMovieSelectFolder.js: use errorMessage as key
- ImportMovieFooter.js: use errorMessage as key
- CustomFormat.js: use item.name as key
- AddSpecificationItem.js: use preset.name as key
- QualityProfileItems.js: use message as key
- QualityProfileFormatItems.js: use message as key

Backend (cherry-picked from batch-3):
- OsPath.cs: Remove ReferenceEquals on struct
- SkyHookProxy.cs: Add null-conditional for Credits

* refactor(notifications): consolidate GetPosterUrl to base class

* docs: add architectural decisions log

* fix(sonar): enable path traversal suppressions for media management app

---------

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-19 19:35:14 -06:00
Cody Kickertz
b7d5ffb6e9
fix: remaining React index-as-key issues + backend null safety (#78)
* fix: SonarCloud null safety and struct comparison issues

- OsPath.cs: Remove ReferenceEquals checks on struct (always false)
- SkyHookProxy.cs: Add null-conditional operators for Credits.Cast/Crew

* fix: remaining React index-as-key issues and backend null safety

Frontend:
- Fix 8 remaining index-as-key violations using content-based keys
- ImportMovieSelectFolder.js: use errorMessage as key
- ImportMovieFooter.js: use errorMessage as key
- CustomFormat.js: use item.name as key
- AddSpecificationItem.js: use preset.name as key
- QualityProfileItems.js: use message as key
- QualityProfileFormatItems.js: use message as key

Backend (cherry-picked from batch-3):
- OsPath.cs: Remove ReferenceEquals on struct
- SkyHookProxy.cs: Add null-conditional for Credits

---------

Co-authored-by: admin <admin@ardentleatherworks.com>
2025-12-19 16:11:24 -06:00
Cody Kickertz
a5c2675c2b
Merge pull request #77 from cheir-mneme/fix/sonarcloud-batch-3
fix: SonarCloud null safety and struct comparison
2025-12-19 16:06:20 -06:00
admin
70cfd14971 fix: SonarCloud null safety and struct comparison issues
- OsPath.cs: Remove ReferenceEquals checks on struct (always false)
- SkyHookProxy.cs: Add null-conditional operators for Credits.Cast/Crew
2025-12-19 15:53:17 -06:00
Cody Kickertz
2612b184d8
Merge pull request #74 from cheir-mneme/fix/sonarcloud-bugs-2
fix: SonarCloud bugs batch 2
2025-12-19 15:44:53 -06:00
Cody Kickertz
88c81cf233
Merge pull request #73 from cheir-mneme/fix/sonarcloud-bugs
Fix SonarCloud bugs: threading, React state, sorting
2025-12-19 15:44:38 -06:00
admin
835ec47313 fix: SonarCloud bugs batch 2
- S2445: Make _connections readonly for thread-safe locking (MessageHub.cs)
- S6756: Use setState callbacks for 5 React components
- S1764: Remove duplicate expression in QualityProfileSelectInput.tsx
- S2583: Remove unreachable conditions in NotificationDefinition.cs
- S2259: Fix null reference in Pushcut.cs
2025-12-19 15:22:56 -06:00
Cody Kickertz
5aa9fd0abe
Merge pull request #72 from cheir-mneme/fix/sonarcloud-cleanup
Fix SonarCloud issues and add suppression config
2025-12-19 15:16:39 -06:00
admin
6d17e5eaff Fix SonarCloud bugs: threading, React state, sorting
Backend:
- S2445: Make _connections readonly in MessageHub.cs to fix locking issue

Frontend:
- S6756: Use callback form of setState when referencing previous state
  - Collection.js, DiscoverMovie.js, ImportMovie.js
  - ImportMovieSelectMovie.js, EditQualityProfileModalContentConnector.js
- S2871: Add localeCompare for proper alphabetical sorting
  - Collection.js, DiscoverMovie.js, MovieIndex.tsx
- S1764: Remove duplicate condition in QualityProfileSelectInput.tsx
2025-12-19 15:15:24 -06:00
Cody Kickertz
220eba471b
Merge pull request #71 from cheir-mneme/fix/eslint-v9-migration
Migrate to ESLint 9 flat config
2025-12-19 15:03:41 -06:00
admin
4cf5f1d576 Fix SonarCloud issues and add suppression config
Backend:
- Add regex timeout to prevent ReDoS (S6444):
  - SkyHookProxy.cs: ImdbUrlRegex, TmdbUrlRegex
  - PushsaferSettings.cs: HexColorRegex
  - Parser.cs: ImdbIdRegex

Frontend:
- Fix sorting without localeCompare (S2871):
  - MovieIndex.tsx, Collection.js, DiscoverMovie.js

Config:
- Add sonar-project.properties with documented false positive suppressions:
  - S8135: TMDB public API token (not a secret)
  - S6680: Directory depth iteration (naturally bounded)
  - S6674: NLog structured logging placeholder syntax
  - S4662: PostCSS mixin directives
  - S5145: Sanitized log data
2025-12-19 15:03:23 -06:00
admin
cca1b47936 Migrate to ESLint 9 flat config
- Create eslint.config.mjs with ESM flat config format
- Remove legacy .eslintrc.js and .eslintignore
- Remove eslint-plugin-filenames (not ESLint 9 compatible)
- Update lint-staged to use new config
- Clean up unused eslint-disable directives
2025-12-19 14:44:01 -06:00
Cody Kickertz
32d072dd8a
Merge pull request #70 from cheir-mneme/fix/p4-frontend
fix(frontend): React quality improvements - keys, types, memoization
2025-12-19 14:39:40 -06:00
admin
a7852b6fcf fix(frontend): address React and TypeScript quality issues
- Replace index-as-key antipattern with stable keys (#34)
- Remove TypeScript any types in favor of proper types (#37)
- Memoize inline style objects to prevent unnecessary re-renders (#41)

Files: 17 frontend components updated
2025-12-19 14:20:40 -06:00
Cody Kickertz
0366c8f258
Merge pull request #68 from cheir-mneme/fix/p4-backend
perf: backend optimizations for regex caching and O(n*m) patterns
2025-12-19 13:45:24 -06:00
Cody Kickertz
fcb1c783f7
Merge pull request #69 from cheir-mneme/fix/p4-audit-security
fix(security): address audit findings - path validation and ReDoS
2025-12-19 13:33:59 -06:00
admin
189039c875 fix(security): add path validation to OpenWriteStream and regex timeouts
- DiskProviderBase: Add Ensure.That path validation to OpenWriteStream
- CleanseLogMessage: Add 5-second timeout to all 22 regex patterns to prevent ReDoS
2025-12-19 13:22:25 -06:00
admin
dda89e2fda Optimize O(n*m) Contains patterns with HashSet
- MovieService.FindByTitle: Convert title lists to HashSets
- MoviesSearchService: Convert queue IDs to HashSet
2025-12-19 13:11:07 -06:00
admin
0e5abe56f0 Cache regex instances as static compiled fields
- SkyHookProxy: Cache IMDB/TMDB URL regexes
- PushsaferSettings: Cache hex color validation regex
- Parser: Cache IMDB ID validation regex
2025-12-19 13:08:40 -06:00
Cody Kickertz
b85eb4fcde
Merge pull request #67 from cheir-mneme/fix/p3-security
fix(security): P3 security vulnerabilities and mitigations
2025-12-19 12:27:44 -06:00
admin
019f0862b3 fix(security): address P3 vulnerabilities and add mitigations
Security fixes:
- XXE prevention: disable XmlResolver in UTorrentProxy.cs (#42)
- Path traversal: validate paths in LogFileController.cs (#44)
- Path traversal: validate paths in MediaCoverController.cs (#44)
- ReDoS mitigation: add 5s timeout to user regex patterns

Documentation:
- CORS: document security rationale in Startup.cs (#43)

Closes #42, #43, #44
Related: #59, #60, #61 (SonarCloud triage - GitHub alerts now at 0 open)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 12:12:54 -06:00
Cody Kickertz
f7fca51da7
Merge pull request #66 from cheir-mneme/fix/p2-ci-tooling
fix(ci): P2 improvements - editorconfig, integration tests, Prettier 3
2025-12-19 12:00:25 -06:00
admin
7961b36547 fix(ci): P2 improvements - editorconfig, integration tests, Prettier 3
- Remove duplicate dotnet_style_qualification rules in .editorconfig
- Update Radarr branding to Aletheia in .editorconfig
- Add integration tests step to build.yml (with continue-on-error)
- Upgrade Prettier to 3.7.4, eslint-plugin-prettier to 5.5.4
- Upgrade eslint-config-prettier to 10.1.8
- Fix pre-existing lint errors (unused vars, radix parameter)
- Reformat frontend code with Prettier 3 formatting changes

Closes #57 (SonarCloud deferred - needs org setup)
Closes #58, #62 (partial - ESLint 9 deferred), #63

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 11:46:44 -06:00
Cody Kickertz
b10c795c24
Merge pull request #65 from cheir-mneme/fix/ci-p1-workflow
fix(ci): add CODEOWNERS, enable test blocking, add pre-commit hooks
2025-12-19 11:29:59 -06:00
admin
1fcbee8227 chore: update yarn.lock with husky and lint-staged 2025-12-19 11:13:45 -06:00
admin
37ed597adf fix(ci): add CODEOWNERS, enable test blocking, add pre-commit hooks 2025-12-19 11:03:07 -06:00
Cody Kickertz
ca643b656e
Merge pull request #64 from cheir-mneme/fix/ci-p0-cleanup
fix(ci): pin Trivy action and update branding
2025-12-19 10:53:53 -06:00
admin
c0ae8a8506 fix(ci): pin Trivy action and update branding 2025-12-19 10:44:32 -06:00