diff --git a/sdk/typescript/_bundled_plugin/mcp/server.mjs.br.part-000 b/sdk/typescript/_bundled_plugin/mcp/server.mjs.br.part-000 index 0fe7a541..4bbb9370 100644 Binary files a/sdk/typescript/_bundled_plugin/mcp/server.mjs.br.part-000 and b/sdk/typescript/_bundled_plugin/mcp/server.mjs.br.part-000 differ diff --git a/sdk/typescript/_bundled_plugin/mcp/server.mjs.br.part-001 b/sdk/typescript/_bundled_plugin/mcp/server.mjs.br.part-001 index afeb4973..5a7967da 100644 Binary files a/sdk/typescript/_bundled_plugin/mcp/server.mjs.br.part-001 and b/sdk/typescript/_bundled_plugin/mcp/server.mjs.br.part-001 differ diff --git a/sdk/typescript/_bundled_plugin/references/scan-artifacts.md b/sdk/typescript/_bundled_plugin/references/scan-artifacts.md index 5b93cb25..921e3466 100644 --- a/sdk/typescript/_bundled_plugin/references/scan-artifacts.md +++ b/sdk/typescript/_bundled_plugin/references/scan-artifacts.md @@ -47,7 +47,7 @@ Workbench-owned Standard scans submit findings and coverage through `record_code - The writer validates candidates against assigned source paths, merges rows with the same CWE ids, locations, and optional instance, preserves their text, and assigns deterministic `candidate_id` values. - After normalization, compact validation adds exactly one `validation` object to every row with `disposition` (`reportable`, `suppressed`, `not_applicable`, or `deferred`), `method`, `confidence` (`high`, `medium`, or `low`), `confidence_rationale`, concise `rubric` and `evidence`, `counterevidence_or_proof_gap`, `remaining_uncertainty`, and optional `artifact_paths`. Add `source`, `control`, `sink`, or `preconditions` only when they clarify or differ from the discovery fields. - Compact attack-path analysis adds exactly one `attack_path` object to each validation row marked `reportable` or `deferred`, with `decision` (`reportable`, `ignore`, or `deferred`), `dataflow`, `reachability`, `counterevidence`, `impact` and `likelihood` (`high`, `medium`, `low`, `ignore`, or `unknown`), `severity` (`critical`, `high`, `medium`, `low`, `ignore`, or `unknown`), `severity_rationale`, `change_conditions`, and `proof_gap` when deferred. A `reportable` decision requires severity `critical`, `high`, `medium`, or `low`; `ignore` requires severity `ignore`; `deferred` uses a provisional reportable severity or `unknown`. - - Record all validations through `record_codex_security_candidate_validations` and all eligible attack-path decisions through `record_codex_security_candidate_attack_paths`. The tools atomically preserve all discovery fields and candidate order. + - Record all validations through `record_codex_security_candidate_validations` and all eligible attack-path decisions through `record_candidate_attack_paths`. The tools atomically preserve all discovery fields and candidate order. - Optional compact validation evidence: `/validation_artifacts//` - Create this directory only for actual PoCs, crafted inputs, or logs and reference those paths from the row's `validation` object. Do not create placeholder per-candidate directories or narrative reports. diff --git a/sdk/typescript/_bundled_plugin/skills/attack-path-analysis/SKILL.md b/sdk/typescript/_bundled_plugin/skills/attack-path-analysis/SKILL.md index 32972e65..ff54a11a 100644 --- a/sdk/typescript/_bundled_plugin/skills/attack-path-analysis/SKILL.md +++ b/sdk/typescript/_bundled_plugin/skills/attack-path-analysis/SKILL.md @@ -18,7 +18,7 @@ Use the shared scan artifact path conventions in `../../references/scan-artifact ### Compact Deep Candidate Mode -When `$deep-security-scan` invokes this skill, load the per-scan threat model and read the validated candidates with `list_codex_security_candidates({ scanId, cursor?, limit? })`. Analyze every `reportable` or `deferred` candidate in one invocation. Record one nested attack-path decision per eligible candidate with `record_codex_security_candidate_attack_paths({ scanId, attackPaths: [{ candidateId, attackPath }] })`, using the Deep candidate shape in `../../references/scan-artifacts.md` and preserving every discovery and validation field and the original candidate order. Standard scans assess attack paths in their parent and do not invoke this skill. +When `$deep-security-scan` invokes this skill, load the per-scan threat model and read the validated candidates with `list_codex_security_candidates({ scanId, cursor?, limit? })`. Analyze every `reportable` or `deferred` candidate in one invocation. Record one nested attack-path decision per eligible candidate with `record_candidate_attack_paths({ scanId, attackPaths: [{ candidateId, attackPath }] })`, using the Deep candidate shape in `../../references/scan-artifacts.md` and preserving every discovery and validation field and the original candidate order. Standard scans assess attack paths in their parent and do not invoke this skill. In this mode, the tool atomically records the nested decision in place of a per-finding attack-path report or receipt. Submit all eligible attack-path decisions together; submit `attackPaths: []` when no candidate enters this phase. Keep attack-path facts, counterevidence, severity calibration, and policy adjustment as separate reasoning steps even though their output is compact. All reachability, instance-preservation, and evidence requirements still apply; only the artifact packaging changes. @@ -38,7 +38,7 @@ In this mode, the tool atomically records the nested decision in place of a per- 5. Calibrate impact and likelihood from the repository evidence. 6. Apply a separate final policy-adjustment pass mechanically using those facts and the calibrated severity. 7. Record final policy decision `ignore` explicitly. Outside compact Deep candidate mode, drop it from the surviving finding set; in compact mode, retain the ledger row for coverage mapping. -8. In compact Deep candidate mode, call `record_codex_security_candidate_attack_paths` once with the nested attack-path decision for every eligible candidate; the tool atomically updates the stored candidates. +8. In compact Deep candidate mode, call `record_candidate_attack_paths` once with the nested attack-path decision for every eligible candidate; the tool atomically updates the stored candidates. 9. Outside compact Deep candidate mode, save that finding's visible attack-path report and append one attack-path receipt per candidate id at the default paths from `../../references/scan-artifacts.md`. The receipt must record the candidate id, attack-path reportability decision, attack-path facts or exact proof gap, and attack-path artifact/report reference for that candidate finding. ## Scope and Attack Path Checklist @@ -82,7 +82,7 @@ Apply severity and policy calibration using `references/severity-policy.md`. ## Output Contract -In compact Deep candidate mode, submit the nested record defined in `../../references/scan-artifacts.md` using `record_codex_security_candidate_attack_paths`. Every candidate with validation disposition `reportable` or `deferred` must receive exactly one attack-path decision. The recorded result is the phase closure; do not also create a narrative report or receipt. +In compact Deep candidate mode, submit the nested record defined in `../../references/scan-artifacts.md` using `record_candidate_attack_paths`. Every candidate with validation disposition `reportable` or `deferred` must receive exactly one attack-path decision. The recorded result is the phase closure; do not also create a narrative report or receipt. Outside compact Deep candidate mode, use the following report contract. diff --git a/sdk/typescript/_bundled_plugin/skills/deep-security-scan/SKILL.md b/sdk/typescript/_bundled_plugin/skills/deep-security-scan/SKILL.md index 09ec124a..19d26369 100644 --- a/sdk/typescript/_bundled_plugin/skills/deep-security-scan/SKILL.md +++ b/sdk/typescript/_bundled_plugin/skills/deep-security-scan/SKILL.md @@ -121,7 +121,7 @@ After accepting the terminal manifest, continue in the same turn. A discovery ma 1. Read the canonical review items and candidate set with `list_codex_security_review_items({ scanId, handoffClaimToken?, cursor?, limit? })` and `list_codex_security_candidates({ scanId, cursor?, limit? })`. Follow `nextCursor` until all pages are read. If either tool fails or returns malformed records, report the tool failure and stop; do not repair coordinator-owned discovery artifacts, reopen discovery, or silently drop candidates. 2. Synthesize one canonical validation threat model from the ordered worker threat models and write it to the per-scan `/threat_model.md` path. Preserve relevant attacker models, trust boundaries, privileged surfaces, contradictions, and risk framings conservatively. This threat model is downstream context, not a retroactive discovery filter. 3. Run `$codex-security:validation` once in compact Deep candidate mode over the canonical merged candidates, recording every result with `record_codex_security_candidate_validations`. -4. Run `$codex-security:attack-path-analysis` once in compact Deep candidate mode over the reportable or deferred validated candidates, recording every decision with `record_codex_security_candidate_attack_paths`. +4. Run `$codex-security:attack-path-analysis` once in compact Deep candidate mode over the reportable or deferred validated candidates, recording every decision with `record_candidate_attack_paths`. 5. Assemble complete finding and coverage semantics using `../../references/final-report.md` and `../../references/finding-detail-fields.md`, then call `record_codex_security_scan_draft({ scanId, handoffClaimToken?, scope?, threatModel?, findings, coverage })`. - Use the existing shared final-report contract: an evidence-supported lowercase vulnerability-family `ruleId`, the candidate's exact CWE array in `taxonomy.cwe`, its actual `provenance.source`, genuine nonempty code evidence, and coverage surfaces with canonical `label` and `disposition` fields. Preserve candidate and worker provenance. - Set coverage to `partial` when deferred work or a `needs_follow_up` surface remains; retain the actual evidence and reason. diff --git a/sdk/typescript/tests-ts/attack-path-tool-name.test.ts b/sdk/typescript/tests-ts/attack-path-tool-name.test.ts new file mode 100644 index 00000000..03a007f4 --- /dev/null +++ b/sdk/typescript/tests-ts/attack-path-tool-name.test.ts @@ -0,0 +1,48 @@ +import { spawnSync } from "node:child_process"; +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "bun:test"; +import { PLUGIN_ROOT } from "./plugin-root.js"; + +test("keeps model-visible attack-path tool names within the Codex limit", () => { + const node = Bun.which("node"); + expect(node).not.toBeNull(); + const state = mkdtempSync(join(tmpdir(), "codex-security-mcp-tools-")); + + try { + const server = spawnSync(node!, [join(PLUGIN_ROOT, "mcp", "server.mjs")], { + encoding: "utf8", + env: { ...process.env, CODEX_SECURITY_STATE_DIR: state }, + input: [ + '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"codex-security-test","version":"1.0.0"}}}', + '{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}', + '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}', + "", + ].join("\n"), + timeout: 30_000, + }); + expect(server.status, server.stderr).toBe(0); + + const tools = server.stdout + .trim() + .split("\n") + .map((line) => JSON.parse(line)) + .find((response) => response.id === 2).result.tools as { + name: string; + _meta?: { ui?: { visibility?: string[] } }; + }[]; + + expect(tools.map((tool) => tool.name)).toContain( + "record_candidate_attack_paths", + ); + for (const tool of tools) { + if (tool._meta?.ui?.visibility?.includes("model") === false) continue; + expect(`mcp__codex_security__${tool.name}`.length).toBeLessThanOrEqual( + 64, + ); + } + } finally { + rmSync(state, { recursive: true, force: true }); + } +}); diff --git a/sdk/typescript/tests-ts/runtime.test.ts b/sdk/typescript/tests-ts/runtime.test.ts index 8205d5fd..65a26b24 100644 --- a/sdk/typescript/tests-ts/runtime.test.ts +++ b/sdk/typescript/tests-ts/runtime.test.ts @@ -421,7 +421,7 @@ describe("plugin runtime preparation", () => { "start_codex_security_prompt_only_scan", "start_codex_security_deep_scan", "record_codex_security_scan_draft", - "record_codex_security_candidate_attack_paths", + "record_candidate_attack_paths", "complete_codex_security_scan", ]) { expect(names.has(name)).toBe(true);