feat(review): the brief's threat model on the review side (decision 164, 167, 218)
The code-correctness reviewer's dimension 6 shrinks to what the engines do not read: command, skill and agent markdown carrying shell, with Claude Code's threshold (a concrete attack path, high confidence), the keys SECURITY_INJECTION or SECURITY_RISK, and threat_model_ref quoting the brief's Outside: line; the code-level bullets go to the engines. The coordinator puts a Voyage security finding with a threat_model_ref into the trailing JSON block's known_outside, never into findings. review-finalize gains the pass `outside`, right after engine: it only raises. An entry the brief at the review's brief_path does not back now (line gone, threat model not usable, an engine finding, not a security finding) goes back into the findings at its catalogue tier with a Source line, R-step and raised verdict, as the engine put-back does; the rest are listed under the new `## Outside the Threat Model` section. verdict-gate decideOpenFindings (and so scripts/release-check.mjs) re-checks every entry against brief_path through the new notBackedOutside and exits 2 for one not backed. review-validator shape-checks the optional known_outside (REVIEW_KNOWN_OUTSIDE_MALFORMED). threat-model.mjs gains reviewThreatModel and isKnownEntry for the three. /trekreview Phase 8.8 lists the known issues outside the threat model (not answered, not counted); the review template shows the section and field; Handover 1 names the optional ## Threat Model and its code, Handover 6 names known_outside and its code. Part 2, step 2.5 of the E plan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
98171d7d3b
commit
c47061191c
10 changed files with 585 additions and 30 deletions
|
|
@ -22,6 +22,7 @@ import { parseDocument } from '../util/frontmatter.mjs';
|
|||
import { issue, ok, fail } from '../util/result.mjs';
|
||||
import { isMain } from '../util/is-main.mjs';
|
||||
import { extractFindingsBlock } from '../review/findings-schema.mjs';
|
||||
import { isKnownEntry } from '../review/threat-model.mjs';
|
||||
|
||||
export const REVIEW_REQUIRED_FRONTMATTER = [
|
||||
'type',
|
||||
|
|
@ -76,8 +77,10 @@ export function remediationStepSources(body) {
|
|||
// `fixed` without its R-step), REVIEW_POLICY_MALFORMED (`review_policy`,
|
||||
// `review_policy_sha256`, a finding's `instruction_ref`), REVIEW_ROUND_MALFORMED
|
||||
// (`round`, `round_base`, `finalized`, `resolved`, `ran`, a finding's
|
||||
// `carried_from`) and REVIEW_PRE_EXISTING_MALFORMED (a finding's `pre_existing`,
|
||||
// `pre_existing_counts`).
|
||||
// `carried_from`), REVIEW_PRE_EXISTING_MALFORMED (a finding's `pre_existing`,
|
||||
// `pre_existing_counts`) and REVIEW_KNOWN_OUTSIDE_MALFORMED (the optional
|
||||
// `known_outside` list, E 2.5: Voyage's own security findings the brief's
|
||||
// threat model puts outside; lib/review/threat-model.mjs `isKnownEntry`).
|
||||
|
||||
const FULL_SHA_RE = /^(?:[0-9a-f]{40}|[0-9a-f]{64})$/;
|
||||
const SHA256_RE = /^[0-9a-f]{64}$/;
|
||||
|
|
@ -163,6 +166,7 @@ function review12Issues(fm, body) {
|
|||
const policy = (msg) => out.push(issue('REVIEW_POLICY_MALFORMED', msg));
|
||||
const pre = (msg) => out.push(issue('REVIEW_PRE_EXISTING_MALFORMED', msg));
|
||||
const answers = (msg) => out.push(issue('REVIEW_ANSWERS_MALFORMED', msg));
|
||||
const outside = (msg) => out.push(issue('REVIEW_KNOWN_OUTSIDE_MALFORMED', msg));
|
||||
|
||||
// Frontmatter.
|
||||
if ('round' in fm && !(Number.isInteger(fm.round) && fm.round >= 1 && fm.round <= 3)) {
|
||||
|
|
@ -211,6 +215,17 @@ function review12Issues(fm, body) {
|
|||
round(`resolved must be an array of 40-char hex finding ids, got ${JSON.stringify(r)}`);
|
||||
}
|
||||
}
|
||||
if ('known_outside' in payload) {
|
||||
const k = payload.known_outside;
|
||||
if (!Array.isArray(k)) outside(`known_outside must be an array, got ${JSON.stringify(k)}`);
|
||||
else {
|
||||
k.forEach((e, i) => {
|
||||
if (!isKnownEntry(e)) {
|
||||
outside(`known_outside[${i}] needs a string rule_key and file, an integer line >= 0 and a non-empty threat_model_ref, got ${JSON.stringify(e)}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if ('ran' in payload) {
|
||||
const r = payload.ran;
|
||||
const okRan = isPlainObject(r)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue