fix(#2119): single SECURITY.md writer — auditor is return-only (#2154)

* fix(2119): single SECURITY.md writer — auditor is return-only

The gsd-security-auditor held Write/Edit and was instructed to write
SECURITY.md (no <N>- prefix, no template frontmatter), while the
orchestrator's Step 6 also wrote the correct padded <N>-SECURITY.md
from templates/SECURITY.md. Two writers, two naming conventions, two
shapes — the auditor's unprefixed file was invisible to the workflow's
*-SECURITY.md glob detector and unparseable for the threats_open gate.

Fix (option 1 from the issue): make the auditor return-only.
- Remove Write/Edit from auditor's tools
- Rewrite all 'Write SECURITY.md' instructions to 'Return structured
  verdict' with threats_open count
- Add explicit constraint in workflow Step 5 spawn prompt
- Update existing test (was asserting Write in tools — now asserts absence)
- Add new regression test for single-writer contract
- Update docs/AGENTS.md stale Tools/Produces rows
- Regenerate golden fixtures + agent size baseline

* docs(changeset): backfill PR number (#2154)

* chore(#2119): regenerate pi/qwen golden fixtures after next merge

The single-writer change edits gsd-core/workflows/secure-phase.md and
agents/gsd-security-auditor.md; pi.json (added on next) and qwen.json (merge
straggler) were the only runtime fixtures still holding pre-change hashes for
those files. All other runtimes already reflect the change. Regenerated via
the sanctioned gen-golden-install-parity script.

* merge origin/next — regenerate goldens + baseline for merged state

* fix slash-command syntax: /gsd-secure-phase → /gsd:secure-phase (#2154 CI fix)
This commit is contained in:
Tom Boucher
2026-07-13 00:47:15 -04:00
committed by GitHub
parent 5867996a6a
commit b5ce72f729
26 changed files with 140 additions and 61 deletions

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2154
---
**`/gsd-secure-phase` now has a single SECURITY.md writer** — the `gsd-security-auditor` subagent previously held `Write`/`Edit` tools and was instructed to "write SECURITY.md" with no padded `<N>-` prefix and no template frontmatter, while the orchestrator's Step 6 also wrote the phase-scoped `<N>-SECURITY.md` from `templates/SECURITY.md`. The auditor is now return-only (drops `Write`/`Edit`, returns a structured verdict with `threats_open`); the orchestrator is the sole file writer. The workflow's Step 5 spawn constraints explicitly forbid the auditor from writing SECURITY.md. (#2119)

View File

@@ -1,10 +1,8 @@
---
name: gsd-security-auditor
description: Verifies threat mitigations from PLAN.md threat model exist in implemented code. Produces SECURITY.md. Spawned by /gsd:secure-phase.
description: Verifies threat mitigations from PLAN.md threat model exist in implemented code. Returns structured security verdict (SECURED / OPEN_THREATS / ESCALATE). Spawned by /gsd:secure-phase.
tools:
- Read
- Write
- Edit
- Bash
- Glob
- Grep
@@ -15,11 +13,11 @@ color: red
<role>
An implemented phase has been submitted for security audit. Verify that every declared threat mitigation is present in the code — do not accept documentation or intent as evidence.
Does NOT scan blindly for new vulnerabilities. Verifies each threat in `<threat_model>` by its declared disposition (mitigate / accept / transfer). Reports gaps. Writes SECURITY.md.
Does NOT scan blindly for new vulnerabilities. Verifies each threat in `<threat_model>` by its declared disposition (mitigate / accept / transfer). Reports gaps. Returns a structured verdict — the orchestrator owns the SECURITY.md file write (#2119: single-writer contract).
**Mandatory Initial Read:** If prompt contains `<required_reading>`, load ALL listed files before any action.
**Implementation files are READ-ONLY.** Only create/modify: SECURITY.md. Implementation security gaps → OPEN_THREATS or ESCALATE. Never patch implementation.
**Implementation files are READ-ONLY.** The auditor does NOT write any files — it returns a structured verdict (SECURED / OPEN_THREATS / ESCALATE). The orchestrator persists SECURITY.md. Implementation security gaps → OPEN_THREATS or ESCALATE. Never patch implementation.
</role>
<adversarial_stance>
@@ -79,20 +77,20 @@ Classify each threat before verification. Record classification for every threat
- L3: deep trace — follow the data flow end-to-end, check edge cases and ordering, confirm no bypass path exists.
</step>
<step name="verify_and_write">
<step name="verify_and_return">
For each `mitigate` threat: grep for declared mitigation pattern in cited files → found = `CLOSED`, not found = `OPEN`. Apply depth per `asvs_level` (see analyze_threats step).
For `accept` threats: check SECURITY.md accepted risks log → entry present = `CLOSED`, absent = `OPEN`.
For `accept` threats: check existing SECURITY.md accepted risks log → entry present = `CLOSED`, absent = `OPEN`.
For `transfer` threats: check for transfer documentation → present = `CLOSED`, absent = `OPEN`.
For each `threat_flag` in SUMMARY.md `## Threat Flags`: if maps to existing threat ID → informational. If no mapping → log as `unregistered_flag` in SECURITY.md (not a blocker).
For each `threat_flag` in SUMMARY.md `## Threat Flags`: if maps to existing threat ID → informational. If no mapping → log as `unregistered_flag` in the structured return (not a blocker).
**Severity-aware `threats_open` computation (severity order: critical > high > medium > low):**
`threats_open` (the SECURITY.md frontmatter gate field) = the count of threats whose status is OPEN AND whose severity rank ≥ the `block_on` rank. `block_on: none` ⇒ 0 (nothing ever blocks). `block_on: low` ⇒ all open threats block. `block_on: high` (default) ⇒ only high and critical open threats block.
Open threats BELOW the block threshold are recorded in SECURITY.md as **open — below {block_on} threshold (non-blocking)** and MUST NOT be counted in `threats_open`.
Open threats BELOW the block threshold are recorded in the return as **open — below {block_on} threshold (non-blocking)** and MUST NOT be counted in `threats_open`.
**Fail-closed for missing severity:** if an OPEN threat has no severity or an unparseable severity (e.g. a legacy register predating the Severity column), treat it as `critical` for this computation — it COUNTS toward `threats_open` (blocking). Never silently drop an unranked open threat.
Write SECURITY.md. Set `threats_open` to the severity-filtered count. Return structured result.
Return the structured result (SECURED / OPEN_THREATS / ESCALATE) with `threats_open` set to the severity-filtered count. The orchestrator writes SECURITY.md from this data — the auditor does NOT write any files (#2119).
</step>
</execution_flow>
@@ -116,7 +114,7 @@ Write SECURITY.md. Set `threats_open` to the severity-filtered count. Return str
### Unregistered Flags
{none / list from SUMMARY.md ## Threat Flags with no threat mapping}
SECURITY.md: {path}
**threats_open:** {count}
```
## OPEN_THREATS
@@ -145,9 +143,9 @@ SECURITY.md: {path}
*Only blocking-open threats count toward `threats_open` in SECURITY.md frontmatter.*
Next: Implement mitigations or document as accepted in SECURITY.md accepted risks log, then re-run /gsd:secure-phase.
Next: Implement mitigations or document as accepted risks, then re-run /gsd:secure-phase.
SECURITY.md: {path}
**threats_open:** {count}
```
## ESCALATE
@@ -172,6 +170,6 @@ SECURITY.md: {path}
- [ ] Each threat verified by disposition type (mitigate / accept / transfer)
- [ ] Threat flags from SUMMARY.md `## Threat Flags` incorporated
- [ ] Implementation files never modified
- [ ] SECURITY.md written to correct path
- [ ] Structured return: SECURED / OPEN_THREATS / ESCALATE
- [ ] No files written — structured verdict returned only (orchestrator writes SECURITY.md)
- [ ] Structured return: SECURED / OPEN_THREATS / ESCALATE with `threats_open` count
</success_criteria>

View File

@@ -479,10 +479,10 @@ Communication style, decision patterns, debugging approach, UX preferences, vend
|----------|-------|
| **Spawned by** | `/gsd-secure-phase` |
| **Parallelism** | Single instance |
| **Tools** | Read, Write, Edit, Bash, Glob, Grep |
| **Tools** | Read, Bash, Glob, Grep |
| **Model (balanced)** | Sonnet |
| **Color** | Red |
| **Produces** | `{phase}-SECURITY.md` |
| **Produces** | Structured verdict (SECURED / OPEN_THREATS / ESCALATE) — orchestrator writes `{phase}-SECURITY.md` (#2119) |
**Key behaviors:**
- Verifies each threat by its declared disposition (mitigate / accept / transfer)

View File

@@ -108,7 +108,7 @@ Agent(
"<files_to_read>{PLAN, SUMMARY, impl files, SECURITY.md}</files_to_read>" +
"<threat_register>{threat register}</threat_register>" +
"<config>asvs_level: {SECURITY_ASVS}, block_on: {SECURITY_BLOCK_ON}</config>" +
"<constraints>Never modify implementation files. Verify mitigations exist — do not scan for new threats. Escalate implementation gaps.</constraints>" +
"<constraints>Never modify implementation files. Verify mitigations exist — do not scan for new threats. Escalate implementation gaps. Return a structured verdict only — do NOT write SECURITY.md (the orchestrator owns the file write).</constraints>" +
"${AGENT_SKILLS_AUDITOR}",
subagent_type="gsd-security-auditor",
model="{AUDITOR_MODEL}",

View File

@@ -27,7 +27,7 @@
"gsd-project-researcher.md": 22242,
"gsd-research-synthesizer.md": 13847,
"gsd-roadmapper.md": 22273,
"gsd-security-auditor.md": 8981,
"gsd-security-auditor.md": 9431,
"gsd-ui-auditor.md": 17249,
"gsd-ui-checker.md": 14118,
"gsd-ui-researcher.md": 19557,

View File

@@ -29,7 +29,7 @@
"agents/gsd-project-researcher.md": "85de7f562872ee9b",
"agents/gsd-research-synthesizer.md": "18a2e1b30ff7ae3a",
"agents/gsd-roadmapper.md": "7a8465ac6d4dd29e",
"agents/gsd-security-auditor.md": "2ce13af25179dd10",
"agents/gsd-security-auditor.md": "7730a026680cb821",
"agents/gsd-ui-auditor.md": "f777f9c7bf62788c",
"agents/gsd-ui-checker.md": "216af34b01e277aa",
"agents/gsd-ui-researcher.md": "5f86de1decbd16d2",
@@ -287,7 +287,7 @@
"gsd-core/workflows/resume-project.md": "98e2cf8908e73a52",
"gsd-core/workflows/review.md": "43c052bba1cbd4ac",
"gsd-core/workflows/scan.md": "a7fecd67e5cd655f",
"gsd-core/workflows/secure-phase.md": "96b199dfac00e60f",
"gsd-core/workflows/secure-phase.md": "52ddc46233e8fa66",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "6d25100a9de15b31",
"gsd-core/workflows/settings-integrations.md": "4d3001ad2b5dad8f",

View File

@@ -29,7 +29,7 @@
"agents/gsd-project-researcher.md": "4531b7cc8f5e5f7d",
"agents/gsd-research-synthesizer.md": "4a4f68e6c75b133a",
"agents/gsd-roadmapper.md": "bb2f57695dbab32c",
"agents/gsd-security-auditor.md": "f22374cc1db28dca",
"agents/gsd-security-auditor.md": "4db2c41181ad1f97",
"agents/gsd-ui-auditor.md": "dcd5712e6b160a53",
"agents/gsd-ui-checker.md": "5c27ec0d88ef87c2",
"agents/gsd-ui-researcher.md": "bcc591f2dfebdb60",
@@ -358,7 +358,7 @@
"gsd-core/workflows/resume-project.md": "f28da1200e4545f4",
"gsd-core/workflows/review.md": "ad7c0f372ed986ae",
"gsd-core/workflows/scan.md": "003883d71c37da7d",
"gsd-core/workflows/secure-phase.md": "29fc6b62c5c5dc62",
"gsd-core/workflows/secure-phase.md": "22ab3bb5da494ea7",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "414db4dbea97ba44",
"gsd-core/workflows/settings-integrations.md": "70515c5838fb9826",

View File

@@ -28,7 +28,7 @@
"agents/gsd-project-researcher.md": "d7f355894519f9fe",
"agents/gsd-research-synthesizer.md": "1c738df9932d325a",
"agents/gsd-roadmapper.md": "453e9471ad27c7ea",
"agents/gsd-security-auditor.md": "45bd98918cd3a004",
"agents/gsd-security-auditor.md": "4551e5f621cf13ff",
"agents/gsd-ui-auditor.md": "a0b09cc8e4645956",
"agents/gsd-ui-checker.md": "33ffdc73d2105a24",
"agents/gsd-ui-researcher.md": "4b36852c839f1134",
@@ -357,7 +357,7 @@
"gsd-core/workflows/resume-project.md": "af9761bcec0f6fe9",
"gsd-core/workflows/review.md": "eec3a15bebb7fcf0",
"gsd-core/workflows/scan.md": "75c670d08cee8680",
"gsd-core/workflows/secure-phase.md": "64ec4d06ca85720a",
"gsd-core/workflows/secure-phase.md": "8030d2b2a5bfdf07",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "94d61da368e9f85b",
"gsd-core/workflows/settings-integrations.md": "dfe3672c4fabf139",

View File

@@ -28,7 +28,7 @@
"agents/gsd-project-researcher.md": "f468e96f8339d1e0",
"agents/gsd-research-synthesizer.md": "7be02e47f4fd901b",
"agents/gsd-roadmapper.md": "8a7f1f1256a6aed5",
"agents/gsd-security-auditor.md": "4f9fc3f654af4944",
"agents/gsd-security-auditor.md": "757f72894f79f11b",
"agents/gsd-ui-auditor.md": "40c0dcc15bcfb9fb",
"agents/gsd-ui-checker.md": "8126405043f99cb6",
"agents/gsd-ui-researcher.md": "9e3ac030767167e0",
@@ -286,7 +286,7 @@
"gsd-core/workflows/resume-project.md": "7f8dc986f0f35d96",
"gsd-core/workflows/review.md": "b0baf1dafebe3821",
"gsd-core/workflows/scan.md": "47371c2073d6c0be",
"gsd-core/workflows/secure-phase.md": "59d3c50aba8c9a6c",
"gsd-core/workflows/secure-phase.md": "d6ac1f4db6a5da75",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "339def28c34b0797",
"gsd-core/workflows/settings-integrations.md": "53649313d20694ae",

View File

@@ -32,7 +32,7 @@
"agents/gsd-project-researcher.md": "049f816c6caa4316",
"agents/gsd-research-synthesizer.md": "2f7dcbff50371d4c",
"agents/gsd-roadmapper.md": "bbb23d3097911516",
"agents/gsd-security-auditor.md": "c35c8ec2f85b331f",
"agents/gsd-security-auditor.md": "38935b2d0c532c29",
"agents/gsd-ui-auditor.md": "9338efa31b9b7b99",
"agents/gsd-ui-checker.md": "151d12b4e007cbbf",
"agents/gsd-ui-researcher.md": "1bb303f3a3c4dfc9",
@@ -290,7 +290,7 @@
"gsd-core/workflows/resume-project.md": "e23981178fa37b3d",
"gsd-core/workflows/review.md": "6c689f4ff8146d28",
"gsd-core/workflows/scan.md": "dfd92717caea0ce7",
"gsd-core/workflows/secure-phase.md": "cf78183f06a02582",
"gsd-core/workflows/secure-phase.md": "00de56d6d993bb2c",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "69f3a19bf2c61160",
"gsd-core/workflows/settings-integrations.md": "76eee76d6eb57657",

View File

@@ -29,7 +29,7 @@
"agents/gsd-project-researcher.md": "e43c59f7f1f2f37a",
"agents/gsd-research-synthesizer.md": "87955470c3c129b2",
"agents/gsd-roadmapper.md": "20b69eff61a7a9fa",
"agents/gsd-security-auditor.md": "d3b8f44034a76c9d",
"agents/gsd-security-auditor.md": "bcd9c4859eb5b448",
"agents/gsd-ui-auditor.md": "a26bbc733817959b",
"agents/gsd-ui-checker.md": "25822359044cd708",
"agents/gsd-ui-researcher.md": "e37d9f53ade25d1f",
@@ -358,7 +358,7 @@
"gsd-core/workflows/resume-project.md": "f28da1200e4545f4",
"gsd-core/workflows/review.md": "ad7c0f372ed986ae",
"gsd-core/workflows/scan.md": "003883d71c37da7d",
"gsd-core/workflows/secure-phase.md": "29fc6b62c5c5dc62",
"gsd-core/workflows/secure-phase.md": "22ab3bb5da494ea7",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "414db4dbea97ba44",
"gsd-core/workflows/settings-integrations.md": "70515c5838fb9826",

View File

@@ -128,8 +128,8 @@
"agents/gsd-research-synthesizer.toml": "053616d4941a1458",
"agents/gsd-roadmapper.md": "e15d82d7781dbff3",
"agents/gsd-roadmapper.toml": "0b17f618eafe9be8",
"agents/gsd-security-auditor.md": "a4008a6b1d01833b",
"agents/gsd-security-auditor.toml": "42f529475bd28c22",
"agents/gsd-security-auditor.md": "d7b62f9a93cfbf78",
"agents/gsd-security-auditor.toml": "e991aa6e7c70f813",
"agents/gsd-ui-auditor.md": "abbf560bc8d5069c",
"agents/gsd-ui-auditor.toml": "5e9dd62a12a16a1e",
"agents/gsd-ui-checker.md": "b65d350a4e0564e9",
@@ -140,7 +140,7 @@
"agents/gsd-user-profiler.toml": "b9c244bb8fbf8140",
"agents/gsd-verifier.md": "4ac4b860e2504374",
"agents/gsd-verifier.toml": "8ed9fb961409e894",
"config.toml": "fa48d84b92174890",
"config.toml": "b5f627b42f060910",
"gsd-core/VERSION": "ef0deccd81a6723c",
"gsd-core/bin/check-latest-version.cjs": "e4a224058c8f4d74",
"gsd-core/bin/ensure-runtime-build.cjs": "51bc64467ab30f62",
@@ -393,7 +393,7 @@
"gsd-core/workflows/resume-project.md": "9965f87eb278f7f8",
"gsd-core/workflows/review.md": "5faef3f4feb45c99",
"gsd-core/workflows/scan.md": "1a3caa5d724d39e9",
"gsd-core/workflows/secure-phase.md": "db91810d16964b1e",
"gsd-core/workflows/secure-phase.md": "ab387a4bca381c18",
"gsd-core/workflows/session-report.md": "dd8fa011c9394075",
"gsd-core/workflows/settings-advanced.md": "2431433811616f76",
"gsd-core/workflows/settings-integrations.md": "77730321d3d6d317",

View File

@@ -29,7 +29,7 @@
"agents/gsd-project-researcher.agent.md": "d73bdbe986ffa8a6",
"agents/gsd-research-synthesizer.agent.md": "f03eed4aa89e47c5",
"agents/gsd-roadmapper.agent.md": "322048cf8ddcb4e5",
"agents/gsd-security-auditor.agent.md": "6f6a88b35dc2a24b",
"agents/gsd-security-auditor.agent.md": "464cfbe9aafcd5af",
"agents/gsd-ui-auditor.agent.md": "92f50549e84ef482",
"agents/gsd-ui-checker.agent.md": "47d8cf3486009e11",
"agents/gsd-ui-researcher.agent.md": "0746daeb54f83008",
@@ -288,7 +288,7 @@
"gsd-core/workflows/resume-project.md": "40db7f350f5866d8",
"gsd-core/workflows/review.md": "4b649f31865a1785",
"gsd-core/workflows/scan.md": "dcc2f76d0850e2fb",
"gsd-core/workflows/secure-phase.md": "d87bd706f85bcad6",
"gsd-core/workflows/secure-phase.md": "9bec6635ee1cbaed",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "230a658de9c017a6",
"gsd-core/workflows/settings-integrations.md": "a1d146d6bfd14db5",

View File

@@ -29,7 +29,7 @@
"agents/gsd-project-researcher.md": "beeac940d3a10e76",
"agents/gsd-research-synthesizer.md": "6315f016d55176f4",
"agents/gsd-roadmapper.md": "d28e7d4bac46dde2",
"agents/gsd-security-auditor.md": "5ff44ee432387d93",
"agents/gsd-security-auditor.md": "1e6a10833f556e4c",
"agents/gsd-ui-auditor.md": "d824acc3b2a18c53",
"agents/gsd-ui-checker.md": "c6c24e8066470830",
"agents/gsd-ui-researcher.md": "0f5be5e55501f7e8",
@@ -358,7 +358,7 @@
"gsd-core/workflows/resume-project.md": "7f8dc986f0f35d96",
"gsd-core/workflows/review.md": "3ba8bb85c8ede5b8",
"gsd-core/workflows/scan.md": "47371c2073d6c0be",
"gsd-core/workflows/secure-phase.md": "c55975672c4e1895",
"gsd-core/workflows/secure-phase.md": "3063b0b6f7b56d46",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "bf8ea69c8f7ae019",
"gsd-core/workflows/settings-integrations.md": "166ca51b1f33c2a3",

View File

@@ -29,7 +29,7 @@
"agents/gsd-project-researcher.md": "425a7df7f37a5c06",
"agents/gsd-research-synthesizer.md": "9d31c87fc2c87ffa",
"agents/gsd-roadmapper.md": "64dce5d5f9fa5654",
"agents/gsd-security-auditor.md": "e4d35ada4ea67d7f",
"agents/gsd-security-auditor.md": "ed330ecbd9dbc377",
"agents/gsd-ui-auditor.md": "86797e85f718dfac",
"agents/gsd-ui-checker.md": "cfc8a3bac0a0ef5b",
"agents/gsd-ui-researcher.md": "8799b6013e06ae49",
@@ -287,7 +287,7 @@
"gsd-core/workflows/resume-project.md": "a0443839f1f83c2d",
"gsd-core/workflows/review.md": "761dd1ae5be40613",
"gsd-core/workflows/scan.md": "b28f65d88c522767",
"gsd-core/workflows/secure-phase.md": "f2957d4b88fb3746",
"gsd-core/workflows/secure-phase.md": "a503dc469fd7a252",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "49be159144d7f426",
"gsd-core/workflows/settings-integrations.md": "1dce76db0aca08a5",

View File

@@ -29,7 +29,7 @@
"agents/gsd-project-researcher.md": "60573a38d3dfd9fe",
"agents/gsd-research-synthesizer.md": "1f7cd286c5783c86",
"agents/gsd-roadmapper.md": "277e0a3252553ab7",
"agents/gsd-security-auditor.md": "0113435969e869c4",
"agents/gsd-security-auditor.md": "30b1f87cdfc05de1",
"agents/gsd-ui-auditor.md": "9b988b95d28e56ed",
"agents/gsd-ui-checker.md": "e078ea5a07313976",
"agents/gsd-ui-researcher.md": "cc9578c4f686d926",
@@ -358,7 +358,7 @@
"gsd-core/workflows/resume-project.md": "7f8dc986f0f35d96",
"gsd-core/workflows/review.md": "f8109b9ec1f56962",
"gsd-core/workflows/scan.md": "47371c2073d6c0be",
"gsd-core/workflows/secure-phase.md": "e8855104c1e0417c",
"gsd-core/workflows/secure-phase.md": "4977cf9e0462745b",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "edd858cd6cfddaf1",
"gsd-core/workflows/settings-integrations.md": "3ea8095d5fad891b",

View File

@@ -30,7 +30,7 @@
".kimi/hooks/managed-hooks-registry.cjs": "08ec2585a3f8f132",
".kimi/package.json": "dbf8353f77358bc1",
"agents/gsd.md": "60fee7782ae4f2c6",
"agents/gsd.yaml": "253a23ddda06c6c2",
"agents/gsd.yaml": "b5f16c9fcf92cbff",
"agents/subagents/gsd-advisor-researcher.md": "81bdc6cbd8fcde40",
"agents/subagents/gsd-advisor-researcher.yaml": "662ced4837207406",
"agents/subagents/gsd-ai-researcher.md": "f4cd2f17d2c3e35f",
@@ -87,8 +87,8 @@
"agents/subagents/gsd-research-synthesizer.yaml": "898104ab3bb0b81a",
"agents/subagents/gsd-roadmapper.md": "62359d6876022b48",
"agents/subagents/gsd-roadmapper.yaml": "679772cb14f3a015",
"agents/subagents/gsd-security-auditor.md": "e621d1ee6b7aee6c",
"agents/subagents/gsd-security-auditor.yaml": "fe8a4345cc13571d",
"agents/subagents/gsd-security-auditor.md": "c6108af63b5f481d",
"agents/subagents/gsd-security-auditor.yaml": "924783f1da6777b4",
"agents/subagents/gsd-ui-auditor.md": "e4a319070959ebbc",
"agents/subagents/gsd-ui-auditor.yaml": "3fc98c1d9e8f10fd",
"agents/subagents/gsd-ui-checker.md": "07cd4e382ca55994",
@@ -351,7 +351,7 @@
"gsd-core/workflows/resume-project.md": "f28da1200e4545f4",
"gsd-core/workflows/review.md": "ad7c0f372ed986ae",
"gsd-core/workflows/scan.md": "003883d71c37da7d",
"gsd-core/workflows/secure-phase.md": "29fc6b62c5c5dc62",
"gsd-core/workflows/secure-phase.md": "22ab3bb5da494ea7",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "414db4dbea97ba44",
"gsd-core/workflows/settings-integrations.md": "70515c5838fb9826",

View File

@@ -29,7 +29,7 @@
"agents/gsd-project-researcher.md": "dae210ae0b3c6e2b",
"agents/gsd-research-synthesizer.md": "e02c6ad5d1b74171",
"agents/gsd-roadmapper.md": "1658a40b20d8b575",
"agents/gsd-security-auditor.md": "e36e436c0d5c26d5",
"agents/gsd-security-auditor.md": "64aa435793af52ec",
"agents/gsd-ui-auditor.md": "e810012e685b2466",
"agents/gsd-ui-checker.md": "4f88fd4c9d4c56a3",
"agents/gsd-ui-researcher.md": "ecb617901cb7ad06",
@@ -358,7 +358,7 @@
"gsd-core/workflows/resume-project.md": "ad9f06a10bab8cc0",
"gsd-core/workflows/review.md": "2d28a6683ff587de",
"gsd-core/workflows/scan.md": "ad8ebcad4626d4a8",
"gsd-core/workflows/secure-phase.md": "e9a488cec3b4efdc",
"gsd-core/workflows/secure-phase.md": "71e6e689e80288ec",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "252b0d3edc315339",
"gsd-core/workflows/settings-integrations.md": "d1711a95f44fdbde",

View File

@@ -254,7 +254,7 @@
"gsd-core/workflows/resume-project.md": "f28da1200e4545f4",
"gsd-core/workflows/review.md": "ad7c0f372ed986ae",
"gsd-core/workflows/scan.md": "003883d71c37da7d",
"gsd-core/workflows/secure-phase.md": "29fc6b62c5c5dc62",
"gsd-core/workflows/secure-phase.md": "22ab3bb5da494ea7",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "414db4dbea97ba44",
"gsd-core/workflows/settings-integrations.md": "70515c5838fb9826",

View File

@@ -29,7 +29,7 @@
"agents/gsd-project-researcher.md": "b5baac64a15c85e2",
"agents/gsd-research-synthesizer.md": "6cd9b501dc97bd50",
"agents/gsd-roadmapper.md": "c357a77ab919e9e5",
"agents/gsd-security-auditor.md": "d6d8f82501f10b92",
"agents/gsd-security-auditor.md": "9e3bc9a62036352c",
"agents/gsd-ui-auditor.md": "47937e784c9ae541",
"agents/gsd-ui-checker.md": "7d708c53a106f748",
"agents/gsd-ui-researcher.md": "e3768304c1c77753",
@@ -287,7 +287,7 @@
"gsd-core/workflows/resume-project.md": "7f20769f302e5427",
"gsd-core/workflows/review.md": "bcbc20cb8df021cc",
"gsd-core/workflows/scan.md": "949692db4834dd27",
"gsd-core/workflows/secure-phase.md": "6758f1acf4113e9e",
"gsd-core/workflows/secure-phase.md": "ef7b5ad194b687bf",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "5e05212fb5cba531",
"gsd-core/workflows/settings-integrations.md": "29c5de27fbbb18e9",

View File

@@ -29,7 +29,7 @@
"agents/gsd-project-researcher.md": "ddf7794e81300032",
"agents/gsd-research-synthesizer.md": "a124b00271748d07",
"agents/gsd-roadmapper.md": "493ef92b42b12cf4",
"agents/gsd-security-auditor.md": "fbd3798eec23651b",
"agents/gsd-security-auditor.md": "1e2eea5b2ab16d6e",
"agents/gsd-ui-auditor.md": "771ae08260534d5c",
"agents/gsd-ui-checker.md": "7ecd910efa6eb00e",
"agents/gsd-ui-researcher.md": "9e1a84a55a4cac99",
@@ -287,7 +287,7 @@
"gsd-core/workflows/resume-project.md": "f242e4c8aba18ea2",
"gsd-core/workflows/review.md": "835cf8c9594f17c1",
"gsd-core/workflows/scan.md": "63631467651d9ca8",
"gsd-core/workflows/secure-phase.md": "6cc236e53c2e7d56",
"gsd-core/workflows/secure-phase.md": "4a647aec1e4d2dfe",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "39e66386f6c48025",
"gsd-core/workflows/settings-integrations.md": "f8f756709ec02363",

View File

@@ -29,7 +29,7 @@
"agents/gsd-project-researcher.md": "f6697b316b5995ba",
"agents/gsd-research-synthesizer.md": "04036f38c1d373ea",
"agents/gsd-roadmapper.md": "fb62e1e3de84b5f9",
"agents/gsd-security-auditor.md": "13b660e2d336ed8e",
"agents/gsd-security-auditor.md": "cacf711cb835300b",
"agents/gsd-ui-auditor.md": "20cc99872e9b998b",
"agents/gsd-ui-checker.md": "56698909c270b130",
"agents/gsd-ui-researcher.md": "c348aa3ff8412ecb",
@@ -287,7 +287,7 @@
"gsd-core/workflows/resume-project.md": "82cfe1b8cb17c085",
"gsd-core/workflows/review.md": "3e72508a5dccd45a",
"gsd-core/workflows/scan.md": "12c11b2edc165df9",
"gsd-core/workflows/secure-phase.md": "7bf923689bf58288",
"gsd-core/workflows/secure-phase.md": "185a15d389951e6e",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "2f86ec7b998f9485",
"gsd-core/workflows/settings-integrations.md": "b082fc518b484c07",

View File

@@ -29,7 +29,7 @@
"agents/gsd-project-researcher.md": "f572892f138734ff",
"agents/gsd-research-synthesizer.md": "29949bf3f049a8f1",
"agents/gsd-roadmapper.md": "840ac933e3b094f9",
"agents/gsd-security-auditor.md": "b7202c44366697dd",
"agents/gsd-security-auditor.md": "4b86fa11ebda981e",
"agents/gsd-ui-auditor.md": "76f446c50edf81f8",
"agents/gsd-ui-checker.md": "15949ccab982b71c",
"agents/gsd-ui-researcher.md": "0e8ec8509d476904",
@@ -358,7 +358,7 @@
"gsd-core/workflows/resume-project.md": "f28da1200e4545f4",
"gsd-core/workflows/review.md": "ad7c0f372ed986ae",
"gsd-core/workflows/scan.md": "003883d71c37da7d",
"gsd-core/workflows/secure-phase.md": "29fc6b62c5c5dc62",
"gsd-core/workflows/secure-phase.md": "22ab3bb5da494ea7",
"gsd-core/workflows/session-report.md": "2e5b1205324ddefa",
"gsd-core/workflows/settings-advanced.md": "414db4dbea97ba44",
"gsd-core/workflows/settings-integrations.md": "70515c5838fb9826",

View File

@@ -0,0 +1,73 @@
/**
* Regression test for #2119: /gsd-secure-phase dual SECURITY.md writers.
*
* The gsd-security-auditor agent must NOT have Write/Edit tools — the
* orchestrator (secure-phase.md Step 6) is the sole SECURITY.md writer.
* The auditor returns a structured verdict; it never writes files.
*/
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const AGENT_PATH = path.join(__dirname, '..', 'agents', 'gsd-security-auditor.md');
function parseYamlTools(content) {
const lines = content.split(/\r?\n/);
let inFrontmatter = false;
let inTools = false;
const tools = [];
for (const line of lines) {
const trimmed = line.trim();
if (trimmed === '---') {
inFrontmatter = !inFrontmatter;
if (!inFrontmatter) break;
continue;
}
if (!inFrontmatter) continue;
if (trimmed.startsWith('tools:')) {
inTools = true;
continue;
}
if (inTools) {
if (trimmed.startsWith('- ')) {
tools.push(trimmed.slice(2).trim());
} else if (trimmed && !trimmed.startsWith('#')) {
inTools = false;
}
}
}
return tools;
}
describe('#2119 — security auditor is return-only (no file writes)', () => {
const content = fs.readFileSync(AGENT_PATH, 'utf-8');
test('auditor tools do not include Write or Edit', () => {
const tools = parseYamlTools(content);
assert.ok(tools.length > 0, 'tools list should be non-empty');
assert.ok(
!tools.includes('Write'),
`Write must not be in auditor tools (got: ${tools.join(', ')}) — orchestrator is the sole SECURITY.md writer (#2119)`,
);
assert.ok(
!tools.includes('Edit'),
`Edit must not be in auditor tools (got: ${tools.join(', ')}) — orchestrator is the sole SECURITY.md writer (#2119)`,
);
});
test('auditor description does not claim to produce SECURITY.md', () => {
const lines = content.split(/\r?\n/);
const descLine = lines.find((l) => l.startsWith('description:'));
assert.ok(descLine, 'description field must exist');
assert.ok(
!descLine.includes('Produces SECURITY.md'),
'description must not claim to produce SECURITY.md — auditor returns a verdict, orchestrator writes (#2119)',
);
assert.ok(
descLine.includes('Returns structured') || descLine.includes('returns'),
'description should state the auditor returns a structured verdict',
);
});
});

View File

@@ -57,15 +57,18 @@ describe('SECURE: gsd-security-auditor agent', () => {
);
});
test('tools include Read, Write, Bash, Glob, Grep', () => {
test('tools include Read, Bash, Glob, Grep but NOT Write or Edit (#2119)', () => {
const content = fs.readFileSync(agentPath, 'utf-8');
const requiredTools = ['Read', 'Write', 'Bash', 'Glob', 'Grep'];
const requiredTools = ['Read', 'Bash', 'Glob', 'Grep'];
for (const tool of requiredTools) {
assert.ok(
content.includes(`- ${tool}`),
`tools must include ${tool}`
);
}
// #2119: auditor is return-only — orchestrator is the sole SECURITY.md writer
assert.ok(!content.includes('- Write'), 'tools must NOT include Write (#2119)');
assert.ok(!content.includes('- Edit'), 'tools must NOT include Edit (#2119)');
});
test('has <role> section', () => {

View File

@@ -66,7 +66,7 @@
"resume-project.md": 17270,
"review.md": 47168,
"scan.md": 7732,
"secure-phase.md": 13520,
"secure-phase.md": 13622,
"session-report.md": 4044,
"settings-advanced.md": 40019,
"settings-integrations.md": 15892,