workflow.security_asvs_level was display-only — the planner hardcoded 'mitigate if ASVS L1 requires it' and the auditor only echoed the level, so L2/L3 behaved identically to L1. - New reference gsd-core/references/security-asvs-levels.md defines L1 (opportunistic), L2 (standard), L3 (comprehensive) for both planner threat disposition and auditor verification depth (higher = superset). - planner: disposition now scales with the configured ASVS level (no hardcoded L1) + @-pointer to the reference. - auditor: verification depth scales with asvs_level (L1 grep-presence, L2 boundary/vector check, L3 end-to-end trace + bypass check). - planning-config.md + INVENTORY updated; planner kept under its 48K cap by extracting the goal-backward worked example to planner-guidance.md. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -459,7 +459,7 @@ Only include what Claude literally cannot do.
|
||||
**Step 0: Extract Requirement IDs**
|
||||
Read ROADMAP.md `**Requirements:**` line for this phase. Strip brackets if present (e.g., `[AUTH-01, AUTH-02]` → `AUTH-01, AUTH-02`). Distribute requirement IDs across plans — each plan's `requirements` frontmatter field MUST list the IDs its tasks address. **CRITICAL:** Every requirement ID MUST appear in at least one plan. Plans with an empty `requirements` field are invalid.
|
||||
|
||||
**Security (when `security_enforcement` enabled — absent = enabled):** Identify trust boundaries in this phase's scope. Map STRIDE categories to applicable tech stack from RESEARCH.md security domain. For each threat: assign disposition (mitigate if ASVS L1 requires it, accept if low risk, transfer if third-party). Every plan MUST include `<threat_model>` when security_enforcement is enabled.
|
||||
**Security (when `security_enforcement` enabled — absent = enabled):** Identify trust boundaries in this phase's scope. Map STRIDE categories to applicable tech stack from RESEARCH.md security domain. For each threat: assign disposition (`mitigate`/`accept`/`transfer`) per the configured OWASP ASVS level — see @~/.claude/gsd-core/references/security-asvs-levels.md. Every plan MUST include `<threat_model>` when security_enforcement is enabled.
|
||||
|
||||
**Package legitimacy gate (npm/pip/cargo only):**
|
||||
- Require RESEARCH.md `## Package Legitimacy Audit` before package-manager install tasks.
|
||||
@@ -477,66 +477,16 @@ Take phase goal from ROADMAP.md. Must be outcome-shaped, not task-shaped.
|
||||
**Step 2: Derive Observable Truths**
|
||||
"What must be TRUE for this goal to be achieved?" List 3-7 truths from USER's perspective.
|
||||
|
||||
For "working chat interface":
|
||||
- User can see existing messages
|
||||
- User can type a new message
|
||||
- User can send the message
|
||||
- Sent message appears in the list
|
||||
- Messages persist across page refresh
|
||||
|
||||
**Test:** Each truth verifiable by a human using the application.
|
||||
|
||||
**Step 3: Derive Required Artifacts**
|
||||
For each truth: "What must EXIST for this to be true?"
|
||||
|
||||
"User can see existing messages" requires:
|
||||
- Message list component (renders Message[])
|
||||
- Messages state (loaded from somewhere)
|
||||
- API route or data source (provides messages)
|
||||
- Message type definition (shapes the data)
|
||||
|
||||
**Test:** Each artifact = a specific file or database object.
|
||||
|
||||
**Step 4: Derive Required Wiring**
|
||||
For each artifact: "What must be CONNECTED for this to function?"
|
||||
|
||||
Message list component wiring:
|
||||
- Imports Message type (not using `any`)
|
||||
- Receives messages prop or fetches from API
|
||||
- Maps over messages to render (not hardcoded)
|
||||
- Handles empty state (not just crashes)
|
||||
|
||||
**Step 5: Identify Key Links**
|
||||
"Where is this most likely to break?" Key links = critical connections where breakage causes cascading failures.
|
||||
|
||||
## Must-Haves Output Format
|
||||
|
||||
```yaml
|
||||
must_haves:
|
||||
truths:
|
||||
- "User can see existing messages"
|
||||
- "User can send a message"
|
||||
- "Messages persist across refresh"
|
||||
artifacts:
|
||||
- path: "src/components/Chat.tsx"
|
||||
provides: "Message list rendering"
|
||||
min_lines: 30
|
||||
- path: "src/app/api/chat/route.ts"
|
||||
provides: "Message CRUD operations"
|
||||
exports: ["GET", "POST"]
|
||||
- path: "prisma/schema.prisma"
|
||||
provides: "Message model"
|
||||
contains: "model Message"
|
||||
key_links:
|
||||
- from: "src/components/Chat.tsx"
|
||||
to: "src/app/api/chat/route.ts"
|
||||
via: "fetch in useEffect — calls /api/chat endpoint"
|
||||
pattern: "fetch.*api/chat"
|
||||
- from: "src/app/api/chat/route.ts"
|
||||
to: "prisma/schema.prisma"
|
||||
via: "database query via prisma.message"
|
||||
pattern: "prisma\\.message\\.(find|create)"
|
||||
```
|
||||
See @~/.claude/gsd-core/references/planner-guidance.md for a worked example and the `must_haves` YAML format.
|
||||
|
||||
</goal_backward>
|
||||
|
||||
|
||||
@@ -69,10 +69,15 @@ For each threat in `<threat_model>`, determine verification method by dispositio
|
||||
| `transfer` | Verify transfer documentation present (insurance, vendor SLA, etc.) |
|
||||
|
||||
Classify each threat before verification. Record classification for every threat — no threat skipped.
|
||||
|
||||
**Verification depth scales with `asvs_level`** (see @~/.claude/gsd-core/references/security-asvs-levels.md for full definitions):
|
||||
- L1: verify mitigation is PRESENT in the cited file (grep-level — pattern exists).
|
||||
- L2: verify the mitigation ADDRESSES the threat vector and is placed at the correct boundary (a check in the wrong layer does not close the 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">
|
||||
For each `mitigate` threat: grep for declared mitigation pattern in cited files → found = `CLOSED`, not found = `OPEN`.
|
||||
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 `transfer` threats: check for transfer documentation → present = `CLOSED`, absent = `OPEN`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user