nexus-agents 8.76.2 → 8.78.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ast-rule-runner-BXBBL5G7.js → ast-rule-runner-U5N43D4U.js} +3 -3
- package/dist/{child-mcp-config-3IELNFHI.js → child-mcp-config-IRZHH2TU.js} +2 -2
- package/dist/{chunk-UF3BNMOV.js → chunk-33HHRRKZ.js} +34 -31
- package/dist/chunk-33HHRRKZ.js.map +1 -0
- package/dist/{chunk-PE4QQAAY.js → chunk-3K7OHJLM.js} +53 -38
- package/dist/chunk-3K7OHJLM.js.map +1 -0
- package/dist/{chunk-A6QRKIGL.js → chunk-4FDESAVV.js} +3 -3
- package/dist/{chunk-WFHUSSKZ.js → chunk-5CIP4EWI.js} +21 -5
- package/dist/chunk-5CIP4EWI.js.map +1 -0
- package/dist/{chunk-J527NA52.js → chunk-5EXZHBAQ.js} +3 -3
- package/dist/{chunk-T52Y554H.js → chunk-7RCC7WGS.js} +2 -2
- package/dist/{chunk-BAGUYKZL.js → chunk-7ZMNE7U2.js} +34 -12
- package/dist/chunk-7ZMNE7U2.js.map +1 -0
- package/dist/{chunk-CAIJB3CO.js → chunk-ACXBBUW3.js} +72 -5
- package/dist/chunk-ACXBBUW3.js.map +1 -0
- package/dist/{chunk-NBTG2OQC.js → chunk-AE2U6NUZ.js} +2 -2
- package/dist/{chunk-ZVQ2Q7OM.js → chunk-AVEDKF3J.js} +2 -2
- package/dist/{chunk-IPI4I2UW.js → chunk-CMZPHXDH.js} +2 -2
- package/dist/{chunk-MSPYAOAU.js → chunk-DWQ7TG5L.js} +2 -2
- package/dist/{chunk-6E3DFUYA.js → chunk-EMWRUQQS.js} +5 -5
- package/dist/{chunk-F76Y5QXV.js → chunk-ER76ZRBU.js} +9 -9
- package/dist/{chunk-T6W3N3N3.js → chunk-F7R2E74V.js} +2 -2
- package/dist/{chunk-PJZQQYLJ.js → chunk-GHNHZSDW.js} +7 -7
- package/dist/{chunk-VFTP7WSH.js → chunk-J76ZM6QF.js} +2 -2
- package/dist/{chunk-AONC4VYB.js → chunk-LIVTFARG.js} +2 -2
- package/dist/{chunk-EVBLCOEN.js → chunk-MYF73MI3.js} +2 -2
- package/dist/{chunk-MRGBENPM.js → chunk-NEIPHVTA.js} +2 -2
- package/dist/{chunk-IDPA4X6J.js → chunk-NW5MCYOE.js} +3 -3
- package/dist/{chunk-G744HQMZ.js → chunk-OZFXXGGZ.js} +75 -12
- package/dist/chunk-OZFXXGGZ.js.map +1 -0
- package/dist/{chunk-CMG3P6OI.js → chunk-PSCY6MSD.js} +4 -4
- package/dist/{chunk-RC4ZQ4ZE.js → chunk-Q6JZQWQB.js} +28 -31
- package/dist/chunk-Q6JZQWQB.js.map +1 -0
- package/dist/{chunk-AWCSYKUR.js → chunk-QNRB5U7W.js} +2 -2
- package/dist/{chunk-FRHYZJGC.js → chunk-SKAPTWVH.js} +3 -3
- package/dist/{chunk-2P4HP2A6.js → chunk-T63EIQYI.js} +2 -2
- package/dist/{chunk-FMAJIIXZ.js → chunk-UNPDTD6N.js} +2 -2
- package/dist/{chunk-GOXBEH6M.js → chunk-VFFG3HIY.js} +2 -2
- package/dist/{chunk-MCRMY7K7.js → chunk-WABZQ477.js} +4 -4
- package/dist/{chunk-VKLUJZQV.js → chunk-WUN3IB3T.js} +2 -2
- package/dist/{chunk-MSSRXYMZ.js → chunk-XQ34WJOM.js} +2 -2
- package/dist/{chunk-NOSQXAW3.js → chunk-YUDJV6JF.js} +4 -4
- package/dist/{cli-circuit-breaker-H5CESPLC.js → cli-circuit-breaker-DJU6WTWT.js} +3 -3
- package/dist/cli.js +65 -51
- package/dist/cli.js.map +1 -1
- package/dist/{composite-router-DSYVXQ7C.js → composite-router-F3D2QRHI.js} +2 -2
- package/dist/{consensus-vote-OKA2PL74.js → consensus-vote-3ZA6SHMI.js} +16 -16
- package/dist/{context-retriever-C5KY23EG.js → context-retriever-J24ZMIZG.js} +8 -8
- package/dist/{doctor-deep-LBPZXYN4.js → doctor-deep-WWOPRJJS.js} +3 -3
- package/dist/{doctor-live-QAT3FLUJ.js → doctor-live-55CKYQ6V.js} +10 -10
- package/dist/{expert-bridge-F7V2AXUD.js → expert-bridge-5MFBN4ZW.js} +4 -4
- package/dist/{factory-MZTDIMCP.js → factory-3ZA63QDH.js} +9 -9
- package/dist/{factory-ECJNRE2W.js → factory-TXEYHBQV.js} +5 -5
- package/dist/{improvement-review-UEVIATKC.js → improvement-review-VC46AY77.js} +5 -5
- package/dist/index.d.ts +75 -3
- package/dist/index.js +30 -30
- package/dist/{init-opencode-WXEXOV6X.js → init-opencode-R5JTQZG5.js} +5 -5
- package/dist/issue-triage-M7XEMQZ7.js +16 -0
- package/dist/{pr-reviewer-helpers-VRPD3CNI.js → pr-reviewer-helpers-HRM74BLX.js} +4 -4
- package/dist/{registry-command-JZLWVBLG.js → registry-command-ZPKPR6WV.js} +2 -2
- package/dist/{repo-security-plan-IS65FSZF.js → repo-security-plan-LXKTNEGB.js} +3 -3
- package/dist/{research-helpers-synthesize-TLZPEOAU.js → research-helpers-synthesize-FZLLZSJM.js} +4 -4
- package/dist/{routing-memory-YHEH7ULH.js → routing-memory-35Z7UVYC.js} +2 -2
- package/dist/{session-memory-5MD3ZFJX.js → session-memory-G7VGV2SC.js} +3 -3
- package/dist/{setup-config-RFOBGXUH.js → setup-config-KLKXB2LM.js} +3 -3
- package/dist/{setup-custom-api-DKXRZY4C.js → setup-custom-api-TJMRUQFK.js} +14 -11
- package/dist/setup-custom-api-TJMRUQFK.js.map +1 -0
- package/dist/setup-data-dir-NQITBZYA.js +30 -0
- package/dist/{tool-memory-HCCMGPVI.js → tool-memory-65MWYDEP.js} +5 -5
- package/dist/{unified-registry-3TWHRO5L.js → unified-registry-2HCLBGWM.js} +10 -10
- package/dist/{weather-report-MGOA7OOC.js → weather-report-RMRBC6LH.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-BAGUYKZL.js.map +0 -1
- package/dist/chunk-CAIJB3CO.js.map +0 -1
- package/dist/chunk-G744HQMZ.js.map +0 -1
- package/dist/chunk-PE4QQAAY.js.map +0 -1
- package/dist/chunk-RC4ZQ4ZE.js.map +0 -1
- package/dist/chunk-UF3BNMOV.js.map +0 -1
- package/dist/chunk-WFHUSSKZ.js.map +0 -1
- package/dist/issue-triage-OJZ275JY.js +0 -16
- package/dist/setup-custom-api-DKXRZY4C.js.map +0 -1
- package/dist/setup-data-dir-JXSO4FDY.js +0 -30
- /package/dist/{ast-rule-runner-BXBBL5G7.js.map → ast-rule-runner-U5N43D4U.js.map} +0 -0
- /package/dist/{child-mcp-config-3IELNFHI.js.map → child-mcp-config-IRZHH2TU.js.map} +0 -0
- /package/dist/{chunk-A6QRKIGL.js.map → chunk-4FDESAVV.js.map} +0 -0
- /package/dist/{chunk-J527NA52.js.map → chunk-5EXZHBAQ.js.map} +0 -0
- /package/dist/{chunk-T52Y554H.js.map → chunk-7RCC7WGS.js.map} +0 -0
- /package/dist/{chunk-NBTG2OQC.js.map → chunk-AE2U6NUZ.js.map} +0 -0
- /package/dist/{chunk-ZVQ2Q7OM.js.map → chunk-AVEDKF3J.js.map} +0 -0
- /package/dist/{chunk-IPI4I2UW.js.map → chunk-CMZPHXDH.js.map} +0 -0
- /package/dist/{chunk-MSPYAOAU.js.map → chunk-DWQ7TG5L.js.map} +0 -0
- /package/dist/{chunk-6E3DFUYA.js.map → chunk-EMWRUQQS.js.map} +0 -0
- /package/dist/{chunk-F76Y5QXV.js.map → chunk-ER76ZRBU.js.map} +0 -0
- /package/dist/{chunk-T6W3N3N3.js.map → chunk-F7R2E74V.js.map} +0 -0
- /package/dist/{chunk-PJZQQYLJ.js.map → chunk-GHNHZSDW.js.map} +0 -0
- /package/dist/{chunk-VFTP7WSH.js.map → chunk-J76ZM6QF.js.map} +0 -0
- /package/dist/{chunk-AONC4VYB.js.map → chunk-LIVTFARG.js.map} +0 -0
- /package/dist/{chunk-EVBLCOEN.js.map → chunk-MYF73MI3.js.map} +0 -0
- /package/dist/{chunk-MRGBENPM.js.map → chunk-NEIPHVTA.js.map} +0 -0
- /package/dist/{chunk-IDPA4X6J.js.map → chunk-NW5MCYOE.js.map} +0 -0
- /package/dist/{chunk-CMG3P6OI.js.map → chunk-PSCY6MSD.js.map} +0 -0
- /package/dist/{chunk-AWCSYKUR.js.map → chunk-QNRB5U7W.js.map} +0 -0
- /package/dist/{chunk-FRHYZJGC.js.map → chunk-SKAPTWVH.js.map} +0 -0
- /package/dist/{chunk-2P4HP2A6.js.map → chunk-T63EIQYI.js.map} +0 -0
- /package/dist/{chunk-FMAJIIXZ.js.map → chunk-UNPDTD6N.js.map} +0 -0
- /package/dist/{chunk-GOXBEH6M.js.map → chunk-VFFG3HIY.js.map} +0 -0
- /package/dist/{chunk-MCRMY7K7.js.map → chunk-WABZQ477.js.map} +0 -0
- /package/dist/{chunk-VKLUJZQV.js.map → chunk-WUN3IB3T.js.map} +0 -0
- /package/dist/{chunk-MSSRXYMZ.js.map → chunk-XQ34WJOM.js.map} +0 -0
- /package/dist/{chunk-NOSQXAW3.js.map → chunk-YUDJV6JF.js.map} +0 -0
- /package/dist/{cli-circuit-breaker-H5CESPLC.js.map → cli-circuit-breaker-DJU6WTWT.js.map} +0 -0
- /package/dist/{composite-router-DSYVXQ7C.js.map → composite-router-F3D2QRHI.js.map} +0 -0
- /package/dist/{consensus-vote-OKA2PL74.js.map → consensus-vote-3ZA6SHMI.js.map} +0 -0
- /package/dist/{context-retriever-C5KY23EG.js.map → context-retriever-J24ZMIZG.js.map} +0 -0
- /package/dist/{doctor-deep-LBPZXYN4.js.map → doctor-deep-WWOPRJJS.js.map} +0 -0
- /package/dist/{doctor-live-QAT3FLUJ.js.map → doctor-live-55CKYQ6V.js.map} +0 -0
- /package/dist/{expert-bridge-F7V2AXUD.js.map → expert-bridge-5MFBN4ZW.js.map} +0 -0
- /package/dist/{factory-ECJNRE2W.js.map → factory-3ZA63QDH.js.map} +0 -0
- /package/dist/{factory-MZTDIMCP.js.map → factory-TXEYHBQV.js.map} +0 -0
- /package/dist/{improvement-review-UEVIATKC.js.map → improvement-review-VC46AY77.js.map} +0 -0
- /package/dist/{init-opencode-WXEXOV6X.js.map → init-opencode-R5JTQZG5.js.map} +0 -0
- /package/dist/{issue-triage-OJZ275JY.js.map → issue-triage-M7XEMQZ7.js.map} +0 -0
- /package/dist/{pr-reviewer-helpers-VRPD3CNI.js.map → pr-reviewer-helpers-HRM74BLX.js.map} +0 -0
- /package/dist/{registry-command-JZLWVBLG.js.map → registry-command-ZPKPR6WV.js.map} +0 -0
- /package/dist/{repo-security-plan-IS65FSZF.js.map → repo-security-plan-LXKTNEGB.js.map} +0 -0
- /package/dist/{research-helpers-synthesize-TLZPEOAU.js.map → research-helpers-synthesize-FZLLZSJM.js.map} +0 -0
- /package/dist/{routing-memory-YHEH7ULH.js.map → routing-memory-35Z7UVYC.js.map} +0 -0
- /package/dist/{session-memory-5MD3ZFJX.js.map → session-memory-G7VGV2SC.js.map} +0 -0
- /package/dist/{setup-config-RFOBGXUH.js.map → setup-config-KLKXB2LM.js.map} +0 -0
- /package/dist/{setup-data-dir-JXSO4FDY.js.map → setup-data-dir-NQITBZYA.js.map} +0 -0
- /package/dist/{tool-memory-HCCMGPVI.js.map → tool-memory-65MWYDEP.js.map} +0 -0
- /package/dist/{unified-registry-3TWHRO5L.js.map → unified-registry-2HCLBGWM.js.map} +0 -0
- /package/dist/{weather-report-MGOA7OOC.js.map → weather-report-RMRBC6LH.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/security/firewall/firewall-policy-mode.ts","../src/security/audit-trail.ts","../src/security/audit-bridge.ts","../src/security/trust-classifier.ts","../src/security/firewall/firewall-types.ts","../src/security/firewall/agent-trust-labels.ts","../src/security/firewall/firewall-passthrough.ts","../src/security/firewall/firewall-trust-reason.ts","../src/security/policy-gate.ts","../src/security/action-schema.ts","../src/security/firewall/firewall-policy-stage.ts","../src/security/corroboration-validator.ts","../src/security/firewall/firewall-pipeline.ts","../src/security/firewall/github-adapter.ts","../src/dogfooding/untrusted-input-firewall.ts","../src/scm/url-parsers.ts","../src/scm/github-provider-traits.ts","../src/dogfooding/issue-triage-types.ts","../src/dogfooding/issue-triage-helpers.ts","../src/dogfooding/issue-triage.ts"],"sourcesContent":["/**\n * Rollout gate for `HostileInputFirewall` behaviour changes (#5382, epic #5281).\n *\n * `HostileInputFirewall` is a PUBLISHED API: re-exported through\n * `src/exports/security.ts`, carried in `api-surface.txt`, and pinned by an\n * export-contract test. Epic #5281 found it has fallen BEHIND the hand-composed\n * production path rather than being dead scaffolding, and its remaining children\n * change what `process()` decides — #5380 raises one policy check to seven,\n * #5381 makes reputation gating mode-aware.\n *\n * A supermajority panel ratified this gate FIRST (6 approve / 1 reject; the lone\n * rejection argued the gate binds even more firmly than proposed) so those\n * changes have somewhere to land that is not a silent behaviour change shipped\n * in a patch release to consumers this repo cannot see.\n *\n * The invariant that makes it a gate: **`off` is the default, and under `off`\n * behaviour is byte-identical to pre-#5382.** A gate whose default changes\n * behaviour has not gated anything.\n *\n * Deliberately NOT a new mechanism. This flag has the same shape as\n * `NEXUS_REPUTATION_GATING` (#3122) — and as `NEXUS_ACCESS_POLICY_MODE` did\n * until its reader, the access-constraint deriver, was deleted in #5108 — so it\n * delegates to the shared `resolveEnvMode` helper (#3130) and coerces\n * identically. These env-var names are a stability contract; adding another\n * resolver with subtly different coercion is the sprawl that helper exists to\n * prevent.\n *\n * @module security/firewall/firewall-policy-mode\n */\n\nimport { z } from 'zod';\nimport { resolveEnvMode } from '../env-mode.js';\nimport type { ILogger } from '../../core/index.js';\n\n/**\n * Rollout state for firewall policy behaviour.\n *\n * - `off` — pre-#5382 behaviour exactly. The default.\n * - `audit` — compute the stricter outcome and REPORT it, but enforce the old\n * one. This is the mode that makes a rollout measurable: it answers \"what\n * would change?\" without changing it.\n * - `enforce` — apply the stricter outcome.\n */\nexport const FirewallPolicyModeSchema = z.enum(['off', 'audit', 'enforce']);\nexport type FirewallPolicyMode = z.infer<typeof FirewallPolicyModeSchema>;\n\n/**\n * Default is `off`, and that is the compatibility promise, not a placeholder.\n *\n * Note this differs from `DEFAULT_REPUTATION_GATING_MODE`, which is `enforce`\n * (#4667) — that flag governs an INTERNAL path this repo owns end to end, and\n * was flipped only after measurement over the real triage path. This one\n * governs a published surface with unknown external callers, so it starts off\n * and stays off until the same kind of measurement justifies a flip. Any future\n * flip is a MAJOR version change, not a patch.\n */\nexport const DEFAULT_FIREWALL_POLICY_MODE: FirewallPolicyMode = 'off';\n\n/** Env var carrying the mode. Named to match its two sibling flags. */\nexport const FIREWALL_POLICY_ENV_VAR = 'NEXUS_FIREWALL_POLICY';\n\n/**\n * Resolve the firewall policy mode from the environment.\n *\n * Never throws, because a security layer must not fail-closed at startup on an\n * operator typo (#3130). The two non-happy paths resolve DIFFERENTLY, though:\n * unset or empty resolves silently to `off` (absence is the normal state), while\n * an explicit-but-invalid value resolves to `audit` and emits one `warn`.\n *\n * @param env Environment to read (injectable for tests).\n * @param logger Injectable for tests; defaults to the shared module logger.\n */\nexport function resolveFirewallPolicyMode(\n env: NodeJS.ProcessEnv = process.env,\n logger?: ILogger\n): FirewallPolicyMode {\n return resolveEnvMode(\n env[FIREWALL_POLICY_ENV_VAR],\n FirewallPolicyModeSchema,\n DEFAULT_FIREWALL_POLICY_MODE,\n FIREWALL_POLICY_ENV_VAR,\n {\n ...(logger !== undefined ? { logger } : {}),\n // An explicit-but-invalid value lands on `audit`, NOT on the unset\n // default `off`. Unset means \"the operator has not opted in\" and `off` is\n // right for it; a typo means \"the operator opted in and mistyped how\",\n // and answering that with the most permissive mode hands them a firewall\n // that refuses nothing while they believe it is on. `audit` reports\n // without refusing, so it cannot break an external caller any more than\n // `off` can, and it emits the `wouldRefuse` telemetry the rollout is\n // supposed to be collecting — which `off` does not.\n invalidFallback: 'audit',\n }\n );\n}\n","/**\n * nexus-agents/security - Audit Trail\n *\n * Machine-readable JSON audit events for security pipeline decisions.\n * Every trust classification, policy gate decision, corroboration check,\n * and reputation assessment is recorded as a structured event.\n *\n * Satisfies CLAUDE.md requirement: \"Every action on untrusted input must\n * log: trust tier, sources cited, policy gate decision, stripped content.\"\n *\n * @module security/audit-trail\n * (Source: Issue #832 — Security audit trail)\n */\n\nimport { getTimeProvider } from '../core/index.js';\nimport type { TrustTier } from './trust-types.js';\nimport type { AgentActionType } from './action-schema.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Maximum stored events before oldest are evicted. */\nconst MAX_EVENTS = 10_000;\n\n/**\n * Discriminated union of audit event types.\n * Each event captures a single security pipeline decision.\n */\nexport type AuditEvent =\n | TrustClassificationEvent\n | PolicyGateEvent\n | CorroborationEvent\n | ReputationEvent\n | SanitizationEvent\n | GraphExecutionAuditEvent\n | ClawGuardViolationEvent;\n\n/** Base fields shared by all audit events. */\ninterface AuditEventBase {\n readonly id: string;\n readonly timestamp: string;\n readonly component: string;\n}\n\n/** Trust classification decision. */\nexport interface TrustClassificationEvent extends AuditEventBase {\n readonly type: 'trust_classification';\n readonly username: string;\n readonly assignedTier: TrustTier;\n readonly userRole: string;\n /**\n * Present only when a maintainer allowlist was consulted (#4992). A\n * classification that consulted no list records nothing here rather than\n * `false` — \"not measured\" and \"measured false\" must stay distinguishable in\n * the audit record.\n */\n readonly isAllowlisted?: boolean;\n readonly wasDowngraded: boolean;\n readonly reason: string;\n}\n\n/** Policy gate evaluation result. */\nexport interface PolicyGateEvent extends AuditEventBase {\n readonly type: 'policy_gate';\n /**\n * The agent action evaluated, for the security policy-gate path\n * (security/policy-gate.ts). Optional because the PIPELINE policy path\n * (pipeline/policy-evaluator.ts → #3710) records stage-boundary policy\n * decisions that have no `AgentAction` — they carry {@link stageType} +\n * {@link mode} + {@link ruleIds} instead. Security emitters always set it.\n */\n readonly actionType?: AgentActionType;\n readonly allowed: boolean;\n readonly requiresApproval: boolean;\n readonly inputTrustTier: TrustTier;\n readonly violationRules: readonly string[];\n /**\n * Pipeline-policy fields (#3710). Carried for the dev-pipeline\n * consensus→execute seam so the DURABLE record can distinguish soak (`warn`)\n * from enforce (`block`) and which rules/stage fired — without these the\n * persisted event is useless to the tune/readiness loop. Absent for the\n * security policy-gate path.\n */\n /** Enforcement mode the decision was made under: `warn` (soak) or `block` (enforce). */\n readonly mode?: 'off' | 'warn' | 'block';\n /** IDs of the policy rules that fired (mirrors `violationRules` for the pipeline path). */\n readonly ruleIds?: readonly string[];\n /** Type of the stage the gate guarded (e.g. `execute`). */\n readonly stageType?: string;\n /**\n * #3727: discriminates a per-EVALUATION SUMMARY record (`'summary'` — emitted\n * once per pipeline policy evaluation INCLUDING clean ones, the DENOMINATOR for\n * the would-block rate) from a per-VIOLATION record (`'violation'` — the\n * existing #3710 per-violation records). Absent for the security policy-gate\n * path. Denominator = count(recordKind==='summary'); numerator = summaries with\n * `violationCount > 0`. Scope the #3710 count-parity assertion to `'violation'`.\n */\n readonly recordKind?: 'summary' | 'violation';\n /** #3727: number of violations in THIS evaluation (set on the summary record). */\n readonly violationCount?: number;\n}\n\n/** Corroboration validation result. */\nexport interface CorroborationEvent extends AuditEventBase {\n readonly type: 'corroboration';\n readonly actionType: AgentActionType;\n readonly satisfied: boolean;\n readonly sourceCount: number;\n readonly missingRequirements: readonly string[];\n}\n\n/** Reputation assessment result. */\nexport interface ReputationEvent extends AuditEventBase {\n readonly type: 'reputation';\n readonly username: string;\n readonly reputationScore: number;\n readonly isSuspicious: boolean;\n readonly effectiveTier: TrustTier;\n readonly signalCount: number;\n}\n\n/** Summary of a single element stripped during sanitization. */\nexport interface StrippedElementSummary {\n /** Truncated tag text (≤30 chars + '...' from the sanitizer). */\n readonly tag: string;\n /** Reason the element was removed (e.g. 'Trail of Bits injection vector'). */\n readonly reason: string;\n}\n\n/** Max stripped-element details retained per sanitization event. */\nexport const MAX_STRIPPED_ELEMENTS_PER_EVENT = 20;\n\n/** Input sanitization result. */\nexport interface SanitizationEvent extends AuditEventBase {\n readonly type: 'sanitization';\n readonly source: string;\n readonly wasModified: boolean;\n /** Whether input exceeded the configured limit. Absent on events that predate this field. */\n readonly truncated?: boolean;\n readonly strippedCount: number;\n readonly injectionFlagCount: number;\n /**\n * Per-element tag/reason details, truncated to at most\n * MAX_STRIPPED_ELEMENTS_PER_EVENT entries. Required by CLAUDE.md's\n * Untrusted Input Policy: \"Log stripped elements for audit trail.\"\n */\n readonly strippedElements: readonly StrippedElementSummary[];\n}\n\n/**\n * ClawGuard AUDIT-mode violation (#4097). Recorded a tool call that violated\n * the derived access policy but was allowed under `audit` mode. Its only\n * producer (the access-constraint deriver's MCP guard) was deleted in #5108,\n * so no new events of this type are written; the member stays in the union\n * because `AuditEvent` is published and existing ledgers may carry it.\n * Removal is a breaking change scheduled for the next major (#6319).\n */\nexport interface ClawGuardViolationEvent extends AuditEventBase {\n readonly type: 'clawguard_violation';\n /** The tool whose call violated the policy. */\n readonly toolName: string;\n /** Human-readable warning from the access decision (may be truncated). */\n readonly warning: string;\n /** Source of the derived policy (`llm` / `fallback-keyword` / `bypass`). */\n readonly policySource: string;\n /** Policy mode under which the violation was allowed (e.g. `audit`). */\n readonly mode: string;\n /** Request ID of the offending tool call, for correlation. */\n readonly requestId: string;\n /**\n * Which rule produced the verdict (#5106) — `unbypassable:tool`,\n * `unbypassable:path`, `allowedTools`, `allowedTools:confirm_risky`.\n *\n * A first-class field rather than prose inside `warning`, because `warning`\n * is truncated at 500 chars and a long attacker-selectable `path` argument\n * pushes the rule off the end. A chain reader must be able to tell an\n * unbypassable denylist hit from an allowlist miss without parsing a string\n * that may have been cut mid-word.\n *\n * Absent for verdicts that carry no rule (an audit-mode allowlist\n * observation), which is why it is optional rather than defaulted — there is\n * no rule to name, and inventing one would misreport.\n */\n readonly matchedRule?: string;\n}\n\n/** Graph execution lifecycle event (Issue #839). */\nexport interface GraphExecutionAuditEvent extends AuditEventBase {\n readonly type: 'graph_execution';\n readonly graphEvent: string;\n readonly nodeId?: string;\n readonly stepNumber: number;\n readonly detail: string;\n}\n\n/**\n * Query filter for retrieving audit events.\n *\n * The post-mortem dimensions (#3197) — `actionType`, `actor`, `violationRule`\n * — NARROW to events that actually carry the field (events lacking it are\n * excluded), unlike `trustTier`'s legacy keep-non-applicable behavior. Only\n * dimensions backed by a real event field are offered: `resource` and\n * `policyName` from the original ask were dropped because no AuditEvent\n * records them (a filter with no backing field would be dead config); the\n * policy-rule intent is served by `violationRule` (PolicyGateEvent's\n * `violationRules`).\n */\nexport interface AuditQuery {\n readonly type?: AuditEvent['type'];\n readonly since?: string;\n readonly until?: string;\n readonly trustTier?: TrustTier;\n /** Match PolicyGate/Corroboration events by their `actionType`. */\n readonly actionType?: AgentActionType;\n /** Match Trust/Reputation events by `username` (the acting/assessed user). */\n readonly actor?: string;\n /** Match PolicyGate events whose `violationRules` include this rule name. */\n readonly violationRule?: string;\n readonly limit?: number;\n}\n\n// ============================================================================\n// AuditTrail\n// ============================================================================\n\n/**\n * Append-only audit trail for security pipeline decisions.\n * Events are bounded by MAX_EVENTS to prevent unbounded growth.\n */\n/**\n * Optional durable sink: receives every fully-formed event appended to the\n * trail, so security decisions can be mirrored to a persistent, hash-chained\n * store (see security/audit-bridge.ts). Default-off — when absent, the trail\n * behaves exactly as before (#3291).\n */\nexport type DurableAuditSink = (event: AuditEvent) => void;\n\nexport class AuditTrail {\n private events: AuditEvent[] = [];\n private nextId = 1;\n\n constructor(private readonly durableSink?: DurableAuditSink) {}\n\n /** Appends an event to the trail. Returns the assigned event ID. */\n append(event: Omit<AuditEvent, 'id' | 'timestamp'>): string {\n const id = `audit-${String(this.nextId++)}`;\n const fullEvent = {\n ...event,\n id,\n timestamp: getTimeProvider().nowIso(),\n } as AuditEvent;\n\n this.events.push(fullEvent);\n this.enforceLimit();\n\n // Mirror to the durable store when wired (#3291). Best-effort: a sink\n // failure must never break the in-memory security pipeline.\n if (this.durableSink !== undefined) {\n try {\n this.durableSink(fullEvent);\n } catch {\n // Sink implementations already swallow+log; this is belt-and-suspenders.\n }\n }\n\n return id;\n }\n\n /** Queries events matching the given filter. */\n query(filter: AuditQuery = {}): readonly AuditEvent[] {\n let results = this.events as readonly AuditEvent[];\n\n if (filter.type !== undefined) {\n results = results.filter((e) => e.type === filter.type);\n }\n\n if (filter.since !== undefined) {\n results = filterSince(results, filter.since);\n }\n\n if (filter.until !== undefined) {\n results = filterUntil(results, filter.until);\n }\n\n if (filter.trustTier !== undefined) {\n results = filterByTrustTier(results, filter.trustTier);\n }\n\n if (filter.actionType !== undefined) {\n results = filterByActionType(results, filter.actionType);\n }\n\n if (filter.actor !== undefined) {\n results = filterByActor(results, filter.actor);\n }\n\n if (filter.violationRule !== undefined) {\n results = filterByViolationRule(results, filter.violationRule);\n }\n\n const limit = filter.limit ?? results.length;\n return results.slice(-limit);\n }\n\n /** Returns the total number of events. */\n get size(): number {\n return this.events.length;\n }\n\n /** Clears all events. */\n clear(): void {\n this.events = [];\n }\n\n /** Enforces MAX_EVENTS bound. */\n private enforceLimit(): void {\n if (this.events.length > MAX_EVENTS) {\n this.events = this.events.slice(-MAX_EVENTS);\n }\n }\n}\n\n// ============================================================================\n// Filter Helpers\n// ============================================================================\n\nfunction filterSince(events: readonly AuditEvent[], since: string): readonly AuditEvent[] {\n const sinceTime = new Date(since).getTime();\n return events.filter((e) => new Date(e.timestamp).getTime() >= sinceTime);\n}\n\nfunction filterUntil(events: readonly AuditEvent[], until: string): readonly AuditEvent[] {\n const untilTime = new Date(until).getTime();\n return events.filter((e) => new Date(e.timestamp).getTime() <= untilTime);\n}\n\nfunction filterByTrustTier(events: readonly AuditEvent[], tier: TrustTier): readonly AuditEvent[] {\n return events.filter((e) => {\n if (e.type === 'trust_classification') return e.assignedTier === tier;\n if (e.type === 'policy_gate') return e.inputTrustTier === tier;\n if (e.type === 'reputation') return e.effectiveTier === tier;\n return true;\n });\n}\n\n/**\n * Narrow to events carrying the given `actionType` (#3197). Only PolicyGate and\n * Corroboration events have one; all others are excluded.\n */\nfunction filterByActionType(\n events: readonly AuditEvent[],\n actionType: AgentActionType\n): readonly AuditEvent[] {\n return events.filter(\n (e) => (e.type === 'policy_gate' || e.type === 'corroboration') && e.actionType === actionType\n );\n}\n\n/**\n * Narrow to events for the given actor (#3197), matched on `username`. Only\n * Trust-classification and Reputation events carry a username; others are\n * excluded so an actor filter never returns unrelated rows.\n */\nfunction filterByActor(events: readonly AuditEvent[], actor: string): readonly AuditEvent[] {\n return events.filter(\n (e) => (e.type === 'trust_classification' || e.type === 'reputation') && e.username === actor\n );\n}\n\n/**\n * Narrow to PolicyGate events whose `violationRules` include the given rule\n * name (#3197) — the security post-mortem \"who tripped rule X\" query.\n */\nfunction filterByViolationRule(events: readonly AuditEvent[], rule: string): readonly AuditEvent[] {\n return events.filter((e) => e.type === 'policy_gate' && e.violationRules.includes(rule));\n}\n\n// ============================================================================\n// Convenience Emitters\n// ============================================================================\n\n/**\n * Records a trust classification decision.\n */\nexport function emitTrustEvent(\n trail: AuditTrail,\n data: Omit<TrustClassificationEvent, 'id' | 'timestamp' | 'type' | 'component'>\n): string {\n return trail.append({\n type: 'trust_classification',\n component: 'trust-classifier',\n ...data,\n });\n}\n\n/**\n * Records a policy gate evaluation.\n */\nexport function emitPolicyEvent(\n trail: AuditTrail,\n data: Omit<PolicyGateEvent, 'id' | 'timestamp' | 'type' | 'component'>\n): string {\n return trail.append({\n type: 'policy_gate',\n component: 'policy-gate',\n ...data,\n });\n}\n\n/**\n * Records a PIPELINE-policy gate decision (#3710) — the dev-pipeline\n * consensus→execute seam. Distinct from {@link emitPolicyEvent} (the security\n * policy-gate path with an `AgentAction`): this carries `mode`/`ruleIds`/\n * `stageType` so the durable record distinguishes soak(warn) from enforce(block)\n * and is usable by the tune/readiness loop. ONE append per call.\n */\nexport function emitPipelinePolicyEvent(\n trail: AuditTrail,\n data: Omit<PolicyGateEvent, 'id' | 'timestamp' | 'type' | 'component' | 'actionType'>\n): string {\n return trail.append({\n type: 'policy_gate',\n component: 'pipeline-policy-evaluator',\n ...data,\n });\n}\n\n/** The pipeline-policy would-block rate over a window (#3727). */\nexport interface PolicyWouldBlockRate {\n /** Total pipeline-policy evaluations (the denominator — summary records). */\n readonly evaluations: number;\n /** Evaluations that had ≥1 violation (what enforce mode WOULD block). */\n readonly wouldBlock: number;\n /** `wouldBlock / evaluations`; 0 when there are no evaluations. */\n readonly rate: number;\n}\n\n/**\n * Compute the pipeline-policy would-block RATE from durable audit events (#3727)\n * — the read-side of the per-evaluation summary records, and the signal the\n * #3769-enforce soak-readiness gate needs. Denominator = per-evaluation SUMMARY\n * records (`recordKind === 'summary'`); numerator = summaries with\n * `violationCount > 0` (the would-block fraction, independent of warn/block mode).\n * Per-violation records (`recordKind === 'violation'`) are intentionally NOT\n * counted — counting them would double-count and break the denominator.\n */\nexport function computePolicyWouldBlockRate(events: readonly AuditEvent[]): PolicyWouldBlockRate {\n let evaluations = 0;\n let wouldBlock = 0;\n for (const e of events) {\n if (e.type !== 'policy_gate' || e.recordKind !== 'summary') continue;\n evaluations += 1;\n if ((e.violationCount ?? 0) > 0) wouldBlock += 1;\n }\n return { evaluations, wouldBlock, rate: evaluations > 0 ? wouldBlock / evaluations : 0 };\n}\n\n/**\n * Records a corroboration validation.\n */\nexport function emitCorroborationEvent(\n trail: AuditTrail,\n data: Omit<CorroborationEvent, 'id' | 'timestamp' | 'type' | 'component'>\n): string {\n return trail.append({\n type: 'corroboration',\n component: 'corroboration-validator',\n ...data,\n });\n}\n\n/**\n * Records a reputation assessment.\n */\nexport function emitReputationEvent(\n trail: AuditTrail,\n data: Omit<ReputationEvent, 'id' | 'timestamp' | 'type' | 'component'>\n): string {\n return trail.append({\n type: 'reputation',\n component: 'reputation-model',\n ...data,\n });\n}\n\n/**\n * Records an input sanitization result.\n */\nexport function emitSanitizationEvent(\n trail: AuditTrail,\n data: Omit<SanitizationEvent, 'id' | 'timestamp' | 'type' | 'component'>\n): string {\n return trail.append({\n type: 'sanitization',\n component: 'input-sanitizer',\n ...data,\n });\n}\n\n/**\n * Records a graph execution lifecycle event.\n */\nexport function emitGraphExecutionEvent(\n trail: AuditTrail,\n data: Omit<GraphExecutionAuditEvent, 'id' | 'timestamp' | 'type' | 'component'>\n): string {\n return trail.append({\n type: 'graph_execution',\n component: 'graph-executor',\n ...data,\n });\n}\n\n/**\n * Creates an onEvent callback that bridges graph events to the audit trail.\n * Pass the returned function as `onEvent` in GraphExecuteOptions.\n *\n * @example\n * const trail = createAuditTrail();\n * await executeGraph(graph, inputs, { onEvent: createGraphAuditBridge(trail) });\n */\nexport function createGraphAuditBridge(\n trail: AuditTrail\n): (event: { readonly type: string; readonly [key: string]: unknown }) => void {\n return (event) => {\n const nodeId = typeof event['nodeId'] === 'string' ? event['nodeId'] : undefined;\n const stepNumber = typeof event['stepNumber'] === 'number' ? event['stepNumber'] : 0;\n emitGraphExecutionEvent(trail, {\n graphEvent: event.type,\n ...(nodeId !== undefined ? { nodeId } : {}),\n stepNumber,\n detail: formatGraphEventDetail(event),\n });\n };\n}\n\ntype GraphEventLike = { readonly type: string; readonly [key: string]: unknown };\n\n/**\n * A node that produced nothing: paused for human input, or refused by its\n * precondition. The audit trail is hash-chained, so this must not land in it as\n * \"completed in 0ms\".\n */\nfunction formatNotCompleted(event: GraphEventLike): string {\n const detail = event['detail'];\n const suffix = typeof detail === 'string' && detail !== '' ? `: ${detail}` : '';\n return `Node ${String(event['nodeId'])} ${String(event['reason'])} (did not complete)${suffix}`;\n}\n\n/** A completion, qualified when the run actually paused rather than finished. */\nfunction formatCompletion(event: GraphEventLike): string {\n return event['halted'] === true\n ? `HALTED awaiting input after ${String(event['totalSteps'])} steps, ${String(event['durationMs'])}ms — NOT complete`\n : `Complete: ${String(event['totalSteps'])} steps, ${String(event['durationMs'])}ms`;\n}\n\n/** Formats a brief detail string from a graph event. */\nfunction formatGraphEventDetail(event: GraphEventLike): string {\n if (event.type === 'node_not_completed') return formatNotCompleted(event);\n switch (event.type) {\n case 'node_started':\n return `Node ${String(event['nodeId'])} starting`;\n case 'node_completed':\n return `Node ${String(event['nodeId'])} completed in ${String(event['durationMs'])}ms`;\n case 'node_error':\n return `Node ${String(event['nodeId'])} failed: ${String(event['error'])}`;\n case 'state_updated':\n return `State updated: ${String(event['updatedKeys'])}`;\n case 'step_completed':\n return `Step ${String(event['stepNumber'])}: ${String(event['nodesExecuted'])} nodes`;\n case 'execution_complete':\n return formatCompletion(event);\n default:\n return event.type;\n }\n}\n\n/**\n * Creates a new AuditTrail instance. Pass a {@link DurableAuditSink} (e.g. from\n * `createDurableAuditSink(auditLogger)`) to mirror appended security decisions\n * to a durable, hash-chained store (#3291). Default: in-memory only.\n */\nexport function createAuditTrail(durableSink?: DurableAuditSink): AuditTrail {\n return new AuditTrail(durableSink);\n}\n","/**\n * Security → durable audit bridge (#3291, epic #3288 item 3).\n *\n * The security `AuditTrail` (audit-trail.ts) is in-memory-only, so every\n * trust/policy/reputation/sanitization decision is lost on process exit. The\n * durable `AuditLogger` (audit/) persists with a tamper-evident hash chain but\n * lacks these rich security event types. This bridge maps each security\n * `AuditEvent` (the discriminated union) into a durable `AuditEventInput` and\n * forwards it to an `IAuditLogger`, so security decisions become durable and\n * hash-verifiable — satisfying CLAUDE.md's \"immutable audit\" mandate.\n *\n * Per the #3291 confirmation vote (fold-in design): security events are folded\n * into the durable schema with `category`/`action` distinguishing them\n * (queryable by `action: 'security.*'`), rather than standing up a parallel\n * SecurityAuditLogger.\n *\n * @module security/audit-bridge\n */\n\nimport { createLogger, getErrorMessage } from '../core/index.js';\nimport { createAuditTrail } from './audit-trail.js';\nimport type {\n AuditEvent as SecurityAuditEvent,\n AuditTrail,\n DurableAuditSink,\n} from './audit-trail.js';\nimport type {\n AuditEventInput,\n AuditActor,\n AuditOutcome,\n AuditSeverity,\n IAuditLogger,\n} from '../audit/audit-types.js';\n\nconst logger = createLogger({ component: 'SecurityAuditBridge' });\n\nfunction systemActor(id: string, name?: string): AuditActor {\n return name !== undefined ? { type: 'system', id, name } : { type: 'system', id };\n}\n\nfunction userActor(username: string): AuditActor {\n return { type: 'user', id: username };\n}\n\ntype TrustEvent = Extract<SecurityAuditEvent, { type: 'trust_classification' }>;\ntype PolicyEvent = Extract<SecurityAuditEvent, { type: 'policy_gate' }>;\ntype CorroborationEvt = Extract<SecurityAuditEvent, { type: 'corroboration' }>;\ntype ReputationEvt = Extract<SecurityAuditEvent, { type: 'reputation' }>;\ntype SanitizationEvt = Extract<SecurityAuditEvent, { type: 'sanitization' }>;\ntype GraphEvt = Extract<SecurityAuditEvent, { type: 'graph_execution' }>;\ntype ClawGuardEvt = Extract<SecurityAuditEvent, { type: 'clawguard_violation' }>;\n\nfunction mapTrust(e: TrustEvent): AuditEventInput {\n const severity: AuditSeverity = e.wasDowngraded ? 'warning' : 'info';\n return {\n category: 'authorization',\n severity,\n outcome: 'success',\n action: 'security.trust_classification',\n actor: userActor(e.username),\n description: e.reason,\n metadata: {\n assignedTier: e.assignedTier,\n userRole: e.userRole,\n // Absent when no allowlist was consulted (#4992) — never a default false.\n ...(e.isAllowlisted !== undefined ? { isAllowlisted: e.isAllowlisted } : {}),\n wasDowngraded: e.wasDowngraded,\n component: e.component,\n },\n };\n}\n\n/**\n * Optional pipeline-policy metadata fields, absent on the security path. Extracted\n * so {@link mapPolicyGate} stays under the complexity cap. `actionType`/`mode`/\n * `ruleIds`/`stageType` are the #3710 round-trip fields; `recordKind`/\n * `violationCount` are #3727 (the summary/violation discriminator + per-evaluation\n * count the durable would-block rate needs).\n */\nfunction pipelinePolicyMetadata(e: PolicyEvent): Record<string, unknown> {\n return {\n ...(e.actionType !== undefined ? { actionType: e.actionType } : {}),\n ...(e.mode !== undefined ? { mode: e.mode } : {}),\n ...(e.ruleIds !== undefined ? { ruleIds: e.ruleIds } : {}),\n ...(e.stageType !== undefined ? { stageType: e.stageType } : {}),\n ...(e.recordKind !== undefined ? { recordKind: e.recordKind } : {}),\n ...(e.violationCount !== undefined ? { violationCount: e.violationCount } : {}),\n };\n}\n\nfunction mapPolicyGate(e: PolicyEvent): AuditEventInput {\n const outcome: AuditOutcome = e.allowed ? 'success' : 'denied';\n // #3710/#3727: the pipeline-policy path carries mode/ruleIds/stageType +\n // recordKind/violationCount and no actionType; these MUST round-trip into the\n // durable metadata (see pipelinePolicyMetadata). The security path leaves them\n // undefined and keeps its actionType-keyed shape.\n return {\n category: 'authorization',\n severity: e.allowed ? 'info' : 'warning',\n outcome,\n action: 'security.policy_gate',\n actor: systemActor(e.component),\n policyName: 'security.policy_gate',\n policyDecision: e.allowed ? 'allow' : 'deny',\n ...(e.violationRules.length > 0 ? { violationType: e.violationRules.join(',') } : {}),\n metadata: {\n requiresApproval: e.requiresApproval,\n inputTrustTier: e.inputTrustTier,\n violationRules: e.violationRules,\n ...pipelinePolicyMetadata(e),\n },\n };\n}\n\nfunction mapCorroboration(e: CorroborationEvt): AuditEventInput {\n return {\n category: 'security',\n severity: e.satisfied ? 'info' : 'warning',\n outcome: e.satisfied ? 'success' : 'denied',\n action: 'security.corroboration',\n actor: systemActor(e.component),\n metadata: {\n actionType: e.actionType,\n sourceCount: e.sourceCount,\n missingRequirements: e.missingRequirements,\n },\n };\n}\n\nfunction mapReputation(e: ReputationEvt): AuditEventInput {\n return {\n category: 'security',\n severity: e.isSuspicious ? 'warning' : 'info',\n outcome: 'success',\n action: 'security.reputation',\n actor: userActor(e.username),\n metadata: {\n reputationScore: e.reputationScore,\n isSuspicious: e.isSuspicious,\n effectiveTier: e.effectiveTier,\n signalCount: e.signalCount,\n component: e.component,\n },\n };\n}\n\nfunction mapSanitization(e: SanitizationEvt): AuditEventInput {\n return {\n category: 'security',\n severity: e.injectionFlagCount > 0 ? 'warning' : 'info',\n outcome: 'success',\n action: 'security.sanitization',\n actor: systemActor(e.component, e.source),\n metadata: {\n source: e.source,\n wasModified: e.wasModified,\n ...(e.truncated !== undefined ? { truncated: e.truncated } : {}),\n strippedCount: e.strippedCount,\n injectionFlagCount: e.injectionFlagCount,\n strippedElements: e.strippedElements,\n },\n };\n}\n\nfunction mapGraphExecution(e: GraphEvt): AuditEventInput {\n return {\n category: 'system',\n severity: 'info',\n outcome: 'success',\n action: 'security.graph_execution',\n actor: systemActor(e.component),\n description: e.detail,\n metadata: {\n graphEvent: e.graphEvent,\n ...(e.nodeId !== undefined ? { nodeId: e.nodeId } : {}),\n stepNumber: e.stepNumber,\n },\n };\n}\n\n/**\n * Map a ClawGuard AUDIT-mode violation (#4097) to a durable event. `outcome` is\n * `success` because audit mode ALLOWED the call (it is log-and-allow, not a\n * denial); `severity` is `warning` to flag the policy violation. Queryable by\n * `action: 'security.clawguard_violation'`.\n */\nfunction mapClawGuard(e: ClawGuardEvt): AuditEventInput {\n return {\n category: 'authorization',\n severity: 'warning',\n outcome: 'success',\n action: 'security.clawguard_violation',\n actor: systemActor(e.component),\n metadata: {\n toolName: e.toolName,\n warning: e.warning,\n policySource: e.policySource,\n mode: e.mode,\n requestId: e.requestId,\n },\n };\n}\n\n/**\n * Map a security `AuditEvent` (discriminated union) to a durable\n * `AuditEventInput`. Pure — no side effects. The durable logger assigns\n * id/timestamp/hash, so those are omitted here.\n */\nexport function securityAuditEventToInput(event: SecurityAuditEvent): AuditEventInput {\n switch (event.type) {\n case 'trust_classification':\n return mapTrust(event);\n case 'policy_gate':\n return mapPolicyGate(event);\n case 'corroboration':\n return mapCorroboration(event);\n case 'reputation':\n return mapReputation(event);\n case 'sanitization':\n return mapSanitization(event);\n case 'graph_execution':\n return mapGraphExecution(event);\n case 'clawguard_violation':\n return mapClawGuard(event);\n }\n}\n\n/**\n * Build a {@link SecurityAuditSink} that maps security events into the durable\n * schema and writes them through `auditLogger`. Errors are swallowed and logged\n * — durable mirroring must never break the security pipeline.\n */\nexport function createDurableAuditSink(auditLogger: IAuditLogger): DurableAuditSink {\n return (event: SecurityAuditEvent) => {\n try {\n auditLogger.log(securityAuditEventToInput(event));\n } catch (error) {\n logger.warn('Failed to mirror security event to durable audit log', {\n type: event.type,\n error: getErrorMessage(error),\n });\n }\n };\n}\n\n/**\n * Wrap an optional `auditLogger` into a durable {@link AuditTrail} (#4097) — the\n * single representation of \"mirror security events to the shared hash chain when\n * a logger is threaded.\" Returns undefined when none is present, so the no-logger\n * path establishes NO trail and stays byte-identical (mirrors the dev-pipeline\n * `buildPolicyAuditTrail` guard). Consumers establish the trail ONLY when this\n * returns one; `run-graph-workflow.ts` is the remaining caller since #5108.\n */\nexport function createDurableAuditTrail(auditLogger?: IAuditLogger): AuditTrail | undefined {\n if (auditLogger === undefined) return undefined;\n return createAuditTrail(createDurableAuditSink(auditLogger));\n}\n","/**\n * nexus-agents/security - Trust Classifier\n *\n * Classifies GitHub users and content into trust tiers based on\n * repository relationship, allowlist membership, and content analysis.\n * Works with the input sanitizer to determine how agent decisions\n * should weight each input source.\n *\n * @module security/trust-classifier\n * (Source: Issue #818, #819 — Phase 1: Input Sanitization)\n */\n\nimport type { TrustTier, GitHubUserRole, SanitizedInput, SanitizerConfig } from './trust-types.js';\nimport { ROLE_DEFAULT_TRUST, TRUST_TIER_NUMERIC } from './trust-types.js';\n\n// ============================================================================\n// GitHub Author Association Mapping\n// ============================================================================\n\n/**\n * Maps GitHub API author_association values to our GitHubUserRole enum.\n * See: https://docs.github.com/en/graphql/reference/enums#commentauthorassociation\n */\nexport function mapAuthorAssociation(association: string): GitHubUserRole {\n switch (association.toUpperCase()) {\n case 'OWNER':\n return 'owner';\n case 'MEMBER':\n return 'member';\n case 'COLLABORATOR':\n return 'collaborator';\n case 'CONTRIBUTOR':\n return 'contributor';\n case 'FIRST_TIMER':\n case 'FIRST_TIME_CONTRIBUTOR':\n case 'NONE':\n return 'unknown';\n case 'MANNEQUIN':\n return 'unknown';\n default:\n return 'unknown';\n }\n}\n\n// ============================================================================\n// Trust Classification\n// ============================================================================\n\n/**\n * Input for trust classification.\n */\nexport interface ClassifyInput {\n /** GitHub username. */\n readonly username: string;\n /** GitHub API author_association value. */\n readonly authorAssociation: string;\n /** Sanitized input (if content has already been through the sanitizer). */\n readonly sanitizedInput?: SanitizedInput;\n /** Sanitizer config (for allowlist check). */\n readonly config?: Partial<SanitizerConfig>;\n}\n\n/**\n * Result of trust classification.\n */\nexport interface ClassifyResult {\n /** Assigned trust tier. */\n readonly trustTier: TrustTier;\n /** GitHub user role. */\n readonly userRole: GitHubUserRole;\n /** Whether the user is on the maintainer allowlist. */\n readonly isAllowlisted: boolean;\n /** Whether content triggered a trust downgrade. */\n readonly wasDowngraded: boolean;\n /** Reason for the assigned tier. */\n readonly reason: string;\n}\n\n/**\n * Classifies a GitHub user and their content into a trust tier.\n *\n * The trust tier is determined by:\n * 1. Allowlist membership (always Tier 1)\n * 2. GitHub author_association → role → default tier\n * 3. Content injection analysis (can only downgrade, never upgrade)\n *\n * ⚠ **Use HostileInputFirewall.process() in agent code paths.** The live\n * paths (`dogfooding/issue-triage`, `dogfooding/pr-reviewer`) route through\n * it as of #4992. Calling classifyTrust() directly emits no audit-trail\n * event, and unless the caller supplies `config.allowlistedMaintainers` no\n * allowlist is consulted — `isAllowlisted: false` is then a default, not a\n * measurement, and must not be recorded as one. Direct use is for unit tests\n * and non-decision analysis only. (The Rule of Two is enforced separately by\n * `evaluatePolicy` in policy-gate; the firewall evaluates it too, as a\n * signal, and refuses on it only under `NEXUS_FIREWALL_POLICY=enforce`.)\n *\n * @see packages/nexus-agents/src/security/firewall/firewall-pipeline.ts\n * @see packages/nexus-agents/src/security/policy-gate.ts\n */\nexport function classifyTrust(input: ClassifyInput): ClassifyResult {\n const allowlistedMaintainers = input.config?.allowlistedMaintainers ?? [];\n const isAllowlisted = allowlistedMaintainers.includes(input.username);\n const userRole = mapAuthorAssociation(input.authorAssociation);\n\n if (isAllowlisted) {\n return {\n trustTier: '1',\n userRole,\n isAllowlisted: true,\n wasDowngraded: false,\n reason: `User ${input.username} is on the maintainer allowlist`,\n };\n }\n\n const baseTier = ROLE_DEFAULT_TRUST[userRole];\n\n // Explicit false means the sanitization stage did not measure content.\n // Absence is legacy sanitizer output and remains measured fail-closed.\n if (input.sanitizedInput !== undefined && input.sanitizedInput.contentTierMeasured !== false) {\n const contentTier = input.sanitizedInput.trustTier;\n const downgraded = TRUST_TIER_NUMERIC[contentTier] > TRUST_TIER_NUMERIC[baseTier];\n\n return {\n trustTier: downgraded ? contentTier : baseTier,\n userRole,\n isAllowlisted: false,\n wasDowngraded: downgraded,\n reason: downgraded\n ? `Downgraded from Tier ${baseTier} to ${contentTier}: injection patterns detected`\n : `Role ${userRole} → Tier ${baseTier}`,\n };\n }\n\n return {\n trustTier: baseTier,\n userRole,\n isAllowlisted: false,\n wasDowngraded: false,\n reason: `Role ${userRole} → Tier ${baseTier}`,\n };\n}\n\n/**\n * Checks whether a trust tier can influence agent decisions.\n * Tiers 3-4 are informational only — they cannot drive actions.\n */\nexport function canInfluenceDecisions(tier: TrustTier): boolean {\n return TRUST_TIER_NUMERIC[tier] <= 2;\n}\n\n/**\n * Checks whether a trust tier requires corroboration with Tier 1 sources.\n * Tier 2 requires corroboration; Tier 1 is self-sufficient.\n */\nexport function requiresCorroboration(tier: TrustTier): boolean {\n return tier === '2';\n}\n\n/**\n * Returns the minimum trust tier required for a given action type.\n * Actions that modify state require higher trust.\n */\nexport function getRequiredTrustTier(actionType: string): TrustTier {\n switch (actionType) {\n case 'GeneratePatchPlan':\n return '1'; // Requires maintainer-level trust\n case 'DraftReply':\n case 'ProposeLabels':\n return '2'; // Requires at least collaborator-level trust\n case 'SummarizeIssue':\n case 'ClassifyIssue':\n case 'IdentifyDuplicates':\n return '3'; // Read-only, can use any input\n case 'RequestHumanApproval':\n case 'RefuseAction':\n return '4'; // Always allowed (safety actions)\n default:\n return '1'; // Unknown actions require highest trust\n }\n}\n","/**\n * nexus-agents/security/firewall - Types\n *\n * Configuration, result, and adapter interface types for the\n * HostileInputFirewall pipeline. Uses Zod schemas for runtime\n * validation at construction boundaries.\n *\n * @module security/firewall/firewall-types\n * (Source: Issue #826 — Reusable Hostile Input Firewall)\n */\n\nimport { z } from 'zod';\nimport type { IAuditLogger } from '../../audit/audit-types.js';\nimport type { AgentAction } from '../action-schema.js';\nimport type { Violation } from '../policy-gate.js';\nimport type { FirewallPolicyMode } from './firewall-policy-mode.js';\nimport type {\n ReputationAssessment,\n ReputationGatingMode,\n GitHubUserMetadata,\n} from '../reputation-model.js';\n\n// ============================================================================\n// Source Adapter Interface\n// ============================================================================\n\n/**\n * Metadata extracted from a platform-specific input source.\n */\nexport interface SourceMetadata {\n readonly username: string;\n readonly authorAssociation: string;\n readonly content: string;\n readonly sourceType: string;\n}\n\n/**\n * Adapter that extracts normalized metadata from platform-specific input.\n * Each platform (GitHub, GitLab, etc.) implements this interface.\n */\nexport interface ISourceAdapter {\n readonly platform: string;\n extractMetadata(input: unknown): SourceMetadata;\n}\n\n// ============================================================================\n// Stage Configuration\n// ============================================================================\n\n/**\n * Controls which pipeline stages run. Disabled stages use safe defaults.\n */\nexport const FirewallStagesSchema = z.object({\n sanitization: z.boolean().default(true),\n trustClassification: z.boolean().default(true),\n reputationAssessment: z.boolean().default(false),\n policyEnforcement: z.boolean().default(true),\n corroboration: z.boolean().default(false),\n audit: z.boolean().default(true),\n});\nexport type FirewallStages = z.infer<typeof FirewallStagesSchema>;\n\n/** Creates default stage configuration. */\nexport function createDefaultStages(): FirewallStages {\n return FirewallStagesSchema.parse({});\n}\n\n// ============================================================================\n// Firewall Configuration\n// ============================================================================\n\n/**\n * Configuration for the HostileInputFirewall.\n * The adapter is required; all other fields have sensible defaults.\n */\nexport const FirewallConfigSchema = z.object({\n stages: FirewallStagesSchema.default(() => ({\n sanitization: true,\n trustClassification: true,\n reputationAssessment: false,\n policyEnforcement: true,\n corroboration: false,\n audit: true,\n })),\n allowlistedMaintainers: z.array(z.string().min(1)).default([]),\n maxInputLength: z.number().int().positive().default(50_000),\n context: z\n .object({\n hasWriteAccess: z.boolean().default(false),\n hasSecretAccess: z.boolean().default(false),\n })\n .default(() => ({\n hasWriteAccess: false,\n hasSecretAccess: false,\n })),\n});\n\n/**\n * Full config including the adapter (not Zod-validated since it's an interface).\n */\nexport interface FirewallConfig {\n readonly adapter: ISourceAdapter;\n readonly stages?: Partial<FirewallStages>;\n readonly allowlistedMaintainers?: readonly string[];\n readonly maxInputLength?: number;\n readonly context?: {\n readonly hasWriteAccess?: boolean;\n readonly hasSecretAccess?: boolean;\n };\n /**\n * Rollout gate for behaviour changes to this published API (#5382).\n * Defaults to `NEXUS_FIREWALL_POLICY`, and to `off` when that is unset —\n * under `off` the firewall behaves exactly as it did before #5382.\n *\n * Explicit here as well as in the environment because the firewall is a\n * library: an embedding consumer must be able to opt in per instance without\n * setting a process-wide variable.\n */\n readonly policyMode?: FirewallPolicyMode;\n /**\n * Environment to resolve `policyMode` from when it is not given explicitly.\n * Injectable so the resolution path itself is testable — without this the\n * flag could be unreachable in production with every unit test still passing.\n */\n readonly env?: NodeJS.ProcessEnv;\n /**\n * Optional durable audit logger. When provided, every security decision the\n * firewall records is mirrored to this persistent, hash-chained store via\n * the audit bridge (#3291). When absent, decisions are in-memory only.\n */\n readonly auditLogger?: IAuditLogger;\n /**\n * Rollout gate for REPUTATION demotion (#5381). Distinct from `policyMode`:\n * different env var (`NEXUS_REPUTATION_GATING`) and — load-bearing — a\n * different default, `enforce` rather than `off`. Production reads this same\n * knob (`issue-triage.ts`, `pr-reviewer-helpers.ts`), and the firewall reading\n * a different one is what let the two compositions disagree under identical\n * configuration.\n */\n readonly reputationGatingMode?: ReputationGatingMode;\n /**\n * Supplies the reputation assessment. Defaults to `assessReputation` over the\n * instance's cache.\n *\n * Injectable for the same reason as `env` above: without it the reconciliation\n * is unobservable. The firewall hands the reputation engine only\n * `authorAssociation` + `injectionFlags` — the two inputs the trust classifier\n * already consumed — so reputation is never stricter than the classifier and\n * `reconcileTrustTier` returns the classifier tier every time. Deleting the\n * reconciliation passed 1588 tests (#5405). This seam is what lets a test\n * present a stricter tier and prove the check can fire.\n */\n readonly reputationAssessor?: (metadata: GitHubUserMetadata) => ReputationAssessment;\n /**\n * Whether the sanitizer's content tier is applied as a classification\n * downgrade (#4992). Default `true` — the firewall's behaviour since #826:\n * injection-bearing content from a Tier-2 author classifies as Tier 4.\n *\n * `false` keeps the classifier role-only. The sanitization stage still runs\n * and still records its injection flags — only the tier downgrade is\n * withheld. The dogfooding paths (`issue-triage`, `pr-reviewer`) set this\n * because they route content signals through reputation gating, which has\n * its own rollout knob (`NEXUS_REPUTATION_GATING`); applying the same signal\n * at classification too would bypass that knob and change the recorded\n * `trustTier` under the default `NEXUS_FIREWALL_POLICY=off`, which #5382\n * promises is pass-through.\n */\n readonly contentDowngrade?: boolean;\n}\n\n/**\n * Per-call inputs to {@link HostileInputFirewall.process} (#4992).\n *\n * These are the facts that vary by CALL rather than by instance, so a\n * process-wide firewall (the dogfooding singleton) can serve many repositories\n * and many access postures without holding any of them globally.\n */\nexport interface FirewallProcessOptions {\n /**\n * Maintainer allowlist for THIS call, from the repository context. Replaces —\n * does not merge with — the construction-time list, and is forgotten after\n * the call. When neither this nor the construction-time list was supplied,\n * no allowlist is consulted and `FirewallResult.isAllowlisted` is absent.\n */\n readonly allowlistedMaintainers?: readonly string[];\n /**\n * Access posture of the caller for THIS call, feeding the Rule-of-Two check.\n * Replaces the construction-time `context` for the call. Without it a shared\n * instance would evaluate every caller against one posture, and\n * `wouldRefuse` could never fire for a caller whose posture differs.\n */\n readonly context?: {\n readonly hasWriteAccess: boolean;\n readonly hasSecretAccess: boolean;\n };\n /**\n * The caller's own reputation measurement for THIS call. When present, the\n * reputation gate runs on it under `NEXUS_REPUTATION_GATING`, whether or not\n * the instance's `reputationAssessment` stage is on: `effectiveTrustTier` is\n * the enforced tier, `reputationGate` is returned, and the Rule-of-Two check,\n * `wouldRefuse` and the trust audit event all use that tier. This is what\n * lets a caller with richer signals than the firewall can see (account age,\n * comment history) act on ONE gate rather than two that can disagree.\n *\n * `assessment: undefined` means the caller measured nothing (reputation\n * disabled) but still wants the gate decision recorded on the classifier\n * tier; omitting the option entirely leaves the stage to the instance config.\n */\n readonly reputation?: {\n readonly assessment: ReputationAssessment | undefined;\n };\n /**\n * The action the caller intends to take on this input, for THIS call (#5380).\n *\n * With it, the `policyEnforcement` stage runs the full `evaluatePolicy` set —\n * the same seven checks production runs — against the enforced tier and the\n * call's access posture, and `FirewallResult.policy` carries every violation\n * plus the decision's own `requiresApproval`. Without it only the Rule of\n * Two, the one context-only check, can run; the six action-scoped checks are\n * then listed under `policy.unmeasured` rather than silently counted as\n * passed. `process()` is input-shaped and constructs no action itself, so\n * this is the only way those checks reach it.\n */\n readonly action?: AgentAction;\n /**\n * The repository's label set, consulted by the label-validity check when\n * `action` is a `ProposeLabels` (#5380). When absent, `evaluatePolicy`\n * reports `LABEL_SET_UNAVAILABLE` as a blocking violation — unevaluable\n * label validity fails closed, exactly as it does on the production path.\n */\n readonly existingLabels?: ReadonlySet<string>;\n}\n\n// ============================================================================\n// Agent Trust Label (ATL) Data\n// ============================================================================\n\n/**\n * Structured data for an Agent Trust Label.\n */\nexport const ATLDataSchema = z.object({\n tier: z.enum(['1', '2', '3', '4']),\n source: z.string().min(1),\n user: z.string().min(1),\n sanitized: z.boolean(),\n rep: z.number().min(0).max(1).optional(),\n});\nexport type ATLData = z.infer<typeof ATLDataSchema>;\n\n// ============================================================================\n// Firewall Error\n// ============================================================================\n\n/**\n * Error codes for firewall pipeline failures.\n */\nexport type FirewallErrorCode =\n | 'EXTRACTION_FAILED'\n | 'SANITIZATION_FAILED'\n | 'CLASSIFICATION_FAILED'\n | 'REPUTATION_FAILED'\n | 'INVALID_CONFIG'\n /**\n * #5382: a blocking policy violation refused the input outright, rather than\n * being surfaced as a signal on a successful result. Only reachable when the\n * firewall policy mode is `enforce` — under the default `off` a violation is\n * still returned via `ruleOfTwoViolation` on an `ok()` result.\n */\n | 'POLICY_REFUSED';\n\n/**\n * Structured error from the firewall pipeline.\n */\nexport interface FirewallError {\n readonly code: FirewallErrorCode;\n readonly message: string;\n readonly stage: string;\n /**\n * The blocking policy violations behind a `POLICY_REFUSED` from the policy\n * stage (#5383) — the structured form of the rules `message` names, so a\n * consumer that maps a refusal onto its own action record can list the rule\n * ids without parsing the message. Absent for every other code, and for the\n * corroboration stage's refusal, which carries `missing` instead.\n */\n readonly violations?: readonly Violation[];\n /**\n * The unmet corroboration requirements behind a `POLICY_REFUSED` from the\n * corroboration stage (#6309) — the structured form of what `message`\n * names, so a consumer recording the refusal can list them without parsing\n * prose. Absent for every other code and stage.\n */\n readonly missing?: readonly string[];\n}\n","/**\n * nexus-agents/security/firewall - Agent Trust Labels (ATL)\n *\n * Generates and parses structured trust labels that travel with\n * processed inputs through the agent pipeline. Format:\n * [ATL:tier=3,source=github-comment,user=octocat,sanitized=true,rep=0.45]\n *\n * @module security/firewall/agent-trust-labels\n * (Source: Issue #826 — Reusable Hostile Input Firewall)\n */\n\nimport type { ATLData } from './firewall-types.js';\nimport { ATLDataSchema } from './firewall-types.js';\n\n/** ATL prefix and suffix markers. */\nconst ATL_PREFIX = '[ATL:';\nconst ATL_SUFFIX = ']';\n\n/** Pattern to match and extract ATL strings. */\nconst ATL_PATTERN = /^\\[ATL:(.+)\\]$/;\n\n/**\n * Generates an Agent Trust Label string from structured data.\n *\n * @example\n * generateATL({ tier: '3', source: 'github-comment', user: 'octocat', sanitized: true })\n * // => \"[ATL:tier=3,source=github-comment,user=octocat,sanitized=true]\"\n */\nexport function generateATL(data: ATLData): string {\n const validated = ATLDataSchema.parse(data);\n const parts: string[] = [\n `tier=${validated.tier}`,\n `source=${encodeATLValue(validated.source)}`,\n `user=${encodeATLValue(validated.user)}`,\n `sanitized=${String(validated.sanitized)}`,\n ];\n\n if (validated.rep !== undefined) {\n parts.push(`rep=${validated.rep.toFixed(2)}`);\n }\n\n return `${ATL_PREFIX}${parts.join(',')}${ATL_SUFFIX}`;\n}\n\n/**\n * Parses an ATL string back into structured data.\n * Returns undefined if the string is not a valid ATL.\n */\nexport function parseATL(atl: string): ATLData | undefined {\n const match = ATL_PATTERN.exec(atl.trim());\n if (match === null) return undefined;\n\n const body = match[1];\n if (body === undefined) return undefined;\n\n const raw = parseKeyValuePairs(body);\n if (raw === undefined) return undefined;\n\n return validateParsedATL(raw);\n}\n\n/** Parses comma-separated key=value pairs into a record. */\nfunction parseKeyValuePairs(body: string): Record<string, string> | undefined {\n const pairs = body.split(',');\n const raw: Record<string, string> = {};\n for (const pair of pairs) {\n const eqIndex = pair.indexOf('=');\n if (eqIndex < 1) return undefined;\n raw[pair.slice(0, eqIndex)] = pair.slice(eqIndex + 1);\n }\n return raw;\n}\n\n/** Validates and converts raw key-value pairs to ATLData. */\nfunction validateParsedATL(raw: Record<string, string>): ATLData | undefined {\n const tier = raw['tier'];\n const source = raw['source'];\n const user = raw['user'];\n const sanitized = raw['sanitized'];\n if (tier === undefined || source === undefined || user === undefined || sanitized === undefined) {\n return undefined;\n }\n\n const parsed: ATLData = {\n tier: tier as ATLData['tier'],\n source: decodeATLValue(source),\n user: decodeATLValue(user),\n sanitized: sanitized === 'true',\n ...(raw['rep'] !== undefined ? { rep: parseFloat(raw['rep']) } : {}),\n };\n\n const result = ATLDataSchema.safeParse(parsed);\n return result.success ? result.data : undefined;\n}\n\n/** Encodes special characters in ATL values. */\nfunction encodeATLValue(value: string): string {\n return value.replace(/,/g, '%2C').replace(/=/g, '%3D').replace(/\\]/g, '%5D');\n}\n\n/** Decodes special characters in ATL values. */\nfunction decodeATLValue(value: string): string {\n return value.replace(/%2C/g, ',').replace(/%3D/g, '=').replace(/%5D/g, ']');\n}\n","/**\n * nexus-agents/security/firewall - Passthrough defaults for disabled stages\n *\n * Split out of the pipeline so it stays under the file-size lint (#4992).\n *\n * @module security/firewall/firewall-passthrough\n */\n\nimport { mapAuthorAssociation } from '../trust-classifier.js';\nimport type { ClassifyResult } from '../trust-classifier.js';\nimport { ROLE_DEFAULT_TRUST } from '../trust-types.js';\nimport type { SanitizedInput } from '../trust-types.js';\nimport type { SourceMetadata } from './firewall-types.js';\n\nexport function createPassthroughSanitized(meta: SourceMetadata): SanitizedInput {\n const userRole = mapAuthorAssociation(meta.authorAssociation);\n return {\n content: meta.content,\n originalLength: meta.content.length,\n trustTier: ROLE_DEFAULT_TRUST[userRole],\n contentTierMeasured: false,\n userRole,\n injectionFlags: [],\n strippedElements: [],\n truncated: false,\n wasModified: false,\n sanitizedAt: new Date().toISOString(),\n };\n}\n\nexport function createPassthroughClassification(meta: SourceMetadata): ClassifyResult {\n return {\n trustTier: '3',\n userRole: mapAuthorAssociation(meta.authorAssociation),\n isAllowlisted: false,\n wasDowngraded: false,\n reason: 'Trust classification disabled — default Tier 3',\n };\n}\n","/**\n * nexus-agents/security/firewall - Trust audit reason\n *\n * The trust audit event's `reason` must state what the reputation gate did —\n * or, under `audit`, what it would have done (#4992 review). A suppressed\n * demotion that leaves no trace reads as a clean classification.\n *\n * @module security/firewall/firewall-trust-reason\n */\n\nimport type { ReputationGateDecision } from '../reputation-model.js';\n\n/**\n * Appends the gate's effect to the classifier's reason.\n *\n * @param reason The classifier's own reason.\n * @param demoted Whether the enforced tier differs from the classifier tier.\n * @param gate The gate decision, or `undefined` when no gate ran.\n */\nexport function describeGate(\n reason: string,\n demoted: boolean,\n gate: ReputationGateDecision | undefined\n): string {\n if (gate === undefined) return reason;\n if (demoted) {\n return `${reason}; demoted to Tier ${gate.enforcedTier} by reputation gating (${gate.mode})`;\n }\n if (gate.demotionSuppressed) {\n return `${reason}; would demote to Tier ${gate.reconciledTier} (reputation gating: ${gate.mode})`;\n }\n return reason;\n}\n","/**\n * nexus-agents/security - Policy Gate\n *\n * Deterministic rule engine that validates all agent actions before\n * GitHub state mutations can occur. No LLM in the validation path.\n *\n * Defense layer 2 of the three-layer hardening architecture.\n * See: docs/architecture/UNTRUSTED_INPUT_HARDENING.md\n *\n * @module security/policy-gate\n * (Source: Issue #818, #822 — Phase 2: Policy Gate)\n */\n\nimport { z } from 'zod';\n\nimport type { AgentAction, AgentActionType, SourceCitation } from './action-schema.js';\nimport {\n isMutatingAction,\n isReadOnlyAction,\n requiresCitation,\n requiresHumanApproval,\n} from './action-schema.js';\nimport type { TrustTier } from './trust-types.js';\nimport { TRUST_TIER_NUMERIC } from './trust-types.js';\nimport { getRequiredTrustTier, canInfluenceDecisions } from './trust-classifier.js';\nimport type { AuditTrail } from './audit-trail.js';\nimport { emitPolicyEvent } from './audit-trail.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Violation detected by the policy gate.\n */\nexport const ViolationSchema = z.object({\n /** Machine-readable rule identifier. */\n rule: z.string().min(1),\n /** Human-readable description of the violation. */\n message: z.string().min(1),\n /** Severity: 'block' prevents execution, 'warn' logs only. */\n severity: z.enum(['block', 'warn']),\n});\nexport type Violation = z.infer<typeof ViolationSchema>;\n\n/**\n * Decision returned by the policy gate.\n */\nexport interface PolicyDecision {\n /** Whether the action is allowed to proceed. */\n readonly allowed: boolean;\n /** Whether human approval is required before execution. */\n readonly requiresApproval: boolean;\n /** All detected violations (blocking and warnings). */\n readonly violations: readonly Violation[];\n /** Timestamp of the evaluation (ISO 8601). */\n readonly evaluatedAt: string;\n}\n\n/**\n * Context for evaluating a policy decision.\n */\nexport interface ActionContext {\n /** Trust tier of the primary input source. */\n readonly inputTrustTier: TrustTier;\n /** Whether the agent currently has write access to the repository. */\n readonly hasWriteAccess: boolean;\n /** Whether the agent currently has access to secrets/tokens. */\n readonly hasSecretAccess: boolean;\n /** Set of labels that exist on the repository (for ProposeLabels validation). */\n readonly existingLabels?: ReadonlySet<string>;\n}\n\n// ============================================================================\n// Policy Rules\n// ============================================================================\n\n/** Extract sources from an action, handling actions that lack a sources field. */\nfunction getActionSources(action: AgentAction): readonly SourceCitation[] {\n if ('sources' in action) {\n return action.sources;\n }\n return [];\n}\n\n/** Check that citations exist for actions that require them. */\nfunction checkCitationRequirement(action: AgentAction): Violation | undefined {\n if (!requiresCitation(action.type)) return undefined;\n const sources = getActionSources(action);\n if (sources.length === 0) {\n return {\n rule: 'REQUIRE_CITATION',\n message: `Action '${action.type}' requires at least one source citation`,\n severity: 'block',\n };\n }\n return undefined;\n}\n\n/** Check that the input trust tier meets action requirements. */\nfunction checkTrustRequirement(action: AgentAction, context: ActionContext): Violation | undefined {\n const requiredTier = getRequiredTrustTier(action.type);\n const requiredNumeric = TRUST_TIER_NUMERIC[requiredTier];\n const inputNumeric = TRUST_TIER_NUMERIC[context.inputTrustTier];\n\n if (inputNumeric > requiredNumeric) {\n return {\n rule: 'INSUFFICIENT_TRUST',\n message: `Action '${action.type}' requires Tier ${requiredTier} but input is Tier ${context.inputTrustTier}`,\n severity: 'block',\n };\n }\n return undefined;\n}\n\n/** Check that Tier 3-4 input cannot drive decisions. */\nfunction checkInfluenceBlock(action: AgentAction, context: ActionContext): Violation | undefined {\n if (!canInfluenceDecisions(context.inputTrustTier) && isMutatingAction(action.type)) {\n return {\n rule: 'UNTRUSTED_INFLUENCE',\n message: `Tier ${context.inputTrustTier} input cannot drive mutating action '${action.type}'`,\n severity: 'block',\n };\n }\n return undefined;\n}\n\n/**\n * Enforce the Rule of Two: no agent may simultaneously\n * (a) process untrusted input, (b) have write access, AND (c) access secrets.\n *\n * A violation is REFUSED, never routed to human approval (#4735, panel\n * option A, 7-0). The rule measures the capability posture of the process —\n * callers derive `hasWriteAccess` from `!dryRun` and `hasSecretAccess` from\n * token presence for the whole run — not the blast radius of one action, so a\n * human approving one action would not remove the agent's simultaneous\n * possession of all three legs. The only remedy is to drop a leg, and the\n * violation message names all three so the caller's existing logging carries\n * the diagnosis (this module has no logger of its own).\n *\n * Exported (#3198) so the firewall's `policyEnforcement` stage can surface the\n * same assessment during input composition without duplicating the predicate.\n */\nexport function checkRuleOfTwo(context: ActionContext): Violation | undefined {\n const isUntrusted = TRUST_TIER_NUMERIC[context.inputTrustTier] >= 3;\n if (isUntrusted && context.hasWriteAccess && context.hasSecretAccess) {\n return {\n rule: 'RULE_OF_TWO',\n message:\n `RULE_OF_TWO: agent simultaneously (a) processes untrusted input ` +\n `(Tier ${context.inputTrustTier}), (b) has write access, and ` +\n `(c) has secret/token access. Refused; there is no approval path — ` +\n `drop a leg: dry-run, run without the token, or split the agent (#4735).`,\n severity: 'block',\n };\n }\n return undefined;\n}\n\n/**\n * Labels that GRANT PRIVILEGE or REDUCE SCRUTINY, and so may never be proposed\n * by an agent acting on external input (#4688).\n *\n * These are not ordinary taxonomy labels. In this repository they are control\n * inputs to CI:\n *\n * - `owner-ratified` — the label `check-governor-ratification.ts` accepts as\n * proof of owner ratification. Applying it BYPASSES the governance-of-the-\n * governor gate on `src/audit/`, `.rules/`, `CODEOWNERS` and friends.\n * - `skip-pr-review` — suppresses the PR review workflow.\n * - `pr-review-ci` — triggers the review workflow; less dangerous than the\n * two above, but still a workflow control rather than a description.\n *\n * Why this exists BEFORE it is needed: no production code applies a proposed\n * label today (`addLabels` has no non-test caller), so the path is latent. But\n * the consensus panel's dissenting seat was right that labels are not\n * zero-blast-radius, and the day someone wires triage output to `addLabels` is\n * the day an issue body can propose its own ratification. A guard added after\n * that wiring is a guard added after the incident.\n *\n * This is deliberately checked on the ACTION's effect rather than the author's\n * trust: an OWNER-authored body proposing `owner-ratified` is precisely the\n * self-modification the governor exists to prevent, so author trust must not\n * soften it.\n */\nconst PRIVILEGE_GRANTING_LABELS: ReadonlySet<string> = new Set([\n 'owner-ratified',\n 'skip-pr-review',\n 'pr-review-ci',\n]);\n\n/**\n * Refuse any proposal naming a privilege-granting label.\n *\n * Independent of {@link checkLabelValidity} on purpose: this check needs no\n * repository world state and reports privileged labels even when label\n * validity is unevaluated.\n */\nfunction checkPrivilegedLabels(action: AgentAction): Violation | undefined {\n if (action.type !== 'ProposeLabels') return undefined;\n\n // Case-insensitive, because the gate this protects is (#4689 follow-up):\n // `check-governor-ratification.ts` compares `l.toLowerCase()`, so\n // `Owner-Ratified` would satisfy ratification while slipping an exact-match\n // denylist. A guard must be at least as permissive in what it REJECTS as its\n // consumer is in what it ACCEPTS.\n const privileged = action.labels.filter((l) => PRIVILEGE_GRANTING_LABELS.has(l.toLowerCase()));\n if (privileged.length === 0) return undefined;\n\n return {\n rule: 'PRIVILEGED_LABEL',\n message:\n `Proposed labels grant privilege or reduce review scrutiny: ` +\n `${privileged.join(', ')}. These are CI control inputs, not descriptions, ` +\n `and are never proposable from agent-processed input (#4688).`,\n severity: 'block',\n };\n}\n\n/** Check that proposed labels exist in the repository's label set. */\nfunction checkLabelValidity(action: AgentAction, context: ActionContext): Violation | undefined {\n if (action.type !== 'ProposeLabels') return undefined;\n const labels = context.existingLabels;\n if (labels === undefined) {\n return {\n rule: 'LABEL_SET_UNAVAILABLE',\n message: 'repository label set not supplied; label validity unevaluated',\n severity: 'block',\n };\n }\n\n const invalid = action.labels.filter((l) => !labels.has(l));\n if (invalid.length > 0) {\n return {\n rule: 'INVALID_LABELS',\n message: `Proposed labels not in repository: ${invalid.join(', ')}`,\n severity: 'block',\n };\n }\n return undefined;\n}\n\n/** Check that source citations meet trust requirements for the action. */\nfunction checkSourceTrustTiers(action: AgentAction): Violation | undefined {\n const sources = getActionSources(action);\n if (sources.length === 0) return undefined;\n\n const requiredTier = getRequiredTrustTier(action.type);\n const requiredNumeric = TRUST_TIER_NUMERIC[requiredTier];\n\n for (const source of sources) {\n if (source.type === 'issueComment') {\n const sourceTierNumeric = TRUST_TIER_NUMERIC[source.authorTrustTier];\n if (sourceTierNumeric > requiredNumeric) {\n return {\n rule: 'SOURCE_TRUST_MISMATCH',\n message: `Source from '${source.author}' (Tier ${source.authorTrustTier}) insufficient for action requiring Tier ${requiredTier}`,\n severity: 'warn',\n };\n }\n }\n }\n return undefined;\n}\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Rule ids that only an ACTION-shaped evaluation can produce (#5380).\n *\n * Of the seven checks {@link evaluatePolicy} runs, one — {@link checkRuleOfTwo}\n * — reads the `ActionContext` alone; the other six read the `AgentAction` and\n * emit these ids. A caller that has a context but no action (the firewall's\n * input-shaped `process()` without a supplied action) can run only the Rule of\n * Two, and must report THESE as unmeasured rather than let their absence from\n * a violation list read as a pass. Kept beside the check list below so a new\n * action-scoped check is added to both or to neither.\n */\nexport const ACTION_SCOPED_POLICY_RULES: readonly string[] = [\n 'REQUIRE_CITATION',\n 'INSUFFICIENT_TRUST',\n 'UNTRUSTED_INFLUENCE',\n 'LABEL_SET_UNAVAILABLE',\n 'INVALID_LABELS',\n 'PRIVILEGED_LABEL',\n 'SOURCE_TRUST_MISMATCH',\n];\n\n/**\n * Evaluate an agent action against the policy gate.\n *\n * This is a deterministic check — no LLM in the loop. Returns a\n * PolicyDecision indicating whether the action is allowed, requires\n * human approval, or is blocked.\n *\n * @param action - The validated AgentAction to evaluate.\n * @param context - The current execution context.\n * @returns PolicyDecision with violations and approval requirements.\n */\nexport function evaluatePolicy(\n action: AgentAction,\n context: ActionContext,\n auditTrail?: AuditTrail\n): PolicyDecision {\n const violations: Violation[] = [];\n\n const checks = [\n checkCitationRequirement(action),\n checkTrustRequirement(action, context),\n checkInfluenceBlock(action, context),\n checkRuleOfTwo(context),\n checkLabelValidity(action, context),\n checkPrivilegedLabels(action),\n checkSourceTrustTiers(action),\n ];\n\n for (const violation of checks) {\n if (violation !== undefined) {\n violations.push(violation);\n }\n }\n\n const hasBlockingViolation = violations.some((v) => v.severity === 'block');\n // #4463: gate on irreversibility + external visibility, not on mutation as\n // such. ProposeLabels and GeneratePatchPlan are reversible and internal, and\n // reach here having already cleared citation, trust-tier, influence-block,\n // Rule-of-Two and label-validity checks. DraftReply still gates because it\n // publishes text under the project's identity on a surface others read.\n // `isMutatingAction` stays broad above (line ~113) for the influence block:\n // low-trust input must not drive ANY mutating action, approved or not.\n const needsApproval = !hasBlockingViolation && requiresHumanApproval(action.type);\n\n const decision: PolicyDecision = {\n allowed: !hasBlockingViolation,\n requiresApproval: needsApproval,\n violations,\n evaluatedAt: new Date().toISOString(),\n };\n\n // #3191: when an audit trail is supplied, record the decision so policy\n // outcomes are part of the durable audit record (the gate previously emitted\n // nothing). Optional — pure callers pass no trail and incur no side effect.\n if (auditTrail !== undefined) {\n emitPolicyEvent(auditTrail, {\n actionType: action.type,\n allowed: decision.allowed,\n requiresApproval: decision.requiresApproval,\n inputTrustTier: context.inputTrustTier,\n violationRules: violations.map((v) => v.rule),\n });\n }\n\n return decision;\n}\n\n/**\n * Quick check: can this action type proceed at all given the input trust tier?\n * Useful for early rejection before full policy evaluation.\n */\nexport function canProceed(actionType: AgentActionType, inputTrustTier: TrustTier): boolean {\n if (isReadOnlyAction(actionType)) {\n const requiredTier = getRequiredTrustTier(actionType);\n return TRUST_TIER_NUMERIC[inputTrustTier] <= TRUST_TIER_NUMERIC[requiredTier];\n }\n return canInfluenceDecisions(inputTrustTier);\n}\n","/**\n * nexus-agents/security - Typed Action Schema\n *\n * Zod schemas and TypeScript types for the typed action constraint system.\n * Agents processing untrusted GitHub input MUST emit only predefined typed\n * actions (never free-form tool calls). This module defines those action\n * schemas, validates them at runtime, and classifies them as read-only or\n * mutating for the policy gate.\n *\n * @module security/action-schema\n * (Source: Issue #818, #820)\n */\n\nimport { z } from 'zod';\n\nimport { TrustTierSchema } from './trust-types.js';\n\n// ============================================================================\n// Result Type (local — avoids circular dependency with core/types)\n// ============================================================================\n\n/** Validation result using the project Result pattern. */\nexport type ActionValidationResult =\n { ok: true; value: AgentAction } | { ok: false; error: string };\n\n// ============================================================================\n// Source Citations\n// ============================================================================\n\n/**\n * Source citation from a file tracked in the repository.\n *\n * `existsOnBaseRef` records whether the cited path was present on the base ref\n * *before* the untrusted change under review. A citation built from a PR's own\n * changed-file list can name a path the author invented in that same PR, which\n * is repo evidence in name only — the same mislabel #4667 fixed for issue\n * bodies. Absent means the producer did not check; `false` means it checked and\n * the path is author-supplied.\n */\nconst RepoFileSource = z.object({\n type: z.literal('repoFile'),\n path: z.string().min(1),\n line: z.number().int().positive().optional(),\n existsOnBaseRef: z.boolean().optional(),\n commit: z\n .string()\n .regex(/^[a-f0-9]{7,40}$/)\n .optional(),\n});\n\n/** Source citation from a GitHub issue comment. */\nconst IssueCommentSource = z.object({\n type: z.literal('issueComment'),\n issueNumber: z.number().int().positive(),\n commentId: z.number().int().positive(),\n author: z.string().min(1),\n authorTrustTier: TrustTierSchema,\n});\n\n/**\n * Source citation from the body of a GitHub issue (#4667).\n *\n * Triage previously cited the issue as a `repoFile` with a synthesised path\n * (`issues/42`). That is not a repo file, and the mislabel is why corroboration\n * always passed: `hasSourceAtTier` treats repo files as Tier 1 unconditionally,\n * so untrusted issue text was corroborating actions at maintainer trust.\n *\n * Modelled on `IssueCommentSource` — it carries the author and their tier, so\n * the trust of the content travels with the citation. It is deliberately NOT an\n * `issueComment`: that requires a `commentId`, and faking one to fix a mislabel\n * would trade an honest error for a dishonest one.\n */\nconst IssueBodySource = z.object({\n type: z.literal('issueBody'),\n issueNumber: z.number().int().positive(),\n author: z.string().min(1),\n authorTrustTier: TrustTierSchema,\n});\n\n/** Source citation from a CI pipeline result. */\nconst CIResultSource = z.object({\n type: z.literal('ciResult'),\n runId: z.number().int().positive(),\n status: z.enum(['pass', 'fail']),\n job: z.string().min(1),\n});\n\n/** Source citation from a policy or governance document. */\nconst PolicyDocSource = z.object({\n type: z.literal('policyDoc'),\n path: z.string().min(1),\n section: z.string().min(1),\n});\n\n/** Source citation from a maintainer slash-command or explicit instruction. */\nconst MaintainerCommandSource = z.object({\n type: z.literal('maintainerCommand'),\n username: z.string().min(1),\n commentId: z.number().int().positive(),\n});\n\n/**\n * Discriminated union of all valid source citation types.\n * Every decision-making action MUST cite at least one source.\n */\nexport const SourceCitationSchema = z.discriminatedUnion('type', [\n IssueBodySource,\n RepoFileSource,\n IssueCommentSource,\n CIResultSource,\n PolicyDocSource,\n MaintainerCommandSource,\n]);\n\n/** Inferred TypeScript type for a source citation. */\nexport type SourceCitation = z.infer<typeof SourceCitationSchema>;\n\n// ============================================================================\n// Typed Actions\n// ============================================================================\n\n/** Read-only analysis action: summarize an issue with citations. */\nconst SummarizeIssueAction = z.object({\n type: z.literal('SummarizeIssue'),\n summary: z.string().min(10).max(2000),\n sources: z.array(SourceCitationSchema).min(1).max(20),\n});\n\n/** Suggest labels for an issue (max 5, must match existing label set). */\nconst ProposeLabelsAction = z.object({\n type: z.literal('ProposeLabels'),\n labels: z.array(z.string()).min(1).max(5),\n reason: z.string().min(10).max(500),\n sources: z.array(SourceCitationSchema).min(1).max(20),\n});\n\n/** Draft a reply comment (always requires human approval before posting). */\nexport const DRAFT_REPLY_BODY_MAX_LENGTH = 2000;\n\nconst DraftReplyAction = z.object({\n type: z.literal('DraftReply'),\n body: z.string().min(10).max(DRAFT_REPLY_BODY_MAX_LENGTH),\n requiresApproval: z.literal(true),\n sources: z.array(SourceCitationSchema).min(1).max(20),\n});\n\n/** Explicit escalation to a human maintainer with reason and context. */\nconst RequestHumanApprovalAction = z.object({\n type: z.literal('RequestHumanApproval'),\n reason: z.string().min(10).max(500),\n context: z.string().min(10).max(2000),\n});\n\n/**\n * Propose a set of file modifications (requires maintainer corroboration).\n * Forbidden from Tier 3-4 input without maintainer corroboration.\n */\nconst GeneratePatchPlanAction = z.object({\n type: z.literal('GeneratePatchPlan'),\n files: z\n .array(\n z.object({\n path: z.string().min(1),\n operation: z.enum(['modify', 'create', 'delete']),\n description: z.string().min(10).max(500),\n })\n )\n .min(1)\n .max(10),\n rationale: z.string().min(10).max(1000),\n requiresApproval: z.literal(true),\n sources: z.array(SourceCitationSchema).min(2).max(20),\n});\n\n/** Categorize an issue by type with confidence score. */\nconst ClassifyIssueAction = z.object({\n type: z.literal('ClassifyIssue'),\n category: z.enum(['bug', 'feature', 'question', 'documentation', 'security', 'performance']),\n confidence: z.number().min(0).max(1),\n sources: z.array(SourceCitationSchema).min(1).max(20),\n});\n\n/** Identify potential duplicate issues with similarity scores. */\nconst IdentifyDuplicatesAction = z.object({\n type: z.literal('IdentifyDuplicates'),\n candidates: z.array(z.number().int().positive()).min(1).max(10),\n similarity: z.array(z.number().min(0).max(1)),\n sources: z.array(SourceCitationSchema).min(1).max(20),\n});\n\n/** Explicit refusal to act, with escalation target. */\nconst RefuseActionAction = z.object({\n type: z.literal('RefuseAction'),\n reason: z.string().min(10).max(500),\n escalateTo: z.enum(['maintainer', 'security']),\n});\n\n/** Handoff delegation from one agent to another by capability. (Issue #834) */\nconst HandoffMessageAction = z.object({\n type: z.literal('HandoffMessage'),\n targetCapability: z.string().min(1).max(100),\n reason: z.string().min(5).max(500),\n inputTrustTier: z.enum(['1', '2', '3', '4']),\n sources: z.array(SourceCitationSchema).min(1).max(20),\n});\n\n/**\n * Discriminated union of all valid agent actions.\n * This is the ONLY schema agents may emit when processing untrusted input.\n */\nexport const AgentActionSchema = z.discriminatedUnion('type', [\n SummarizeIssueAction,\n ProposeLabelsAction,\n DraftReplyAction,\n RequestHumanApprovalAction,\n GeneratePatchPlanAction,\n ClassifyIssueAction,\n IdentifyDuplicatesAction,\n RefuseActionAction,\n HandoffMessageAction,\n]);\n\n/** Inferred TypeScript type for an agent action. */\nexport type AgentAction = z.infer<typeof AgentActionSchema>;\n\n/** All valid action type discriminator values. */\nexport type AgentActionType = AgentAction['type'];\n\n// ============================================================================\n// Action Classification\n// ============================================================================\n\n/**\n * Action types that are read-only and do not modify GitHub state.\n * These can be executed without human approval (subject to policy gate).\n */\nconst READ_ONLY_ACTIONS: ReadonlySet<AgentActionType> = new Set<AgentActionType>([\n 'SummarizeIssue',\n 'ClassifyIssue',\n 'IdentifyDuplicates',\n 'RefuseAction',\n 'RequestHumanApproval',\n 'HandoffMessage',\n]);\n\n/**\n * Action types that can modify GitHub state (labels, comments, code).\n *\n * Used for the untrusted-input influence block: low-trust input must not drive\n * ANY of these, approved or not. NOT the approval set — see\n * {@link APPROVAL_REQUIRED_ACTIONS}, which is narrower (#4463).\n */\nconst MUTATING_ACTIONS: ReadonlySet<AgentActionType> = new Set<AgentActionType>([\n 'ProposeLabels',\n 'DraftReply',\n 'GeneratePatchPlan',\n]);\n\n/**\n * Action types that MUST include at least one source citation.\n * Escalation and refusal actions are exempt (they report inability to act).\n */\nconst CITATION_REQUIRED_ACTIONS: ReadonlySet<AgentActionType> = new Set<AgentActionType>([\n 'SummarizeIssue',\n 'ProposeLabels',\n 'DraftReply',\n 'GeneratePatchPlan',\n 'ClassifyIssue',\n 'IdentifyDuplicates',\n 'HandoffMessage',\n]);\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Validate an unknown value against the AgentActionSchema.\n * Returns a Result: `{ ok: true; value }` on success or `{ ok: false; error }` on failure.\n *\n * @param input - The value to validate (typically parsed JSON from an agent).\n * @returns Validation result following the project Result pattern.\n */\nexport function validateAgentAction(input: unknown): ActionValidationResult {\n const result = AgentActionSchema.safeParse(input);\n if (result.success) {\n return { ok: true, value: result.data };\n }\n const messages = result.error.issues.map((issue) => `${issue.path.join('.')}: ${issue.message}`);\n return { ok: false, error: `Action validation failed: ${messages.join('; ')}` };\n}\n\n/**\n * Check whether an action type is read-only (does not modify GitHub state).\n *\n * @param actionType - The action type discriminator value.\n * @returns True if the action is read-only.\n */\nexport function isReadOnlyAction(actionType: AgentActionType): boolean {\n return READ_ONLY_ACTIONS.has(actionType);\n}\n\n/**\n * Check whether an action type can modify GitHub state.\n * Mutating actions always require human approval before execution.\n *\n * @param actionType - The action type discriminator value.\n * @returns True if the action can modify state.\n */\nexport function isMutatingAction(actionType: AgentActionType): boolean {\n return MUTATING_ACTIONS.has(actionType);\n}\n\n/**\n * Action types that still require human approval after every policy check has\n * passed (#4463).\n *\n * Deliberately narrower than {@link MUTATING_ACTIONS}. Approval is a gate on\n * IRREVERSIBILITY and EXTERNAL VISIBILITY, not on mutation as such:\n *\n * - `ProposeLabels` — reversible in one click, internal to the tracker, and its\n * schema carries no `requiresApproval` field. Not gated: it reaches this point\n * having already passed citation, trust-tier, influence-block, Rule-of-Two and\n * label-validity checks, so pausing bought delay, not safety.\n * - `DraftReply` — **publishes text under the project's identity**, on a surface\n * other people read. Untrusted issue/PR content is in scope by definition\n * here, so a prompt-injected reply is attacker-authored text posted publicly.\n * Deleting it afterwards does not un-publish it.\n * - `GeneratePatchPlan` — gated, and deliberately so: its own schema encodes\n * `requiresApproval: z.literal(true)` alongside a two-source corroboration\n * minimum (`sources.min(2)`). Dropping the gate here while the schema still\n * mandates the flag would put two sources of truth in conflict, and the\n * two-factor design is intentional for an action that proposes file writes\n * from potentially untrusted input.\n */\nconst APPROVAL_REQUIRED_ACTIONS: ReadonlySet<AgentActionType> = new Set<AgentActionType>([\n 'DraftReply',\n 'GeneratePatchPlan',\n]);\n\n/**\n * Whether an action needs human approval even after passing every policy check.\n *\n * Distinct from {@link isMutatingAction}, which stays broad because it also\n * drives the untrusted-input influence block — low-trust input must not be able\n * to drive ANY mutating action, approved or not.\n *\n * @param actionType - The action type discriminator value.\n * @returns True if a human must approve before execution.\n */\nexport function requiresHumanApproval(actionType: AgentActionType): boolean {\n return APPROVAL_REQUIRED_ACTIONS.has(actionType);\n}\n\n/**\n * Check whether an action type requires at least one source citation.\n * Escalation (RequestHumanApproval) and refusal (RefuseAction) are exempt.\n *\n * @param actionType - The action type discriminator value.\n * @returns True if the action must include source citations.\n */\nexport function requiresCitation(actionType: AgentActionType): boolean {\n return CITATION_REQUIRED_ACTIONS.has(actionType);\n}\n","/**\n * nexus-agents/security/firewall - Policy stage\n *\n * The `policyEnforcement` stage of {@link HostileInputFirewall} (#5380). It\n * used to run ONE of the seven checks `evaluatePolicy` runs — `checkRuleOfTwo`,\n * the only one that reads the `ActionContext` alone. The other six read an\n * `AgentAction`, which input-shaped `process()` never had, so they were not\n * \"passing\": they were never evaluated, and the result could not say so.\n *\n * This module gives the stage two honest shapes. With the action the caller\n * intends to take (`FirewallProcessOptions.action`) it runs `evaluatePolicy` in\n * full; without one it runs the Rule of Two and NAMES the six action-scoped\n * rules as unmeasured, so their absence from the violation list cannot be read\n * as a pass.\n *\n * @module security/firewall/firewall-policy-stage\n */\n\nimport { createLogger } from '../../core/index.js';\nimport type { AgentAction, AgentActionType } from '../action-schema.js';\nimport type { AuditTrail } from '../audit-trail.js';\nimport { ACTION_SCOPED_POLICY_RULES, checkRuleOfTwo, evaluatePolicy } from '../policy-gate.js';\nimport type { ActionContext, Violation } from '../policy-gate.js';\nimport type { TrustTier } from '../trust-types.js';\nimport type { FirewallPolicyMode } from './firewall-policy-mode.js';\nimport type { FirewallError, FirewallProcessOptions } from './firewall-types.js';\n\nconst logger = createLogger({ component: 'HostileInputFirewall' });\n\n/**\n * What the `policyEnforcement` stage evaluated, and against what (#5380).\n *\n * A discriminated union keeps a reader from mistaking one shape for the other:\n *\n * - `scope: 'action'` — an action was supplied; all seven checks ran and\n * `violations` is the complete list. `allowed` and `requiresApproval` are\n * the decision's own fields (`PolicyDecision`), surfaced, not re-derived;\n * the firewall does not act on `requiresApproval` any more than the\n * production gate does (#4735: Rule of Two is refuse-only, and there is no\n * approval path here).\n * - `scope: 'context'` — no action was supplied; only the Rule of Two (the one\n * check that reads the context alone) ran. The six action-scoped checks are\n * listed in `unmeasured` by rule id, and `requiresApproval` — which depends\n * on the action type — is not reported at all rather than defaulted.\n */\nexport type FirewallPolicyEvaluation =\n | {\n readonly scope: 'action';\n readonly actionType: AgentActionType;\n readonly allowed: boolean;\n readonly requiresApproval: boolean;\n readonly violations: readonly Violation[];\n /** Always empty for a full evaluation; present so both shapes read the same way. */\n readonly unmeasured: readonly string[];\n }\n | {\n readonly scope: 'context';\n /** Why the six action-scoped checks did not run. */\n readonly reason: 'no-action-supplied';\n /** At most the `RULE_OF_TWO` violation. */\n readonly violations: readonly Violation[];\n /** The rule ids `evaluatePolicy` could not evaluate without an action. */\n readonly unmeasured: readonly string[];\n };\n\n/**\n * Builds the `ActionContext` for one call from the facts the pipeline has:\n * the ENFORCED tier (post reputation gate), the call's access posture, and the\n * repository label set when the caller supplied one. `existingLabels` is\n * spread in only when present so `evaluatePolicy` sees absence as absence and\n * fails the label-validity check closed (`LABEL_SET_UNAVAILABLE`).\n */\nexport function buildActionContext(\n effectiveTrustTier: TrustTier,\n context: { readonly hasWriteAccess: boolean; readonly hasSecretAccess: boolean },\n options: FirewallProcessOptions | undefined\n): ActionContext {\n return {\n inputTrustTier: effectiveTrustTier,\n hasWriteAccess: context.hasWriteAccess,\n hasSecretAccess: context.hasSecretAccess,\n ...(options?.existingLabels !== undefined ? { existingLabels: options.existingLabels } : {}),\n };\n}\n\n/**\n * Runs the policy checks the call's facts allow.\n *\n * With an action: `evaluatePolicy` in full — the seven checks production runs\n * — with the decision recorded on `auditTrail` as a `policy_gate` event when\n * one is given, so the durable record carries the verdict and not just the\n * trust tier. Without one: the Rule of Two alone (previously the stage's whole\n * behaviour, #3198), with the action-scoped rule ids reported as unmeasured.\n */\nexport function evaluateFirewallPolicy(\n context: ActionContext,\n action: AgentAction | undefined,\n auditTrail: AuditTrail | undefined\n): FirewallPolicyEvaluation {\n if (action === undefined) {\n const violation = checkRuleOfTwo(context);\n return {\n scope: 'context',\n reason: 'no-action-supplied',\n violations: violation !== undefined ? [violation] : [],\n unmeasured: ACTION_SCOPED_POLICY_RULES,\n };\n }\n const decision = evaluatePolicy(action, context, auditTrail);\n return {\n scope: 'action',\n actionType: action.type,\n allowed: decision.allowed,\n requiresApproval: decision.requiresApproval,\n violations: decision.violations,\n unmeasured: [],\n };\n}\n\n/**\n * The violations that refuse under `enforce` and count as `wouldRefuse` under\n * `audit`: every `severity: 'block'` entry, whichever check produced it. A\n * `warn` violation never refuses, and an absent evaluation (stage disabled)\n * yields none — the mode gates the response to a violation, never its\n * detection.\n */\nexport function blockingViolations(\n policy: FirewallPolicyEvaluation | undefined\n): readonly Violation[] {\n return policy?.violations.filter((v) => v.severity === 'block') ?? [];\n}\n\n/**\n * The fail-closed half of the #5382 gate: under `enforce`, a blocking policy\n * violation refuses the input instead of riding along as a signal on an\n * `ok()` result that a caller checking only `result.ok` walks straight past.\n *\n * This gates the RESPONSE to a violation, never its detection. It cannot\n * manufacture a refusal where the `policyEnforcement` stage never ran, and it\n * cannot refuse a non-blocking (`warn`) violation — so `enforce` is not a\n * kill switch, and an allowlisted maintainer stays served. Any `block`\n * violation refuses, whichever of the seven checks produced it (#5380), and\n * the message names every blocking rule. `requiresApproval` never refuses —\n * it is not a violation, and there is no approval path here.\n *\n * @returns the refusal, or `undefined` when the input passes or the mode has\n * not opted in.\n */\nexport function policyRefusal(\n policy: FirewallPolicyEvaluation | undefined,\n policyMode: FirewallPolicyMode,\n user: string,\n effectiveTrustTier: TrustTier\n): FirewallError | undefined {\n const blocking = blockingViolations(policy);\n if (blocking.length === 0 || policyMode !== 'enforce') return undefined;\n logger.warn('Firewall REFUSED input under enforce mode', {\n user,\n effectiveTrustTier,\n rules: blocking.map((v) => v.rule),\n });\n return {\n code: 'POLICY_REFUSED',\n message:\n `Refused by firewall policy: ` + blocking.map((v) => `${v.rule} — ${v.message}`).join('; '),\n stage: 'policy',\n violations: blocking,\n };\n}\n","/**\n * nexus-agents/security - Corroboration Validator\n *\n * Validates that agent decisions are backed by sufficient evidence from\n * authoritative sources. Each action type has specific corroboration\n * requirements (e.g., closing issues requires CI pass or maintainer comment).\n *\n * Defense layer 3 of the three-layer hardening architecture.\n * See: docs/architecture/UNTRUSTED_INPUT_HARDENING.md\n *\n * @module security/corroboration-validator\n * (Source: Issue #818, #823 — Phase 2: Corroboration Validator)\n */\n\nimport type { AgentAction, AgentActionType, SourceCitation } from './action-schema.js';\nimport type { TrustTier } from './trust-types.js';\nimport { TRUST_TIER_NUMERIC } from './trust-types.js';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Result of corroboration validation.\n */\nexport interface CorroborationResult {\n /** Whether corroboration requirements are satisfied. */\n readonly satisfied: boolean;\n /** Sources that contributed to corroboration. */\n readonly corroboratingSources: readonly SourceCitation[];\n /** Missing corroboration requirements (empty when satisfied). */\n readonly missing: readonly string[];\n /** Action type that was validated. */\n readonly actionType: AgentActionType;\n /**\n * True when the floor was cleared, and EVERY `repoFile` citation that cleared\n * it is one the producer checked and found absent from the base ref\n * (`existsOnBaseRef === false`) — i.e. a path the author of the untrusted\n * change invented in that same change.\n *\n * `satisfied` deliberately does not read this: which actions are permitted is\n * unchanged. What changes is that the record can now say the corroboration\n * was author-supplied, instead of attributing repo provenance to a path that\n * has none. False when any citation is verified, when none were checked, or\n * when the floor was not cleared at all.\n */\n readonly clearedOnlyByUnverifiedSources: boolean;\n}\n\n/**\n * Rule defining what corroboration an action requires.\n */\nexport interface CorroborationRule {\n /** Human-readable description of what's required. */\n readonly description: string;\n /** Predicate: does this set of sources satisfy the requirement? */\n readonly isSatisfied: (sources: readonly SourceCitation[]) => boolean;\n}\n\n// ============================================================================\n// Source Helpers\n// ============================================================================\n\n/** Check if sources include a passing CI result. */\nfunction hasCIPass(sources: readonly SourceCitation[]): boolean {\n return sources.some((s) => s.type === 'ciResult' && s.status === 'pass');\n}\n\n/** Check if sources include a maintainer command. */\nfunction hasMaintainerCommand(sources: readonly SourceCitation[]): boolean {\n return sources.some((s) => s.type === 'maintainerCommand');\n}\n\n/** Check if sources include a Tier 1 issue comment. */\nfunction hasTier1Comment(sources: readonly SourceCitation[]): boolean {\n return sources.some((s) => s.type === 'issueComment' && s.authorTrustTier === '1');\n}\n\n/**\n * Did every `repoFile` citation get checked against the base ref and found\n * absent? Requires at least one such citation, so an empty or unchecked set is\n * false rather than vacuously true — the empty case here means \"nothing to\n * report\", not \"everything is unverified\".\n */\nfunction allRepoFilesAreAuthorSupplied(sources: readonly SourceCitation[]): boolean {\n const repoFiles = sources.filter((s) => s.type === 'repoFile');\n if (repoFiles.length === 0) return false;\n return repoFiles.every((s) => s.existsOnBaseRef === false);\n}\n\n/** Check if sources include a repo file reference. */\nfunction hasRepoFileRef(sources: readonly SourceCitation[]): boolean {\n return sources.some((s) => s.type === 'repoFile');\n}\n\n/** Check if sources include a repo file with line reference. */\nfunction hasCodeLevelEvidence(sources: readonly SourceCitation[]): boolean {\n return sources.some((s) => s.type === 'repoFile' && s.line !== undefined);\n}\n\n/** Check if sources include a policy document reference. */\nfunction hasPolicyDocRef(sources: readonly SourceCitation[]): boolean {\n return sources.some((s) => s.type === 'policyDoc');\n}\n\n/**\n * True when an ISSUE BODY source is authored at or above `maxTier` (#4667).\n *\n * Deliberately narrower than {@link hasSourceAtTier}, which returns `true` for\n * any non-authored source — repo files, CI results and policy docs are all\n * Tier 1 there. Reusing it here made a CI result alone satisfy ProposeLabels,\n * which the corroboration tests correctly forbid.\n */\nfunction hasIssueBodyAtTier(sources: readonly SourceCitation[], maxTier: TrustTier): boolean {\n const maxNumeric = TRUST_TIER_NUMERIC[maxTier];\n return sources.some(\n (s) => s.type === 'issueBody' && TRUST_TIER_NUMERIC[s.authorTrustTier] <= maxNumeric\n );\n}\n\n/** Check if at least one source meets a minimum trust tier. */\nfunction hasSourceAtTier(sources: readonly SourceCitation[], maxTier: TrustTier): boolean {\n const maxNumeric = TRUST_TIER_NUMERIC[maxTier];\n return sources.some((s) => {\n // Author-attributed content carries its author's trust, not the repo's.\n // `issueBody` was previously cited as a `repoFile` and so counted as Tier 1\n // unconditionally — untrusted issue text corroborating at maintainer trust\n // (#4667).\n if (s.type === 'issueComment' || s.type === 'issueBody') {\n return TRUST_TIER_NUMERIC[s.authorTrustTier] <= maxNumeric;\n }\n // Repo files, CI results, policy docs, maintainer commands = Tier 1\n return true;\n });\n}\n\n// ============================================================================\n// Per-Action Corroboration Rules\n// ============================================================================\n\n/**\n * Corroboration rules for each action type.\n * See CLAUDE.md \"Corroboration Requirements\" table.\n */\nconst ACTION_CORROBORATION_RULES: Readonly<Record<AgentActionType, readonly CorroborationRule[]>> =\n {\n SummarizeIssue: [\n {\n description: 'At least one Tier 1/2 source',\n isSatisfied: (s) => hasSourceAtTier(s, '2'),\n },\n ],\n ProposeLabels: [\n {\n // #4667: the old description read \"issue body (repo file)\" — the rule\n // was written when triage cited the issue as a `repoFile`, so an issue\n // body satisfied it unconditionally regardless of who wrote it. Now\n // that the citation is honest (`issueBody`, carrying its author's\n // tier), the rule has to say what it always meant: an issue body\n // corroborates a label proposal only from a sufficiently trusted\n // author. Dropping the clause entirely would make this rule\n // unsatisfiable for every author including the repo owner — trading a\n // check that could never fail for one that can never pass.\n description:\n 'Issue body from a Tier 1/2 author, OR repo file / maintainer instruction / policy doc',\n isSatisfied: (s) =>\n hasIssueBodyAtTier(s, '2') ||\n hasRepoFileRef(s) ||\n hasMaintainerCommand(s) ||\n hasPolicyDocRef(s),\n },\n ],\n DraftReply: [\n {\n description: 'At least one Tier 1 source citation',\n isSatisfied: (s) =>\n hasRepoFileRef(s) ||\n hasCIPass(s) ||\n hasMaintainerCommand(s) ||\n hasPolicyDocRef(s) ||\n hasTier1Comment(s),\n },\n ],\n GeneratePatchPlan: [\n {\n description: 'Failing test OR bug reproduction steps (code-level evidence)',\n isSatisfied: (s) => hasCodeLevelEvidence(s) || hasCIPass(s),\n },\n {\n description: 'Maintainer corroboration',\n isSatisfied: (s) => hasMaintainerCommand(s) || hasTier1Comment(s),\n },\n ],\n ClassifyIssue: [\n {\n description: 'At least one source citation',\n isSatisfied: (s) => s.length > 0,\n },\n ],\n IdentifyDuplicates: [\n {\n description: 'At least one source citation',\n isSatisfied: (s) => s.length > 0,\n },\n ],\n RequestHumanApproval: [],\n RefuseAction: [],\n HandoffMessage: [\n {\n description: 'At least one source citation for trust tier propagation',\n isSatisfied: (s) => s.length > 0,\n },\n ],\n };\n\n// ============================================================================\n// Public API\n// ============================================================================\n\n/**\n * Validate that an agent action has sufficient corroboration from\n * authoritative sources.\n *\n * @param action - The validated AgentAction to check.\n * @returns CorroborationResult indicating whether requirements are met.\n */\nexport function validateCorroboration(action: AgentAction): CorroborationResult {\n const rules = ACTION_CORROBORATION_RULES[action.type];\n const sources: readonly SourceCitation[] = 'sources' in action ? action.sources : [];\n\n if (rules.length === 0) {\n return {\n satisfied: true,\n corroboratingSources: sources,\n missing: [],\n actionType: action.type,\n clearedOnlyByUnverifiedSources: allRepoFilesAreAuthorSupplied(sources),\n };\n }\n\n const missing: string[] = [];\n const corroborating: SourceCitation[] = [];\n\n for (const rule of rules) {\n if (rule.isSatisfied(sources)) {\n for (const s of sources) {\n if (!corroborating.includes(s)) {\n corroborating.push(s);\n }\n }\n } else {\n missing.push(rule.description);\n }\n }\n\n const satisfied = missing.length === 0;\n return {\n satisfied,\n corroboratingSources: corroborating,\n missing,\n actionType: action.type,\n // Only meaningful about a floor that was actually cleared; a refused action\n // has no corroboration to characterise.\n clearedOnlyByUnverifiedSources: satisfied && allRepoFilesAreAuthorSupplied(corroborating),\n };\n}\n\n/**\n * Get the corroboration rules for an action type.\n * Useful for displaying requirements to users.\n */\nexport function getCorroborationRules(actionType: AgentActionType): readonly CorroborationRule[] {\n return ACTION_CORROBORATION_RULES[actionType];\n}\n","/**\n * nexus-agents/security/firewall - Pipeline Engine\n *\n * HostileInputFirewall: a composition layer that orchestrates existing\n * security modules (sanitizer, trust-classifier, reputation-model,\n * audit-trail) into a configurable, source-agnostic pipeline.\n *\n * Replaces ad-hoc manual composition found in issue-triage, pr-reviewer,\n * and secure-handler with a single reusable abstraction.\n *\n * @module security/firewall/firewall-pipeline\n * (Source: Issue #826 — Reusable Hostile Input Firewall)\n */\n\nimport type { Result } from '../../core/result.js';\nimport { err, ok } from '../../core/result.js';\nimport { resolveFirewallPolicyMode, type FirewallPolicyMode } from './firewall-policy-mode.js';\nimport {\n AuditTrail,\n createAuditTrail,\n emitReputationEvent,\n emitSanitizationEvent,\n MAX_STRIPPED_ELEMENTS_PER_EVENT,\n emitTrustEvent,\n} from '../audit-trail.js';\nimport { createDurableAuditSink } from '../audit-bridge.js';\nimport { sanitizeInput } from '../input-sanitizer.js';\nimport type {\n ReputationAssessment,\n GitHubUserMetadata,\n ReputationGatingMode,\n} from '../reputation-model.js';\nimport {\n assessReputation,\n ReputationCache,\n gateWithReputation,\n resolveReputationGatingMode,\n} from '../reputation-model.js';\nimport type { ReputationGateDecision } from '../reputation-model.js';\nimport type { ClassifyResult } from '../trust-classifier.js';\nimport { classifyTrust, mapAuthorAssociation } from '../trust-classifier.js';\nimport type { SanitizedInput, TrustTier } from '../trust-types.js';\nimport { generateATL } from './agent-trust-labels.js';\nimport {\n createPassthroughClassification,\n createPassthroughSanitized,\n} from './firewall-passthrough.js';\nimport { describeGate } from './firewall-trust-reason.js';\nimport type {\n ATLData,\n FirewallConfig,\n FirewallError,\n FirewallProcessOptions,\n FirewallStages,\n SourceMetadata,\n} from './firewall-types.js';\nimport { FirewallConfigSchema } from './firewall-types.js';\nimport type { Violation } from '../policy-gate.js';\nimport {\n blockingViolations,\n buildActionContext,\n evaluateFirewallPolicy,\n policyRefusal,\n type FirewallPolicyEvaluation,\n} from './firewall-policy-stage.js';\nimport { validateCorroboration } from '../corroboration-validator.js';\nimport type { AgentAction, SourceCitation } from '../action-schema.js';\nimport { createLogger } from '../../core/index.js';\n\nconst logger = createLogger({ component: 'HostileInputFirewall' });\n\n// ============================================================================\n// Firewall Result\n// ============================================================================\n\n/**\n * Output of the firewall pipeline. Aggregates results from each stage.\n */\nexport interface FirewallResult {\n readonly sanitized: SanitizedInput;\n readonly trust: ClassifyResult;\n /**\n * Whether the author is on the maintainer allowlist — present ONLY when an\n * allowlist was consulted (#4992), i.e. one was supplied at construction or\n * per call. `trust.isAllowlisted` is the classifier's published always-boolean\n * field and reads `false` whether the list was empty or never supplied; this\n * field is the one to record, because absence here means \"not measured\"\n * rather than \"measured false\" — the same treatment `reputationGate` gets.\n */\n readonly isAllowlisted?: boolean;\n readonly reputation?: ReputationAssessment;\n /**\n * The tier consumers should ENFORCE on (#3106): the classifier tier\n * reconciled with the reputation assessment (demotion-only; Tier-1/allowlist\n * wins; equals `trust.trustTier` when reputation is absent). Previously the\n * reputation tier was computed but dropped — `trust.trustTier` alone left\n * reputation unenforced.\n */\n readonly effectiveTrustTier: TrustTier;\n /**\n * The reputation gating decision behind `effectiveTrustTier` (#5381).\n *\n * **Absent means the reputation stage did not run** — not \"it ran and\n * suppressed nothing\". `ReputationGateDecision.demotionSuppressed` is a\n * required boolean, so surfacing it unconditionally would report `false` for a\n * check that never happened. Since the stage defaults to off, that\n * unevaluated case is the common one.\n */\n readonly reputationGate?: ReputationGateDecision;\n readonly atl: string;\n /**\n * Rule-of-Two assessment surfaced by the `policyEnforcement` stage (#3198):\n * present (`severity: 'block'`) when the effective tier is untrusted AND the\n * context has both write and secret access; `undefined` when the stage is\n * disabled or the rule holds. Since #5380 a view onto {@link policy} — its\n * `RULE_OF_TWO` entry — kept so existing consumers read the same field.\n */\n readonly ruleOfTwoViolation?: Violation;\n /**\n * The `policyEnforcement` stage's full verdict (#5380). **Absent means the\n * stage did not run.** Its `scope` says how much of `evaluatePolicy` could be\n * evaluated ({@link FirewallPolicyEvaluation}), so \"seven checks, none fired\"\n * is distinguishable from \"one check, six unmeasured\". `wouldRefuse` and the\n * `enforce` refusal both derive from `policy.violations`, whichever scope.\n */\n readonly policy?: FirewallPolicyEvaluation;\n /**\n * The rollout mode this run was evaluated under (#5382). Recorded on the\n * result rather than left implicit so a consumer reading a verdict can tell\n * WHICH policy produced it — a result that does not say which rules were in\n * force cannot be audited later.\n */\n readonly policyMode: FirewallPolicyMode;\n /**\n * Whether `enforce` would have refused this input.\n *\n * This is what makes `audit` mode measurable, and it is the field that makes\n * the mode a real gate rather than a switch with two indistinguishable\n * settings: under `audit` the answer is computed and reported while the input\n * is still allowed through, so an operator can size the impact of flipping to\n * `enforce` before flipping it.\n *\n * Always `false` under `enforce`, because an input that would be refused IS\n * refused — it comes back as a `POLICY_REFUSED` error, not a result.\n */\n readonly wouldRefuse: boolean;\n readonly auditEvents: readonly { readonly id: string; readonly type: string }[];\n /**\n * Whether a durable `AuditLogger` was configured for this instance (#4992\n * review). `configured` means this run's events were HANDED to that logger;\n * delivery to the hash chain is subject to the logger's own severity filter\n * (trust events are `info`), its bounded queue and its timed, fail-loud\n * flush, and is NOT confirmed per call — the write is queued. `none` means\n * the events exist only in the in-memory trail, which the next `process()`\n * call clears. This is a construction-time fact, not a per-call outcome.\n */\n readonly auditSink: 'configured' | 'none';\n readonly durationMs: number;\n}\n\n/**\n * Outcome of {@link HostileInputFirewall.validateAction} (#5382).\n *\n * A discriminated union rather than a struct with optional fields, deliberately:\n * a caller cannot read `satisfied` without first narrowing on `evaluated`, so\n * \"the stage did not run\" is structurally impossible to misread as \"the stage\n * ran and passed\". `stages.corroboration` defaults to `false`, which makes the\n * unevaluated branch the COMMON case — exactly where a silent `satisfied: true`\n * would do the most damage.\n */\nexport type ActionValidation =\n | {\n readonly evaluated: false;\n /** Why no verdict exists. Absence is attributable, not anonymous. */\n readonly reason: 'corroboration-stage-disabled';\n readonly policyMode: FirewallPolicyMode;\n }\n | {\n readonly evaluated: true;\n readonly satisfied: boolean;\n /** Unmet corroboration requirements; empty when satisfied. */\n readonly missing: readonly string[];\n readonly corroboratingSources: readonly SourceCitation[];\n /**\n * The validator's #5796 marker: the floor was cleared, and only by\n * `repoFile` citations the producer found absent from the base ref.\n * Carried so a consumer can report it without re-deriving the rule.\n */\n readonly clearedOnlyByUnverifiedSources: boolean;\n readonly policyMode: FirewallPolicyMode;\n /** Whether `enforce` would have refused this action (see FirewallResult). */\n readonly wouldRefuse: boolean;\n };\n\n// ============================================================================\n// HostileInputFirewall\n// ============================================================================\n\n/**\n * Orchestrates existing security modules into a configurable pipeline.\n * Each stage is independently toggleable via config.stages.\n */\nexport class HostileInputFirewall {\n private readonly stages: FirewallStages;\n /**\n * Construction-time allowlist, or `undefined` when none was supplied (#4992).\n * The Zod default of `[]` is deliberately NOT taken here: an absent list and\n * an empty list must stay distinguishable so `isAllowlisted` can be omitted\n * rather than recorded as `false` when nothing was consulted.\n */\n private readonly allowlisted: readonly string[] | undefined;\n private readonly maxInputLength: number;\n private readonly adapter: FirewallConfig['adapter'];\n private readonly reputationCache: ReputationCache;\n private readonly auditTrail: AuditTrail;\n private readonly context: { readonly hasWriteAccess: boolean; readonly hasSecretAccess: boolean };\n /** #5382 rollout gate; resolved once at construction, not per call. */\n private readonly policyMode: FirewallPolicyMode;\n /** #5381 reputation-demotion gate; a DIFFERENT knob from `policyMode`. */\n private readonly reputationGatingMode: ReputationGatingMode;\n /** #5405 seam: how a reputation assessment is obtained. */\n private readonly assessReputationFn: (metadata: GitHubUserMetadata) => ReputationAssessment;\n /** #4992: whether the sanitizer's content tier downgrades the classifier tier. */\n private readonly contentDowngrade: boolean;\n /** #4992 review: whether a durable logger was configured (not per-call delivery). */\n private readonly auditSink: 'configured' | 'none';\n\n constructor(config: FirewallConfig) {\n const validated = FirewallConfigSchema.parse({\n stages: config.stages,\n allowlistedMaintainers: config.allowlistedMaintainers,\n maxInputLength: config.maxInputLength,\n context: config.context,\n });\n this.stages = validated.stages;\n this.allowlisted =\n config.allowlistedMaintainers !== undefined ? validated.allowlistedMaintainers : undefined;\n this.maxInputLength = validated.maxInputLength;\n this.adapter = config.adapter;\n this.reputationCache = new ReputationCache();\n // Mirror security decisions to the durable, hash-chained audit log when a\n // logger is provided; otherwise stay in-memory only (#3291).\n this.auditTrail = createAuditTrail(\n config.auditLogger !== undefined ? createDurableAuditSink(config.auditLogger) : undefined\n );\n this.auditSink = config.auditLogger !== undefined ? 'configured' : 'none';\n this.context = validated.context;\n // Explicit config wins; otherwise the environment; otherwise `off`. Resolved\n // once here rather than per `process()` call so a mid-run env change cannot\n // make two inputs in the same batch answer to different policies.\n this.policyMode = config.policyMode ?? resolveFirewallPolicyMode(config.env ?? process.env);\n // Same resolve-once discipline, but a SEPARATE knob: `NEXUS_REPUTATION_GATING`,\n // defaulting to `enforce`. Production reads this one, so the firewall reading\n // it too is what makes the two compositions agree under one configuration.\n this.reputationGatingMode =\n config.reputationGatingMode ?? resolveReputationGatingMode(config.env ?? process.env);\n this.assessReputationFn =\n config.reputationAssessor ?? ((metadata) => assessReputation(metadata, this.reputationCache));\n this.contentDowngrade = config.contentDowngrade ?? true;\n }\n\n /**\n * Processes untrusted input through the firewall pipeline.\n * Returns a structured FirewallResult or a typed FirewallError.\n *\n * `options` carries the per-call facts (#4992): the repository's maintainer\n * allowlist and the caller's access posture. Each replaces its\n * construction-time counterpart for this call only, so one shared instance\n * never holds a repository's allowlist or a caller's posture process-wide.\n */\n process(input: unknown, options?: FirewallProcessOptions): Result<FirewallResult, FirewallError> {\n const start = Date.now();\n this.auditTrail.clear();\n const allowlist = options?.allowlistedMaintainers ?? this.allowlisted;\n const context = options?.context ?? this.context;\n\n // Stage 1: Extract metadata via adapter\n const metaResult = this.runExtraction(input);\n if (!metaResult.ok) return metaResult;\n const meta = metaResult.value;\n\n // Stage 2: Sanitize input\n const sanitized = this.runSanitization(meta, allowlist);\n\n // Stage 3: Classify trust\n const trust = this.runClassification(meta, sanitized, allowlist);\n\n // Stage 4: Assess reputation — the caller's when supplied, else the stage.\n const reputation = this.runReputation(meta, sanitized, options?.reputation);\n\n const { tier: effectiveTrustTier, gate: reputationGate } = this.runReputationGate(\n trust.trustTier,\n reputation,\n options?.reputation !== undefined\n );\n\n // Trust event on the tier the consumer acts on, not the pre-reputation one.\n this.recordTrustDecision(meta, trust, effectiveTrustTier, reputationGate, allowlist);\n\n // Stage 5: Generate ATL (labelled with the enforced tier)\n const atl = this.buildATL(meta, effectiveTrustTier, sanitized, reputation);\n\n // Stage 6: policy enforcement (#3198, #5380). Signal only: the consumer\n // enforces — except under `enforce`, where a blocking violation refuses (#5382).\n const policy = this.runPolicyEnforcement(meta, effectiveTrustTier, context, options);\n const refusal = policyRefusal(policy, this.policyMode, meta.username, effectiveTrustTier);\n if (refusal !== undefined) return err(refusal);\n\n return ok(\n this.assembleResult({\n sanitized,\n trust,\n // Measured or absent: present only when an allowlist was consulted.\n isAllowlisted: allowlist !== undefined ? trust.isAllowlisted : undefined,\n reputation,\n effectiveTrustTier,\n reputationGate,\n atl,\n policy,\n start,\n })\n );\n }\n\n /**\n * Runs the policy checks the call's facts allow — see\n * {@link evaluateFirewallPolicy} (#5380; Rule-of-Two-only since #3198). The\n * decision reaches the audit trail when the audit stage is on. Returns\n * `undefined` when the stage is disabled, so absence keeps meaning \"not run\".\n */\n private runPolicyEnforcement(\n meta: SourceMetadata,\n effectiveTrustTier: TrustTier,\n context: { readonly hasWriteAccess: boolean; readonly hasSecretAccess: boolean },\n options: FirewallProcessOptions | undefined\n ): FirewallPolicyEvaluation | undefined {\n if (!this.stages.policyEnforcement) return undefined;\n\n const evaluation = evaluateFirewallPolicy(\n buildActionContext(effectiveTrustTier, context, options),\n options?.action,\n this.stages.audit ? this.auditTrail : undefined\n );\n const blocking = blockingViolations(evaluation);\n if (blocking.length > 0) {\n logger.warn('Firewall surfaced blocking policy violations', {\n user: meta.username,\n effectiveTrustTier,\n scope: evaluation.scope,\n rules: blocking.map((v) => v.rule),\n });\n }\n return evaluation;\n }\n\n /**\n * Builds the successful result. Optional fields are spread in only when they\n * were evaluated, so absence keeps meaning \"not measured\" (see the field\n * docs on {@link FirewallResult}).\n */\n private assembleResult(parts: {\n readonly sanitized: SanitizedInput;\n readonly trust: ClassifyResult;\n readonly isAllowlisted: boolean | undefined;\n readonly reputation: ReputationAssessment | undefined;\n readonly effectiveTrustTier: TrustTier;\n readonly reputationGate: ReputationGateDecision | undefined;\n readonly atl: string;\n readonly policy: FirewallPolicyEvaluation | undefined;\n readonly start: number;\n }): FirewallResult {\n const { isAllowlisted, reputation, reputationGate, policy } = parts;\n const ruleOfTwoViolation = policy?.violations.find((v) => v.rule === 'RULE_OF_TWO');\n const blocking = blockingViolations(policy).length > 0;\n return {\n sanitized: parts.sanitized,\n trust: parts.trust,\n ...(isAllowlisted !== undefined ? { isAllowlisted } : {}),\n ...(reputation !== undefined ? { reputation } : {}),\n effectiveTrustTier: parts.effectiveTrustTier,\n ...(reputationGate !== undefined ? { reputationGate } : {}),\n atl: parts.atl,\n ...(ruleOfTwoViolation !== undefined ? { ruleOfTwoViolation } : {}),\n ...(policy !== undefined ? { policy } : {}),\n policyMode: this.policyMode,\n // Reached only when we did NOT refuse, so this is \"audit mode saw\n // something enforce would have stopped\". Under `off` it stays false: the\n // signal is already on `policy.violations`, and reporting a would-be\n // refusal for a mode that has not opted in would overstate the gate.\n wouldRefuse: blocking && this.policyMode === 'audit',\n auditEvents: this.auditTrail.query().map((e) => ({ id: e.id, type: e.type })),\n auditSink: this.auditSink,\n durationMs: Date.now() - parts.start,\n };\n }\n\n /**\n * Validates corroboration for a decided action (#5382).\n *\n * Separate from {@link process} because the two operate at different points\n * in the lifecycle, which is the real shape of the divergence epic #5281\n * found: `process()` is INPUT-shaped — it sanitizes, classifies and labels\n * untrusted content — while corroboration is ACTION-shaped, asking whether a\n * decision the consumer has now reached is backed by sources of sufficient\n * tier. There is no `AgentAction` in scope during `process()`, so the\n * `stages.corroboration` flag could never have been wired there; this is the\n * entry point that makes it readable.\n *\n * It is also the shape #5383 needs: production validates corroboration per\n * action (`issue-triage.ts:391`), so those callers cannot migrate onto the\n * firewall unless it offers a per-action surface.\n *\n * Returns `evaluated: false` when the stage is disabled — never a satisfied\n * verdict for a check that did not run. Under `enforce` an unsatisfied action\n * is refused with `POLICY_REFUSED`; under `audit` the would-be refusal is\n * reported via `wouldRefuse` and the action is allowed through.\n */\n validateAction(action: AgentAction): Result<ActionValidation, FirewallError> {\n if (!this.stages.corroboration) {\n return ok({\n evaluated: false,\n reason: 'corroboration-stage-disabled',\n policyMode: this.policyMode,\n });\n }\n\n const corroboration = validateCorroboration(action);\n\n if (!corroboration.satisfied && this.policyMode === 'enforce') {\n logger.warn('Firewall REFUSED an uncorroborated action under enforce mode', {\n actionType: corroboration.actionType,\n missing: corroboration.missing,\n });\n return err({\n code: 'POLICY_REFUSED',\n message:\n `Refused by firewall policy: ${corroboration.actionType} lacks required ` +\n `corroboration — ${corroboration.missing.join('; ')}`,\n stage: 'corroboration',\n missing: corroboration.missing,\n });\n }\n\n return ok({\n evaluated: true,\n satisfied: corroboration.satisfied,\n missing: corroboration.missing,\n corroboratingSources: corroboration.corroboratingSources,\n clearedOnlyByUnverifiedSources: corroboration.clearedOnlyByUnverifiedSources,\n policyMode: this.policyMode,\n wouldRefuse: !corroboration.satisfied && this.policyMode === 'audit',\n });\n }\n\n /** Returns the internal audit trail for inspection. */\n getAuditTrail(): AuditTrail {\n return this.auditTrail;\n }\n\n // ==========================================================================\n // Pipeline Stages (private)\n // ==========================================================================\n\n private runExtraction(input: unknown): Result<SourceMetadata, FirewallError> {\n try {\n const meta = this.adapter.extractMetadata(input);\n return ok(meta);\n } catch (cause: unknown) {\n const message = cause instanceof Error ? cause.message : String(cause);\n return err({\n code: 'EXTRACTION_FAILED',\n message: `Adapter extraction failed: ${message}`,\n stage: 'extraction',\n });\n }\n }\n\n private runSanitization(\n meta: SourceMetadata,\n allowlist: readonly string[] | undefined\n ): SanitizedInput {\n if (!this.stages.sanitization) {\n return createPassthroughSanitized(meta);\n }\n\n const result = sanitizeInput(\n meta.content,\n mapAuthorAssociation(meta.authorAssociation),\n meta.username,\n {\n allowlistedMaintainers: [...(allowlist ?? [])],\n maxInputLength: this.maxInputLength,\n }\n );\n\n if (this.stages.audit) {\n emitSanitizationEvent(this.auditTrail, {\n source: meta.sourceType,\n wasModified: result.wasModified,\n ...(result.truncated !== undefined ? { truncated: result.truncated } : {}),\n strippedCount: result.strippedElements.length,\n injectionFlagCount: result.injectionFlags.length,\n strippedElements: result.strippedElements\n .slice(0, MAX_STRIPPED_ELEMENTS_PER_EVENT)\n .map((e) => ({ tag: e.tag, reason: e.reason })),\n });\n }\n\n return result;\n }\n\n private runClassification(\n meta: SourceMetadata,\n sanitized: SanitizedInput,\n allowlist: readonly string[] | undefined\n ): ClassifyResult {\n if (!this.stages.trustClassification) {\n return createPassthroughClassification(meta);\n }\n\n return classifyTrust({\n username: meta.username,\n authorAssociation: meta.authorAssociation,\n // #4992: `contentDowngrade: false` withholds the sanitizer's content tier\n // from the classifier; the flags themselves were still measured above.\n ...(this.contentDowngrade && sanitized.contentTierMeasured !== false\n ? { sanitizedInput: sanitized }\n : {}),\n config: {\n allowlistedMaintainers: [...(allowlist ?? [])],\n },\n });\n }\n\n /**\n * Emits the trust audit event for the tier the consumer acts on — after the\n * reputation gate, so the record cannot describe a tier nobody enforced\n * (#4992 review). A demotion is named in `reason`.\n */\n private recordTrustDecision(\n meta: SourceMetadata,\n trust: ClassifyResult,\n effectiveTrustTier: TrustTier,\n gate: ReputationGateDecision | undefined,\n allowlist: readonly string[] | undefined\n ): void {\n if (!this.stages.audit) return;\n const demoted = effectiveTrustTier !== trust.trustTier;\n emitTrustEvent(this.auditTrail, {\n username: meta.username,\n assignedTier: effectiveTrustTier,\n userRole: trust.userRole,\n // Recorded only when an allowlist was consulted (#4992).\n ...(allowlist !== undefined ? { isAllowlisted: trust.isAllowlisted } : {}),\n wasDowngraded: trust.wasDowngraded || demoted,\n reason: describeGate(trust.reason, demoted, gate),\n });\n }\n\n /**\n * Reconcile the classifier tier with reputation, under the rollout mode\n * production honours (#3106 reconciliation, #5381 gating).\n *\n * #3106's reconciliation is demotion-only; Tier-1/allowlist wins; it equals\n * the classifier tier when reputation is absent. #5381 puts it behind\n * `NEXUS_REPUTATION_GATING`, so `audit` is audit-only here too — previously\n * the firewall enforced unconditionally while production suppressed, on\n * identical configuration.\n *\n * Returns no gate at all when the stage is off, so absence in the result\n * means \"not evaluated\" rather than \"evaluated, nothing suppressed\" —\n * `demotionSuppressed` is a required boolean and would otherwise report\n * `false` for a check that never ran.\n */\n private runReputationGate(\n classifierTier: TrustTier,\n reputation: ReputationAssessment | undefined,\n callerSupplied: boolean\n ): { readonly tier: TrustTier; readonly gate?: ReputationGateDecision } {\n // A caller-supplied measurement runs the gate even when the instance's own\n // reputation stage is off (#4992 review): the caller measured, so record it.\n if (!this.stages.reputationAssessment && !callerSupplied) return { tier: classifierTier };\n const gate = gateWithReputation(classifierTier, reputation, this.reputationGatingMode);\n return { tier: gate.enforcedTier, gate };\n }\n\n private runReputation(\n meta: SourceMetadata,\n sanitized: SanitizedInput,\n supplied: { readonly assessment: ReputationAssessment | undefined } | undefined\n ): ReputationAssessment | undefined {\n if (supplied !== undefined) {\n // The caller's measurement replaces the instance's stage for this call;\n // `undefined` means the caller measured nothing, so nothing is emitted.\n if (supplied.assessment !== undefined && this.stages.audit) {\n emitReputationEvent(this.auditTrail, {\n username: meta.username,\n reputationScore: supplied.assessment.reputationScore,\n isSuspicious: supplied.assessment.isSuspicious,\n effectiveTier: supplied.assessment.effectiveTrustTier,\n signalCount: supplied.assessment.suspiciousSignals.length,\n });\n }\n return supplied.assessment;\n }\n if (!this.stages.reputationAssessment) return undefined;\n\n // #3106: only supply what the firewall actually knows from the event —\n // author association + injection flags. Account-age / contribution /\n // recent-comment data is NOT available here (it's fetched at the wiring\n // layer in a later phase), so it is OMITTED, not fabricated. The engine\n // skips the account/activity signals when their data is absent; until the\n // fetch lands, the firewall's reputation reflects injection + authority\n // signals only — honest rather than always-benign.\n const metadata: GitHubUserMetadata = {\n username: meta.username,\n authorAssociation: meta.authorAssociation.toUpperCase(),\n injectionFlags: sanitized.injectionFlags,\n };\n\n const result = this.assessReputationFn(metadata);\n\n if (this.stages.audit) {\n emitReputationEvent(this.auditTrail, {\n username: meta.username,\n reputationScore: result.reputationScore,\n isSuspicious: result.isSuspicious,\n effectiveTier: result.effectiveTrustTier,\n signalCount: result.suspiciousSignals.length,\n });\n }\n\n return result;\n }\n\n private buildATL(\n meta: SourceMetadata,\n effectiveTrustTier: TrustTier,\n sanitized: SanitizedInput,\n reputation?: ReputationAssessment\n ): string {\n const data: ATLData = {\n tier: effectiveTrustTier,\n source: meta.sourceType,\n user: meta.username,\n sanitized: sanitized.wasModified,\n ...(reputation !== undefined ? { rep: reputation.reputationScore / 100 } : {}),\n };\n return generateATL(data);\n }\n}\n","/**\n * nexus-agents/security/firewall - GitHub Adapter\n *\n * ISourceAdapter implementation for GitHub issues, PRs, and comments.\n * Extracts normalized metadata from GitHub API payloads.\n *\n * @module security/firewall/github-adapter\n * (Source: Issue #826 — Reusable Hostile Input Firewall)\n */\n\nimport { z } from 'zod';\n\nimport { mapAuthorAssociation } from '../trust-classifier.js';\nimport type { ISourceAdapter, SourceMetadata } from './firewall-types.js';\n\n// ============================================================================\n// GitHub Input Types\n// ============================================================================\n\n/**\n * Discriminated union of GitHub input types the adapter can process.\n */\nconst GitHubIssueSchema = z.object({\n type: z.literal('issue'),\n username: z.string().min(1),\n authorAssociation: z.string().min(1),\n title: z.string().default(''),\n body: z.string().default(''),\n});\n\nconst GitHubCommentSchema = z.object({\n type: z.literal('comment'),\n username: z.string().min(1),\n authorAssociation: z.string().min(1),\n body: z.string().default(''),\n});\n\nconst GitHubPRSchema = z.object({\n type: z.literal('pull_request'),\n username: z.string().min(1),\n authorAssociation: z.string().min(1),\n title: z.string().default(''),\n body: z.string().default(''),\n});\n\nexport const GitHubInputSchema = z.discriminatedUnion('type', [\n GitHubIssueSchema,\n GitHubCommentSchema,\n GitHubPRSchema,\n]);\nexport type GitHubInput = z.infer<typeof GitHubInputSchema>;\n\n// ============================================================================\n// GitHub Adapter\n// ============================================================================\n\n/** Maps input type to source type string. */\nfunction toSourceType(type: GitHubInput['type']): string {\n const mapping: Record<GitHubInput['type'], string> = {\n issue: 'github-issue',\n comment: 'github-comment',\n pull_request: 'github-pr',\n };\n return mapping[type];\n}\n\n/** Extracts content from a GitHub input. */\nfunction extractContent(input: GitHubInput): string {\n if (input.type === 'comment') return input.body;\n const title = input.title;\n const body = input.body;\n return title && body ? `${title}\\n\\n${body}` : title || body;\n}\n\n/**\n * Creates a GitHub source adapter.\n * Validates input with Zod and maps GitHub API fields to SourceMetadata.\n */\nexport function createGitHubAdapter(): ISourceAdapter {\n return {\n platform: 'github',\n extractMetadata(input: unknown): SourceMetadata {\n const result = GitHubInputSchema.safeParse(input);\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => `${i.path.join('.')}: ${i.message}`)\n .join('; ');\n throw new Error(`GitHub input validation failed: ${issues}`);\n }\n const parsed = result.data;\n const role = mapAuthorAssociation(parsed.authorAssociation);\n return {\n username: parsed.username,\n authorAssociation: role,\n content: extractContent(parsed),\n sourceType: toSourceType(parsed.type),\n };\n },\n };\n}\n","/**\n * nexus-agents/dogfooding - Untrusted-input firewall (shared instance)\n *\n * The one `HostileInputFirewall` the live untrusted-input paths route through\n * (#4992): `issue-triage` and `pr-reviewer`. Before this module both called\n * `classifyTrust()` directly, which meant no trust classification on any live\n * path reached the security audit trail, and the maintainer allowlist the\n * classifier reads from `config` was never supplied — `isAllowlisted: false`\n * was recorded on every result without ever being measured.\n *\n * Division of labour, ratified by the #4992 panel and completed by #5383:\n *\n * - The firewall is the ONE composition: it sanitizes, classifies, runs the\n * reputation gate, evaluates policy against the caller's access posture, and\n * records every decision on the audit trail. Under the default\n * `NEXUS_FIREWALL_POLICY=off` it REFUSES nothing — but it still evaluates.\n * - It is entered twice per live input, because the callers only know their\n * actions after they know the tier. `runUntrustedInputFirewall` is the\n * INPUT-shaped entry (no action; the Rule of Two measured, the six\n * action-scoped checks named `unmeasured`, `policy.scope: 'context'`), and\n * `evaluateActionThroughFirewall` is the ACTION-shaped entry, called once per\n * action the caller intends to take, which runs the full `evaluatePolicy` set\n * (#5380) and hands back the decision from `FirewallResult.policy`. Neither\n * caller calls `evaluatePolicy` itself any more (#5383): the #4992 panel let\n * them keep it only because the firewall had no action-shaped entry then.\n * `validateActionCorroboration` is the third entry (#6309): the per-action\n * corroboration check, run by the firewall's `corroboration` stage — which\n * this instance enables — rather than composed beside it by the callers.\n * - The callers still measure reputation themselves, with metadata the\n * firewall cannot see (account age, comment history), and pass that\n * measurement per call; the firewall runs the ONE reputation gate, so the\n * trust event, the policy checks and the `wouldRefuse` count all use the one\n * enforced tier. The callers cross-check that the action-shaped run enforced\n * the tier the input-shaped run did, and fail closed if not.\n * - Facts that vary per call — the caller's access posture, the action, the\n * repository label set and, when a source for one exists, the maintainer\n * allowlist — are passed per call via `FirewallProcessOptions`, never held on\n * the shared instance. No allowlist source exists today (no config field, no\n * env var), so the callers pass none and `isAllowlisted` stays absent.\n *\n * @module dogfooding/untrusted-input-firewall\n */\n\nimport type { Result } from '../core/index.js';\nimport { ok, err, createLogger } from '../core/index.js';\nimport type { IAuditLogger } from '../audit/audit-types.js';\nimport { HostileInputFirewall } from '../security/firewall/firewall-pipeline.js';\nimport type { FirewallResult } from '../security/firewall/firewall-pipeline.js';\nimport type { FirewallError, FirewallProcessOptions } from '../security/firewall/firewall-types.js';\nimport type { FirewallPolicyMode } from '../security/firewall/firewall-policy-mode.js';\nimport { createGitHubAdapter } from '../security/firewall/github-adapter.js';\nimport type { GitHubInput } from '../security/firewall/github-adapter.js';\nimport type { AgentAction, SourceCitation } from '../security/action-schema.js';\nimport type { Violation } from '../security/policy-gate.js';\nimport type { TrustTier } from '../security/trust-types.js';\n\nconst logger = createLogger({ component: 'UntrustedInputFirewall' });\n\nlet singleton: HostileInputFirewall | undefined;\n/** The process's durable audit logger, when the bootstrap has one (#4992 review). */\nlet configuredAuditLogger: IAuditLogger | undefined;\n\n/**\n * Supplies the process-wide durable audit logger to the shared firewall.\n *\n * The MCP server creates exactly one `AuditLogger` at startup\n * (`initializeAuditLogger`, gated on `security.audit.enabled`) and threads it\n * by DI; there is no global accessor. `initV2PipelineSubsystems` calls this\n * with that logger so trust events on the live paths reach the hash-chained\n * log instead of an in-memory buffer the next call clears. Without it — the\n * CLI review path, or audit disabled — the firewall reports `auditSink: 'none'`\n * and claims no emission.\n *\n * Replaces the cached instance so the sink cannot be missed by an instance\n * built before bootstrap reached this point.\n */\nexport function configureUntrustedInputFirewall(deps: { auditLogger?: IAuditLogger }): void {\n configuredAuditLogger = deps.auditLogger;\n singleton = undefined;\n}\n\n/**\n * The process-wide firewall, constructed on first use.\n *\n * `contentDowngrade: false` is what keeps the default mode pass-through: the\n * firewall's own classifier is content-aware (injection-bearing content from a\n * Tier-2 author classifies as Tier 4), while the production paths classify by\n * role and route content signals through reputation gating, which has its own\n * rollout knob (`NEXUS_REPUTATION_GATING`). The injection flags are still\n * measured and recorded by the sanitization stage; only the tier downgrade is\n * withheld so the recorded `trustTier` is unchanged under `off`.\n *\n * The reputation stage stays off: the callers assess reputation themselves\n * with metadata the firewall never sees. The corroboration stage is ON\n * (#6309, panel option R): it defaults to off because the firewall is a\n * published API, but the live paths validate corroboration per action and\n * that check runs here, through `validateActionCorroboration`, not beside the\n * firewall. `policyMode` is resolved from `NEXUS_FIREWALL_POLICY` once, at\n * construction.\n */\nexport function getUntrustedInputFirewall(): HostileInputFirewall {\n singleton ??= new HostileInputFirewall({\n adapter: createGitHubAdapter(),\n contentDowngrade: false,\n stages: { corroboration: true },\n ...(configuredAuditLogger !== undefined ? { auditLogger: configuredAuditLogger } : {}),\n });\n return singleton;\n}\n\n// @export-no-consumer-yet — see #4992. Test-only seam: drops or replaces the\n// cached instance so a test can re-read the env or observe the audit trail.\nexport function _setUntrustedInputFirewallForTests(\n firewall: HostileInputFirewall | undefined\n): void {\n singleton = firewall;\n}\n\n/**\n * Runs one untrusted GitHub payload through the shared firewall.\n *\n * Maps the firewall's typed error into the `Result<_, Error>` shape the\n * callers already return, failing closed on every code: an unparseable payload\n * (`EXTRACTION_FAILED`) is as much a reason not to proceed as a policy\n * refusal (`POLICY_REFUSED`, only reachable under `enforce`). Under `audit` a\n * would-be refusal is logged and the result is returned unchanged — that log\n * line is the telemetry an operator sizes the flip to `enforce` on.\n */\nexport function runUntrustedInputFirewall(\n input: GitHubInput,\n options: FirewallProcessOptions\n): Result<FirewallResult, Error> {\n const result = processAndLog(input, options);\n if (!result.ok) return err(asError(result.error));\n return ok(result.value);\n}\n\n/**\n * The firewall's verdict on ONE action a live caller intends to take (#5383),\n * read from `FirewallResult.policy` — the same `evaluatePolicy` decision the\n * callers used to compute beside the firewall, now computed inside it and\n * recorded on the audit trail as a `policy_gate` event.\n *\n * Two shapes, because the mode changes who refuses, never what was decided:\n *\n * - `refused: false` — under `off` and `audit` the firewall returns the\n * decision and the CALLER enforces it, exactly as it did with the direct\n * call: `allowed` is `evaluatePolicy`'s own verdict, whatever the mode.\n * `wouldRefuse` is `audit`'s telemetry.\n * - `refused: true` — under `enforce` the firewall refused the action itself\n * (`POLICY_REFUSED`). `violations` is the blocking list it refused on, so the\n * caller's record can still name the rules; `requiresApproval` is absent\n * because the decision never reached the caller.\n *\n * Either way `allowed` is what the caller acts on, so a per-action decision\n * cannot silently weaken when the mode is `off`.\n */\nexport type FirewallActionDecision =\n | {\n readonly refused: false;\n readonly allowed: boolean;\n readonly requiresApproval: boolean;\n readonly violations: readonly Violation[];\n /** The tier this run enforced — equal to the caller's `enforcedTier`, or the call failed. */\n readonly effectiveTrustTier: TrustTier;\n readonly policyMode: FirewallPolicyMode;\n readonly wouldRefuse: boolean;\n }\n | {\n readonly refused: true;\n readonly allowed: false;\n readonly violations: readonly Violation[];\n readonly policyMode: 'enforce';\n };\n\n/**\n * Runs one action through the shared firewall and returns its policy verdict.\n *\n * `enforcedTier` is the tier the caller's classification run enforced (the\n * reputation gate's, #3122) and stamped on the action's citations. The\n * firewall recomputes that gate here from the same measurement; a run that\n * enforces a DIFFERENT tier fails the call, because a record that disagrees\n * with what was enforced is worse than none (#5719).\n *\n * Fails closed — an `Error`, not a verdict — wherever no verdict exists: that\n * tier disagreement, a non-policy firewall error (an unparseable payload), and\n * a run whose `policy` is absent or `scope: 'context'`, which means the policy\n * stage did not evaluate this action. None of these is \"denied\"; recording\n * `allowed: false` for them would put a measurement where none was taken.\n */\nexport function evaluateActionThroughFirewall(\n input: GitHubInput,\n options: FirewallProcessOptions & {\n readonly action: AgentAction;\n readonly enforcedTier: TrustTier;\n }\n): Result<FirewallActionDecision, Error> {\n const { enforcedTier, ...processOptions } = options;\n const result = processAndLog(input, processOptions);\n if (!result.ok) {\n const { code, stage, violations } = result.error;\n if (code !== 'POLICY_REFUSED' || stage !== 'policy') return err(asError(result.error));\n // A refusal that names no rule cannot be recorded as a policy decision.\n if (violations === undefined || violations.length === 0) return err(asError(result.error));\n return ok({ refused: true, allowed: false, violations, policyMode: 'enforce' });\n }\n const { policy, policyMode, wouldRefuse, effectiveTrustTier } = result.value;\n if (policy?.scope !== 'action') {\n const why = policy === undefined ? 'the policy stage is disabled' : `scope was ${policy.scope}`;\n return err(\n new Error(\n `Untrusted-input firewall did not evaluate policy for action ${options.action.type} (${why})`\n )\n );\n }\n if (effectiveTrustTier !== enforcedTier) {\n return err(\n new Error(\n `Untrusted-input firewall enforced tier ${effectiveTrustTier} for action ` +\n `${options.action.type} but tier ${enforcedTier} for the classification`\n )\n );\n }\n return ok({\n refused: false,\n allowed: policy.allowed,\n requiresApproval: policy.requiresApproval,\n violations: policy.violations,\n effectiveTrustTier,\n policyMode,\n wouldRefuse,\n });\n}\n\n/**\n * The firewall's corroboration verdict on ONE action (#6309), read from\n * `HostileInputFirewall.validateAction` — the same `validateCorroboration`\n * result the callers used to compute beside the firewall, now computed by its\n * corroboration stage under the one `NEXUS_FIREWALL_POLICY` mode.\n *\n * The same two shapes as {@link FirewallActionDecision}, for the same reason:\n *\n * - `refused: false` — under `off` and `audit` the firewall returns the\n * validator's verdict and the CALLER records it (`corroborated`,\n * `INSUFFICIENT_CORROBORATION`), exactly as it did with the direct call.\n * `wouldRefuse` is `audit`'s telemetry; `missing` names the unmet\n * requirements it would refuse on, so a soak can measure the refusal rate.\n * - `refused: true` — under `enforce` the firewall refused the action itself\n * (`POLICY_REFUSED` at stage `corroboration`). `missing` is what it refused\n * on, so the caller's record can still name it.\n */\nexport type FirewallCorroborationDecision =\n | {\n readonly refused: false;\n readonly satisfied: boolean;\n readonly missing: readonly string[];\n readonly corroboratingSources: readonly SourceCitation[];\n readonly clearedOnlyByUnverifiedSources: boolean;\n readonly policyMode: FirewallPolicyMode;\n readonly wouldRefuse: boolean;\n }\n | {\n readonly refused: true;\n readonly satisfied: false;\n readonly stage: 'corroboration';\n readonly missing: readonly string[];\n readonly policyMode: 'enforce';\n };\n\n/**\n * Runs one action through the shared firewall's corroboration stage.\n *\n * Fails closed — an `Error`, not a verdict — where no verdict exists. The\n * named empty case is `evaluated: false`: the stage did not run, so neither\n * `corroborated: true` nor `corroborated: false` is an honest record of it;\n * `satisfied` is never read off it. The shared instance enables the stage, so\n * on the live paths this is reachable only through a replaced instance, and it\n * fails the same way an unevaluated policy stage does. A refusal that names\n * nothing missing is likewise an error, not a corroboration decision.\n */\nexport function validateActionCorroboration(\n action: AgentAction\n): Result<FirewallCorroborationDecision, Error> {\n const result = getUntrustedInputFirewall().validateAction(action);\n if (!result.ok) {\n const { code, stage, missing } = result.error;\n if (code !== 'POLICY_REFUSED' || stage !== 'corroboration') return err(asError(result.error));\n if (missing === undefined || missing.length === 0) return err(asError(result.error));\n logger.warn('Untrusted-input firewall refused an uncorroborated action (enforce mode)', {\n actionType: action.type,\n stage,\n missing,\n });\n return ok({ refused: true, satisfied: false, stage, missing, policyMode: 'enforce' });\n }\n const validation = result.value;\n if (!validation.evaluated) {\n return err(\n new Error(\n `Untrusted-input firewall did not evaluate corroboration for action ${action.type} ` +\n `(${validation.reason})`\n )\n );\n }\n if (validation.wouldRefuse) {\n logger.warn('Untrusted-input firewall would refuse under enforce (audit mode)', {\n actionType: action.type,\n stage: 'corroboration',\n missing: validation.missing,\n });\n }\n return ok({\n refused: false,\n satisfied: validation.satisfied,\n missing: validation.missing,\n corroboratingSources: validation.corroboratingSources,\n clearedOnlyByUnverifiedSources: validation.clearedOnlyByUnverifiedSources,\n policyMode: validation.policyMode,\n wouldRefuse: validation.wouldRefuse,\n });\n}\n\n/** One `process()` call site for both input entries, so the log lines cannot drift. */\nfunction processAndLog(\n input: GitHubInput,\n options: FirewallProcessOptions\n): Result<FirewallResult, FirewallError> {\n const result = getUntrustedInputFirewall().process(input, options);\n if (!result.ok) {\n logger.warn('Untrusted-input firewall rejected the input', {\n user: input.username,\n sourceType: input.type,\n ...(options.action !== undefined ? { actionType: options.action.type } : {}),\n code: result.error.code,\n stage: result.error.stage,\n });\n return result;\n }\n if (result.value.wouldRefuse) {\n // Names every blocking rule and the checks that could NOT run (#5380), so\n // the telemetry sizes the flip to `enforce` on what was measured.\n const policy = result.value.policy;\n logger.warn('Untrusted-input firewall would refuse under enforce (audit mode)', {\n user: input.username,\n sourceType: input.type,\n ...(options.action !== undefined ? { actionType: options.action.type } : {}),\n trustTier: result.value.effectiveTrustTier,\n scope: policy?.scope,\n rules: policy?.violations.filter((v) => v.severity === 'block').map((v) => v.rule),\n unmeasured: policy?.unmeasured,\n });\n }\n return result;\n}\n\nfunction asError({ code, stage, message }: FirewallError): Error {\n return new Error(`Untrusted-input firewall ${code} at stage ${stage}: ${message}`);\n}\n\n/**\n * The one mapping from a caller's issue or PR metadata to the firewall's\n * input (#5383), so the classification run and every per-action run of one\n * caller are fed the same payload by construction.\n */\nexport function firewallInputFor(\n type: GitHubInput['type'],\n source: {\n readonly author: string;\n readonly authorAssociation: string;\n readonly title: string;\n readonly body: string;\n }\n): GitHubInput {\n return {\n type,\n username: source.author,\n authorAssociation: source.authorAssociation,\n title: source.title,\n body: source.body,\n };\n}\n","/**\n * nexus-agents/scm - URL parsers\n *\n * Pure parsers for GitHub PR and issue URLs. Lifted from\n * `dogfooding/github-client.ts` as part of the #2553 consolidation —\n * URL parsing has no transport-layer dependency, so it belongs in the\n * canonical SCM module alongside the rest of the GitHub surface.\n *\n * @module scm/url-parsers\n */\n\nimport type { Result } from '../core/index.js';\nimport { ok, err } from '../core/index.js';\n\n/**\n * Parses a PR URL into owner, repo, and number. Accepts:\n *\n * - `https://github.com/owner/repo/pull/123`\n * - `https://www.github.com/owner/repo/pull/123`\n * - `owner/repo#123`\n * - `owner/repo/pull/123`\n */\nexport function parsePRUrl(url: string): Result<\n {\n owner: string;\n repo: string;\n prNumber: number;\n },\n Error\n> {\n const httpPattern = /github\\.com\\/([^/]+)\\/([^/]+)\\/pull\\/(\\d+)/;\n const shortPattern = /^([^/]+)\\/([^/#]+)(?:#|\\/pull\\/)(\\d+)$/;\n\n const match = httpPattern.exec(url) ?? shortPattern.exec(url);\n\n if (match === null) {\n return err(new Error(`Invalid PR URL format: ${url}`));\n }\n\n const owner = match[1];\n const repo = match[2];\n const numberStr = match[3];\n\n if (owner === undefined || repo === undefined || numberStr === undefined) {\n return err(new Error(`Invalid PR URL format: ${url}`));\n }\n\n const prNumber = parseInt(numberStr, 10);\n\n if (isNaN(prNumber)) {\n return err(new Error(`Invalid PR URL format: ${url}`));\n }\n\n return ok({ owner, repo, prNumber });\n}\n\n/**\n * Parses an issue URL into owner, repo, and number. Accepts:\n *\n * - `https://github.com/owner/repo/issues/123`\n * - `owner/repo#123`\n */\nexport function parseIssueUrl(url: string): Result<\n {\n owner: string;\n repo: string;\n issueNumber: number;\n },\n Error\n> {\n const httpPattern = /github\\.com\\/([^/]+)\\/([^/]+)\\/issues\\/(\\d+)/;\n const shortPattern = /^([^/]+)\\/([^/#]+)#(\\d+)$/;\n\n const match = httpPattern.exec(url) ?? shortPattern.exec(url);\n\n if (match === null) {\n return err(new Error(`Invalid issue URL format: ${url}`));\n }\n\n const owner = match[1];\n const repo = match[2];\n const numberStr = match[3];\n\n if (owner === undefined || repo === undefined || numberStr === undefined) {\n return err(new Error(`Invalid issue URL format: ${url}`));\n }\n\n const issueNumber = parseInt(numberStr, 10);\n\n if (isNaN(issueNumber)) {\n return err(new Error(`Invalid issue URL format: ${url}`));\n }\n\n return ok({ owner, repo, issueNumber });\n}\n","/**\n * nexus-agents/scm - GitHub Provider Trait Implementations\n *\n * Implements IScmReviewer and IScmUserInfo trait interfaces for GitHub.\n * Uses `gh api` for REST API access to get detailed data.\n *\n * @module scm/github-provider-traits\n * (Source: Issue #1136 — Centralized SCM Provider Module)\n */\n\nimport type { Result } from '../core/index.js';\nimport { ok, err, createLogger, getErrorMessage } from '../core/index.js';\nimport type {\n IScmReviewer,\n IScmUserInfo,\n ScmPullRequestDetail,\n ScmIssueDetail,\n ScmCommentDetail,\n ScmReviewDecision,\n ScmUserMetadata,\n ScmFileChange,\n} from './types.js';\nimport { ScmError } from './types.js';\nimport { GitHubProvider } from './github-provider.js';\nimport { CLI_SUBPROCESS_TIMEOUTS } from '../config/timeouts.js';\n\nconst logger = createLogger({ component: 'GitHubProviderTraits' });\n\n// ============================================================================\n// gh API JSON types (internal)\n// ============================================================================\n\ninterface GhApiPrJson {\n number: number;\n title: string;\n body: string | null;\n html_url: string;\n user: { login: string };\n author_association: string;\n base: { ref: string };\n head: { ref: string; sha: string };\n draft: boolean;\n labels: Array<{ name: string }>;\n additions: number;\n deletions: number;\n}\n\ninterface GhApiFileJson {\n filename: string;\n status: string;\n additions: number;\n deletions: number;\n patch?: string;\n previous_filename?: string;\n}\n\ninterface GhApiIssueJson {\n number: number;\n title: string;\n body: string | null;\n user: { login: string };\n author_association: string;\n state: string;\n html_url: string;\n labels: Array<{ name: string }>;\n created_at: string;\n}\n\ninterface GhApiCommentJson {\n id: number;\n body: string;\n user: { login: string };\n author_association: string;\n created_at: string;\n}\n\ninterface GhApiUserJson {\n login: string;\n name: string | null;\n company: string | null;\n followers: number;\n following: number;\n public_repos: number;\n created_at: string;\n}\n\n// ============================================================================\n// gh API executor\n// ============================================================================\n\n/**\n * Resolves a GitHub token from env vars or `gh auth token`.\n * Caches the result to avoid repeated subprocess calls.\n */\nlet cachedGhToken: string | undefined | null = null;\nlet ghTokenPromise: Promise<string | undefined> | undefined;\n\n/** Reset the cached token (for testing). */\nexport function resetGhTokenCache(): void {\n cachedGhToken = null;\n ghTokenPromise = undefined;\n}\n\nasync function resolveGhToken(): Promise<string | undefined> {\n if (cachedGhToken !== null) return cachedGhToken;\n\n ghTokenPromise ??= resolveGhTokenImpl().finally(() => {\n ghTokenPromise = undefined;\n });\n return ghTokenPromise;\n}\n\nasync function resolveGhTokenImpl(): Promise<string | undefined> {\n const envToken = process.env['GITHUB_TOKEN'] ?? process.env['GH_TOKEN'];\n if (envToken !== undefined && envToken.length > 0) {\n cachedGhToken = envToken;\n return envToken;\n }\n\n try {\n const { execFile } = await import('node:child_process');\n const { promisify } = await import('node:util');\n const exec = promisify(execFile);\n const { stdout } = await exec('gh', ['auth', 'token'], { timeout: 5_000 });\n const token = stdout.trim();\n cachedGhToken = token.length > 0 ? token : undefined;\n } catch {\n cachedGhToken = undefined;\n }\n return cachedGhToken;\n}\n\n/** Page size for paginated list endpoints; GitHub's maximum, and its default is 30. */\nconst GH_API_PAGE_SIZE = 100;\n\nasync function execGhApiRaw(args: readonly string[]): Promise<Result<string, ScmError>> {\n const { execFile } = await import('node:child_process');\n const { promisify } = await import('node:util');\n const exec = promisify(execFile);\n\n // Inject token into subprocess environment to prevent keyring access failures\n const token = await resolveGhToken();\n const env = token !== undefined ? { ...process.env, GH_TOKEN: token } : undefined;\n\n try {\n const { stdout } = await exec('gh', [...args], {\n maxBuffer: 10 * 1024 * 1024,\n timeout: CLI_SUBPROCESS_TIMEOUTS.ghCommandMs,\n ...(env !== undefined ? { env } : {}),\n });\n return ok(stdout.trim());\n } catch (error) {\n const execError = error as { message: string; stderr?: string };\n return err(\n new ScmError(`gh api failed: ${execError.message}`, 'github', undefined, {\n endpoint: args[1] ?? '',\n stderr: execError.stderr,\n })\n );\n }\n}\n\nasync function execGhApi(endpoint: string, method?: string): Promise<Result<string, ScmError>> {\n const args = ['api', endpoint];\n if (method !== undefined) args.push('--method', method);\n return execGhApiRaw(args);\n}\n\n/**\n * Fetch EVERY page of a `gh api` list endpoint, as one object per line.\n *\n * A bare `gh api <list-endpoint>` returns GitHub's default first page of 30 and\n * discards the `Link` cursor, so `getPullRequestDetail` saw at most 30 changed\n * files of any PR and `listCommentDetails` at most the 30 OLDEST comments —\n * both returned `ok(...)` with nothing to say a page had been left behind. The\n * review pipeline then computed `reviewCoverage: 'full'` against that truncated\n * denominator and posted \"30 of 30 files reviewed\" on a 120-file PR.\n *\n * `--paginate` alone is not enough: on a JSON-array endpoint it concatenates one\n * array per page, which is not valid JSON. `--slurp` would fix that but landed\n * in gh 2.51 and this repo runs against 2.45. `--jq '.[]'` emits one compact\n * object per line across all pages, which parses on every version.\n */\nasync function execGhApiList<T>(endpoint: string): Promise<Result<T[], ScmError>> {\n const separator = endpoint.includes('?') ? '&' : '?';\n const result = await execGhApiRaw([\n 'api',\n `${endpoint}${separator}per_page=${String(GH_API_PAGE_SIZE)}`,\n '--paginate',\n '--jq',\n '.[]',\n ]);\n if (!result.ok) return result;\n\n // An endpoint with no items yields empty stdout. `''.split('\\n')` is `['']`,\n // so the filter is what keeps \"no comments\" from parsing as one bad line.\n const lines = result.value.split('\\n').filter((l) => l.trim() !== '');\n try {\n return ok(lines.map((l) => JSON.parse(l) as T));\n } catch (error) {\n return err(\n new ScmError(\n `gh api returned unparseable page data: ${getErrorMessage(error)}`,\n 'github',\n undefined,\n {\n endpoint,\n }\n )\n );\n }\n}\n\n// ============================================================================\n// Mappers\n// ============================================================================\n\nfunction mapFileChange(raw: GhApiFileJson): ScmFileChange {\n const statusMap: Record<string, ScmFileChange['status']> = {\n added: 'added',\n removed: 'removed',\n modified: 'modified',\n renamed: 'renamed',\n copied: 'copied',\n changed: 'changed',\n unchanged: 'unchanged',\n };\n const status = statusMap[raw.status] ?? 'unknown';\n return {\n filename: raw.filename,\n status,\n ...(status === 'unknown' ? { rawStatus: raw.status } : {}),\n additions: raw.additions,\n deletions: raw.deletions,\n ...(raw.patch !== undefined ? { patch: raw.patch } : {}),\n ...(raw.previous_filename !== undefined ? { previousFilename: raw.previous_filename } : {}),\n };\n}\n\n// ============================================================================\n// GitHubReviewer — implements IScmReviewer\n// ============================================================================\n\n/**\n * GitHub-specific reviewer that adds PR detail and review capabilities\n * to a GitHubProvider. Implements IScmReviewer trait.\n *\n * @example\n * ```typescript\n * const provider = createGitHubProvider('owner/repo');\n * const reviewer = new GitHubReviewer(provider);\n * const detail = await reviewer.getPullRequestDetail(42);\n * ```\n */\nexport class GitHubReviewer implements IScmReviewer {\n constructor(private readonly provider: GitHubProvider) {}\n\n async getPullRequestDetail(prNumber: number): Promise<Result<ScmPullRequestDetail, ScmError>> {\n const repo = this.provider.repo;\n logger.debug('Getting PR detail', { repo, prNumber });\n\n const prResult = await execGhApi(`repos/${repo}/pulls/${String(prNumber)}`);\n if (!prResult.ok) return prResult;\n\n const filesResult = await execGhApiList<GhApiFileJson>(\n `repos/${repo}/pulls/${String(prNumber)}/files`\n );\n if (!filesResult.ok) return filesResult;\n const files = filesResult.value;\n\n try {\n const pr = JSON.parse(prResult.value) as GhApiPrJson;\n\n return ok({\n number: pr.number,\n title: pr.title,\n body: pr.body ?? '',\n author: pr.user.login,\n base: pr.base.ref,\n head: pr.head.ref,\n url: pr.html_url,\n draft: pr.draft,\n authorAssociation: pr.author_association,\n labels: pr.labels.map((l) => l.name),\n files: files.map(mapFileChange),\n additions: pr.additions,\n deletions: pr.deletions,\n headSha: pr.head.sha,\n });\n } catch {\n return err(new ScmError('Failed to parse PR detail JSON', 'github'));\n }\n }\n\n async createReview(\n prNumber: number,\n body: string,\n decision: ScmReviewDecision\n ): Promise<Result<void, ScmError>> {\n const repo = this.provider.repo;\n const eventMap: Record<ScmReviewDecision, string> = {\n approve: 'APPROVE',\n request_changes: 'REQUEST_CHANGES',\n comment: 'COMMENT',\n };\n\n logger.info('Creating review', { repo, prNumber, decision });\n\n const { execFile } = await import('node:child_process');\n const { promisify } = await import('node:util');\n const exec = promisify(execFile);\n\n try {\n await exec(\n 'gh',\n [\n 'api',\n `repos/${repo}/pulls/${String(prNumber)}/reviews`,\n '--method',\n 'POST',\n '-f',\n `body=${body}`,\n '-f',\n `event=${eventMap[decision]}`,\n ],\n { maxBuffer: 10 * 1024 * 1024, timeout: CLI_SUBPROCESS_TIMEOUTS.ghCommandMs }\n );\n return ok(undefined);\n } catch (error) {\n const execError = error as { message: string };\n return err(new ScmError(`Failed to create review: ${execError.message}`, 'github'));\n }\n }\n\n async getIssueDetail(issueNumber: number): Promise<Result<ScmIssueDetail, ScmError>> {\n const repo = this.provider.repo;\n logger.debug('Getting issue detail', { repo, issueNumber });\n\n const result = await execGhApi(`repos/${repo}/issues/${String(issueNumber)}`);\n if (!result.ok) return result;\n\n try {\n const raw = JSON.parse(result.value) as GhApiIssueJson;\n return ok({\n number: raw.number,\n title: raw.title,\n body: raw.body ?? '',\n labels: raw.labels.map((l) => l.name),\n author: raw.user.login,\n createdAt: raw.created_at,\n authorAssociation: raw.author_association,\n state: raw.state,\n url: raw.html_url,\n });\n } catch {\n return err(new ScmError('Failed to parse issue detail JSON', 'github'));\n }\n }\n\n async listCommentDetails(\n issueNumber: number\n ): Promise<Result<readonly ScmCommentDetail[], ScmError>> {\n const repo = this.provider.repo;\n logger.debug('Listing comment details', { repo, issueNumber });\n\n const result = await execGhApiList<GhApiCommentJson>(\n `repos/${repo}/issues/${String(issueNumber)}/comments`\n );\n if (!result.ok) return result;\n\n try {\n const comments = result.value;\n return ok(\n comments.map((c) => ({\n id: c.id,\n body: c.body,\n author: c.user.login,\n createdAt: c.created_at,\n authorAssociation: c.author_association,\n }))\n );\n } catch {\n return err(new ScmError('Failed to parse comment details JSON', 'github'));\n }\n }\n}\n\n// ============================================================================\n// GitHubUserInfo — implements IScmUserInfo\n// ============================================================================\n\n/**\n * GitHub-specific user info provider. Implements IScmUserInfo trait.\n */\nexport class GitHubUserInfo implements IScmUserInfo {\n async fetchUserMetadata(username: string): Promise<Result<ScmUserMetadata, ScmError>> {\n logger.debug('Fetching user metadata', { username });\n\n const result = await execGhApi(`users/${username}`);\n if (!result.ok) return result;\n\n try {\n const raw = JSON.parse(result.value) as GhApiUserJson;\n return ok({\n login: raw.login,\n name: raw.name,\n company: raw.company,\n followers: raw.followers,\n following: raw.following,\n publicRepos: raw.public_repos,\n createdAt: raw.created_at,\n });\n } catch {\n return err(new ScmError('Failed to parse user metadata JSON', 'github'));\n }\n }\n}\n\n// ============================================================================\n// Factory — compose provider with traits\n// ============================================================================\n\n/**\n * Creates a full-capability GitHub provider with all traits.\n *\n * Returns an object that implements IScmProvider & IScmReviewer & IScmUserInfo.\n * Consumers can narrow the type to only the traits they need.\n *\n * @example\n * ```typescript\n * const provider = createFullGitHubProvider('owner/repo');\n * // Use as ReviewCapableProvider\n * const detail = await provider.getPullRequestDetail(42);\n * // Use as IScmUserInfo\n * const user = await provider.fetchUserMetadata('octocat');\n * ```\n */\nexport function createFullGitHubProvider(\n repo: string\n): GitHubProvider & IScmReviewer & IScmUserInfo {\n const base = new GitHubProvider(repo);\n const reviewer = new GitHubReviewer(base);\n const userInfo = new GitHubUserInfo();\n\n // Compose all trait methods onto the provider\n return Object.assign(base, {\n getPullRequestDetail: reviewer.getPullRequestDetail.bind(reviewer),\n createReview: reviewer.createReview.bind(reviewer),\n getIssueDetail: reviewer.getIssueDetail.bind(reviewer),\n listCommentDetails: reviewer.listCommentDetails.bind(reviewer),\n fetchUserMetadata: userInfo.fetchUserMetadata.bind(userInfo),\n });\n}\n","/**\n * nexus-agents/dogfooding - Issue Triage Types\n *\n * Type definitions for automated GitHub issue triage using\n * the security pipeline (trust classification, corroboration,\n * reputation model).\n *\n * @module dogfooding/issue-triage-types\n * (Source: Issue #828 — Wire remaining security modules)\n */\n\nimport { z } from 'zod';\nimport type { ReputationAssessment } from '../security/reputation-model.js';\n\n// ============================================================================\n// Issue Metadata\n// ============================================================================\n\n/**\n * GitHub issue metadata from the API.\n */\nexport interface IssueMetadata {\n /** Issue number */\n readonly number: number;\n /** Issue title */\n readonly title: string;\n /** Issue body/description */\n readonly body: string;\n /** Author username */\n readonly author: string;\n /** GitHub API author_association (e.g., 'OWNER', 'COLLABORATOR', 'NONE') */\n readonly authorAssociation: string;\n /** Repository owner */\n readonly owner: string;\n /** Repository name */\n readonly repo: string;\n /** Issue URL */\n readonly url: string;\n /** Issue state ('open' | 'closed') */\n readonly state: string;\n /** Issue labels */\n readonly labels: readonly string[];\n /** Creation timestamp (ISO 8601) */\n readonly createdAt: string;\n}\n\n/**\n * GitHub issue comment from the API.\n */\nexport interface IssueComment {\n /** Comment ID */\n readonly id: number;\n /** Comment body */\n readonly body: string;\n /** Author username */\n readonly author: string;\n /** GitHub API author_association */\n readonly authorAssociation: string;\n /** Creation timestamp (ISO 8601) */\n readonly createdAt: string;\n}\n\n// ============================================================================\n// Issue Classification\n// ============================================================================\n\n/**\n * Issue category determined by keyword-based classification.\n */\nexport type IssueCategory =\n 'bug' | 'feature' | 'question' | 'documentation' | 'security' | 'performance';\n\n/**\n * Display names for issue categories.\n */\nexport const CATEGORY_DISPLAY_NAMES: Record<IssueCategory, string> = {\n bug: 'Bug Report',\n feature: 'Feature Request',\n question: 'Question',\n documentation: 'Documentation',\n security: 'Security',\n performance: 'Performance',\n};\n\n/**\n * Emoji for issue categories (GitHub markdown).\n */\nexport const CATEGORY_EMOJI: Record<IssueCategory, string> = {\n bug: ':bug:',\n feature: ':sparkles:',\n question: ':question:',\n documentation: ':books:',\n security: ':lock:',\n performance: ':zap:',\n};\n\n// ============================================================================\n// Triage Configuration\n// ============================================================================\n\n/**\n * Configuration for issue triage.\n */\nexport interface IssueTriageConfig {\n /** Whether to run in dry-run mode (no GitHub mutations). Default: true */\n readonly dryRun: boolean;\n /** GitHub token for API access */\n readonly githubToken?: string | undefined;\n /** Maximum comments to fetch per issue */\n readonly maxComments: number;\n /** Whether to use reputation model for trust assessment */\n readonly enableReputation: boolean;\n}\n\n/**\n * Default issue triage configuration.\n * Read-only by default — proposes actions without executing them.\n */\nexport const DEFAULT_ISSUE_TRIAGE_CONFIG: IssueTriageConfig = {\n dryRun: true,\n maxComments: 50,\n enableReputation: true,\n};\n\n/**\n * Zod schema for issue triage configuration.\n */\nexport const IssueTriageConfigSchema = z.object({\n dryRun: z.boolean().default(true),\n githubToken: z.string().optional(),\n maxComments: z.number().int().min(1).max(100).default(50),\n enableReputation: z.boolean().default(true),\n});\n\n// ============================================================================\n// Proposed Actions\n// ============================================================================\n\n/**\n * A proposed action from the triage pipeline.\n * All actions are validated through the security pipeline before output.\n */\nexport interface ProposedAction {\n /** Action type (matches AgentActionType from security/action-schema) */\n readonly type: string;\n /** Human-readable description of the proposed action */\n readonly description: string;\n /**\n * Whether this action was approved by the policy gate. Also `false` when the\n * firewall REFUSED the action under `NEXUS_FIREWALL_POLICY=enforce` — at the\n * policy stage (#5383) or the corroboration stage (#6309); `details` names\n * the rules and, for the latter, `refusedAtStage: 'corroboration'`.\n */\n readonly policyApproved: boolean;\n /**\n * Whether corroboration requirements were satisfied — the validator's own\n * verdict under every mode; `enforce` additionally refuses on `false`.\n */\n readonly corroborated: boolean;\n /** Details specific to the action type */\n readonly details: Record<string, unknown>;\n}\n\n// ============================================================================\n// Trust Assessment\n// ============================================================================\n\n/**\n * Trust assessment summary for the triage result.\n */\nexport interface TrustAssessment {\n /** Author's trust tier (1-4) */\n readonly trustTier: string;\n /** Author's GitHub role */\n readonly userRole: string;\n /**\n * Whether the author is on the maintainer allowlist — present only when an\n * allowlist was consulted (#4992). Absent means \"no allowlist was consulted\",\n * which is the state on every live path today; it was previously recorded\n * as `false` without being measured.\n */\n readonly isAllowlisted?: boolean;\n /**\n * Whether a durable `AuditLogger` was configured for this process (#4992\n * review). `configured` — the trust event was handed to it; delivery to the\n * hash chain is subject to the logger's own severity filter (trust events\n * are `info`), queue and fail-loud flush, and is not confirmed per call.\n * `none` — no audit logger (audit disabled, or the CLI path), so the event\n * exists only in the firewall's in-memory trail.\n */\n readonly auditSink: 'configured' | 'none';\n /** Reputation score (0-100) if reputation model is enabled */\n readonly reputationScore?: number | undefined;\n /** Coverage of reputation dimensions; `unmeasured` is distinct from zero activity. */\n readonly coverage?: ReputationAssessment['coverage'] | undefined;\n /** Suspicious signals detected */\n readonly suspiciousSignals: readonly string[];\n /** Whether the author is flagged as suspicious */\n readonly isSuspicious: boolean;\n /**\n * Tier the policy gate ACTUALLY enforced (#3122). Equals `trustTier` under\n * `audit`/`off`; equals `reputationReconciledTier` under `enforce`. This is\n * the tier `proposedActions[].policyApproved` was decided against.\n */\n readonly enforcedTrustTier?: string | undefined;\n /**\n * Tier reputation reconciliation computed — what `enforce` mode WOULD gate on\n * (#3122). May exceed `trustTier` (more restrictive) when reputation demotes.\n * Under `audit`/`off` this is reported for telemetry but NOT enforced — read\n * `enforcedTrustTier` for the tier actually in effect.\n */\n readonly reputationReconciledTier?: string | undefined;\n /** Reputation-gating rollout mode applied: `off` | `audit` | `enforce` (#3122). */\n readonly gatingMode?: string | undefined;\n}\n\n// ============================================================================\n// Triage Result\n// ============================================================================\n\n/**\n * Complete triage result for a GitHub issue.\n */\nexport interface IssueTriageResult {\n /** Issue number */\n readonly issueNumber: number;\n /** Repository (owner/repo) */\n readonly repository: string;\n /** Proposed actions (validated through security pipeline) */\n readonly proposedActions: readonly ProposedAction[];\n /** Trust assessment of the issue author */\n readonly trustAssessment: TrustAssessment;\n /** Detected issue category */\n readonly category: IssueCategory;\n /** Category confidence (0-1) */\n readonly categoryConfidence: number;\n /** Total execution time in ms */\n readonly totalDurationMs: number;\n /** Timestamp of triage (ISO 8601) */\n readonly timestamp: string;\n}\n","/**\n * nexus-agents/dogfooding - Issue Triage Helpers\n *\n * Helper functions for issue classification, label extraction, per-action\n * validation and result formatting. Pure except `validateActionsThroughFirewall`,\n * which runs the shared untrusted-input firewall (#5383).\n *\n * @module dogfooding/issue-triage-helpers\n * (Source: Issue #828 — Wire remaining security modules)\n */\n\nimport type { Result } from '../core/index.js';\nimport { ok } from '../core/index.js';\nimport type { AgentAction } from '../security/action-schema.js';\nimport type { GitHubInput } from '../security/firewall/github-adapter.js';\nimport type { FirewallProcessOptions } from '../security/firewall/firewall-types.js';\nimport type { TrustTier } from '../security/trust-types.js';\nimport type { FirewallCorroborationDecision } from './untrusted-input-firewall.js';\nimport {\n evaluateActionThroughFirewall,\n validateActionCorroboration,\n} from './untrusted-input-firewall.js';\nimport type { ScmCommentDetail } from '../scm/types.js';\nimport type {\n IssueCategory,\n IssueComment,\n IssueTriageResult,\n ProposedAction,\n} from './issue-triage-types.js';\nimport { CATEGORY_DISPLAY_NAMES, CATEGORY_EMOJI } from './issue-triage-types.js';\n\n// ============================================================================\n// Issue Classification\n// ============================================================================\n\n/**\n * Keyword sets for each issue category.\n * Lower-cased for case-insensitive matching.\n */\nconst CATEGORY_KEYWORDS: Record<IssueCategory, readonly string[]> = {\n bug: ['bug', 'error', 'crash', 'broken', 'fix', 'fail', 'issue', 'wrong', 'unexpected'],\n feature: ['feature', 'request', 'enhancement', 'proposal', 'add', 'support', 'implement'],\n question: ['question', 'how to', 'help', 'confused', 'explain', 'documentation'],\n documentation: ['docs', 'documentation', 'readme', 'typo', 'example', 'guide'],\n security: ['security', 'vulnerability', 'cve', 'exploit', 'injection', 'xss', 'csrf'],\n performance: ['performance', 'slow', 'memory', 'leak', 'optimize', 'latency', 'timeout'],\n};\n\n/**\n * Classifies an issue by matching keywords in the title and body.\n * Returns the category with the highest keyword match count.\n *\n * @param title - Issue title\n * @param body - Issue body\n * @returns Tuple of [category, confidence]\n */\nexport function categorizeIssue(title: string, body: string): [IssueCategory, number] {\n const text = `${title} ${body}`.toLowerCase();\n const scores: Record<IssueCategory, number> = {\n bug: 0,\n feature: 0,\n question: 0,\n documentation: 0,\n security: 0,\n performance: 0,\n };\n\n let totalMatches = 0;\n\n for (const [category, keywords] of Object.entries(CATEGORY_KEYWORDS)) {\n for (const keyword of keywords) {\n if (text.includes(keyword)) {\n scores[category as IssueCategory]++;\n totalMatches++;\n }\n }\n }\n\n // Find category with highest score\n let bestCategory: IssueCategory = 'bug';\n let bestScore = 0;\n for (const [category, score] of Object.entries(scores)) {\n if (score > bestScore) {\n bestScore = score;\n bestCategory = category as IssueCategory;\n }\n }\n\n // Confidence: ratio of best score to total matches, minimum 0.1\n const confidence = totalMatches > 0 ? Math.min(bestScore / totalMatches, 1) : 0.1;\n\n return [bestCategory, Math.round(confidence * 100) / 100];\n}\n\n// ============================================================================\n// Label Extraction\n// ============================================================================\n\n/**\n * Common label patterns that can be extracted from issue text.\n */\nconst LABEL_HINTS: ReadonlyMap<string, string> = new Map([\n ['bug', 'bug'],\n ['feature request', 'enhancement'],\n ['enhancement', 'enhancement'],\n ['breaking change', 'breaking-change'],\n ['documentation', 'documentation'],\n ['help wanted', 'help wanted'],\n ['good first issue', 'good first issue'],\n ['security', 'security'],\n ['performance', 'performance'],\n ['regression', 'regression'],\n]);\n\n/**\n * Extracts suggested labels from issue title and body text.\n *\n * @param title - Issue title\n * @param body - Issue body\n * @returns Array of suggested label strings (max 5)\n */\nexport function extractLabelsFromBody(title: string, body: string): string[] {\n const text = `${title} ${body}`.toLowerCase();\n const labels: string[] = [];\n\n for (const [pattern, label] of LABEL_HINTS) {\n if (text.includes(pattern) && !labels.includes(label)) {\n labels.push(label);\n }\n }\n\n return labels.slice(0, 5);\n}\n\n/** Maps SCM comment details to the triage representation. */\nexport function mapIssueComments(comments: readonly ScmCommentDetail[]): IssueComment[] {\n return comments.map((comment) => ({\n id: comment.id,\n body: comment.body,\n author: comment.author,\n authorAssociation: comment.authorAssociation,\n createdAt: comment.createdAt,\n }));\n}\n\n/** Creates a human-readable description for a typed action. */\nexport function describeAction(action: AgentAction): string {\n switch (action.type) {\n case 'ClassifyIssue':\n return `Classified as ${action.category} (${String(Math.round(action.confidence * 100))}% confidence)`;\n case 'ProposeLabels':\n return `Suggest labels: ${action.labels.join(', ')}`;\n case 'SummarizeIssue':\n return action.summary.slice(0, 100);\n default:\n return `${action.type} action`;\n }\n}\n\n/**\n * Builds details object for a proposed action.\n *\n * A corroboration refusal (`enforce`, #6309) is recorded where a policy\n * refusal is: its rule joins `policyViolations`, and `refusedAtStage` names\n * the stage so the record cannot be read as a trust-tier block. Under `off`\n * and `audit` the check is recorded, never refused; `corroborationWouldRefuse`\n * is `audit`'s telemetry and is `false` under `off` by construction.\n */\nexport function buildActionDetails(\n action: AgentAction,\n policy: { allowed: boolean; violations: readonly { rule: string; message: string }[] },\n corrob: FirewallCorroborationDecision\n): Record<string, unknown> {\n const policyRules = policy.violations.map((violation) => violation.rule);\n return {\n ...(corrob.refused\n ? {\n policyViolations: [...policyRules, 'INSUFFICIENT_CORROBORATION'],\n missingCorroboration: corrob.missing,\n refusedAtStage: corrob.stage,\n }\n : {\n policyViolations: policyRules,\n missingCorroboration: corrob.missing,\n corroborationWouldRefuse: corrob.wouldRefuse,\n }),\n ...(action.type === 'ClassifyIssue' && { category: action.category }),\n ...(action.type === 'ProposeLabels' && { labels: action.labels }),\n };\n}\n\n/**\n * Validates every action through the firewall's policy gate and its\n * corroboration stage (originally Issue #828; #5383 moved the policy\n * evaluation inside the firewall and #6309 the corroboration check, so this\n * path has ONE composition).\n *\n * Each action is one firewall run with `action` and the repository label set,\n * then one `validateActionCorroboration` call. The policy decision is read\n * from `FirewallResult.policy` and enforced HERE as `policyApproved`, whatever\n * `NEXUS_FIREWALL_POLICY` is — the mode only decides whether the firewall\n * refuses on its own (`enforce`), and such a refusal lands on the record as\n * `policyApproved: false` with its rules, exactly where the direct\n * `evaluatePolicy` verdict used to land. A corroboration refusal lands the\n * same way (#6309 panel, option R): the action stays on the list, refused,\n * with `refusedAtStage: 'corroboration'` and what was missing — never\n * dropped. Under `off` and `audit` corroboration is recorded as\n * `corroborated`, as the direct `validateCorroboration` call recorded it.\n *\n * `gate.enforcedTier` is the classification run's (the reputation gate's under\n * the #3122 rollout mode); a per-action run that enforces a different tier\n * fails the whole call closed, because the citations were stamped with it. A\n * corroboration stage that did not run fails the call the same way.\n */\nexport function validateActionsThroughFirewall(\n input: GitHubInput,\n gate: Pick<FirewallProcessOptions, 'context' | 'reputation'> & {\n readonly enforcedTier: TrustTier;\n },\n actions: readonly AgentAction[],\n existingLabels: ReadonlySet<string> | undefined\n): Result<ProposedAction[], Error> {\n // Spread in only when present, so the firewall sees absence as absence and\n // fails the label-validity check closed (`LABEL_SET_UNAVAILABLE`).\n const labels = existingLabels !== undefined ? { existingLabels } : {};\n const proposed: ProposedAction[] = [];\n for (const action of actions) {\n const decision = evaluateActionThroughFirewall(input, { ...gate, ...labels, action });\n if (!decision.ok) return decision;\n const corroboration = validateActionCorroboration(action);\n if (!corroboration.ok) return corroboration;\n proposed.push({\n type: action.type,\n description: describeAction(action),\n policyApproved: decision.value.allowed && !corroboration.value.refused,\n corroborated: corroboration.value.satisfied,\n details: buildActionDetails(action, decision.value, corroboration.value),\n });\n }\n return ok(proposed);\n}\n\n// ============================================================================\n// Result Formatting\n// ============================================================================\n\n/**\n * Formats a triage result as a GitHub markdown comment.\n *\n * @param result - The complete triage result\n * @returns Formatted markdown string\n */\nexport function formatTriageComment(result: IssueTriageResult): string {\n const emoji = CATEGORY_EMOJI[result.category];\n const categoryName = CATEGORY_DISPLAY_NAMES[result.category];\n const lines: string[] = [];\n\n lines.push(`## ${emoji} Issue Triage: ${categoryName}`);\n lines.push('');\n lines.push(\n `**Category:** ${categoryName} (${String(Math.round(result.categoryConfidence * 100))}% confidence)`\n );\n lines.push(\n `**Trust Tier:** ${result.trustAssessment.trustTier} (${result.trustAssessment.userRole})`\n );\n\n if (result.trustAssessment.reputationScore !== undefined) {\n lines.push(`**Reputation Score:** ${String(result.trustAssessment.reputationScore)}/100`);\n }\n\n if (result.trustAssessment.isSuspicious) {\n lines.push('');\n lines.push(':warning: **Suspicious signals detected:**');\n for (const signal of result.trustAssessment.suspiciousSignals) {\n lines.push(`- ${signal}`);\n }\n }\n\n if (result.proposedActions.length > 0) {\n lines.push('');\n lines.push('### Proposed Actions');\n lines.push('');\n for (const action of result.proposedActions) {\n const status = formatActionStatus(action);\n lines.push(\n `- ${status} **${action.type}**: ${action.description}${formatRefusalReason(action)}`\n );\n }\n }\n\n lines.push('');\n lines.push(`---`);\n lines.push(`_Triage completed in ${String(result.totalDurationMs)}ms_`);\n\n return lines.join('\\n');\n}\n\n/**\n * Formats the policy/corroboration status of an action.\n */\nfunction formatActionStatus(action: ProposedAction): string {\n if (action.policyApproved && action.corroborated) return ':white_check_mark:';\n if (action.policyApproved && !action.corroborated) return ':yellow_circle:';\n return ':no_entry:';\n}\n\n/** The refusal-bearing subset of `ProposedAction.details`, read with guards. */\ninterface ActionRefusalDetails {\n readonly policyViolations: readonly string[];\n readonly missingCorroboration: readonly string[];\n readonly refusedAtStage?: 'corroboration';\n}\n\nfunction isStringArray(value: unknown): value is readonly string[] {\n return Array.isArray(value) && value.every((v) => typeof v === 'string');\n}\n\n/**\n * Reads WHY an action was refused (or left uncorroborated) off its `details`\n * (#6309 review): `details` is untyped on the record, so this is the one\n * place the keys `buildActionDetails` writes are read back. A key that is\n * absent or malformed reads as empty, never as a rule.\n */\nexport function readActionRefusal(action: ProposedAction): ActionRefusalDetails {\n const { policyViolations, missingCorroboration, refusedAtStage } = action.details;\n return {\n policyViolations: isStringArray(policyViolations) ? policyViolations : [],\n missingCorroboration: isStringArray(missingCorroboration) ? missingCorroboration : [],\n ...(refusedAtStage === 'corroboration' ? { refusedAtStage } : {}),\n };\n}\n\n/**\n * The parenthetical after a refused action's line, so a corroboration refusal\n * is distinguishable from a policy refusal where a reader sees it (#6309\n * review). Empty for an action that was not refused.\n */\nfunction formatRefusalReason(action: ProposedAction): string {\n if (action.policyApproved) return '';\n const refusal = readActionRefusal(action);\n const policyRules = refusal.policyViolations.filter((r) => r !== 'INSUFFICIENT_CORROBORATION');\n const parts: string[] = [];\n if (policyRules.length > 0) parts.push(`policy: ${policyRules.join(', ')}`);\n if (refusal.refusedAtStage !== undefined) {\n parts.push(`refused at ${refusal.refusedAtStage}: ${refusal.missingCorroboration.join('; ')}`);\n }\n // A refusal that names nothing is still a refusal; say so rather than print nothing.\n return ` (${parts.length > 0 ? parts.join('; ') : 'refused: no rule recorded'})`;\n}\n","/**\n * nexus-agents/dogfooding - Issue Triage Processor\n *\n * Deterministic GitHub issue triage using the full security pipeline:\n * - Input sanitization (input-sanitizer.ts)\n * - Trust classification (trust-classifier.ts)\n * - Reputation assessment (reputation-model.ts) [NEW — #828]\n * - Typed agent actions (action-schema.ts)\n * - Policy gate validation (policy-gate.ts)\n * - Corroboration validation (corroboration-validator.ts) [NEW — #828]\n *\n * Read-only by default (dryRun: true). Proposes actions but never\n * auto-posts to GitHub without explicit opt-in.\n *\n * @module dogfooding/issue-triage\n * (Source: Issue #828 — Wire remaining security modules)\n */\n\nimport type { Result } from '../core/index.js';\nimport { ok, err, createLogger, getTimeProvider } from '../core/index.js';\nimport { sanitizeInput } from '../security/input-sanitizer.js';\nimport { hasToken } from '../scm/token-resolver.js';\nimport type { ClassifyResult } from '../security/trust-classifier.js';\nimport type { FirewallResult } from '../security/firewall/firewall-pipeline.js';\nimport { firewallInputFor, runUntrustedInputFirewall } from './untrusted-input-firewall.js';\nimport type { TrustTier } from '../security/trust-types.js';\nimport type { FirewallProcessOptions } from '../security/firewall/firewall-types.js';\nimport { assessReputation, ReputationCache } from '../security/reputation-model.js';\nimport type {\n ReputationAssessment,\n GitHubUserMetadata,\n ReputationGateDecision,\n} from '../security/reputation-model.js';\nimport type { AgentAction, SourceCitation } from '../security/action-schema.js';\nimport { parseIssueUrl } from '../scm/url-parsers.js';\nimport { createFullGitHubProvider } from '../scm/github-provider-traits.js';\nimport type { ScmUserMetadata } from '../scm/types.js';\nimport {\n categorizeIssue,\n extractLabelsFromBody,\n mapIssueComments,\n validateActionsThroughFirewall,\n} from './issue-triage-helpers.js';\nimport type {\n IssueMetadata,\n IssueComment,\n IssueTriageConfig,\n IssueTriageResult,\n ProposedAction,\n TrustAssessment,\n} from './issue-triage-types.js';\nimport { DEFAULT_ISSUE_TRIAGE_CONFIG } from './issue-triage-types.js';\n\nconst logger = createLogger({ component: 'IssueTriage' });\n\n/**\n * Applies the two safety actions the untrusted-input rules mandate (#4667).\n *\n * They are mutually exclusive by construction: a hostile tier refuses, a\n * suspicious-but-not-hostile one escalates. Emitting both would ask a human to\n * approve something the system has already declined.\n */\nfunction applySafetyActions(\n actions: readonly AgentAction[],\n gateDecision: ReputationGateDecision,\n reputation: ReputationAssessment | undefined,\n issue: IssueMetadata\n): AgentAction[] {\n const withRefusal = appendRefusalIfHostile(actions, gateDecision, issue);\n return appendApprovalIfBorderline(withRefusal, gateDecision, reputation, issue);\n}\n\n/**\n * Appends a `RequestHumanApproval` for suspicious-but-not-hostile input (#4667).\n *\n * Triage was binary: tier 4 refuses, everything else proceeds. That left no way\n * to express the common real case — reputation noticed something (a new\n * account, rapid comments, a weak signal) without it amounting to hostility.\n * Those proposals are not safe to auto-apply and not fair to refuse, so they\n * escalate.\n *\n * Deliberately mutually exclusive with the refusal: a hostile tier already\n * emits `RefuseAction`, and stacking \"refused\" with \"please approve\" would ask\n * a human to approve something the system just declined.\n */\nfunction appendApprovalIfBorderline(\n actions: readonly AgentAction[],\n gateDecision: ReputationGateDecision,\n reputation: ReputationAssessment | undefined,\n issue: IssueMetadata\n): AgentAction[] {\n if (gateDecision.enforcedTier === '4') return [...actions];\n // Tier 1 is the allowlist escape hatch — asking a maintainer to approve a\n // maintainer's own issue is noise, and it would undo the \"allowlist wins\"\n // guarantee that tier exists to provide.\n if (gateDecision.enforcedTier === '1') return [...actions];\n if (reputation?.isSuspicious !== true) return [...actions];\n\n // `no_prior_contributions` counts the author's comments ON THIS ISSUE\n // (`countAuthorComments(author, comments)`), so a freshly filed issue always\n // trips it — it is true for essentially every new issue and therefore carries\n // no information. Escalating on it alone would escalate on everything, which\n // is how an approval gate becomes noise and then gets ignored. Require at\n // least one signal that actually distinguishes this author.\n const distinguishing = reputation.suspiciousSignals.filter(\n (sig) => sig !== 'no_prior_contributions'\n );\n if (distinguishing.length === 0) return [...actions];\n\n const signals = distinguishing.join(', ');\n return [\n ...actions,\n {\n type: 'RequestHumanApproval',\n reason:\n `Issue #${String(issue.number)} carries suspicious reputation signals but did not ` +\n `reach the hostile tier. Proposed actions need a human decision.`,\n context:\n `Author ${issue.author} at enforced tier ${gateDecision.enforcedTier} ` +\n `(${gateDecision.mode} mode). Signals: ${signals.length > 0 ? signals : '(none recorded)'}.`,\n },\n ];\n}\n\n/**\n * Appends an explicit `RefuseAction` when the enforced tier is hostile (#4667).\n *\n * The generated actions are kept rather than replaced: they are the audit trail\n * of what was declined, and every one of them is already blocked by the policy\n * gate at tier 4. What was missing is a positive statement that the input was\n * refused and where to escalate it.\n */\nfunction appendRefusalIfHostile(\n actions: readonly AgentAction[],\n gateDecision: ReputationGateDecision,\n issue: IssueMetadata\n): AgentAction[] {\n if (gateDecision.enforcedTier !== '4') return [...actions];\n return [\n ...actions,\n {\n type: 'RefuseAction',\n reason:\n `Issue #${String(issue.number)} was classified at hostile trust tier 4 ` +\n `(${gateDecision.mode} mode). Automated triage actions are withheld pending human review.`,\n escalateTo: 'security',\n },\n ];\n}\n\n/**\n * GitHub issue triage processor.\n *\n * Wires all 8 security modules into a read-only triage pipeline:\n * 1. Fetch issue + comments from GitHub API\n * 2. Sanitize untrusted content (input-sanitizer)\n * 3. Classify author trust (trust-classifier)\n * 4. Assess author reputation (reputation-model) [#828]\n * 5. Generate typed actions (action-schema)\n * 6. Validate through policy gate (policy-gate)\n * 7. Validate corroboration (corroboration-validator) [#828]\n * 8. Return proposed actions\n */\n/** Warn when a demotion was computed but the gating mode did not enforce it (#3122). */\nfunction logSuppressedDemotion(\n issueNumber: number,\n author: string,\n trustResult: ClassifyResult,\n gateDecision: ReputationGateDecision\n): void {\n if (!gateDecision.demotionSuppressed) return;\n logger.warn('Reputation demotion suppressed by gating mode (would block under enforce)', {\n issueNumber,\n author,\n mode: gateDecision.mode,\n classifierTier: trustResult.trustTier,\n reconciledTier: gateDecision.reconciledTier,\n });\n}\n\nexport class IssueTriage {\n private readonly config: IssueTriageConfig;\n private readonly reputationCache: ReputationCache;\n\n constructor(config?: Partial<IssueTriageConfig>) {\n this.config = { ...DEFAULT_ISSUE_TRIAGE_CONFIG, ...config };\n this.reputationCache = new ReputationCache();\n }\n\n /**\n * Triages a GitHub issue through the full security pipeline.\n */\n async triageIssue(issueUrl: string): Promise<Result<IssueTriageResult, Error>> {\n const startTime = getTimeProvider().now();\n\n logger.info('Starting issue triage', { issueUrl });\n\n const parseResult = parseIssueUrl(issueUrl);\n if (!parseResult.ok) return parseResult;\n\n const { owner, repo, issueNumber } = parseResult.value;\n\n const fetchResult = await this.fetchIssueData(owner, repo, issueNumber);\n if (!fetchResult.ok) return fetchResult;\n\n const { issue: issueResult, existingLabels } = fetchResult.value;\n\n // Sanitize untrusted content (Issue #828 — input-sanitizer wiring)\n const safeTitle = this.sanitizeContent(issueResult.title, issueResult.author);\n const safeBody = this.sanitizeContent(issueResult.body, issueResult.author);\n\n // Reputation is measured here, with data the firewall cannot see (account\n // age, comment history), and handed to the firewall per call.\n const reputation = this.assessAuthorReputation(fetchResult.value);\n\n // #4992: classify through the shared HostileInputFirewall so the trust\n // decision reaches the security audit trail. Refuses only under\n // NEXUS_FIREWALL_POLICY=enforce; `validateActions` below re-enters the\n // firewall per action for the policy decision (#5383). The firewall runs\n // the ONE reputation gate (#3122: off/audit/enforce; audit reports a\n // would-be demotion without enforcing it; the allowlist Tier 1 remains the\n // escape hatch), so its Rule-of-Two signal and the per-action policy gate\n // act on the same enforced tier.\n const firewall = this.classifyAuthor(issueResult, reputation);\n if (!firewall.ok) return firewall;\n const trustResult = firewall.value.trust;\n const gateDecision = firewall.value.reputationGate;\n if (gateDecision === undefined) {\n // Structurally unreachable — the option is always passed — but a missing\n // gate must not be papered over with the classifier tier.\n return err(new Error('Untrusted-input firewall returned no reputation gate decision'));\n }\n logSuppressedDemotion(issueNumber, issueResult.author, trustResult, gateDecision);\n\n // Generate and validate actions, at the tier the gate ENFORCED (#5719)\n const enforced = { ...trustResult, trustTier: gateDecision.enforcedTier };\n const actions = this.generateActions(safeTitle, safeBody, issueResult, enforced);\n // #4667: a hostile enforced tier must produce an explicit refusal. Before\n // this, tier 4 merely meant every generated action failed the policy gate —\n // the caller saw fewer approved actions and no statement that anything was\n // refused, so the fail-closed escalation the rules mandate had no producer.\n // RefuseAction is tier-4 \"always allowed\" (trust-classifier.ts:170), so it\n // survives the gate that blocks the rest.\n const withEscalation = applySafetyActions(actions, gateDecision, reputation, issueResult);\n // #5383: each action is its own firewall run; the policy decision is the\n // firewall's, enforced there as `policyApproved` under every mode.\n const validatedActions = validateActionsThroughFirewall(\n firewallInputFor('issue', issueResult),\n { ...this.firewallOptions(reputation), enforcedTier: gateDecision.enforcedTier },\n withEscalation,\n existingLabels\n );\n if (!validatedActions.ok) return validatedActions;\n\n const result = this.buildResult({\n issue: issueResult,\n actions: validatedActions.value,\n trustResult,\n isAllowlisted: firewall.value.isAllowlisted,\n auditSink: firewall.value.auditSink,\n reputation,\n gateDecision,\n safeContent: { title: safeTitle, body: safeBody },\n startTime,\n });\n\n logger.info('Issue triage completed', {\n issueNumber,\n category: result.category,\n actionCount: result.proposedActions.length,\n durationMs: result.totalDurationMs,\n });\n\n return ok(result);\n }\n\n /**\n * Sanitizes untrusted issue content before processing.\n * (Source: Issue #828 — input-sanitizer wiring)\n */\n private sanitizeContent(text: string, author: string): string {\n if (text.length === 0) return text;\n const result = sanitizeInput(text, 'unknown', author);\n if (result.wasModified) {\n logger.warn('Issue content sanitized', {\n author,\n strippedCount: result.strippedElements.length,\n injectionFlags: result.injectionFlags,\n });\n }\n return result.content;\n }\n\n /**\n * Classifies the issue author's trust tier through the shared firewall\n * (#4992; originally Issue #828 — trust-classifier wiring).\n *\n * The access posture is passed per call so the firewall's Rule-of-Two check\n * sees the same facts the per-action runs enforce on. No maintainer\n * allowlist is passed: there is no source for one today (no config field, no\n * env var), so none is consulted and `isAllowlisted` stays absent on the\n * result rather than being recorded as `false`.\n */\n private classifyAuthor(\n issue: IssueMetadata,\n reputation: ReputationAssessment | undefined\n ): Result<FirewallResult, Error> {\n return runUntrustedInputFirewall(\n firewallInputFor('issue', issue),\n this.firewallOptions(reputation)\n );\n }\n\n /** The per-call facts every firewall run of this triage shares (#4992, #5383). */\n private firewallOptions(\n reputation: ReputationAssessment | undefined\n ): Pick<FirewallProcessOptions, 'context' | 'reputation'> {\n return { context: this.accessContext(), reputation: { assessment: reputation } };\n }\n\n /**\n * The access posture this triage runs under — the two Rule-of-Two conjuncts\n * that are about the agent rather than the input. Passed to every firewall\n * run (#4992, #5383) so the classification and the per-action policy checks\n * cannot disagree on it.\n */\n private accessContext(): { hasWriteAccess: boolean; hasSecretAccess: boolean } {\n return {\n hasWriteAccess: !this.config.dryRun,\n // #4681: read the token from where it ACTUALLY comes from. The previous\n // form (`this.config.githubToken !== undefined`) was written to make this\n // conjunct \"real\", but no production caller ever sets `githubToken` — the\n // SCM provider resolves the live credential from GITHUB_TOKEN/GH_TOKEN.\n // So the conjunct was permanently false and Rule of Two could never trip,\n // which is precisely the constant it was introduced to remove.\n // `hasToken()` is the canonical resolver-backed check.\n hasSecretAccess: this.config.githubToken !== undefined || hasToken('github'),\n };\n }\n\n /**\n * Assesses the issue author's reputation using the reputation model.\n * This is one of the two NEW security module wirings completing #828.\n * (Source: Issue #828 — reputation-model wiring)\n */\n private assessAuthorReputation(data: {\n issue: IssueMetadata;\n comments: readonly IssueComment[];\n commentsAvailable: boolean;\n accountAgeDays?: number;\n }): ReputationAssessment | undefined {\n if (!this.config.enableReputation) return undefined;\n const { issue, comments, commentsAvailable, accountAgeDays } = data;\n\n // #4681: scan BOTH the title and the body. Scanning only the body left a\n // real bypass: an injection payload is plain text, so content-sanitization\n // does not strip it from the title, and its flags were discarded here — the\n // identical payload was refused at Tier 4 in the body but raised no signal\n // at all in the title, then reached the emitted SummarizeIssue verbatim.\n const bodyScan = sanitizeInput(issue.body, 'unknown', issue.author);\n const titleScan = sanitizeInput(issue.title, 'unknown', issue.author);\n const injectionFlags = [...new Set([...titleScan.injectionFlags, ...bodyScan.injectionFlags])];\n\n // #3121: accountAgeDays is the author's REAL account age (fetched in\n // fetchIssueData) or undefined when the lookup failed. When undefined it is\n // OMITTED so the engine skips the new_account signal (#3106) — never\n // fabricated. priorContributions/recentCommentCount use real comment data.\n const metadata: GitHubUserMetadata = {\n username: issue.author,\n ...(accountAgeDays !== undefined ? { accountAgeDays } : {}),\n ...(commentsAvailable\n ? {\n priorContributions: countAuthorComments(issue.author, comments),\n recentCommentCount: countRecentComments(issue.author, comments),\n recentCommentWindowMinutes: 10,\n }\n : {}),\n authorAssociation: issue.authorAssociation,\n injectionFlags,\n };\n\n return assessReputation(metadata, commentsAvailable ? this.reputationCache : undefined);\n }\n\n /**\n * Generates typed agent actions based on issue analysis.\n */\n private generateActions(\n safeTitle: string,\n safeBody: string,\n issue: IssueMetadata,\n /**\n * The classify result with `trustTier` RECONCILED to the tier the policy\n * gate actually enforced (#5719). Stamping a citation with the\n * pre-reputation tier makes the record disagree with what anyone enforced,\n * and `checkSourceTrustTiers` inspects only `issueComment`, so nothing\n * catches it. `userRole` is still the classifier's — that is what it names.\n */\n trustResult: ClassifyResult\n ): AgentAction[] {\n const actions: AgentAction[] = [];\n const source = this.createIssueSource(issue, trustResult.trustTier);\n\n // Always generate ClassifyIssue action\n const [category, confidence] = categorizeIssue(safeTitle, safeBody);\n actions.push({\n type: 'ClassifyIssue',\n category,\n confidence,\n sources: [source],\n });\n\n // Generate ProposeLabels if we found label hints\n const labels = extractLabelsFromBody(safeTitle, safeBody);\n if (labels.length > 0) {\n actions.push({\n type: 'ProposeLabels',\n labels,\n reason: `Keyword-based label extraction from issue #${String(issue.number)}`,\n sources: [source],\n });\n }\n\n // Generate SummarizeIssue for semi-trusted+ authors\n if (trustResult.trustTier === '1' || trustResult.trustTier === '2') {\n const summary = `Issue #${String(issue.number)} \"${safeTitle}\" by ${issue.author} (${trustResult.userRole})`;\n actions.push({\n type: 'SummarizeIssue',\n summary: summary.length >= 10 ? summary : `${summary} — awaiting further analysis`,\n sources: [source],\n });\n }\n\n return actions;\n }\n\n /**\n * Builds the final triage result.\n */\n private buildResult(opts: {\n issue: IssueMetadata;\n actions: readonly ProposedAction[];\n trustResult: ClassifyResult;\n /** Present only when the firewall consulted an allowlist (#4992). */\n isAllowlisted: boolean | undefined;\n auditSink: FirewallResult['auditSink'];\n reputation: ReputationAssessment | undefined;\n gateDecision: ReputationGateDecision;\n safeContent: { title: string; body: string };\n startTime: number;\n }): IssueTriageResult {\n const {\n issue,\n actions,\n trustResult,\n isAllowlisted,\n auditSink,\n reputation,\n gateDecision,\n safeContent,\n startTime,\n } = opts;\n const [category, confidence] = categorizeIssue(safeContent.title, safeContent.body);\n\n // Tier 1 actors (owner/maintainer) cannot be suspicious — reconcile\n // the trust-classifier result with the reputation-model result.\n const isTier1 = trustResult.trustTier === '1';\n\n const trustAssessment: TrustAssessment = {\n trustTier: trustResult.trustTier,\n userRole: trustResult.userRole,\n // Measured or absent (#4992): never the classifier's default `false`.\n ...(isAllowlisted !== undefined ? { isAllowlisted } : {}),\n auditSink,\n reputationScore: reputation?.reputationScore,\n coverage: reputation?.coverage,\n suspiciousSignals: isTier1 ? [] : (reputation?.suspiciousSignals ?? []),\n isSuspicious: isTier1 ? false : (reputation?.isSuspicious ?? false),\n // #3122: surface both the enforced tier (what the gate used) and the\n // reconciled tier (what reputation computed) so telemetry can't mistake\n // a would-be demotion for an enforced one.\n enforcedTrustTier: gateDecision.enforcedTier,\n reputationReconciledTier: gateDecision.reconciledTier,\n gatingMode: gateDecision.mode,\n };\n\n return {\n issueNumber: issue.number,\n repository: `${issue.owner}/${issue.repo}`,\n proposedActions: actions,\n trustAssessment,\n category,\n categoryConfidence: confidence,\n totalDurationMs: getTimeProvider().now() - startTime,\n timestamp: getTimeProvider().nowIso(),\n };\n }\n\n /**\n * Creates a repo file source citation for the triage.\n */\n private createIssueSource(issue: IssueMetadata, trustTier: TrustTier): SourceCitation {\n return {\n type: 'issueBody',\n issueNumber: issue.number,\n author: issue.author,\n authorTrustTier: trustTier,\n };\n }\n\n /**\n * Fetches issue data from the SCM provider and maps to dogfooding types.\n */\n private async fetchIssueData(\n owner: string,\n repo: string,\n issueNumber: number\n ): Promise<\n Result<\n {\n issue: IssueMetadata;\n comments: IssueComment[];\n commentsAvailable: boolean;\n accountAgeDays?: number;\n existingLabels?: ReadonlySet<string>;\n },\n Error\n >\n > {\n const provider = createFullGitHubProvider(`${owner}/${repo}`);\n\n const detailResult = await provider.getIssueDetail(issueNumber);\n if (!detailResult.ok) return err(detailResult.error);\n\n const detail = detailResult.value;\n const issue: IssueMetadata = { ...detail, owner, repo };\n\n const commentsResult = await provider.listCommentDetails(issueNumber);\n if (!commentsResult.ok) {\n logger.warn('Failed to fetch issue comments; activity reputation is unmeasured', {\n issueNumber,\n error: commentsResult.error.message,\n });\n }\n const comments = commentsResult.ok ? mapIssueComments(commentsResult.value) : [];\n const commentsAvailable = commentsResult.ok;\n\n const labelsResult = await provider.listRepositoryLabels();\n if (!labelsResult.ok) {\n logger.warn('Failed to fetch repository labels; label validity is unmeasured', {\n issueNumber,\n error: labelsResult.error.message,\n });\n }\n\n // #3121: fetch the author's REAL account age (their account creation date,\n // not the issue date). Best-effort — on failure or an unparseable date we\n // omit it, so the reputation engine SKIPS the new_account signal (#3106)\n // rather than fabricating a value. Reputation must not block on this.\n const accountAgeDays = await this.fetchAccountAgeDays(provider, detail.author);\n\n return ok({\n issue,\n comments,\n commentsAvailable,\n ...(accountAgeDays !== undefined ? { accountAgeDays } : {}),\n ...(labelsResult.ok ? { existingLabels: new Set(labelsResult.value) } : {}),\n });\n }\n\n /**\n * Best-effort lookup of a GitHub user's account age in days. Returns\n * `undefined` if the user-metadata fetch fails or the creation date can't be\n * parsed (#3121) — callers must treat absence as \"unknown\", not \"benign\".\n */\n private async fetchAccountAgeDays(\n provider: { fetchUserMetadata: (u: string) => Promise<Result<ScmUserMetadata, Error>> },\n username: string\n ): Promise<number | undefined> {\n try {\n const result = await provider.fetchUserMetadata(username);\n if (!result.ok) return undefined;\n const createdMs = Date.parse(result.value.createdAt);\n if (!Number.isFinite(createdMs)) return undefined;\n return Math.floor((getTimeProvider().now() - createdMs) / 86_400_000);\n } catch {\n // Truly best-effort: even an unexpected rejection (token resolution,\n // transport) must not break triage — fall back to \"unknown\" age.\n return undefined;\n }\n }\n}\n\n/** Counts how many comments the author has made on the issue. */\nfunction countAuthorComments(author: string, comments: readonly IssueComment[]): number {\n return comments.filter((comment) => comment.author === author).length;\n}\n\n/** Counts recent comments from the author (within 10 minutes). */\nfunction countRecentComments(author: string, comments: readonly IssueComment[]): number {\n const tenMinutesAgo = Date.now() - 10 * 60 * 1000;\n return comments.filter(\n (comment) => comment.author === author && new Date(comment.createdAt).getTime() > tenMinutesAgo\n ).length;\n}\n\n/**\n * Creates an IssueTriage instance.\n */\nexport function createIssueTriage(config?: Partial<IssueTriageConfig>): IssueTriage {\n return new IssueTriage(config);\n}\n"],"mappings":"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","names":["logger","z","z","z","z","z","z","logger","logger","z","z","logger","logger","logger","logger","z","z","logger"]}
|