* fix(#663): resolve open CodeQL/Dependabot security alerts
- ReDoS: collapse ambiguous nested quantifiers in phase-heading regexes
(verify/validate/commands) and the plan-filename lookahead (phase) to
provably-equivalent non-backtracking forms
- prototype pollution: guard __proto__/constructor/prototype in setConfigValue
- remove dead no-op .replace(/-/g,'-') in phase.cts
- escape all regex metachars in bug-2839 test
- add contents:read permissions to security-scan + install-smoke workflows
- pin qs >= 6.15.2 via overrides (DoS GHSA)
- broaden prompt-injection allowlist to translated security-model docs
Closes#663
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(#663): regression tests for prototype-pollution guard and roadmap-phase ReDoS
Behavioral test that config-set rejects __proto__/constructor/prototype keys
without polluting Object.prototype, plus a ReDoS guard (timing-bound) and
behavior-preservation assertions for the collapsed phase-heading regexes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(#663): make ReDoS regression assert structured result, not elapsed time
Replace elapsed-time assertions (which tripped local/no-elapsed-assertion
ESLint rule and were unsound for synchronous ReDoS) with structured-result
assertions on adversarial inputs: assert that malformed phase headings/
unchecked-item lines without a terminating colon/space yield an empty Set,
which is both the correct behavior and an exercise of the fixed linear regex
on the catastrophic-backtracking input shape.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#663): add Security changeset fragment for #665
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(#663): fold prototype-pollution regression into config.test.cjs
The standalone bug-663-config-prototype-pollution.test.cjs was a 9th
config-module test file, tripping lint-test-file-count (the allowlist is
ratcheted and must not grow). Consolidated into config.test.cjs instead.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Two windows-only failure clusters surfaced when the chunking fix in
52f23ac0 made Windows tests actually run:
1) Cleanup EBUSY race. On Windows, fs.rmSync without {maxRetries,retryDelay}
races against AV scanners / file-indexers / just-exited child processes
that still hold handles when teardown fires. Surfaces as
EBUSY: resource busy or locked, rmdir 'C:\Users\...\AppData\Local\Temp\gsd-...'
in bug-1736, bug-2248, bug-2698, bug-2838, and every test routing through
the shared tests/helpers.cjs cleanup() (≈170 consumers — bug-2774 et al).
Fix: add {maxRetries: 10, retryDelay: 100} to the shared helper plus the
four inline cleanup sites. On POSIX the retry loop is dead code (first
try succeeds), so no impact on ubuntu/macos.
2) bug-2839 had a local parseFrontmatter that anchored on /^---\n/ — on a
Windows checkout with autocrlf=true the file content is CRLF, the regex
never matches, the function returns null, and the before() hook asserts
"agent must have YAML frontmatter" → entire suite cancels. The shared
tests/helpers.cjs parseFrontmatter is already CRLF-aware (split /\r?\n/);
switch to it.
Validated: plex2 (ubuntu docker) 11224/0 pass post-patch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(#2839): make /gsd-code-review-fix cleanup transactional
Cleanup tail in agents/gsd-code-fixer.md previously did 'git worktree
remove' without any recovery marker. If the process was killed between
fix commits and worktree removal, the orphan worktree + branch survived
with no resume path — the next run had no way to discover or finish
the cleanup.
Introduce a recovery sentinel at ${phase_dir}/.review-fix-recovery-pending.json
with strict ordering:
- Sentinel written AFTER 'git worktree add' succeeds (never points at a
worktree that does not exist).
- Sentinel removed ONLY AFTER 'git worktree remove' returns successfully
(interruption between commits and removal leaves a sentinel behind).
- New runs detect a pre-existing sentinel, force-remove the recorded
orphan worktree, then drop the stale sentinel before continuing —
making the agent self-healing after a crash.
Closes#2839
* fix(#2839): harden sentinel JSON parse and scope ordering assertion
Address CodeRabbit review feedback on PR #2846:
- agents/gsd-code-fixer.md: Guard the recovery-sentinel JSON parse with
try/catch so a corrupted/truncated sentinel (a realistic crash artifact)
emits a warning and yields an empty prior_wt instead of aborting setup.
This preserves the self-healing recovery path even when the sentinel
itself is the casualty of the original crash.
- tests/bug-2839-review-fix-transactional-cleanup.test.cjs: Scope the
cleanup-ordering assertion to the cleanup-tail section of the
setup_worktree step rather than first global occurrences. Previously
the assertion could pass on pre-recovery references even if cleanup-tail
ordering regressed. The regex also now accepts the shell-variable form
(\`rm -f \"\$sentinel\"\`) used in the cleanup tail.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>