test: add missing tag key/value path traversal tests (#412)#417
Conversation
…#412) PR #403 added assertPathContained() validation for tagKey and tagValue in indexTagBasedData(), but tests were skipped because the test helper lacked a UnifiedDataRepository stub. This left the security checks for custom tag keys and values without regression coverage — a silent failure risk if the re-throw guard in the catch block or the assertPathContained calls were ever removed or broken. This commit closes the gap by: - Extending createIndexService() to accept an optional UnifiedDataRepository, allowing tag-based data indexing to be exercised in tests. - Adding a minimal createStubUnifiedDataRepo() that returns controlled Data items from findAllForModel() (with listVersions returning [] so the standard type-tag loop completes without side effects). - Adding two test cases that inject Data items with malicious path traversal strings ("../../../malicious") as a custom tag key and tag value respectively, and assert that handleModelCreated rejects with "Path traversal detected". Both tests also implicitly verify the re-throw guard in the catch block of indexTagBasedData(), since the error must propagate through the try-catch to reach assertRejects. Closes #412
There was a problem hiding this comment.
Review Summary
This PR adds two important security tests for path traversal protection in indexTagBasedData(). The tests close a coverage gap identified in #412 by verifying that the assertPathContained() checks added in PR #403 work correctly for custom tag keys and tag values.
Blocking Issues
None.
Code Quality Assessment
✅ TypeScript strict mode: No any types; proper type imports used (type UnifiedDataRepository)
✅ Code style (CLAUDE.md): Named exports used, copyright header present, tests follow foo.ts → foo_test.ts pattern
✅ Domain-driven design:
SymlinkRepoIndexServicecorrectly positioned in infrastructure layerUnifiedDataRepositoryfollows repository patternDataentity used correctly with factory method
✅ Test coverage:
- Tests verify path traversal protection for malicious tag keys (
"../../../malicious": "value") - Tests verify path traversal protection for malicious tag values (
"safe-key": "../../../malicious") - Tests implicitly verify the re-throw guard in the catch block (lines 585-593)
✅ Security: These tests prevent silent regressions in critical path traversal protection code
Test Design Review
The stub implementation is well-designed:
findAllForModel()returns controlled test datalistVersions()returns[]which is correct since path traversal checks occur beforelistVersionsis called- Other methods throw
"not implemented"which is appropriate for a focused test stub
The test flow correctly validates:
- Malicious tag key →
assertPathContained()throws at line 547-551 - Malicious tag value →
assertPathContained()throws at line 556-560 - Path traversal errors propagate through the catch block re-throw guard (lines 588-590)
CI Status
✅ Lint, Test, and Format Check: passed
LGTM! 🔒
Summary
tagKeyandtagValuevalidation inindexTagBasedData(), closing the test coverage gap identified in test: add missing tag key/value path traversal test vectors for symlink_repo_index_service #412createIndexService()test helper to accept an optionalUnifiedDataRepositorystubcreateStubUnifiedDataRepo()helper that returns controlledDataitems for testing tag-based indexingContext
PR #403 added
assertPathContained()checks for custom tag keys and tag values insideindexTagBasedData(), but explicitly skipped writing tests because the test helper had no way to inject aUnifiedDataRepository. Without tests, regressions in these security checks (e.g., accidentally removing the re-throw guard in thecatchblock, or removing theassertPathContainedcalls) would be completely silent.What the tests verify
Test 1 — malicious tag key: Creates a
Dataitem with tag{ "type": "resource", "../../../malicious": "value" }. Asserts thathandleModelCreated→indexModel→indexTagBasedDatarejects with"Path traversal detected"when the tag key would escape the model directory.Test 2 — malicious tag value: Creates a
Dataitem with tag{ "type": "resource", "safe-key": "../../../malicious" }. Asserts the same rejection when the tag value would escape the tag key directory.Both tests also implicitly verify the re-throw guard in the
catchblock ofindexTagBasedData(), since the error must propagate throughtry-catchto reachassertRejects.Test plan
deno run test src/infrastructure/repo/symlink_repo_index_service_test.ts— 19/19 passdeno run test— full suite 1809/1809 passdeno check— passesdeno lint— passesdeno fmt --check— passesCloses #412
🤖 Generated with Claude Code