Summary
The plan_load_dod handler (introduced in PR #395, issue #388) defines its repo parameter as a bare z.string().optional() with no regex validation. This is inconsistent with every other handler in the codebase, which use repoOptionalSchema from lib/schemas/repo.ts.
The handler passes args.repo straight into getAdapter({ repo: args.repo }) and then into adapter.fetchIssue({ number: args.plan_id, repo: args.repo }). The GitHub adapter has its own GITHUB_REPO_SLUG adapter-level check, but the GitLab adapter path runs through glab api projects/<url-encoded-slug>/issues/N string concatenation. An unvalidated repo value containing shell metacharacters or path traversal could be passed to execSync via the glab command string.
The schema layer is the documented first line of defence for adapter inputs.
Implementation Steps
-
Update handlers/plan_load_dod.ts line 17 (current input schema):
const inputSchema = z.object({
plan_id: z.number().int().positive(),
repo: z.string().optional(),
});
Replace with:
import { repoOptionalSchema } from '../lib/schemas/repo.js';
// ...
const inputSchema = z.object({
plan_id: z.number().int().positive(),
repo: repoOptionalSchema,
});
-
Add a test case asserting that malformed repo values are rejected at the handler boundary (e.g. repo: '../../../etc/passwd', repo: 'foo;bar', repo: '').
-
Add a test case asserting valid GitLab nested groups are accepted.
Test Procedures
- Run the existing
plan_load_dod test suite — all should still pass.
- Add new test cases covering shell metacharacters, path traversal, and nested groups.
- Verify error messages match the shared
REPO_SLUG_ERROR constant.
Acceptance Criteria
Dependencies
Metadata
| Field |
Value |
| Repository |
Wave-Engineering/mcp-server-sdlc |
| Surfaced by |
code-reviewer trust-score gate (plan #390) |
Summary
The
plan_load_dodhandler (introduced in PR #395, issue #388) defines itsrepoparameter as a barez.string().optional()with no regex validation. This is inconsistent with every other handler in the codebase, which userepoOptionalSchemafromlib/schemas/repo.ts.The handler passes
args.repostraight intogetAdapter({ repo: args.repo })and then intoadapter.fetchIssue({ number: args.plan_id, repo: args.repo }). The GitHub adapter has its ownGITHUB_REPO_SLUGadapter-level check, but the GitLab adapter path runs throughglab api projects/<url-encoded-slug>/issues/Nstring concatenation. An unvalidatedrepovalue containing shell metacharacters or path traversal could be passed toexecSyncvia the glab command string.The schema layer is the documented first line of defence for adapter inputs.
Implementation Steps
Update
handlers/plan_load_dod.tsline 17 (current input schema):Replace with:
Add a test case asserting that malformed
repovalues are rejected at the handler boundary (e.g.repo: '../../../etc/passwd',repo: 'foo;bar',repo: '').Add a test case asserting valid GitLab nested groups are accepted.
Test Procedures
plan_load_dodtest suite — all should still pass.REPO_SLUG_ERRORconstant.Acceptance Criteria
handlers/plan_load_dod.tsimports and usesrepoOptionalSchemaz.string()removed forrepofieldplan_load_dodtests still passREPO_SLUG_ERRORconstantDependencies
Metadata