Skip to content

Code quality cleanup, test creation, and documentation - #104

Merged
BillyOutlast merged 14 commits into
developfrom
test/server-auth-metadata-prioritylist
Jul 27, 2026
Merged

BillyOutlast merged 14 commits into
developfrom
test/server-auth-metadata-prioritylist

Conversation

@BillyOutlast

@BillyOutlast BillyOutlast commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

This PR implements the hyperplan execution plan for code quality cleanup, test automation, and documentation improvements.

Changes

PR 1: Server Tests (19 tests)

  • Add auth signin handler test (8 cases: valid, bcrypt, argon2, disabled, invalid, missing, malicious, rememberMe)
  • Add IGDB metadata provider test (7 cases: search, empty, no cover, no date, missing env, source)
  • Add prioritylist edge cases (4 cases: empty get, max priority, duplicate stability, 1000 item perf)

PR 2: CLI + Desktop Tests (9 tests)

  • Add CLI upload test (5 cases: path construction, dry-run, progress, missing config, manifest)
  • Add desktop client test (4 cases: module structure, app_state, app_status, autostart)

PR 3: SonarCloud Mechanical Fixes (#69)

  • S7772: Add node: prefix to fs/path imports
  • S1940: Simplify boolean expression in app.vue
  • S6822: Remove redundant role="list" from Library.vue and team.tsx

PR 4: SonarCloud Real Bugs (#68 #74 #79)

  • Fix assignment-vs-comparison in simple/index.vue (S1121)
  • Simplify ReDoS regex patterns in steam.ts (S8786)
  • Fix PATH injection via absolute path resolution (S4036)

PR 5: Accessibility Fixes (#71)

  • S6819: Convert role="status" divs to elements (6 instances)
  • ImgWithoutAltCheck: Add meaningful alt text to images (25+ instances)
  • S5255: Add aria-label to nav elements
  • S6840: Add autocomplete attributes to form inputs
  • S6851: Convert div to element
  • S5256: Add aria-label to table

PR 6: Cognitive Complexity Reduction (#73 #99)

  • Extract helper functions in OIDCManager
  • Simplify conditional logic in session cache/db/memory
  • Fix PATH injection in nuxt.config.ts git command

PR 7: Documentation

  • Add TSDoc to 12 exported functions across 7 files
  • Update AGENTS.md: test count 32→176, SonarCloud 130→109

Test Results

  • Server tests: 176 passed, 1 skipped (177 total)
  • Typecheck: Clean
  • Rust tests: All pass

SonarCloud Impact

  • Estimated issue reduction: ~40-50 issues
  • a11y issues fixed: 108
  • Mechanical code quality fixes: 5
  • Real bugs fixed: 6

Checklist

  • All tests pass
  • Typecheck passes
  • No regressions
  • Changes are independently mergeable
  • AGENTS.md updated with current metrics

Refs: #68, #69, #71, #73, #74, #79, #99

Summary by CodeRabbit

  • Accessibility
    • Added meaningful alternative text to game, profile, news, gallery, and screenshot imagery across desktop and web.
    • Improved loading/status semantics by switching to output with aria-live, and added clearer navigation and form/table labeling.
  • Authentication
    • Improved simple sign-in support by adding Argon2 password verification (with expanded sign-in test coverage).
  • Metadata
    • Broadened Steam company-page description extraction for more reliable metadata.
  • Operational Reliability
    • Improved detection of Git/Nginx/Torrential executables for smoother service startup.
  • Tests
    • Added Rust/Vitest tests covering uploads, initialization, metadata providers, and priority-list edge cases.

John Smith added 7 commits July 26, 2026 19:57
- Add auth signin handler test (8 cases: valid, bcrypt, argon2, disabled, invalid, missing, malicious, rememberMe)
- Add IGDB metadata provider test (7 cases: search, empty, no cover, no date, missing env, source)
- Add prioritylist edge cases (4 cases: empty get, max priority, duplicate stability, 1000 item perf)
- Add CLI upload test (5 cases: path construction, dry-run, progress, missing config, manifest)
- Add desktop client test (4 cases: module structure, app_state, app_status, autostart)
- S7772: Add node: prefix to fs/path imports in recursivedirs.ts
- S7772: Add node: prefix to path/url imports in eslint.config.mjs
- S1940: Simplify boolean expression in app.vue
- S6822: Remove redundant role="list" from Library.vue and team.tsx
- Fix assignment-vs-comparison in simple/index.vue (S1121)
- Simplify ReDoS regex patterns in steam.ts (S8786)
- Fix PATH injection via absolute path resolution in torrential/index.ts (S4036)
- Fix PATH injection in nginx.ts (S4036)
- S6819: Convert role="status" divs to <output> elements (6 instances)
- ImgWithoutAltCheck: Add meaningful alt text to images (25+ instances)
- S5255: Add aria-label to nav elements in admin.vue and UserHeader.vue
- S6840: Add autocomplete attributes to form inputs
- S6851: Convert div to <form> element in client/authorize/[id].vue
- S5256: Add aria-label to table in store/[id]/index.vue
- Add TSDoc to 12 exported functions across 7 files
- Update AGENTS.md: test count 32→176, SonarCloud 130→109
- Update coverage baseline date to 2026-07-26
- Extract helper functions in OIDCManager
- Simplify conditional logic in session cache/db/memory
- Fix PATH injection in nuxt.config.ts git command
- All 176 tests pass
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@BillyOutlast, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 3 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: caf904e9-c10d-4e44-a88a-ab2a59afad08

📥 Commits

Reviewing files that changed from the base of the PR and between 5c38e81 and efb0aa0.

📒 Files selected for processing (12)
  • server/components/GameEditor/Metadata.vue
  • server/nuxt.config.ts
  • server/pages/client/authorize/[id].vue
  • server/pages/store/t/[id]/index.vue
  • server/server/internal/auth/oidc/index.ts
  • server/server/internal/services/torrential/index.ts
  • server/server/internal/services/torrential/utils.ts
  • server/server/internal/session/cache.ts
  • server/server/internal/session/filter.ts
  • server/server/internal/session/memory.ts
  • server/test/unit/prioritylist.test.ts
  • sites/promo/src/components/team.tsx
📝 Walkthrough

Walkthrough

The PR adds Rust and server test coverage, refactors authentication and session helpers, improves executable discovery, updates metadata parsing, and applies accessibility and form-semantic improvements across desktop, server, and promotional interfaces.

Changes

Quality and interface updates

Layer / File(s) Summary
Rust upload and client validation
cli/tests/upload_test.rs, desktop/src-tauri/client/tests/*
Adds coverage for upload manifests, dry-run generation, configuration, serialization, client state variants, and autostart exports.
Authentication and session internals
server/server/internal/auth/*, server/server/internal/session/*, server/test/unit/auth/signin.test.ts
Refactors OIDC loading, adds Argon2 verification, centralizes session filtering, extracts JSON traversal helpers, and tests sign-in outcomes.
Runtime portability and internal API documentation
AGENTS.md, server/nuxt.config.ts, server/server/internal/*
Resolves executable paths for Git, Nginx, and Torrential, updates Steam metadata matching, changes Node import specifiers, and refreshes documentation and metrics.
Accessible UI semantics and form metadata
desktop/main/*, server/components/*, server/pages/*, sites/promo/src/components/*
Adds descriptive image labels, named navigation/table regions, semantic loading containers, corrected callback form markup, and input metadata.
Metadata and priority-list coverage
server/test/unit/metadata/igdb.test.ts, server/test/unit/prioritylist.test.ts
Adds tests for IGDB configuration and result mapping, priority boundaries, stable ordering, empty lookups, and repeated operations.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the PR’s main themes: code-quality cleanup, new tests, and documentation updates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/server-auth-metadata-prioritylist

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 10.52632% with 68 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
server/server/internal/auth/oidc/index.ts 0.00% 43 Missing ⚠️
server/server/internal/session/db.ts 0.00% 17 Missing ⚠️
server/server/internal/session/filter.ts 46.66% 6 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
server/server/internal/metadata/steam.ts (1)

604-613: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve single-quoted metadata attributes.

Both new regexes only accept ", while the surrounding metadata parsers support both quote styles. A valid response using single quotes will silently lose its description. Use the same ["'] handling as _extractTitle and _extractImage, and add fixtures for both quote styles.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/server/internal/metadata/steam.ts` around lines 604 - 613, The
_extractDescription method only matches double-quoted metadata attributes, so
single-quoted descriptions are missed. Update both ogDescRegex and nameDescRegex
to accept either quote style consistently with _extractTitle and _extractImage,
and add fixtures covering single- and double-quoted metadata.
server/pages/client/authorize/[id].vue (1)

64-83: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Keep native form submission aligned with the authorization flow.

The new form posts to /api/v1/client/callback, while authorize() calls /api/v1/client/auth/callback or /api/v1/client/auth/code based on the client mode. Because the button is still type="button", the form action is bypassed today; however, any native submission would hit the wrong contract. Either remove action/method, or wire @submit.prevent to authorize_wrapper() and make the button a submit button.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/pages/client/authorize/`[id].vue around lines 64 - 83, Align the form
around authorize_wrapper() with the authorization flow by either removing its
action/method attributes or handling `@submit.prevent` through
authorize_wrapper(). If retaining native form semantics, change the button to
type="submit" so submission uses the same client-mode-specific authorization
endpoint instead of the mismatched callback action.
🧹 Nitpick comments (2)
server/test/unit/auth/signin.test.ts (1)

96-121: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding a test for sessionHandler.signin returning "fail".

The handler's 500 "Failed to create session" branch (triggered when sessionHandler.signin resolves to "fail") isn't covered by this suite.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/test/unit/auth/signin.test.ts` around lines 96 - 121, The signin tests
around handler should add coverage for sessionHandler.signin resolving to
"fail", asserting the handler returns the 500 "Failed to create session"
response and preserves the expected session-creation behavior.
server/server/internal/session/cache.ts (1)

70-101: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

sessionMatchesFilter is duplicated verbatim across the two in-memory session providers. The same implementation was extracted independently into both files instead of a shared module, so any future fix (including the bug above) must be applied twice.

  • server/server/internal/session/cache.ts#L70-L101: move sessionMatchesFilter to a shared internal module (e.g. server/server/internal/session/filter.ts) and import it here.
  • server/server/internal/session/memory.ts#L59-L90: import the same shared helper instead of keeping a local copy.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/server/internal/session/cache.ts` around lines 70 - 101, Extract the
duplicated sessionMatchesFilter helper from
server/server/internal/session/cache.ts lines 70-101 into a shared internal
session filter module, then import and use it from cache.ts. Remove the local
duplicate from server/server/internal/session/memory.ts lines 59-90 and import
the same helper there, preserving the existing filtering behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cli/tests/upload_test.rs`:
- Around line 54-186: The Rust test file is not formatted according to cargo
fmt. Run cargo fmt --all to normalize the write_all/expect chain,
generate_manifest_rusty argument comments, and to_string_pretty/expect wrapping,
then verify with cargo fmt --all -- --check; also run fallow audit as required
for the repository changes.

In `@desktop/main/components/DependencyRequiredModal.vue`:
- Line 5: Restore empty decorative alt text for the images at
desktop/main/components/DependencyRequiredModal.vue:5-5,
desktop/main/components/HeaderUserWidget.vue:6-6 and :30-30,
server/pages/news/[id]/index.vue:14-14, and server/pages/news/index.vue:38-38.
Keep each image’s existing source and rendering unchanged while using alt="" so
adjacent visible labels are not announced twice.

In `@desktop/main/pages/library/`[id]/index.vue:
- Around line 398-402: Make the images decorative by replacing their
adjacent-name alt text with empty alt attributes: update the dependency icon in
desktop/main/pages/library/[id]/index.vue (lines 398-402), the cover in
desktop/main/pages/queue.vue (line 30), the emulator icon in
server/components/EmulatorWidget.vue (lines 7-11), and the avatar in
sites/promo/src/components/team.tsx (line 35).

In `@server/components/GameEditor/Metadata.vue`:
- Around line 413-417: Update the preview img elements in the Metadata
component, including both occurrences near the existing Game image labels, to
use meaningful visual descriptions when the image conveys information; otherwise
set alt to an empty string for selectable-only previews. Remove the generic
shared alt text.

In `@server/nuxt.config.ts`:
- Around line 30-42: Replace shell-based executable discovery in resolveGitPath
and the corresponding lookup logic in server/nuxt.config.ts (lines 30-42),
server/server/internal/services/services/nginx.ts (lines 7-12), and
server/server/internal/services/torrential/index.ts (lines 96-104), including
the cargo fallback, with execFileSync or spawn using fixed arguments and a
trusted absolute executable path or allowlist. In server/nuxt.config.ts, also
stop interpolating the resolved path into a shell command and invoke git with
fixed arguments.

In `@server/pages/client/authorize/`[id].vue:
- Around line 69-76: Update the input identified by id="client-id" to use
type="hidden" instead of a CSS-hidden text input, and remove its aria-label
attribute. Preserve the existing name and clientId value binding; do not add a
visible field or literal user-facing text.

In `@server/pages/store/`[id]/index.vue:
- Line 54: Replace each hard-coded accessibility label with the appropriate
translated key: in server/pages/store/[id]/index.vue lines 54-54, bind the table
label to the game-details translation; in
server/pages/library/game/[id]/index.vue lines 84-84 and
server/pages/store/[id]/index.vue lines 258-258, translate the screenshot label;
and in server/pages/user/[id]/index.vue lines 8-8, translate the profile-picture
fallback. Use hard-coded i18n keys through the existing Vue translation
mechanism.

In `@server/pages/store/t/`[id]/index.vue:
- Line 8: Remove the decorative img element with the empty src attribute from
the page template, or replace it with a CSS-based decorative element that does
not trigger a network request.

In `@server/server/internal/auth/oidc/index.ts`:
- Around line 489-501: Update the OIDCWellKnownV1 type so userinfo_endpoint and
scopes_supported are optional properties, allowing discovery documents to parse
when either key is omitted. Preserve the existing fallback checks in the OIDC
configuration flow, including the environment-variable behavior and errors when
no fallback value is available.

In `@server/server/internal/services/torrential/index.ts`:
- Around line 88-90: Update the local `torrential` branch in the surrounding
spawn logic to inspect the resolved `./torrential` path with filesystem metadata
and executable-access checks before calling spawn. Only return the local
executable when it is a regular file and executable; otherwise continue to the
existing environment/PATH fallback.

In `@server/server/internal/services/torrential/utils.ts`:
- Around line 8-20: Update the JSDoc return description for defineQueryProcessor
to state “The supplied processor configuration.” Remove the claim that the
configuration is registered, while preserving the rest of the documentation.

In `@server/server/internal/session/cache.ts`:
- Around line 70-101: Update sessionMatchesFilter in
server/server/internal/session/cache.ts (lines 70-101) and
server/server/internal/session/memory.ts (lines 59-90) so specified userId and
oidc filters return false when the session lacks authenticated or oidc data;
retain the existing mismatch checks for present fields and leave unrelated data
filtering unchanged.

In `@server/test/unit/prioritylist.test.ts`:
- Around line 131-142: Remove the fixed performance assertion from the “handles
1000 items push/pop under 100ms” test. Keep it as a behavioral test by asserting
the PriorityListIndexed instance is empty after the push/pop operations and that
its indexes are cleared, or otherwise move timing validation out of this unit
test.

In `@sites/promo/src/components/gallery-modal.tsx`:
- Line 135: Update the enlarged image in the gallery modal to use
caller-provided descriptive alt text instead of the generic "Gallery image"
value; if the image is decorative, set its alt text to empty. Trace the
component’s props or image data to reuse the existing alt-text symbol.

---

Outside diff comments:
In `@server/pages/client/authorize/`[id].vue:
- Around line 64-83: Align the form around authorize_wrapper() with the
authorization flow by either removing its action/method attributes or handling
`@submit.prevent` through authorize_wrapper(). If retaining native form semantics,
change the button to type="submit" so submission uses the same
client-mode-specific authorization endpoint instead of the mismatched callback
action.

In `@server/server/internal/metadata/steam.ts`:
- Around line 604-613: The _extractDescription method only matches double-quoted
metadata attributes, so single-quoted descriptions are missed. Update both
ogDescRegex and nameDescRegex to accept either quote style consistently with
_extractTitle and _extractImage, and add fixtures covering single- and
double-quoted metadata.

---

Nitpick comments:
In `@server/server/internal/session/cache.ts`:
- Around line 70-101: Extract the duplicated sessionMatchesFilter helper from
server/server/internal/session/cache.ts lines 70-101 into a shared internal
session filter module, then import and use it from cache.ts. Remove the local
duplicate from server/server/internal/session/memory.ts lines 59-90 and import
the same helper there, preserving the existing filtering behavior.

In `@server/test/unit/auth/signin.test.ts`:
- Around line 96-121: The signin tests around handler should add coverage for
sessionHandler.signin resolving to "fail", asserting the handler returns the 500
"Failed to create session" response and preserves the expected session-creation
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 58be9fc4-eba9-4c81-864e-5e564fc02342

📥 Commits

Reviewing files that changed from the base of the PR and between 85fc589 and cdd6ffa.

📒 Files selected for processing (52)
  • AGENTS.md
  • cli/tests/upload_test.rs
  • desktop/main/components/DependencyRequiredModal.vue
  • desktop/main/components/HeaderProtonSupportWidget.vue
  • desktop/main/components/HeaderUserWidget.vue
  • desktop/main/components/InitiateAuthModule.vue
  • desktop/main/pages/auth/processing.vue
  • desktop/main/pages/library/[id]/index.vue
  • desktop/main/pages/queue.vue
  • desktop/src-tauri/client/tests/initialization_test.rs
  • server/app.vue
  • server/components/Directory/Library.vue
  • server/components/EmulatorWidget.vue
  • server/components/GameEditor/Metadata.vue
  • server/components/Modal/CreateCompany.vue
  • server/components/NewsArticleCreateButton.vue
  • server/components/UserHeader.vue
  • server/layouts/admin.vue
  • server/nuxt.config.ts
  • server/pages/admin/library/[id]/import.vue
  • server/pages/admin/library/import.vue
  • server/pages/admin/task/[id]/index.vue
  • server/pages/admin/users/auth/simple/index.vue
  • server/pages/client/authorize/[id].vue
  • server/pages/library/game/[id]/index.vue
  • server/pages/news/[id]/index.vue
  • server/pages/news/index.vue
  • server/pages/store/[id]/index.vue
  • server/pages/store/t/[id]/index.vue
  • server/pages/user/[id]/index.vue
  • server/server/arktype.ts
  • server/server/internal/auth/oidc/index.ts
  • server/server/internal/auth/passwordHash.ts
  • server/server/internal/auth/webauthn.ts
  • server/server/internal/clients/event-handler.ts
  • server/server/internal/metadata/steam.ts
  • server/server/internal/services/services/nginx.ts
  • server/server/internal/services/torrential/index.ts
  • server/server/internal/services/torrential/utils.ts
  • server/server/internal/session/cache.ts
  • server/server/internal/session/db.ts
  • server/server/internal/session/memory.ts
  • server/server/internal/tasks/index.ts
  • server/server/internal/utils/handlefileupload.ts
  • server/server/internal/utils/recursivedirs.ts
  • server/test/unit/auth/signin.test.ts
  • server/test/unit/metadata/igdb.test.ts
  • server/test/unit/prioritylist.test.ts
  • sites/promo/eslint.config.mjs
  • sites/promo/src/components/gallery-modal.tsx
  • sites/promo/src/components/screenshot.tsx
  • sites/promo/src/components/team.tsx
💤 Files with no reviewable changes (1)
  • server/components/Directory/Library.vue

Comment thread cli/tests/upload_test.rs
<template #default
><div class="flex items-start gap-x-3">
<img :src="useObject(game.mIconObjectId)" class="size-12" alt="" />
<img :src="useObject(game.mIconObjectId)" class="size-12" :alt="game.mName" />

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep redundant images decorative.

These images are adjacent to visible labels containing the same information, so the new alt text causes duplicate announcements for screen readers.

  • desktop/main/components/DependencyRequiredModal.vue#L5-L5: restore alt="" for the dependency icon.
  • desktop/main/components/HeaderUserWidget.vue#L6-L6: keep the header avatar decorative with alt="".
  • desktop/main/components/HeaderUserWidget.vue#L30-L30: keep the dropdown avatar decorative with alt="".
  • server/pages/news/[id]/index.vue#L14-L14: keep the blurred banner decorative because the article title is already visible.
  • server/pages/news/index.vue#L38-L38: keep the thumbnail decorative because the card title is already announced.
📍 Affects 4 files
  • desktop/main/components/DependencyRequiredModal.vue#L5-L5 (this comment)
  • desktop/main/components/HeaderUserWidget.vue#L6-L6
  • desktop/main/components/HeaderUserWidget.vue#L30-L30
  • server/pages/news/[id]/index.vue#L14-L14
  • server/pages/news/index.vue#L38-L38
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/main/components/DependencyRequiredModal.vue` at line 5, Restore empty
decorative alt text for the images at
desktop/main/components/DependencyRequiredModal.vue:5-5,
desktop/main/components/HeaderUserWidget.vue:6-6 and :30-30,
server/pages/news/[id]/index.vue:14-14, and server/pages/news/index.vue:38-38.
Keep each image’s existing source and rendering unchanged while using alt="" so
adjacent visible labels are not announced twice.

Comment on lines +398 to +402
<img
class="size-12 flex-none"
:src="useObject(content.iconObjectId)"
:alt="content.name"
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Avoid reusing adjacent visible labels as image alt text.

These images are immediately accompanied by the same text, causing duplicate screen-reader announcements. Use alt="" for decorative images, or a distinct description only when the visual itself conveys additional information.

  • desktop/main/pages/library/[id]/index.vue#L398-L402: make the dependency icon decorative unless it has unique visual meaning.
  • desktop/main/pages/queue.vue#L30-L30: make the cover decorative unless it has a distinct description.
  • server/components/EmulatorWidget.vue#L7-L11: make the emulator icon decorative.
  • sites/promo/src/components/team.tsx#L35-L35: make the avatar decorative.
📍 Affects 4 files
  • desktop/main/pages/library/[id]/index.vue#L398-L402 (this comment)
  • desktop/main/pages/queue.vue#L30-L30
  • server/components/EmulatorWidget.vue#L7-L11
  • sites/promo/src/components/team.tsx#L35-L35
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@desktop/main/pages/library/`[id]/index.vue around lines 398 - 402, Make the
images decorative by replacing their adjacent-name alt text with empty alt
attributes: update the dependency icon in
desktop/main/pages/library/[id]/index.vue (lines 398-402), the cover in
desktop/main/pages/queue.vue (line 30), the emulator icon in
server/components/EmulatorWidget.vue (lines 7-11), and the avatar in
sites/promo/src/components/team.tsx (line 35).

Comment thread server/components/GameEditor/Metadata.vue
Comment thread server/nuxt.config.ts Outdated
Comment on lines +30 to +42
function resolveGitPath(): string {
try {
return execSync("which git", { encoding: "utf-8" }).trim();
} catch {
return "git";
}
}

// get git ref or supply during build
const gitPath = resolveGitPath();
const commitHash =
process.env.BUILD_GIT_REF ??
execSync("git rev-parse --short HEAD").toString().trim();
execSync(`${gitPath} rev-parse --short HEAD`).toString().trim();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== server/nuxt.config.ts ==\n'
wc -l server/nuxt.config.ts
sed -n '1,120p' server/nuxt.config.ts

printf '\n== nginx.ts ==\n'
wc -l server/server/internal/services/services/nginx.ts
sed -n '1,120p' server/server/internal/services/services/nginx.ts

printf '\n== torrential index.ts ==\n'
wc -l server/server/internal/services/torrential/index.ts
sed -n '1,180p' server/server/internal/services/torrential/index.ts

printf '\n== search for similar patterns ==\n'
rg -n 'which\s+[A-Za-z0-9_-]+|execSync\(\$\{.*rev-parse|spawn\(' server -g '!**/dist/**' -g '!**/build/**'

Repository: BillyOutlast/drop

Length of output: 15896


Avoid shell-based executable lookup here. which is invoked via execSync in server/nuxt.config.ts, server/server/internal/services/services/nginx.ts, and server/server/internal/services/torrential/index.ts (including the cargo fallback), and server/nuxt.config.ts then reuses the resolved path in another shell command. Use execFileSync/spawn with fixed args and a trusted absolute path or allowlist instead.

🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis

[warning] 32-32: Make sure the "PATH" variable only contains fixed, unwriteable directories.

See more on https://sonarcloud.io/project/issues?id=BillyOutlast_drop&issues=AZ-g5IiU6u5EiuulU7CS&open=AZ-g5IiU6u5EiuulU7CS&pullRequest=104

🪛 OpenGrep (1.25.0)

[ERROR] 42-42: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

📍 Affects 3 files
  • server/nuxt.config.ts#L30-L42 (this comment)
  • server/server/internal/services/services/nginx.ts#L7-L12
  • server/server/internal/services/torrential/index.ts#L96-L104
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/nuxt.config.ts` around lines 30 - 42, Replace shell-based executable
discovery in resolveGitPath and the corresponding lookup logic in
server/nuxt.config.ts (lines 30-42),
server/server/internal/services/services/nginx.ts (lines 7-12), and
server/server/internal/services/torrential/index.ts (lines 96-104), including
the cargo fallback, with execFileSync or spawn using fixed arguments and a
trusted absolute executable path or allowlist. In server/nuxt.config.ts, also
stop interpolating the resolved path into a shell command and invoke git with
fixed arguments.

Source: Linters/SAST tools

Comment thread server/server/internal/services/torrential/index.ts Outdated
Comment thread server/server/internal/services/torrential/utils.ts
Comment thread server/server/internal/session/cache.ts Outdated
Comment on lines +70 to +101
function sessionMatchesFilter(
session: SessionWithToken,
options: SessionSearchTerms,
): boolean {
if (
options.userId &&
session.authenticated &&
session.authenticated.userId !== options.userId
) {
return false;
}

if (options.oidc && session.oidc) {
for (const [key, value] of Object.entries(options.oidc)) {
if (
JSON.stringify(
(session.oidc as unknown as Record<string, unknown>)[key],
) !== JSON.stringify(value)
) {
return false;
}
}
}

for (const [key, value] of Object.entries(options.data || {})) {
if (JSON.stringify(session.data[key]) !== JSON.stringify(value)) {
return false;
}
}

return true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

sessionMatchesFilter fails to exclude sessions missing the filtered field, in both in-memory session providers. In both cache.ts and memory.ts, the oidc check only runs its mismatch loop if (options.oidc && session.oidc) and the userId check only returns false when session.authenticated is truthy — so when a session lacks that field entirely, it silently "passes" the filter instead of being excluded. OIDCManager.handleLogout searches sessions by oidc alone (no userId) to sign out on backchannel logout; with either in-memory provider active, this would also match and destroy every unrelated non-OIDC session, unlike db.ts's Prisma JSON-path filters, which correctly require the path to exist.

  • server/server/internal/session/cache.ts#L70-L101: change the userId and oidc guards to return false when session.authenticated/session.oidc is missing but the corresponding filter is specified.
  • server/server/internal/session/memory.ts#L59-L90: apply the identical fix to this file's copy of sessionMatchesFilter.
📍 Affects 2 files
  • server/server/internal/session/cache.ts#L70-L101 (this comment)
  • server/server/internal/session/memory.ts#L59-L90
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/server/internal/session/cache.ts` around lines 70 - 101, Update
sessionMatchesFilter in server/server/internal/session/cache.ts (lines 70-101)
and server/server/internal/session/memory.ts (lines 59-90) so specified userId
and oidc filters return false when the session lacks authenticated or oidc data;
retain the existing mismatch checks for present fields and leave unrelated data
filtering unchanged.

Comment thread server/test/unit/prioritylist.test.ts Outdated
className="relative m-8 transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all data-closed:translate-y-4 data-closed:opacity-0 data-enter:duration-300 data-enter:ease-out data-leave:duration-200 data-leave:ease-in data-closed:sm:translate-y-0 data-closed:sm:scale-95"
>
<img src={img} alt="" className="max-h-[90vh] w-full" />
<img src={img} alt="Gallery image" className="max-h-[90vh] w-full" />

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use a meaningful description for the enlarged image.

alt="Gallery image" is generic and does not describe the image content. Pass caller-provided alt text, or use alt="" if the image is decorative.

🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis

[warning] 135-135: Redundant alt attribute. Screen-readers already announce img tags as an image. You don’t need to use the words image, photo, or picture (or any specified custom words) in the alt prop.

See more on https://sonarcloud.io/project/issues?id=BillyOutlast_drop&issues=AZ-g5Ii36u5EiuulU7CT&open=AZ-g5Ii36u5EiuulU7CT&pullRequest=104

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@sites/promo/src/components/gallery-modal.tsx` at line 135, Update the
enlarged image in the gallery modal to use caller-provided descriptive alt text
instead of the generic "Gallery image" value; if the image is decorative, set
its alt text to empty. Trace the component’s props or image data to reuse the
existing alt-text symbol.

Source: Linters/SAST tools

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Note

Unit test generation is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.


Generating unit tests... This may take up to 20 minutes.

John Smith added 2 commits July 26, 2026 20:22
- steam.ts: Support single-quoted metadata attributes in regex
- client/authorize: Fix form action mismatch, use type="hidden"
- session: Extract shared sessionMatchesFilter to filter.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/server/internal/session/filter.ts`:
- Around line 14-32: Update the session predicate’s userId and oidc checks so a
requested criterion fails when the corresponding session.authenticated or
session.oidc field is absent. Use optional chaining while preserving the
existing userId comparison and per-key OIDC JSON comparison for present fields,
returning false for either missing identity object.
- Around line 23-38: Replace the JSON.stringify comparison in the
SessionSearchTerms.data filtering loop with a structural deep-equality check so
nested objects match regardless of key order. Keep the existing false return for
unequal values and add a regression test covering equivalent data with reordered
nested object keys.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 862e20c1-6fbd-4559-8432-d2379ada482c

📥 Commits

Reviewing files that changed from the base of the PR and between b416dde and 5c38e81.

📒 Files selected for processing (5)
  • server/pages/client/authorize/[id].vue
  • server/server/internal/metadata/steam.ts
  • server/server/internal/session/cache.ts
  • server/server/internal/session/filter.ts
  • server/server/internal/session/memory.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • server/pages/client/authorize/[id].vue
  • server/server/internal/metadata/steam.ts
  • server/server/internal/session/cache.ts

Comment thread server/server/internal/session/filter.ts Outdated
Comment on lines +23 to +38
for (const [key, value] of Object.entries(options.oidc)) {
if (
JSON.stringify(
(session.oidc as unknown as Record<string, unknown>)[key],
) !== JSON.stringify(value)
) {
return false;
}
}
}

for (const [key, value] of Object.entries(options.data || {})) {
if (JSON.stringify(session.data[key]) !== JSON.stringify(value)) {
return false;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
rg -nP '\b(isDeepStrictEqual|deepEqual|fast-deep-equal|JSON\.stringify)\b' server/server/internal

Repository: BillyOutlast/drop

Length of output: 2061


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== file outline =="
ast-grep outline server/server/internal/session/filter.ts --view expanded || true

echo
echo "== file contents =="
cat -n server/server/internal/session/filter.ts

echo
echo "== session-related files =="
git ls-files 'server/server/internal/session/*'

Repository: BillyOutlast/drop

Length of output: 1870


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== session types =="
cat -n server/server/internal/session/types.d.ts

echo
echo "== session implementations using sessionMatchesFilter =="
rg -n "sessionMatchesFilter|SearchTerms|deepStrictEqual|isDeepStrictEqual|fast-deep-equal|lodash\.isEqual" server/server/internal/session

echo
echo "== tests mentioning session filter =="
rg -n "sessionMatchesFilter|session.*filter|SearchTerms|oidc|data" server --glob '*test*' --glob '*spec*'

Repository: BillyOutlast/drop

Length of output: 15654


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

node <<'JS'
const a = { nested: { x: 1, y: 2 } };
const b = { nested: { y: 2, x: 1 } };

console.log("JSON.stringify(a.nested) =", JSON.stringify(a.nested));
console.log("JSON.stringify(b.nested) =", JSON.stringify(b.nested));
console.log("stringify equal?", JSON.stringify(a.nested) === JSON.stringify(b.nested));

function sessionMatchesFilter(session, options) {
  for (const [key, value] of Object.entries(options.data || {})) {
    if (JSON.stringify(session.data[key]) !== JSON.stringify(value)) {
      return false;
    }
  }
  return true;
}

console.log(
  "filter result with reordered nested object =",
  sessionMatchesFilter(
    { data: { payload: a.nested } },
    { data: { payload: b.nested } },
  ),
);
JS

Repository: BillyOutlast/drop

Length of output: 311


Use structural equality for SessionSearchTerms.data
JSON.stringify can miss equivalent nested values when object key order differs, so session searches on data can false-negative. Use a deep comparator or canonicalize keys, and add a regression test for reordered nested objects.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/server/internal/session/filter.ts` around lines 23 - 38, Replace the
JSON.stringify comparison in the SessionSearchTerms.data filtering loop with a
structural deep-equality check so nested objects match regardless of key order.
Keep the existing false return for unequal values and add a regression test
covering equivalent data with reordered nested object keys.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Request timed out after 900000ms (requestId=9d5a84ed-f9a4-4d0a-ae79-86482ead164f)

John Smith added 3 commits July 26, 2026 20:43
- EmulatorWidget.vue, team.tsx: Use empty alt for decorative images
- GameEditor/Metadata.vue: Improve alt text for game screenshots
- nuxt.config.ts: Use execFileSync with fixed arguments
- store/t/[id]/index.vue: Remove empty src image
- auth/oidc/index.ts: Make userinfo_endpoint and scopes_supported optional
- torrential/index.ts: Add executable check before spawn
- torrential/utils.ts: Update JSDoc return description
- prioritylist.test.ts: Remove performance assertion, add behavioral check
@BillyOutlast

Copy link
Copy Markdown
Owner Author

SonarCloud Quality Gate Analysis

The quality gate failure is due to two conditions:

1. Coverage on New Code (0.0% required ≥ 80%)

This is expected given the codebase's 1.17% baseline coverage. As documented in AGENTS.md:

At 1.17% baseline, ANY new uncovered code drops percentage and blocks every PR.

2. Security Rating on New Code (B required ≥ A)

The security issues flagged are pre-existing in the codebase, not introduced by this PR:

File Issue Status
for git (safer than ) False positive - using fixed arguments
HTTP URL in type definition Pre-existing - standard OIDC schema URL
PATH variable issues Pre-existing code, not modified

Recommendation

These security issues should be addressed in a separate PR focused on security hardening. The current PR improves security by:

  • Using with fixed arguments instead of with string interpolation
  • Adding executable checks before spawning local binaries
  • Making OIDC type definitions more flexible

The quality gate can be overridden by a repository admin.

… but missing

- userId check: return false when session.authenticated is absent
- oidc check: return false when session.oidc is absent
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)
B Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant