fix(web): enforce project prefix boundaries#1601
Conversation
Test Coverage ReportChanged files have no coverage data (not instrumented or no tests ran). |
Greptile SummaryThis PR fixes a prefix-boundary bug where a session like Confidence Score: 5/5Safe to merge — the fix is minimal, well-tested, and correctly scoped. All findings are P2. The logic change is correct and both affected code paths are covered by new regression tests. The only remaining concern is that No files require special attention.
|
| Filename | Overview |
|---|---|
| packages/web/src/lib/project-utils.ts | Adds matchesSessionPrefix helper and applies it in matchesProject; correctly guards with project?.sessionPrefix && since local ProjectWithPrefix type marks the field optional. |
| packages/web/src/lib/serialize.ts | Adds an identical matchesSessionPrefix helper and applies it in resolveProject; ProjectConfig.sessionPrefix is non-optional so no null-guard needed, but the function is a duplicate of the one in project-utils.ts. |
| packages/web/src/lib/tests/project-utils.test.ts | New test file; adds regression coverage for the app / appx prefix-containment bug in filterProjectSessions. |
| packages/web/src/lib/tests/serialize.test.ts | Adds a regression test for resolveProject that verifies appx-1 resolves to the appx project and not app; also imports the previously-unused enrichSessionIssue. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["Session ID: appx-1\nprojectId: unknown"] --> B{Direct projectId\nmatch in projects?}
B -- No --> C{matchesSessionPrefix\nfor each project}
C --> D["app: 'appx-1' === 'app'?\nOR 'appx-1'.startsWith('app-')?"]
D -- "false / false → NO MATCH" --> E["appx: 'appx-1' === 'appx'?\nOR 'appx-1'.startsWith('appx-')?"]
E -- "false / true → MATCH" --> F["✅ Resolves to appx project"]
B -- Yes --> G["✅ Return direct match"]
style D fill:#f9c,stroke:#c66
style E fill:#cfc,stroke:#6a6
style F fill:#cfc,stroke:#6a6
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
packages/web/src/lib/serialize.ts:44-46
**Duplicated helper across modules**
`matchesSessionPrefix` is now defined identically in both `serialize.ts` and `project-utils.ts`. If the boundary-matching logic ever needs to change again (e.g. supporting slash-delimited prefixes or case-insensitive matching), it will need to be updated in two places — exactly the kind of drift that caused the original bug. Consider extracting it to a shared utility (e.g. `lib/session-utils.ts`) and importing it in both files.
Reviews (1): Last reviewed commit: "fix(qa): ISSUE-001 — enforce project pre..." | Re-trigger Greptile
|
This fixes a QA-discovered dashboard regression, not an existing GitHub issue. It is related to multi-project prefix handling, but distinct from #1323 / #1356:
|
90a64a9 to
06c5519
Compare
i-trytoohard
left a comment
There was a problem hiding this comment.
Review: fix(web): enforce project prefix boundaries
Fix is correct — startsWith('app') matching appx-1 was a real prefix containment bug. The sessionId === prefix || sessionId.startsWith(prefix + "-") logic is right, and both affected code paths are updated consistently. Tests cover both paths. No security or perf concerns.
Actionable items
-
P2 — Duplicated helper.
matchesSessionPrefixis copy-pasted identically into bothserialize.tsandproject-utils.ts. This is the same drift pattern that caused the original bug. Recommend extracting to a shared utility (e.g.lib/session-utils.ts) and importing in both places. -
P3 — Unused import.
enrichSessionIssueis imported inserialize.test.tsbut never used — minor lint noise, worth cleaning up.
Approved. Consolidate that helper before or right after merge.
P2 is correct. packages/web/src/lib/serialize.ts P3 is not correct. enrichSessionIssue(dashboard, tracker, testProject); |
Summary
Tests