@miller-tech/uap 2.11.1 → 2.16.2
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/config/capacity-policy.json +15 -3
- package/config/model-profiles/qwen38.json +42 -34
- package/dist/.tsbuildinfo +1 -1
- package/dist/bin/cli.js +39 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/capacity/policy.d.ts +15 -0
- package/dist/capacity/policy.d.ts.map +1 -1
- package/dist/capacity/policy.js +23 -0
- package/dist/capacity/policy.js.map +1 -1
- package/dist/capacity/probe.d.ts.map +1 -1
- package/dist/capacity/probe.js +6 -1
- package/dist/capacity/probe.js.map +1 -1
- package/dist/cli/deliver.d.ts.map +1 -1
- package/dist/cli/deliver.js +148 -2
- package/dist/cli/deliver.js.map +1 -1
- package/dist/cli/inference.d.ts +13 -0
- package/dist/cli/inference.d.ts.map +1 -0
- package/dist/cli/inference.js +132 -0
- package/dist/cli/inference.js.map +1 -0
- package/dist/cli/loops.d.ts +39 -0
- package/dist/cli/loops.d.ts.map +1 -0
- package/dist/cli/loops.js +154 -0
- package/dist/cli/loops.js.map +1 -0
- package/dist/cli/wizard-config.d.ts.map +1 -1
- package/dist/cli/wizard-config.js +5 -1
- package/dist/cli/wizard-config.js.map +1 -1
- package/dist/cli/worktree.d.ts.map +1 -1
- package/dist/cli/worktree.js +8 -4
- package/dist/cli/worktree.js.map +1 -1
- package/dist/delivery/adversarial-attack.d.ts +99 -0
- package/dist/delivery/adversarial-attack.d.ts.map +1 -0
- package/dist/delivery/adversarial-attack.js +326 -0
- package/dist/delivery/adversarial-attack.js.map +1 -0
- package/dist/delivery/adversarial-gate.d.ts +120 -0
- package/dist/delivery/adversarial-gate.d.ts.map +1 -0
- package/dist/delivery/adversarial-gate.js +259 -0
- package/dist/delivery/adversarial-gate.js.map +1 -0
- package/dist/delivery/adversarial-sanction.d.ts +52 -0
- package/dist/delivery/adversarial-sanction.d.ts.map +1 -0
- package/dist/delivery/adversarial-sanction.js +134 -0
- package/dist/delivery/adversarial-sanction.js.map +1 -0
- package/dist/delivery/agentic-executor.d.ts +69 -22
- package/dist/delivery/agentic-executor.d.ts.map +1 -1
- package/dist/delivery/agentic-executor.js +152 -8
- package/dist/delivery/agentic-executor.js.map +1 -1
- package/dist/delivery/applier.d.ts +8 -0
- package/dist/delivery/applier.d.ts.map +1 -1
- package/dist/delivery/applier.js +3 -1
- package/dist/delivery/applier.js.map +1 -1
- package/dist/delivery/convergence-loop.d.ts +15 -0
- package/dist/delivery/convergence-loop.d.ts.map +1 -1
- package/dist/delivery/convergence-loop.js.map +1 -1
- package/dist/delivery/criteria-lint.d.ts +74 -0
- package/dist/delivery/criteria-lint.d.ts.map +1 -0
- package/dist/delivery/criteria-lint.js +134 -0
- package/dist/delivery/criteria-lint.js.map +1 -0
- package/dist/delivery/deliver-toggle.d.ts +21 -0
- package/dist/delivery/deliver-toggle.d.ts.map +1 -0
- package/dist/delivery/deliver-toggle.js +40 -0
- package/dist/delivery/deliver-toggle.js.map +1 -0
- package/dist/delivery/delivery-evidence.d.ts +109 -0
- package/dist/delivery/delivery-evidence.d.ts.map +1 -0
- package/dist/delivery/delivery-evidence.js +139 -0
- package/dist/delivery/delivery-evidence.js.map +1 -0
- package/dist/delivery/epic-mission.d.ts +5 -1
- package/dist/delivery/epic-mission.d.ts.map +1 -1
- package/dist/delivery/epic-mission.js +34 -6
- package/dist/delivery/epic-mission.js.map +1 -1
- package/dist/delivery/execution-gate.d.ts.map +1 -1
- package/dist/delivery/execution-gate.js +90 -7
- package/dist/delivery/execution-gate.js.map +1 -1
- package/dist/delivery/index.d.ts +9 -1
- package/dist/delivery/index.d.ts.map +1 -1
- package/dist/delivery/index.js +9 -1
- package/dist/delivery/index.js.map +1 -1
- package/dist/delivery/journey-depth.d.ts +61 -0
- package/dist/delivery/journey-depth.d.ts.map +1 -0
- package/dist/delivery/journey-depth.js +91 -0
- package/dist/delivery/journey-depth.js.map +1 -0
- package/dist/delivery/master-pipeline.d.ts +50 -0
- package/dist/delivery/master-pipeline.d.ts.map +1 -0
- package/dist/delivery/master-pipeline.js +52 -0
- package/dist/delivery/master-pipeline.js.map +1 -0
- package/dist/delivery/mission-acceptance.d.ts.map +1 -1
- package/dist/delivery/mission-acceptance.js +54 -2
- package/dist/delivery/mission-acceptance.js.map +1 -1
- package/dist/delivery/orchestrated-mission.d.ts +4 -1
- package/dist/delivery/orchestrated-mission.d.ts.map +1 -1
- package/dist/delivery/orchestrated-mission.js +18 -9
- package/dist/delivery/orchestrated-mission.js.map +1 -1
- package/dist/delivery/plan-check.d.ts +1 -0
- package/dist/delivery/plan-check.d.ts.map +1 -1
- package/dist/delivery/plan-check.js +48 -0
- package/dist/delivery/plan-check.js.map +1 -1
- package/dist/delivery/task-orchestrator.d.ts +16 -9
- package/dist/delivery/task-orchestrator.d.ts.map +1 -1
- package/dist/delivery/task-orchestrator.js +4 -2
- package/dist/delivery/task-orchestrator.js.map +1 -1
- package/dist/delivery/task-workspace.d.ts +35 -5
- package/dist/delivery/task-workspace.d.ts.map +1 -1
- package/dist/delivery/task-workspace.js +53 -7
- package/dist/delivery/task-workspace.js.map +1 -1
- package/dist/delivery/test-oracle-additive.d.ts +26 -6
- package/dist/delivery/test-oracle-additive.d.ts.map +1 -1
- package/dist/delivery/test-oracle-additive.js +40 -15
- package/dist/delivery/test-oracle-additive.js.map +1 -1
- package/dist/delivery/user-validation.d.ts +14 -0
- package/dist/delivery/user-validation.d.ts.map +1 -1
- package/dist/delivery/user-validation.js +103 -9
- package/dist/delivery/user-validation.js.map +1 -1
- package/dist/delivery/verifier-ladder.d.ts.map +1 -1
- package/dist/delivery/verifier-ladder.js +24 -6
- package/dist/delivery/verifier-ladder.js.map +1 -1
- package/dist/inference/analysis.d.ts +138 -0
- package/dist/inference/analysis.d.ts.map +1 -0
- package/dist/inference/analysis.js +243 -0
- package/dist/inference/analysis.js.map +1 -0
- package/dist/inference/probe.d.ts +85 -0
- package/dist/inference/probe.d.ts.map +1 -0
- package/dist/inference/probe.js +403 -0
- package/dist/inference/probe.js.map +1 -0
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js +45 -18
- package/dist/models/types.js.map +1 -1
- package/dist/self-tuning/profiles/qwen38.d.ts +17 -8
- package/dist/self-tuning/profiles/qwen38.d.ts.map +1 -1
- package/dist/self-tuning/profiles/qwen38.js +21 -11
- package/dist/self-tuning/profiles/qwen38.js.map +1 -1
- package/dist/utils/model-slots.d.ts +11 -5
- package/dist/utils/model-slots.d.ts.map +1 -1
- package/dist/utils/model-slots.js +11 -5
- package/dist/utils/model-slots.js.map +1 -1
- package/docs/INDEX.md +1 -0
- package/docs/guides/CAPACITY_POLICY.md +24 -0
- package/docs/guides/INFERENCE_HEALTH.md +184 -0
- package/docs/guides/PROXY.md +1 -0
- package/docs/guides/QWEN38_EXL3.md +268 -0
- package/docs/plans/hlg-master-architecture-uplift-2026-09-24.md +67 -0
- package/docs/reference/CONFIGURATION.md +10 -1
- package/docs/reference/CONFIGURATION_REFERENCE.md +14 -0
- package/package.json +2 -2
- package/scripts/lib/llama-upstream.sh +7 -1
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/src/policies/enforcers/__pycache__/expert_review_required.cpython-312.pyc +0 -0
- package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-312.pyc +0 -0
- package/src/policies/enforcers/expert_review_required.py +1 -4
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
- package/tools/agents/scripts/anthropic_proxy.py +374 -16
- package/tools/agents/scripts/confidence_escalation.py +4 -2
- package/tools/agents/scripts/project_telemetry.py +1 -0
- package/tools/agents/scripts/tool_risk.py +1 -0
- package/tools/agents/scripts/tool_risk_calibrate.py +1 -0
- package/tools/agents/scripts/toolcall_path_normalizer.py +1 -0
- package/tools/agents/tests/test_anthropic_proxy_streaming.py +52 -1
- package/tools/agents/tests/test_confidence_escalation.py +3 -2
- package/tools/agents/tests/test_count_tokens_scale_per_session.py +126 -0
- package/tools/agents/tests/test_expert_review_pr_scope.py +10 -11
- package/tools/agents/tests/test_lockstep_escalation.py +324 -0
- package/tools/agents/tests/test_thinking_template_kwargs.py +10 -4
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adversarial Red-Team Gate — HLG master architecture, stage 5
|
|
3
|
+
* (docs/plans/hlg-master-architecture-uplift-2026-09-24.md).
|
|
4
|
+
*
|
|
5
|
+
* When a deliver run has converged (all gates green) and BEFORE the verdict
|
|
6
|
+
* is accepted, a skeptical verifier attacks the patch: it writes edge-case
|
|
7
|
+
* tests designed to BREAK the change. If any fail, the run routes back into
|
|
8
|
+
* the convergence loop with that failure as ordinary gate evidence; only a
|
|
9
|
+
* patch that survives proceeds to acceptance (and gate evidence).
|
|
10
|
+
*
|
|
11
|
+
* This module is the STAGE DRIVER: settings resolution, the bounded round
|
|
12
|
+
* loop, breach → re-convergence orchestration, and the repair/rollback
|
|
13
|
+
* rails. The single-round machinery (attack authoring, sanctioning, suite
|
|
14
|
+
* execution, verdicts) lives in adversarial-attack.ts — the split keeps
|
|
15
|
+
* both files under the 500-LOC quality-gate threshold, along the seam the
|
|
16
|
+
* architecture review suggested. This module RE-EXPORTS the attack module's
|
|
17
|
+
* public surface so existing imports from './adversarial-gate.js' keep
|
|
18
|
+
* working.
|
|
19
|
+
*
|
|
20
|
+
* - BOUNDED: at most `maxRounds` attacks per run (default 2). A breach
|
|
21
|
+
* consumes a round and re-enters the convergence loop; the breaching
|
|
22
|
+
* tests REMAIN in the tree, so the repaired state has already survived
|
|
23
|
+
* that attack — the next round, if budget remains, attacks with FRESH
|
|
24
|
+
* tests rather than re-running the old ones forever.
|
|
25
|
+
*
|
|
26
|
+
* ACCEPTED RESIDUAL (C-stage review, 2026-09-24): authored tests execute
|
|
27
|
+
* with HOST FILESYSTEM privileges — sanitized-env strips environment
|
|
28
|
+
* variables but does NOT stop file-based credential reads (~/.aws, ~/.ssh,
|
|
29
|
+
* /etc) from inside a running test; and the repo content quoted into the
|
|
30
|
+
* attack prompt is an INDIRECT PROMPT-INJECTION channel into the authoring
|
|
31
|
+
* model. The additive oracle channel plus lexical+symlink path containment
|
|
32
|
+
* bound what an attack may WRITE and never weaken; what it can READ at
|
|
33
|
+
* runtime is everything the host user can read. This stage therefore runs
|
|
34
|
+
* only on the operator's own deliver run, never on untrusted input.
|
|
35
|
+
*/
|
|
36
|
+
import type { DeliveryResult, LoopExecutor } from './convergence-loop.js';
|
|
37
|
+
import type { GateRung } from './verifier-ladder.js';
|
|
38
|
+
import { type AdversarialRoundResult, type AdversarialStatus, type SuiteRunner } from './adversarial-attack.js';
|
|
39
|
+
export { attackSurface, breachReconvergencePrompt, buildAttackPrompt, pickTestRung, runAdversarialRound, type AdversarialAttackFile, type AdversarialRoundOptions, type AdversarialRoundResult, type AdversarialStatus, type SuiteRun, type SuiteRunner, } from './adversarial-attack.js';
|
|
40
|
+
export { sanctionAttackBlocks, type SanctionedWrite } from './adversarial-sanction.js';
|
|
41
|
+
/** Default attacks per converged run; each breach re-enters the loop once. */
|
|
42
|
+
export declare const DEFAULT_ADVERSARIAL_ROUNDS = 2;
|
|
43
|
+
/** Hard ceiling — the stage must never become the loop it exists to bound. */
|
|
44
|
+
export declare const MAX_ADVERSARIAL_ROUNDS = 4;
|
|
45
|
+
/** Resolved on/off + round budget for the stage. */
|
|
46
|
+
export interface AdversarialGateSettings {
|
|
47
|
+
enabled: boolean;
|
|
48
|
+
maxRounds: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolve the adversarial gate's effective settings.
|
|
52
|
+
*
|
|
53
|
+
* Precedence mirrors `resolveParallelTasks` (task-workspace.ts): the
|
|
54
|
+
* `UAP_DELIVER_ADVERSARIAL_GATE` env var > `.uap.json` `deliver.adversarialGate`
|
|
55
|
+
* > the default. The stage is DEFAULT ON; `0`/`off`/`false` at either layer
|
|
56
|
+
* disables it. A positive integer at either layer retunes the round budget
|
|
57
|
+
* (clamped to [1, MAX_ADVERSARIAL_ROUNDS]); any other truthy value keeps the
|
|
58
|
+
* default budget — a typo must never silently disable a safety gate, and the
|
|
59
|
+
* documented off switch is unambiguous.
|
|
60
|
+
*/
|
|
61
|
+
export declare function resolveAdversarialGate(raw: unknown, env?: NodeJS.ProcessEnv): AdversarialGateSettings;
|
|
62
|
+
/** Options for the whole stage (bounded rounds + re-convergence). */
|
|
63
|
+
export interface AdversarialGateOptions {
|
|
64
|
+
instruction: string;
|
|
65
|
+
projectRoot: string;
|
|
66
|
+
rungs: GateRung[];
|
|
67
|
+
executor: LoopExecutor;
|
|
68
|
+
settings: AdversarialGateSettings;
|
|
69
|
+
/** The converged result under attack. */
|
|
70
|
+
initial: DeliveryResult;
|
|
71
|
+
/**
|
|
72
|
+
* Re-enter the convergence loop with the breach as feedback. The breaching
|
|
73
|
+
* tests are already in the tree, so a successful re-convergence has made
|
|
74
|
+
* THEM pass too — the attack persists as ordinary gate evidence.
|
|
75
|
+
*/
|
|
76
|
+
reconverge: (prompt: string) => Promise<DeliveryResult>;
|
|
77
|
+
runSuite?: SuiteRunner;
|
|
78
|
+
timeoutMs?: number;
|
|
79
|
+
/** Operator-facing progress lines. */
|
|
80
|
+
note?: (line: string) => void;
|
|
81
|
+
/**
|
|
82
|
+
* Re-derive the rung set AT GATE TIME. deliver.ts wires this to
|
|
83
|
+
* `mergeRedetectedRungs(rungs, detectRungs(projectRoot), …)` — the same
|
|
84
|
+
* policy the loop's mid-mission redetection uses — because the rungs this
|
|
85
|
+
* stage receives were detected at t0, and a mission that CREATED its own
|
|
86
|
+
* test gate (greenfield) would otherwise no-surface forever. A throwing
|
|
87
|
+
* detector falls back to `opts.rungs`.
|
|
88
|
+
*/
|
|
89
|
+
redetectRungs?: () => GateRung[];
|
|
90
|
+
/**
|
|
91
|
+
* Called with each breaching round BEFORE reconvergence, so the caller can
|
|
92
|
+
* extend the repair executor's protected set with the breaching test files
|
|
93
|
+
* (the t0 protection snapshot predates them). The post-repair verification
|
|
94
|
+
* below enforces the rule regardless; this is defense in depth.
|
|
95
|
+
*/
|
|
96
|
+
onBreach?: (breach: AdversarialRoundResult) => void;
|
|
97
|
+
}
|
|
98
|
+
/** The stage's outcome, including the (possibly re-converged) final result. */
|
|
99
|
+
export interface AdversarialGateReport {
|
|
100
|
+
status: AdversarialStatus | 'disabled';
|
|
101
|
+
rounds: AdversarialRoundResult[];
|
|
102
|
+
authored: number;
|
|
103
|
+
ran: number;
|
|
104
|
+
failed: number;
|
|
105
|
+
/** The state to accept (survived/no-surface) or reject (breached). */
|
|
106
|
+
result: DeliveryResult;
|
|
107
|
+
/** One-line outcome for telemetry / the gate-evidence artifact. */
|
|
108
|
+
summary: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The stage: attack the converged state up to `settings.maxRounds` times,
|
|
112
|
+
* routing breaches back into the convergence loop as ordinary gate evidence.
|
|
113
|
+
*
|
|
114
|
+
* Round-budget semantics: a breach CONSUMES a round and re-enters the loop.
|
|
115
|
+
* Because the breaching tests stay in the tree, the repaired state has already
|
|
116
|
+
* survived that attack — so exhausting the budget on a successful repair is an
|
|
117
|
+
* accept, not an open question. Only an UNREPAIRED breach rejects the run.
|
|
118
|
+
*/
|
|
119
|
+
export declare function runAdversarialGate(opts: AdversarialGateOptions): Promise<AdversarialGateReport>;
|
|
120
|
+
//# sourceMappingURL=adversarial-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adversarial-gate.d.ts","sourceRoot":"","sources":["../../src/delivery/adversarial-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AAIjC,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,WAAW,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,oBAAoB,EAAE,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEvF,8EAA8E;AAC9E,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAC5C,8EAA8E;AAC9E,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,oDAAoD;AACpD,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,EACZ,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,uBAAuB,CAwBzB;AAED,qEAAqE;AACrE,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,QAAQ,EAAE,YAAY,CAAC;IACvB,QAAQ,EAAE,uBAAuB,CAAC;IAClC,yCAAyC;IACzC,OAAO,EAAE,cAAc,CAAC;IACxB;;;;OAIG;IACH,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IACxD,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,QAAQ,EAAE,CAAC;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACrD;AAED,+EAA+E;AAC/E,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,iBAAiB,GAAG,UAAU,CAAC;IACvC,MAAM,EAAE,sBAAsB,EAAE,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,EAAE,cAAc,CAAC;IACvB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;CACjB;AA+ED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA+FrG"}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adversarial Red-Team Gate — HLG master architecture, stage 5
|
|
3
|
+
* (docs/plans/hlg-master-architecture-uplift-2026-09-24.md).
|
|
4
|
+
*
|
|
5
|
+
* When a deliver run has converged (all gates green) and BEFORE the verdict
|
|
6
|
+
* is accepted, a skeptical verifier attacks the patch: it writes edge-case
|
|
7
|
+
* tests designed to BREAK the change. If any fail, the run routes back into
|
|
8
|
+
* the convergence loop with that failure as ordinary gate evidence; only a
|
|
9
|
+
* patch that survives proceeds to acceptance (and gate evidence).
|
|
10
|
+
*
|
|
11
|
+
* This module is the STAGE DRIVER: settings resolution, the bounded round
|
|
12
|
+
* loop, breach → re-convergence orchestration, and the repair/rollback
|
|
13
|
+
* rails. The single-round machinery (attack authoring, sanctioning, suite
|
|
14
|
+
* execution, verdicts) lives in adversarial-attack.ts — the split keeps
|
|
15
|
+
* both files under the 500-LOC quality-gate threshold, along the seam the
|
|
16
|
+
* architecture review suggested. This module RE-EXPORTS the attack module's
|
|
17
|
+
* public surface so existing imports from './adversarial-gate.js' keep
|
|
18
|
+
* working.
|
|
19
|
+
*
|
|
20
|
+
* - BOUNDED: at most `maxRounds` attacks per run (default 2). A breach
|
|
21
|
+
* consumes a round and re-enters the convergence loop; the breaching
|
|
22
|
+
* tests REMAIN in the tree, so the repaired state has already survived
|
|
23
|
+
* that attack — the next round, if budget remains, attacks with FRESH
|
|
24
|
+
* tests rather than re-running the old ones forever.
|
|
25
|
+
*
|
|
26
|
+
* ACCEPTED RESIDUAL (C-stage review, 2026-09-24): authored tests execute
|
|
27
|
+
* with HOST FILESYSTEM privileges — sanitized-env strips environment
|
|
28
|
+
* variables but does NOT stop file-based credential reads (~/.aws, ~/.ssh,
|
|
29
|
+
* /etc) from inside a running test; and the repo content quoted into the
|
|
30
|
+
* attack prompt is an INDIRECT PROMPT-INJECTION channel into the authoring
|
|
31
|
+
* model. The additive oracle channel plus lexical+symlink path containment
|
|
32
|
+
* bound what an attack may WRITE and never weaken; what it can READ at
|
|
33
|
+
* runtime is everything the host user can read. This stage therefore runs
|
|
34
|
+
* only on the operator's own deliver run, never on untrusted input.
|
|
35
|
+
*/
|
|
36
|
+
import { existsSync, readFileSync, rmSync, writeFileSync } from 'fs';
|
|
37
|
+
import { join } from 'path';
|
|
38
|
+
import { foldDeliveryResult } from './delivery-result.js';
|
|
39
|
+
import { extractTestTitles } from './test-oracle-additive.js';
|
|
40
|
+
import { breachReconvergencePrompt, runAdversarialRound, } from './adversarial-attack.js';
|
|
41
|
+
// The attack + sanction modules' public surface, re-exported so consumers
|
|
42
|
+
// (index.ts, tests) keep a single import site for the whole stage.
|
|
43
|
+
export { attackSurface, breachReconvergencePrompt, buildAttackPrompt, pickTestRung, runAdversarialRound, } from './adversarial-attack.js';
|
|
44
|
+
export { sanctionAttackBlocks } from './adversarial-sanction.js';
|
|
45
|
+
/** Default attacks per converged run; each breach re-enters the loop once. */
|
|
46
|
+
export const DEFAULT_ADVERSARIAL_ROUNDS = 2;
|
|
47
|
+
/** Hard ceiling — the stage must never become the loop it exists to bound. */
|
|
48
|
+
export const MAX_ADVERSARIAL_ROUNDS = 4;
|
|
49
|
+
/**
|
|
50
|
+
* Resolve the adversarial gate's effective settings.
|
|
51
|
+
*
|
|
52
|
+
* Precedence mirrors `resolveParallelTasks` (task-workspace.ts): the
|
|
53
|
+
* `UAP_DELIVER_ADVERSARIAL_GATE` env var > `.uap.json` `deliver.adversarialGate`
|
|
54
|
+
* > the default. The stage is DEFAULT ON; `0`/`off`/`false` at either layer
|
|
55
|
+
* disables it. A positive integer at either layer retunes the round budget
|
|
56
|
+
* (clamped to [1, MAX_ADVERSARIAL_ROUNDS]); any other truthy value keeps the
|
|
57
|
+
* default budget — a typo must never silently disable a safety gate, and the
|
|
58
|
+
* documented off switch is unambiguous.
|
|
59
|
+
*/
|
|
60
|
+
export function resolveAdversarialGate(raw, env = process.env) {
|
|
61
|
+
const off = (v) => v === false || v === 0 || v === '0' || v === 'off';
|
|
62
|
+
const budget = (v) => {
|
|
63
|
+
// Boolean `true` means "on" (the flag form), not a round count —
|
|
64
|
+
// Number(true) === 1 would silently collapse the budget to one round
|
|
65
|
+
// while env 'true' keeps the default. Guard the TYPE, not the value.
|
|
66
|
+
if (typeof v === 'boolean')
|
|
67
|
+
return DEFAULT_ADVERSARIAL_ROUNDS;
|
|
68
|
+
const n = Number(v);
|
|
69
|
+
return Number.isFinite(n) && n > 0
|
|
70
|
+
? Math.min(Math.floor(n), MAX_ADVERSARIAL_ROUNDS)
|
|
71
|
+
: DEFAULT_ADVERSARIAL_ROUNDS;
|
|
72
|
+
};
|
|
73
|
+
const fromEnv = env.UAP_DELIVER_ADVERSARIAL_GATE;
|
|
74
|
+
if (fromEnv !== undefined && fromEnv.trim() !== '') {
|
|
75
|
+
return off(fromEnv)
|
|
76
|
+
? { enabled: false, maxRounds: 0 }
|
|
77
|
+
: { enabled: true, maxRounds: budget(fromEnv) };
|
|
78
|
+
}
|
|
79
|
+
if (raw === undefined || raw === null) {
|
|
80
|
+
return { enabled: true, maxRounds: DEFAULT_ADVERSARIAL_ROUNDS };
|
|
81
|
+
}
|
|
82
|
+
return off(raw)
|
|
83
|
+
? { enabled: false, maxRounds: 0 }
|
|
84
|
+
: { enabled: true, maxRounds: budget(raw) };
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Post-repair verification (C-stage review: vacuous breach repair). The
|
|
88
|
+
* reconvergence prompt's "never delete, skip, or weaken" rule is PROSE, and
|
|
89
|
+
* the repair executor's protected-files set was snapshotted at t0 — before
|
|
90
|
+
* the adversarial tests existed — so nothing structural stops a repair from
|
|
91
|
+
* deleting or gutting the very tests that pinned the breach. After a repair
|
|
92
|
+
* reports success, every breaching test file must still EXIST and still
|
|
93
|
+
* contain its authored titles; anything else is a failed repair, whatever
|
|
94
|
+
* the loop's gates say (a repair that removed the test trivially turns them
|
|
95
|
+
* green). Returns the per-file violations; empty means the attack survived
|
|
96
|
+
* the repair intact.
|
|
97
|
+
*/
|
|
98
|
+
function breachingTestsGutted(projectRoot, breach) {
|
|
99
|
+
const gutted = [];
|
|
100
|
+
for (const f of breach.attackFiles ?? []) {
|
|
101
|
+
const abs = join(projectRoot, f.rel);
|
|
102
|
+
let content = null;
|
|
103
|
+
try {
|
|
104
|
+
content = existsSync(abs) ? readFileSync(abs, 'utf-8') : null;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
content = null;
|
|
108
|
+
}
|
|
109
|
+
if (content === null) {
|
|
110
|
+
gutted.push(`${f.rel}: breaching test file was deleted during repair`);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const present = new Set(extractTestTitles(content));
|
|
114
|
+
const missing = f.titles.filter((t) => !present.has(t));
|
|
115
|
+
if (missing.length > 0) {
|
|
116
|
+
gutted.push(`${f.rel}: ${missing.length} authored adversarial test(s) removed or renamed during repair (${missing
|
|
117
|
+
.slice(0, 2)
|
|
118
|
+
.join('; ')})`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return gutted;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Terminal-breach rollback: a REJECTED run must not leave the user's suite
|
|
125
|
+
* red, so the breaching round's authored files come back OUT — created files
|
|
126
|
+
* removed, appended-to files restored to their pre-attack bytes. (The
|
|
127
|
+
* keep-best rollback rail settled BEFORE this stage runs, so this is the
|
|
128
|
+
* only rail left.) Survived and repaired rounds keep their tests: those
|
|
129
|
+
* pass, and are regression tests now. Best-effort, like rollbackWrites.
|
|
130
|
+
*/
|
|
131
|
+
function rollbackAttackFiles(projectRoot, round) {
|
|
132
|
+
const rolledBack = [];
|
|
133
|
+
for (const f of round.attackFiles ?? []) {
|
|
134
|
+
try {
|
|
135
|
+
if (f.prior === null)
|
|
136
|
+
rmSync(join(projectRoot, f.rel), { force: true });
|
|
137
|
+
else
|
|
138
|
+
writeFileSync(join(projectRoot, f.rel), f.prior, 'utf-8');
|
|
139
|
+
rolledBack.push(f.rel);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
/* rollback is best-effort; the round notes carry the residue */
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return rolledBack;
|
|
146
|
+
}
|
|
147
|
+
function summarize(status, rounds, totals) {
|
|
148
|
+
const counts = `${totals.authored} authored / ${totals.ran} ran / ${totals.failed} failed`;
|
|
149
|
+
if (status === 'disabled')
|
|
150
|
+
return 'adversarial gate: disabled';
|
|
151
|
+
if (status === 'survived') {
|
|
152
|
+
return `adversarial gate: patch survived ${rounds.length} round(s) (${counts})`;
|
|
153
|
+
}
|
|
154
|
+
if (status === 'no-surface') {
|
|
155
|
+
return `adversarial gate: no attack surface found after ${rounds.length} round(s) (${counts})`;
|
|
156
|
+
}
|
|
157
|
+
return `adversarial gate: patch BREACHED (${counts}) — re-convergence could not repair it`;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* The stage: attack the converged state up to `settings.maxRounds` times,
|
|
161
|
+
* routing breaches back into the convergence loop as ordinary gate evidence.
|
|
162
|
+
*
|
|
163
|
+
* Round-budget semantics: a breach CONSUMES a round and re-enters the loop.
|
|
164
|
+
* Because the breaching tests stay in the tree, the repaired state has already
|
|
165
|
+
* survived that attack — so exhausting the budget on a successful repair is an
|
|
166
|
+
* accept, not an open question. Only an UNREPAIRED breach rejects the run.
|
|
167
|
+
*/
|
|
168
|
+
export async function runAdversarialGate(opts) {
|
|
169
|
+
const totals = { authored: 0, ran: 0, failed: 0 };
|
|
170
|
+
const base = (status, rounds, result) => ({
|
|
171
|
+
status,
|
|
172
|
+
rounds,
|
|
173
|
+
...totals,
|
|
174
|
+
result,
|
|
175
|
+
summary: summarize(status, rounds, totals),
|
|
176
|
+
});
|
|
177
|
+
if (!opts.settings.enabled) {
|
|
178
|
+
return base('disabled', [], opts.initial);
|
|
179
|
+
}
|
|
180
|
+
const rounds = [];
|
|
181
|
+
let result = opts.initial;
|
|
182
|
+
for (let round = 1; round <= opts.settings.maxRounds; round++) {
|
|
183
|
+
// Gate-time redetection (C-stage review: stale t0 rungs): the rungs this
|
|
184
|
+
// stage was handed were detected at mission start, so a greenfield
|
|
185
|
+
// mission that CREATED its test gate would no-surface forever. Re-merge
|
|
186
|
+
// the fresh detection the way the loop's mid-mission redetection does.
|
|
187
|
+
let roundRungs = opts.rungs;
|
|
188
|
+
if (opts.redetectRungs) {
|
|
189
|
+
try {
|
|
190
|
+
roundRungs = opts.redetectRungs();
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
roundRungs = opts.rungs;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const filesApplied = [...new Set(result.history.flatMap((h) => h.filesApplied))];
|
|
197
|
+
const r = await runAdversarialRound({
|
|
198
|
+
instruction: opts.instruction,
|
|
199
|
+
projectRoot: opts.projectRoot,
|
|
200
|
+
filesApplied,
|
|
201
|
+
rungs: roundRungs,
|
|
202
|
+
executor: opts.executor,
|
|
203
|
+
round,
|
|
204
|
+
...(opts.runSuite ? { runSuite: opts.runSuite } : {}),
|
|
205
|
+
...(opts.timeoutMs !== undefined ? { timeoutMs: opts.timeoutMs } : {}),
|
|
206
|
+
});
|
|
207
|
+
rounds.push(r);
|
|
208
|
+
totals.authored += r.authored;
|
|
209
|
+
totals.ran += r.ran;
|
|
210
|
+
totals.failed += r.failed;
|
|
211
|
+
opts.note?.(r.status === 'breached'
|
|
212
|
+
? `🛡 adversarial round ${r.round}: BREACH — ${r.failed} adversarial test(s) failed; re-entering the loop`
|
|
213
|
+
: r.status === 'survived'
|
|
214
|
+
? `🛡 adversarial round ${r.round}: survived — ${r.ran}/${r.authored} authored test(s) ran and passed`
|
|
215
|
+
: `🛡 adversarial round ${r.round}: no attack surface found (${r.feedback})`);
|
|
216
|
+
if (r.status !== 'breached') {
|
|
217
|
+
return base(r.status, rounds, result);
|
|
218
|
+
}
|
|
219
|
+
// Breach: let the caller extend the repair's protected set with the
|
|
220
|
+
// breaching test files (its t0 protection snapshot predates them), then
|
|
221
|
+
// feed the failure back into the convergence loop as ordinary evidence.
|
|
222
|
+
opts.onBreach?.(r);
|
|
223
|
+
const repaired = await opts.reconverge(breachReconvergencePrompt(opts.instruction, r));
|
|
224
|
+
const merged = { ...result, history: [...result.history] };
|
|
225
|
+
foldDeliveryResult(merged, repaired);
|
|
226
|
+
merged.success = repaired.success;
|
|
227
|
+
merged.changedTree = Boolean(result.changedTree || repaired.changedTree);
|
|
228
|
+
if (!repaired.success) {
|
|
229
|
+
// TERMINAL breach: the run is rejected, and a rejected run must not
|
|
230
|
+
// leave the user's suite red — roll the round's authored files back.
|
|
231
|
+
const rolledBack = rollbackAttackFiles(opts.projectRoot, r);
|
|
232
|
+
r.notes.push(`terminal breach — authored adversarial test file(s) rolled back: ${rolledBack.join(', ') || 'none recorded'}`);
|
|
233
|
+
merged.finalFeedback =
|
|
234
|
+
`⛔ adversarial gate: the red team broke the patch and the repair loop did not converge.\n\n${repaired.finalFeedback}`;
|
|
235
|
+
return base('breached', rounds, merged);
|
|
236
|
+
}
|
|
237
|
+
// Vacuous-repair check: a "successful" repair that deleted or gutted the
|
|
238
|
+
// breaching tests did not fix anything — it removed the evidence. That
|
|
239
|
+
// is a failed repair, and the (terminal) breach rolls back as above.
|
|
240
|
+
const gutted = breachingTestsGutted(opts.projectRoot, r);
|
|
241
|
+
if (gutted.length > 0) {
|
|
242
|
+
const rolledBack = rollbackAttackFiles(opts.projectRoot, r);
|
|
243
|
+
r.notes.push(`repair gutted the breaching test(s) — repair REJECTED: ${gutted.join('; ')}`);
|
|
244
|
+
if (rolledBack.length > 0) {
|
|
245
|
+
r.notes.push(`terminal breach — authored adversarial test file(s) rolled back: ${rolledBack.join(', ')}`);
|
|
246
|
+
}
|
|
247
|
+
merged.success = false;
|
|
248
|
+
merged.finalFeedback =
|
|
249
|
+
'⛔ adversarial gate: the repair deleted or weakened the breaching adversarial tests instead of fixing the code.\n\n' +
|
|
250
|
+
gutted.map((g) => ` ${g}`).join('\n');
|
|
251
|
+
return base('breached', rounds, merged);
|
|
252
|
+
}
|
|
253
|
+
result = merged;
|
|
254
|
+
}
|
|
255
|
+
// Budget exhausted on a repaired state: the breaching tests remained in the
|
|
256
|
+
// tree, so every repair already had to make them green — accept.
|
|
257
|
+
return base('survived', rounds, result);
|
|
258
|
+
}
|
|
259
|
+
//# sourceMappingURL=adversarial-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adversarial-gate.js","sourceRoot":"","sources":["../../src/delivery/adversarial-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adversarial attack SANCTIONING — the containment boundary every
|
|
3
|
+
* model-authored red-team test crosses before it touches disk. Split from
|
|
4
|
+
* adversarial-attack.ts to keep each module of the adversarial stage under
|
|
5
|
+
* the 500-LOC quality-gate threshold; the round orchestration that calls
|
|
6
|
+
* these functions lives in adversarial-attack.ts, and the stage driver
|
|
7
|
+
* (adversarial-gate.ts) re-exports the public surface.
|
|
8
|
+
*
|
|
9
|
+
* The rule set (composition over invention — nothing here is new machinery,
|
|
10
|
+
* it is the existing additive oracle channel applied to attack writes):
|
|
11
|
+
*
|
|
12
|
+
* - The red team may only ADD tests: NEW test files pass the delta rule
|
|
13
|
+
* (no suppressors, no process.exit, no assert reassignment); appends to
|
|
14
|
+
* existing test files pass the full additive rule (existing content
|
|
15
|
+
* survives verbatim as a prefix).
|
|
16
|
+
* - Paths are contained to the project root lexically AND through
|
|
17
|
+
* symlinks (realParentEscapes — the same check the applier enforces on
|
|
18
|
+
* every other write), capped in count and in BYTES (not UTF-16 units).
|
|
19
|
+
* - Every refusal and every dropped surplus block is recorded in the
|
|
20
|
+
* notes — the audit trail must distinguish "the model tried X and was
|
|
21
|
+
* refused" from "the model never tried".
|
|
22
|
+
*/
|
|
23
|
+
import { type FileBlock } from './applier.js';
|
|
24
|
+
/** At most this many model-authored test files per round. Exported: the
|
|
25
|
+
* attack prompt states the cap to the authoring model. */
|
|
26
|
+
export declare const MAX_ATTACK_FILES = 3;
|
|
27
|
+
export interface SanctionedWrite {
|
|
28
|
+
/** Repo-relative, '/'-separated. */
|
|
29
|
+
rel: string;
|
|
30
|
+
abs: string;
|
|
31
|
+
/** Pre-existing content (append case); null for a new file. */
|
|
32
|
+
prior: string | null;
|
|
33
|
+
/** Test-case titles this write adds. */
|
|
34
|
+
titles: string[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Sanction model-authored blocks through the additive oracle channel. The red
|
|
38
|
+
* team may only ADD tests: new test files (suppressor/exit/assert-patch
|
|
39
|
+
* checks), or verbatim-prefix appends to existing ones (full additive rule).
|
|
40
|
+
*/
|
|
41
|
+
export declare function sanctionAttackBlocks(blocks: FileBlock[], projectRoot: string): {
|
|
42
|
+
writes: SanctionedWrite[];
|
|
43
|
+
notes: string[];
|
|
44
|
+
};
|
|
45
|
+
/** Materialize sanctioned writes; returns nothing (rollback via the writes). */
|
|
46
|
+
export declare function applyWrites(writes: SanctionedWrite[], blocks: FileBlock[]): void;
|
|
47
|
+
/**
|
|
48
|
+
* Undo this round's writes: remove files the round CREATED, restore files it
|
|
49
|
+
* appended to. Only ever touches paths sanctionAttackBlocks sanctioned.
|
|
50
|
+
*/
|
|
51
|
+
export declare function rollbackWrites(writes: SanctionedWrite[]): void;
|
|
52
|
+
//# sourceMappingURL=adversarial-sanction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adversarial-sanction.d.ts","sourceRoot":"","sources":["../../src/delivery/adversarial-sanction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAAqC,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAOjF;0DAC0D;AAC1D,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAIlC,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,wCAAwC;IACxC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EAAE,EACnB,WAAW,EAAE,MAAM,GAClB;IAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAuEhD;AAED,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAMhF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,IAAI,CAS9D"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adversarial attack SANCTIONING — the containment boundary every
|
|
3
|
+
* model-authored red-team test crosses before it touches disk. Split from
|
|
4
|
+
* adversarial-attack.ts to keep each module of the adversarial stage under
|
|
5
|
+
* the 500-LOC quality-gate threshold; the round orchestration that calls
|
|
6
|
+
* these functions lives in adversarial-attack.ts, and the stage driver
|
|
7
|
+
* (adversarial-gate.ts) re-exports the public surface.
|
|
8
|
+
*
|
|
9
|
+
* The rule set (composition over invention — nothing here is new machinery,
|
|
10
|
+
* it is the existing additive oracle channel applied to attack writes):
|
|
11
|
+
*
|
|
12
|
+
* - The red team may only ADD tests: NEW test files pass the delta rule
|
|
13
|
+
* (no suppressors, no process.exit, no assert reassignment); appends to
|
|
14
|
+
* existing test files pass the full additive rule (existing content
|
|
15
|
+
* survives verbatim as a prefix).
|
|
16
|
+
* - Paths are contained to the project root lexically AND through
|
|
17
|
+
* symlinks (realParentEscapes — the same check the applier enforces on
|
|
18
|
+
* every other write), capped in count and in BYTES (not UTF-16 units).
|
|
19
|
+
* - Every refusal and every dropped surplus block is recorded in the
|
|
20
|
+
* notes — the audit trail must distinguish "the model tried X and was
|
|
21
|
+
* refused" from "the model never tried".
|
|
22
|
+
*/
|
|
23
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'fs';
|
|
24
|
+
import { dirname, isAbsolute, resolve, sep } from 'path';
|
|
25
|
+
import { isTestFilePath, realParentEscapes } from './applier.js';
|
|
26
|
+
import { additiveTestDeltaRefusal, additiveTestEditRefusal, extractTestTitles, } from './test-oracle-additive.js';
|
|
27
|
+
/** At most this many model-authored test files per round. Exported: the
|
|
28
|
+
* attack prompt states the cap to the authoring model. */
|
|
29
|
+
export const MAX_ATTACK_FILES = 3;
|
|
30
|
+
/** Per-file content cap for authored tests (guards runaway generations). */
|
|
31
|
+
const MAX_ATTACK_BYTES = 100_000;
|
|
32
|
+
/**
|
|
33
|
+
* Sanction model-authored blocks through the additive oracle channel. The red
|
|
34
|
+
* team may only ADD tests: new test files (suppressor/exit/assert-patch
|
|
35
|
+
* checks), or verbatim-prefix appends to existing ones (full additive rule).
|
|
36
|
+
*/
|
|
37
|
+
export function sanctionAttackBlocks(blocks, projectRoot) {
|
|
38
|
+
const writes = [];
|
|
39
|
+
const notes = [];
|
|
40
|
+
const rootAbs = resolve(projectRoot);
|
|
41
|
+
// Symlink-followed root for the containment check — the lexical resolve
|
|
42
|
+
// alone lets a pre-existing symlink inside the repo redirect an attack-file
|
|
43
|
+
// write outside it (same rule the applier enforces on every other write).
|
|
44
|
+
let realRoot = rootAbs;
|
|
45
|
+
try {
|
|
46
|
+
realRoot = realpathSync(rootAbs);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
/* root unreadable — fall back to the lexical root */
|
|
50
|
+
}
|
|
51
|
+
if (blocks.length > MAX_ATTACK_FILES) {
|
|
52
|
+
const dropped = blocks.slice(MAX_ATTACK_FILES).map((b) => b.path);
|
|
53
|
+
// Surplus blocks are REFUSED, not silently lost — the audit trail records
|
|
54
|
+
// exactly what the model tried to add beyond the cap.
|
|
55
|
+
notes.push(`dropped ${dropped.length} surplus attack block(s) beyond the ${MAX_ATTACK_FILES}-file cap: ${dropped.join(', ')}`);
|
|
56
|
+
}
|
|
57
|
+
for (const block of blocks.slice(0, MAX_ATTACK_FILES)) {
|
|
58
|
+
const rel = block.path.replace(/\\/g, '/').replace(/^\/+/, '');
|
|
59
|
+
const abs = resolve(rootAbs, rel);
|
|
60
|
+
if (isAbsolute(block.path) || (abs !== rootAbs && !abs.startsWith(rootAbs + sep))) {
|
|
61
|
+
notes.push(`refused ${block.path}: path escapes the project root`);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (realParentEscapes(abs, realRoot)) {
|
|
65
|
+
notes.push(`refused ${rel}: a symlink in its parent path escapes the project root`);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (!isTestFilePath(rel)) {
|
|
69
|
+
notes.push(`refused ${rel}: not a test file — the red team may only add tests`);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
// Byte-accurate cap: a runaway generation of multibyte text must count
|
|
73
|
+
// the BYTES it would write, not UTF-16 code units.
|
|
74
|
+
if (Buffer.byteLength(block.content, 'utf-8') > MAX_ATTACK_BYTES) {
|
|
75
|
+
notes.push(`refused ${rel}: content exceeds ${MAX_ATTACK_BYTES} bytes`);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (existsSync(abs)) {
|
|
79
|
+
const prior = readFileSync(abs, 'utf-8');
|
|
80
|
+
const refusal = additiveTestEditRefusal(prior, block.content);
|
|
81
|
+
if (refusal) {
|
|
82
|
+
notes.push(`refused ${rel}: append to an existing test file is not additive — ${refusal}`);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const priorTitles = new Set(extractTestTitles(prior));
|
|
86
|
+
const titles = extractTestTitles(block.content).filter((t) => !priorTitles.has(t));
|
|
87
|
+
if (titles.length === 0) {
|
|
88
|
+
notes.push(`refused ${rel}: the append adds no recognizable test cases`);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
writes.push({ rel, abs, prior, titles });
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const refusal = additiveTestDeltaRefusal(block.content);
|
|
95
|
+
if (refusal) {
|
|
96
|
+
notes.push(`refused ${rel}: ${refusal}`);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const titles = extractTestTitles(block.content);
|
|
100
|
+
if (titles.length === 0) {
|
|
101
|
+
notes.push(`refused ${rel}: no recognizable test cases — nothing runnable to add`);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
writes.push({ rel, abs, prior: null, titles });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return { writes, notes };
|
|
108
|
+
}
|
|
109
|
+
/** Materialize sanctioned writes; returns nothing (rollback via the writes). */
|
|
110
|
+
export function applyWrites(writes, blocks) {
|
|
111
|
+
const contentByRel = new Map(blocks.map((b) => [b.path.replace(/\\/g, '/').replace(/^\/+/, ''), b.content]));
|
|
112
|
+
for (const w of writes) {
|
|
113
|
+
mkdirSync(dirname(w.abs), { recursive: true });
|
|
114
|
+
writeFileSync(w.abs, contentByRel.get(w.rel) ?? '', 'utf-8');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Undo this round's writes: remove files the round CREATED, restore files it
|
|
119
|
+
* appended to. Only ever touches paths sanctionAttackBlocks sanctioned.
|
|
120
|
+
*/
|
|
121
|
+
export function rollbackWrites(writes) {
|
|
122
|
+
for (const w of writes) {
|
|
123
|
+
try {
|
|
124
|
+
if (w.prior === null)
|
|
125
|
+
rmSync(w.abs, { force: true });
|
|
126
|
+
else
|
|
127
|
+
writeFileSync(w.abs, w.prior, 'utf-8');
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
/* rollback is best-effort; the notes carry the residue */
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=adversarial-sanction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adversarial-sanction.js","sourceRoot":"","sources":["../../src/delivery/adversarial-sanction.ts"],"names":[],"mappings":"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"}
|