@lannguyensi/harness 0.53.0 → 0.54.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/CHANGELOG.md +40 -1
- package/dist/cli/delegate/index.d.ts +15 -2
- package/dist/cli/delegate/index.js +128 -4
- package/dist/cli/delegate/index.js.map +1 -1
- package/dist/cli/doctor/bypass-without-auto-approve.js +10 -4
- package/dist/cli/doctor/bypass-without-auto-approve.js.map +1 -1
- package/dist/cli/dry-run.js +32 -1
- package/dist/cli/dry-run.js.map +1 -1
- package/dist/cli/index.js +13 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init/profiles.js +89 -8
- package/dist/cli/init/profiles.js.map +1 -1
- package/dist/cli/init/templates.js +163 -3
- package/dist/cli/init/templates.js.map +1 -1
- package/dist/cli/pack/hook-pre-tool-use.js +200 -95
- package/dist/cli/pack/hook-pre-tool-use.js.map +1 -1
- package/dist/cli/record/index.d.ts +8 -0
- package/dist/cli/record/index.js +55 -7
- package/dist/cli/record/index.js.map +1 -1
- package/dist/cli/validate/checks.js +61 -9
- package/dist/cli/validate/checks.js.map +1 -1
- package/dist/io/extract.d.ts +29 -0
- package/dist/io/extract.js +36 -0
- package/dist/io/extract.js.map +1 -1
- package/dist/policies/index.d.ts +1 -1
- package/dist/policies/index.js +1 -1
- package/dist/policies/index.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.d.ts +37 -0
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js +41 -1
- package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/index.d.ts +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/index.js +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/index.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js +9 -3
- package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js.map +1 -1
- package/dist/runtime/destructive-shell-floor.d.ts +19 -0
- package/dist/runtime/destructive-shell-floor.js +597 -0
- package/dist/runtime/destructive-shell-floor.js.map +1 -0
- package/dist/runtime/intercept.d.ts +10 -7
- package/dist/runtime/intercept.js +108 -9
- package/dist/runtime/intercept.js.map +1 -1
- package/dist/runtime/read-only-bash.d.ts +21 -0
- package/dist/runtime/read-only-bash.js +484 -0
- package/dist/runtime/read-only-bash.js.map +1 -1
- package/dist/runtime/risk-classifier.js +68 -13
- package/dist/runtime/risk-classifier.js.map +1 -1
- package/dist/runtime/when-eval.d.ts +18 -5
- package/dist/runtime/when-eval.js +64 -11
- package/dist/runtime/when-eval.js.map +1 -1
- package/dist/runtime/workflow-policies.d.ts +43 -1
- package/dist/runtime/workflow-policies.js +158 -1
- package/dist/runtime/workflow-policies.js.map +1 -1
- package/dist/schema/extract.d.ts +4 -0
- package/dist/schema/extract.js +64 -1
- package/dist/schema/extract.js.map +1 -1
- package/dist/schema/index.d.ts +13 -0
- package/dist/schema/policies.d.ts +19 -0
- package/dist/schema/policies.js +17 -1
- package/dist/schema/policies.js.map +1 -1
- package/package.json +1 -1
|
@@ -16,16 +16,21 @@
|
|
|
16
16
|
// default; this module's job is only to report the unclassified state
|
|
17
17
|
// honestly.
|
|
18
18
|
//
|
|
19
|
-
// The
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
19
|
+
// The built-in exceptions are floors, not overrides, and each composes
|
|
20
|
+
// under the same highest-severity-wins rule as an operator pattern:
|
|
21
|
+
// harness's own benign meta-commands (see BENIGN_HARNESS_COMMAND below),
|
|
22
|
+
// the read-only-command / kubectl / sed `low` floors, and (since
|
|
23
|
+
// task 2929c5b7) the DESTRUCTIVE floor (`destructive-shell-floor.ts`),
|
|
24
|
+
// which recognizes `dd of=`, `truncate -s`, `shred`, `mkfs`, `find
|
|
25
|
+
// -delete` and friends in the binary so an install that never adopts the
|
|
26
|
+
// new `dangerous-shell` template patterns still classifies them.
|
|
23
27
|
//
|
|
24
28
|
// Design source: lava-ice-logs/2026-04-30/harness-risk-gate-extension.md
|
|
25
29
|
// (design phase B).
|
|
26
30
|
import { RiskSeveritySchema } from "../schema/index.js";
|
|
27
31
|
import { expandToolNameAliases, extractShellCommand } from "./tool-name-aliases.js";
|
|
28
|
-
import { isReadOnlyBashCommand, isReadOnlyKubectlCommand } from "./read-only-bash.js";
|
|
32
|
+
import { isReadOnlyBashCommand, isReadOnlyKubectlCommand, isReadOnlySedCommand, } from "./read-only-bash.js";
|
|
33
|
+
import { classifyDestructiveShellFloor } from "./destructive-shell-floor.js";
|
|
29
34
|
// Ordered severity scale: a value's index here is the comparison key
|
|
30
35
|
// for "highest matched severity wins". Sourced from the schema enum so
|
|
31
36
|
// a future reordering there flows through unchanged.
|
|
@@ -171,16 +176,43 @@ export function classifyRisk(envelope, classifiers) {
|
|
|
171
176
|
`severity ${pat.severity}, categories [${pat.categories.join(", ")}]`);
|
|
172
177
|
}
|
|
173
178
|
}
|
|
174
|
-
// Built-in
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
//
|
|
179
|
+
// Built-in floors. Folded in AFTER the operator loop so they compose by
|
|
180
|
+
// the same highest-severity-wins rule: the benign ones only raise an
|
|
181
|
+
// otherwise-unclassified action up to `low`, and never sink an operator
|
|
182
|
+
// match (a dangerous tail in `harness preflight && rm -rf /var` keeps
|
|
183
|
+
// the higher severity, and a chained command is not read-only); the
|
|
184
|
+
// destructive one raises to `high`/`critical` and is evaluated first,
|
|
185
|
+
// so a recognized mutating head never also takes a benign floor. All
|
|
186
|
+
// of them are gated on a real shell command so a non-shell tool whose
|
|
187
|
+
// serialized input happens to look benign cannot match.
|
|
182
188
|
const shellCommand = extractShellCommand({ raw_input: envelope.raw_input });
|
|
183
189
|
if (shellCommand !== null) {
|
|
190
|
+
// Built-in DESTRUCTIVE floor (task 2929c5b7), evaluated before the
|
|
191
|
+
// benign floors below so a recognized mutating head keeps them from
|
|
192
|
+
// firing at all. It ships in the binary rather than only as a
|
|
193
|
+
// `dangerous-shell` template pattern because `harness init` writes a
|
|
194
|
+
// manifest once and never rewrites it: an install carrying the
|
|
195
|
+
// original four patterns would otherwise take `when-eval.ts`'s
|
|
196
|
+
// loosened `severity_at_least: critical` fallback on upgrade WITHOUT
|
|
197
|
+
// the compensating classification. See
|
|
198
|
+
// `destructive-shell-floor.ts`'s module header and docs/risk-gate.md.
|
|
199
|
+
//
|
|
200
|
+
// Same composition rule as every other floor: highest severity wins,
|
|
201
|
+
// categories union. An operator pattern can raise above it; nothing
|
|
202
|
+
// sinks below it.
|
|
203
|
+
//
|
|
204
|
+
// Pass the UNCAPPED shellCommand for the same reason the read-only
|
|
205
|
+
// floor does (see below): the floor's scan is linear-time, and a
|
|
206
|
+
// destructive tail past the 16 KiB `subject` cap must not be
|
|
207
|
+
// laundered by a long benign head.
|
|
208
|
+
for (const hit of classifyDestructiveShellFloor(shellCommand)) {
|
|
209
|
+
const idx = SEVERITY_ORDER.indexOf(hit.severity);
|
|
210
|
+
if (idx > severityIdx)
|
|
211
|
+
severityIdx = idx;
|
|
212
|
+
for (const cat of hit.categories)
|
|
213
|
+
categories.add(cat);
|
|
214
|
+
reasons.push(`${hit.reason} (severity ${hit.severity})`);
|
|
215
|
+
}
|
|
184
216
|
const lowIdx = SEVERITY_ORDER.indexOf("low");
|
|
185
217
|
if (lowIdx > severityIdx) {
|
|
186
218
|
if (BENIGN_HARNESS_COMMAND.test(subject)) {
|
|
@@ -223,6 +255,29 @@ export function classifyRisk(envelope, classifiers) {
|
|
|
223
255
|
severityIdx = lowIdx;
|
|
224
256
|
reasons.push("built-in: provably read-only kubectl verb recognized (severity low)");
|
|
225
257
|
}
|
|
258
|
+
else if (isReadOnlySedCommand(shellCommand)) {
|
|
259
|
+
// `sed` read-verb floor (task 2929c5b7). Same placement decision
|
|
260
|
+
// as the kubectl floor directly above and for the same measured
|
|
261
|
+
// reason: it is NOT folded into `isReadOnlyBashCommand`, because
|
|
262
|
+
// the understanding-gate PreToolUse blocker and the
|
|
263
|
+
// solution-acceptance write-guard consume that predicate
|
|
264
|
+
// directly and short-circuit on it, so a `sed` recognition there
|
|
265
|
+
// would let `sed 's/a/b/w <verdict-dir>/marker.json' f` past the
|
|
266
|
+
// write-guard. See `isReadOnlySedCommand`'s own docstring for
|
|
267
|
+
// the allowlist and the script scan (sed's `w` command, `s///w`
|
|
268
|
+
// flag, `-f SCRIPTFILE` and GNU `e` all forfeit).
|
|
269
|
+
severityIdx = lowIdx;
|
|
270
|
+
reasons.push("built-in: provably read-only sed invocation recognized (severity low)");
|
|
271
|
+
}
|
|
272
|
+
// NOTE, decision D-013 (task 2929c5b7, review round 3): there is
|
|
273
|
+
// deliberately NO `curl` branch here. Two rounds of this task shipped
|
|
274
|
+
// one and both leaked (a write-flag denylist that missed `-o`, then a
|
|
275
|
+
// flag allowlist that still admitted `-w '%output{FILE}'`, which
|
|
276
|
+
// writes a local file since curl 8.3.0). `curl` stays UNCLASSIFIED
|
|
277
|
+
// like `ssh` and `node -e`: approval-gated by prong (b), never
|
|
278
|
+
// hard-blocked, never floored. Its write-capable spellings are raised
|
|
279
|
+
// to `high` by the destructive floor above instead. See
|
|
280
|
+
// `read-only-bash.ts`'s floor section header.
|
|
226
281
|
}
|
|
227
282
|
}
|
|
228
283
|
if (severityIdx === -1) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"risk-classifier.js","sourceRoot":"","sources":["../../src/runtime/risk-classifier.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,EAAE;AACF,kEAAkE;AAClE,qEAAqE;AACrE,iEAAiE;AACjE,cAAc;AACd,EAAE;AACF,yEAAyE;AACzE,yEAAyE;AACzE,mBAAmB;AACnB,EAAE;AACF,iEAAiE;AACjE,sEAAsE;AACtE,oEAAoE;AACpE,uEAAuE;AACvE,sEAAsE;AACtE,YAAY;AACZ,EAAE;AACF,
|
|
1
|
+
{"version":3,"file":"risk-classifier.js","sourceRoot":"","sources":["../../src/runtime/risk-classifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,13 @@ import type { PolicyWhen } from "../schema/index.js";
|
|
|
2
2
|
import type { DeletionTargetVerdict } from "./deletion-target-resolve.js";
|
|
3
3
|
import type { EnvironmentResolution } from "./environment-resolver.js";
|
|
4
4
|
import type { RiskProfile } from "./risk-classifier.js";
|
|
5
|
+
/**
|
|
6
|
+
* The severity NAME the unclassified fallback is treated as, for
|
|
7
|
+
* surfaces that have to say it out loud (`intercept.ts`'s deny
|
|
8
|
+
* envelope). Exported so no caller hard-codes "high" beside a constant
|
|
9
|
+
* that is derived.
|
|
10
|
+
*/
|
|
11
|
+
export declare const UNCLASSIFIED_FALLBACK_SEVERITY: string;
|
|
5
12
|
/** The enriched-envelope inputs a `when:` block is evaluated against. */
|
|
6
13
|
export interface WhenContext {
|
|
7
14
|
risk: RiskProfile;
|
|
@@ -33,9 +40,13 @@ export interface WhenEvaluation {
|
|
|
33
40
|
matched: boolean;
|
|
34
41
|
/** One entry per DECLARED clause, in manifest-key order. */
|
|
35
42
|
clauses: WhenClauseResult[];
|
|
36
|
-
/** True when at least one clause
|
|
37
|
-
* unclassified
|
|
38
|
-
*
|
|
43
|
+
/** True when at least one clause's outcome was decided by the
|
|
44
|
+
* unclassified fallback rather than a real classification ("unknown
|
|
45
|
+
* is not safe" for `risk.category_in` / `action.reversible`, or the
|
|
46
|
+
* "treated as high" rung for `risk.severity_at_least`) — true
|
|
47
|
+
* whether that fallback made the clause match or fail. Surfaced so
|
|
48
|
+
* `explain-policy` can tell an operator a clause outcome was
|
|
49
|
+
* fail-closed, not a real hit. */
|
|
39
50
|
unclassifiedFallback: boolean;
|
|
40
51
|
}
|
|
41
52
|
/**
|
|
@@ -43,7 +54,9 @@ export interface WhenEvaluation {
|
|
|
43
54
|
*
|
|
44
55
|
* Every clause is optional; only declared clauses are evaluated, and
|
|
45
56
|
* `matched` is their AND. An unclassified risk profile (`classified:
|
|
46
|
-
* false`) satisfies
|
|
47
|
-
* not safe" rule
|
|
57
|
+
* false`) satisfies `risk.category_in` / `action.reversible` by the
|
|
58
|
+
* "unknown is not safe" rule, and satisfies `risk.severity_at_least`
|
|
59
|
+
* up through `high` but never `critical` (see the module header);
|
|
60
|
+
* `environment.name` is always a plain equality test.
|
|
48
61
|
*/
|
|
49
62
|
export declare function evaluateWhen(when: PolicyWhen, ctx: WhenContext): WhenEvaluation;
|
|
@@ -14,12 +14,36 @@
|
|
|
14
14
|
// The Risk Classifier emits `severity: null` / `reversible: null` /
|
|
15
15
|
// `categories: []` for an action no pattern matched (`classified:
|
|
16
16
|
// false`). A null does not silently fail to satisfy a clause: an
|
|
17
|
-
// UNCLASSIFIED action satisfies every `risk
|
|
18
|
-
// clause, so a risk-gating policy treats "we could
|
|
19
|
-
// as risk-bearing rather than letting it slip the
|
|
20
|
-
// action is compared on its real values.
|
|
21
|
-
// such rule: the resolver always returns a
|
|
22
|
-
// `unknown` as the matchable no-resolver-
|
|
17
|
+
// UNCLASSIFIED action satisfies every `risk.category_in` /
|
|
18
|
+
// `action.reversible` clause, so a risk-gating policy treats "we could
|
|
19
|
+
// not classify this" as risk-bearing rather than letting it slip the
|
|
20
|
+
// gate. A *classified* action is compared on its real values.
|
|
21
|
+
// `environment.name` needs no such rule: the resolver always returns a
|
|
22
|
+
// concrete environment, with `unknown` as the matchable no-resolver-
|
|
23
|
+
// fired case.
|
|
24
|
+
//
|
|
25
|
+
// `risk.severity_at_least` is the ONE exception to a blanket "satisfies
|
|
26
|
+
// every threshold". An unknown severity is risk-bearing: it still
|
|
27
|
+
// satisfies `low`/`medium`/`high`, so an approval-required gate on an
|
|
28
|
+
// unrecognized production command stays fail-closed, but it is not
|
|
29
|
+
// itself proof of the WORST tier: an unclassified profile is treated as
|
|
30
|
+
// sitting at the "high" rung, one below `critical`, for this one clause
|
|
31
|
+
// only, so it never triggers a hard, agent-unoverridable block on its
|
|
32
|
+
// own. A hard block deserves a real classification.
|
|
33
|
+
//
|
|
34
|
+
// The rule is deliberately paired with two things this module does NOT
|
|
35
|
+
// do: (1) it does not touch `risk.category_in` / `action.reversible`,
|
|
36
|
+
// which keep the full "satisfies everything" fallback; (2) it leans on
|
|
37
|
+
// the Risk Classifier's built-in floors (`read-only-bash.ts`'s
|
|
38
|
+
// read-only floors, `destructive-shell-floor.ts`'s mutating-head floor)
|
|
39
|
+
// and the manifest's `risk.classifiers[]` to make the common cases
|
|
40
|
+
// explicitly `low` or explicitly `high`/`critical`. The "treated as
|
|
41
|
+
// high" rung is a safety net for the genuinely unenumerable case, not a
|
|
42
|
+
// replacement for classification. There is no manifest opt-in to restore
|
|
43
|
+
// the blanket behavior. Rationale, the incident that motivated it, and
|
|
44
|
+
// the disclosed residual gaps: docs/risk-gate.md, "Unclassified actions
|
|
45
|
+
// and the fail-close rule"; the measurement is in the CHANGELOG entry
|
|
46
|
+
// for agent-tasks task 2929c5b7.
|
|
23
47
|
//
|
|
24
48
|
// Design source: lava-ice-logs/2026-04-30/harness-risk-gate-extension.md
|
|
25
49
|
// (design phase D); the null-handling steer is the Phase 7 #3 review
|
|
@@ -29,6 +53,30 @@ import { RiskSeveritySchema } from "../schema/index.js";
|
|
|
29
53
|
// `severity_at_least`. Sourced from the schema enum so a reordering
|
|
30
54
|
// there flows through unchanged — same pattern as the Risk Classifier.
|
|
31
55
|
const SEVERITY_ORDER = RiskSeveritySchema.options;
|
|
56
|
+
// The rung an UNCLASSIFIED action is treated as sitting at for
|
|
57
|
+
// `risk.severity_at_least` comparisons only (see the module header):
|
|
58
|
+
// one below the top of `SEVERITY_ORDER` ("critical"), i.e. "high" on
|
|
59
|
+
// the shipped four-value scale. Derived from the scale's length rather
|
|
60
|
+
// than a literal "high" so a future scale reordering/extension still
|
|
61
|
+
// lands one rung below the top without a second hand-edit.
|
|
62
|
+
//
|
|
63
|
+
// That derivation has a precondition the schema must keep satisfying: a
|
|
64
|
+
// scale with fewer than two rungs has no "one below the top". Asserted
|
|
65
|
+
// at module load rather than left implicit, because a silently negative
|
|
66
|
+
// index would make EVERY threshold comparison fail and quietly disable
|
|
67
|
+
// the fail-close for unclassified actions.
|
|
68
|
+
if (SEVERITY_ORDER.length < 2) {
|
|
69
|
+
throw new Error(`when-eval: the severity scale must have at least two rungs for the ` +
|
|
70
|
+
`unclassified fallback to sit one below the top (got ${SEVERITY_ORDER.length})`);
|
|
71
|
+
}
|
|
72
|
+
const UNCLASSIFIED_FALLBACK_SEVERITY_INDEX = SEVERITY_ORDER.length - 2;
|
|
73
|
+
/**
|
|
74
|
+
* The severity NAME the unclassified fallback is treated as, for
|
|
75
|
+
* surfaces that have to say it out loud (`intercept.ts`'s deny
|
|
76
|
+
* envelope). Exported so no caller hard-codes "high" beside a constant
|
|
77
|
+
* that is derived.
|
|
78
|
+
*/
|
|
79
|
+
export const UNCLASSIFIED_FALLBACK_SEVERITY = SEVERITY_ORDER[UNCLASSIFIED_FALLBACK_SEVERITY_INDEX];
|
|
32
80
|
function severityIndex(severity) {
|
|
33
81
|
return SEVERITY_ORDER.indexOf(severity);
|
|
34
82
|
}
|
|
@@ -37,8 +85,10 @@ function severityIndex(severity) {
|
|
|
37
85
|
*
|
|
38
86
|
* Every clause is optional; only declared clauses are evaluated, and
|
|
39
87
|
* `matched` is their AND. An unclassified risk profile (`classified:
|
|
40
|
-
* false`) satisfies
|
|
41
|
-
* not safe" rule
|
|
88
|
+
* false`) satisfies `risk.category_in` / `action.reversible` by the
|
|
89
|
+
* "unknown is not safe" rule, and satisfies `risk.severity_at_least`
|
|
90
|
+
* up through `high` but never `critical` (see the module header);
|
|
91
|
+
* `environment.name` is always a plain equality test.
|
|
42
92
|
*/
|
|
43
93
|
export function evaluateWhen(when, ctx) {
|
|
44
94
|
const clauses = [];
|
|
@@ -49,9 +99,12 @@ export function evaluateWhen(when, ctx) {
|
|
|
49
99
|
let matched;
|
|
50
100
|
let actual;
|
|
51
101
|
if (unclassified) {
|
|
52
|
-
// severity is null —
|
|
53
|
-
|
|
54
|
-
|
|
102
|
+
// severity is null — treated as risk-bearing at the "high" rung
|
|
103
|
+
// (SEVERITY_ORDER.length - 2), not at "critical": satisfies
|
|
104
|
+
// low/medium/high thresholds, but never critical on its own. See
|
|
105
|
+
// the module header for why (task 2929c5b7).
|
|
106
|
+
matched = UNCLASSIFIED_FALLBACK_SEVERITY_INDEX >= severityIndex(sevAtLeast);
|
|
107
|
+
actual = "null (unclassified, treated as high)";
|
|
55
108
|
unclassifiedFallback = true;
|
|
56
109
|
}
|
|
57
110
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"when-eval.js","sourceRoot":"","sources":["../../src/runtime/when-eval.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,kEAAkE;AAClE,qEAAqE;AACrE,sEAAsE;AACtE,sEAAsE;AACtE,gCAAgC;AAChC,EAAE;AACF,uEAAuE;AACvE,mEAAmE;AACnE,sDAAsD;AACtD,EAAE;AACF,oEAAoE;AACpE,oEAAoE;AACpE,kEAAkE;AAClE,iEAAiE;AACjE,qEAAqE;AACrE,
|
|
1
|
+
{"version":3,"file":"when-eval.js","sourceRoot":"","sources":["../../src/runtime/when-eval.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,EAAE;AACF,kEAAkE;AAClE,qEAAqE;AACrE,sEAAsE;AACtE,sEAAsE;AACtE,gCAAgC;AAChC,EAAE;AACF,uEAAuE;AACvE,mEAAmE;AACnE,sDAAsD;AACtD,EAAE;AACF,oEAAoE;AACpE,oEAAoE;AACpE,kEAAkE;AAClE,iEAAiE;AACjE,2DAA2D;AAC3D,uEAAuE;AACvE,qEAAqE;AACrE,8DAA8D;AAC9D,uEAAuE;AACvE,qEAAqE;AACrE,cAAc;AACd,EAAE;AACF,wEAAwE;AACxE,kEAAkE;AAClE,sEAAsE;AACtE,mEAAmE;AACnE,wEAAwE;AACxE,wEAAwE;AACxE,sEAAsE;AACtE,oDAAoD;AACpD,EAAE;AACF,uEAAuE;AACvE,sEAAsE;AACtE,uEAAuE;AACvE,+DAA+D;AAC/D,wEAAwE;AACxE,mEAAmE;AACnE,oEAAoE;AACpE,wEAAwE;AACxE,yEAAyE;AACzE,uEAAuE;AACvE,wEAAwE;AACxE,sEAAsE;AACtE,iCAAiC;AACjC,EAAE;AACF,yEAAyE;AACzE,qEAAqE;AACrE,8CAA8C;AAG9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAKxD,6DAA6D;AAC7D,oEAAoE;AACpE,uEAAuE;AACvE,MAAM,cAAc,GAAsB,kBAAkB,CAAC,OAAO,CAAC;AAErE,+DAA+D;AAC/D,qEAAqE;AACrE,qEAAqE;AACrE,uEAAuE;AACvE,qEAAqE;AACrE,2DAA2D;AAC3D,EAAE;AACF,wEAAwE;AACxE,uEAAuE;AACvE,wEAAwE;AACxE,uEAAuE;AACvE,2CAA2C;AAC3C,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;IAC9B,MAAM,IAAI,KAAK,CACb,qEAAqE;QACnE,uDAAuD,cAAc,CAAC,MAAM,GAAG,CAClF,CAAC;AACJ,CAAC;AACD,MAAM,oCAAoC,GAAG,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,8BAA8B,GACzC,cAAc,CAAC,oCAAoC,CAAE,CAAC;AAmDxD,SAAS,aAAa,CAAC,QAAgB;IACrC,OAAO,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAgB,EAChB,GAAgB;IAEhB,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,IAAI,oBAAoB,GAAG,KAAK,CAAC;IACjC,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC;IAE1C,MAAM,UAAU,GAAG,IAAI,CAAC,wBAAwB,CAAC,CAAC;IAClD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,IAAI,OAAgB,CAAC;QACrB,IAAI,MAAc,CAAC;QACnB,IAAI,YAAY,EAAE,CAAC;YACjB,gEAAgE;YAChE,4DAA4D;YAC5D,iEAAiE;YACjE,6CAA6C;YAC7C,OAAO,GAAG,oCAAoC,IAAI,aAAa,CAAC,UAAU,CAAC,CAAC;YAC5E,MAAM,GAAG,sCAAsC,CAAC;YAChD,oBAAoB,GAAG,IAAI,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,OAAO;gBACL,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,QAAS,CAAC,IAAI,aAAa,CAAC,UAAU,CAAC,CAAC;YACjE,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,QAAS,CAAC;QAC9B,CAAC;QACD,OAAO,CAAC,IAAI,CAAC;YACX,MAAM,EAAE,wBAAwB;YAChC,QAAQ,EAAE,MAAM,UAAU,EAAE;YAC5B,MAAM;YACN,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC5C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,IAAI,OAAgB,CAAC;QACrB,IAAI,MAAc,CAAC;QACnB,IAAI,YAAY,EAAE,CAAC;YACjB,gEAAgE;YAChE,+DAA+D;YAC/D,4DAA4D;YAC5D,yDAAyD;YACzD,OAAO,GAAG,IAAI,CAAC;YACf,MAAM,GAAG,mBAAmB,CAAC;YAC7B,oBAAoB,GAAG,IAAI,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;YAClE,MAAM;gBACJ,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;oBAC5B,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;oBACvC,CAAC,CAAC,IAAI,CAAC;QACb,CAAC;QACD,OAAO,CAAC,IAAI,CAAC;YACX,MAAM,EAAE,kBAAkB;YAC1B,QAAQ,EAAE,WAAW,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;YAC7C,MAAM;YACN,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACzC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,CAAC,IAAI,CAAC;YACX,MAAM,EAAE,kBAAkB;YAC1B,QAAQ,EAAE,OAAO;YACjB,MAAM,EAAE,GAAG,CAAC,WAAW,CAAC,IAAI;YAC5B,OAAO,EAAE,GAAG,CAAC,WAAW,CAAC,IAAI,KAAK,OAAO;SAC1C,CAAC,CAAC;IACL,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC7C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,IAAI,OAAgB,CAAC;QACrB,IAAI,MAAc,CAAC;QACnB,IAAI,YAAY,EAAE,CAAC;YACjB,8DAA8D;YAC9D,iEAAiE;YACjE,gEAAgE;YAChE,OAAO,GAAG,IAAI,CAAC;YACf,MAAM,GAAG,qBAAqB,CAAC;YAC/B,oBAAoB,GAAG,IAAI,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,UAAU,CAAC;YAC7C,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,CAAC,IAAI,CAAC;YACX,MAAM,EAAE,mBAAmB;YAC3B,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC;YAC5B,MAAM;YACN,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED,wEAAwE;IACxE,uEAAuE;IACvE,0DAA0D;IAC1D,2DAA2D;IAC3D,qEAAqE;IACrE,sEAAsE;IACtE,sEAAsE;IACtE,qEAAqE;IACrE,uEAAuE;IACvE,sEAAsE;IACtE,iEAAiE;IACjE,sBAAsB;IACtB,MAAM,oBAAoB,GAAG,IAAI,CAAC,qCAAqC,CAAC,CAAC;IACzE,IAAI,oBAAoB,KAAK,SAAS,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC;QAC3C,MAAM,kBAAkB,GAAG,OAAO,EAAE,YAAY,IAAI,KAAK,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC;YACX,MAAM,EAAE,qCAAqC;YAC7C,QAAQ,EAAE,MAAM,CAAC,oBAAoB,CAAC;YACtC,MAAM,EACJ,OAAO,KAAK,IAAI;gBACd,CAAC,CAAC,gDAAgD;gBAClD,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC;YAChC,OAAO,EAAE,kBAAkB,KAAK,oBAAoB;SACrD,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QACxC,OAAO;QACP,oBAAoB;KACrB,CAAC;AACJ,CAAC"}
|
|
@@ -15,11 +15,20 @@ import type { Manifest, Policy, Workflow } from "../schema/index.js";
|
|
|
15
15
|
* later index in the same workflow) by a `merge` step. When BOTH
|
|
16
16
|
* `require-review-evidence` and `require-review-evidence-bash` are
|
|
17
17
|
* declared in `manifest.hooks[]`, `deriveWorkflowGatePolicies` returns
|
|
18
|
-
* the SAME
|
|
18
|
+
* the SAME policies `harness init --template full` would hand-author
|
|
19
19
|
* (`src/cli/init/templates.ts` `review-before-merge` /
|
|
20
20
|
* `review-before-merge-bash`), renamed per workflow so the provenance
|
|
21
21
|
* is visible in `harness list policies` / `harness explain`.
|
|
22
22
|
*
|
|
23
|
+
* Task 2699b476 added the two task-scoped merge surfaces to that set:
|
|
24
|
+
* `review-before-task-merge` (`mcp__agent-tasks__task_merge`) and
|
|
25
|
+
* `review-before-task-finish-automerge`
|
|
26
|
+
* (`mcp__agent-tasks__task_finish` narrowed by `trigger.input_match` to
|
|
27
|
+
* `autoMerge: true`), each derived only when its own hook
|
|
28
|
+
* (`require-review-evidence-task-merge` /
|
|
29
|
+
* `require-review-evidence-task-finish`) is declared. A manifest that
|
|
30
|
+
* predates those hooks derives exactly the pair it always did.
|
|
31
|
+
*
|
|
23
32
|
* Deliberately does NOT touch `src/runtime/intercept.ts`: the engine
|
|
24
33
|
* already knows how to evaluate a `Policy`, so the only thing missing
|
|
25
34
|
* was a `Policy` to hand it. `src/cli/loader.ts#loadManifest` calls
|
|
@@ -68,8 +77,41 @@ import type { Manifest, Policy, Workflow } from "../schema/index.js";
|
|
|
68
77
|
/** The two hooks templates.ts wires for the hand-authored merge gate. */
|
|
69
78
|
export declare const REVIEW_EVIDENCE_HOOK_MCP = "require-review-evidence";
|
|
70
79
|
export declare const REVIEW_EVIDENCE_HOOK_BASH = "require-review-evidence-bash";
|
|
80
|
+
/**
|
|
81
|
+
* The two hooks templates.ts wires for the task-scoped merge surfaces
|
|
82
|
+
* (task 2699b476). Unlike the pair above these are NOT part of
|
|
83
|
+
* `hasWiredMergeGateHooks`: a manifest that predates them still derives
|
|
84
|
+
* the `pull_requests_merge` / `gh pr merge` gates exactly as before, and
|
|
85
|
+
* each task-scoped gate is derived only when ITS OWN hook is declared.
|
|
86
|
+
*
|
|
87
|
+
* That per-hook gating is not a style choice. A derived policy's `hook:`
|
|
88
|
+
* must name a declared hook (`ManifestSchema`'s superRefine), and, more
|
|
89
|
+
* importantly, the hook's `match` is what `harness apply` projects into
|
|
90
|
+
* settings.json's tool-name matcher: without a matcher for
|
|
91
|
+
* `mcp__agent-tasks__task_merge`, Claude Code never spawns `harness
|
|
92
|
+
* policy intercept` for that verb, so a gate derived anyway would be
|
|
93
|
+
* INERT while looking enforced in `harness list policies` (the exact
|
|
94
|
+
* "No-Op that LOOKS protective" shape `checkWorkflowGateWiring` exists
|
|
95
|
+
* to prevent). Deriving nothing until the hook is wired keeps the
|
|
96
|
+
* absence visible instead of fake-covering it.
|
|
97
|
+
*/
|
|
98
|
+
export declare const REVIEW_EVIDENCE_HOOK_TASK_MERGE = "require-review-evidence-task-merge";
|
|
99
|
+
export declare const REVIEW_EVIDENCE_HOOK_TASK_FINISH = "require-review-evidence-task-finish";
|
|
71
100
|
export declare const MERGE_MCP_MATCH = "mcp__agent-tasks__pull_requests_merge";
|
|
72
101
|
export declare const MERGE_BASH_MATCH = "(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S+\\s+)*gh pr merge\\b";
|
|
102
|
+
export declare const TASK_MERGE_MCP_MATCH = "mcp__agent-tasks__task_merge";
|
|
103
|
+
export declare const TASK_FINISH_MCP_MATCH = "mcp__agent-tasks__task_finish";
|
|
104
|
+
/**
|
|
105
|
+
* The `trigger.input_match` predicate that separates the merging mode of
|
|
106
|
+
* `task_finish` from the ordinary one. Both auto-merge modes the MCP
|
|
107
|
+
* server documents (soloMode work claim, review claim + approve) carry
|
|
108
|
+
* `autoMerge: true`; a plain finish omits the argument entirely, and a
|
|
109
|
+
* missing path never satisfies an `input_match` entry, so the gate stays
|
|
110
|
+
* out of the way of the non-merging call.
|
|
111
|
+
*/
|
|
112
|
+
export declare const TASK_FINISH_AUTOMERGE_INPUT_MATCH: Record<string, boolean>;
|
|
113
|
+
/** `toolArgs.taskId` is the only identifier either task-scoped verb carries. */
|
|
114
|
+
export declare const TASK_ID_EXTRACT: Record<string, string>;
|
|
73
115
|
/**
|
|
74
116
|
* True when `workflow.steps` contains a `review_subagent` step with
|
|
75
117
|
* `spawn: "required"` at an index earlier than some `merge` step
|
|
@@ -14,11 +14,20 @@
|
|
|
14
14
|
* later index in the same workflow) by a `merge` step. When BOTH
|
|
15
15
|
* `require-review-evidence` and `require-review-evidence-bash` are
|
|
16
16
|
* declared in `manifest.hooks[]`, `deriveWorkflowGatePolicies` returns
|
|
17
|
-
* the SAME
|
|
17
|
+
* the SAME policies `harness init --template full` would hand-author
|
|
18
18
|
* (`src/cli/init/templates.ts` `review-before-merge` /
|
|
19
19
|
* `review-before-merge-bash`), renamed per workflow so the provenance
|
|
20
20
|
* is visible in `harness list policies` / `harness explain`.
|
|
21
21
|
*
|
|
22
|
+
* Task 2699b476 added the two task-scoped merge surfaces to that set:
|
|
23
|
+
* `review-before-task-merge` (`mcp__agent-tasks__task_merge`) and
|
|
24
|
+
* `review-before-task-finish-automerge`
|
|
25
|
+
* (`mcp__agent-tasks__task_finish` narrowed by `trigger.input_match` to
|
|
26
|
+
* `autoMerge: true`), each derived only when its own hook
|
|
27
|
+
* (`require-review-evidence-task-merge` /
|
|
28
|
+
* `require-review-evidence-task-finish`) is declared. A manifest that
|
|
29
|
+
* predates those hooks derives exactly the pair it always did.
|
|
30
|
+
*
|
|
22
31
|
* Deliberately does NOT touch `src/runtime/intercept.ts`: the engine
|
|
23
32
|
* already knows how to evaluate a `Policy`, so the only thing missing
|
|
24
33
|
* was a `Policy` to hand it. `src/cli/loader.ts#loadManifest` calls
|
|
@@ -67,6 +76,26 @@
|
|
|
67
76
|
/** The two hooks templates.ts wires for the hand-authored merge gate. */
|
|
68
77
|
export const REVIEW_EVIDENCE_HOOK_MCP = "require-review-evidence";
|
|
69
78
|
export const REVIEW_EVIDENCE_HOOK_BASH = "require-review-evidence-bash";
|
|
79
|
+
/**
|
|
80
|
+
* The two hooks templates.ts wires for the task-scoped merge surfaces
|
|
81
|
+
* (task 2699b476). Unlike the pair above these are NOT part of
|
|
82
|
+
* `hasWiredMergeGateHooks`: a manifest that predates them still derives
|
|
83
|
+
* the `pull_requests_merge` / `gh pr merge` gates exactly as before, and
|
|
84
|
+
* each task-scoped gate is derived only when ITS OWN hook is declared.
|
|
85
|
+
*
|
|
86
|
+
* That per-hook gating is not a style choice. A derived policy's `hook:`
|
|
87
|
+
* must name a declared hook (`ManifestSchema`'s superRefine), and, more
|
|
88
|
+
* importantly, the hook's `match` is what `harness apply` projects into
|
|
89
|
+
* settings.json's tool-name matcher: without a matcher for
|
|
90
|
+
* `mcp__agent-tasks__task_merge`, Claude Code never spawns `harness
|
|
91
|
+
* policy intercept` for that verb, so a gate derived anyway would be
|
|
92
|
+
* INERT while looking enforced in `harness list policies` (the exact
|
|
93
|
+
* "No-Op that LOOKS protective" shape `checkWorkflowGateWiring` exists
|
|
94
|
+
* to prevent). Deriving nothing until the hook is wired keeps the
|
|
95
|
+
* absence visible instead of fake-covering it.
|
|
96
|
+
*/
|
|
97
|
+
export const REVIEW_EVIDENCE_HOOK_TASK_MERGE = "require-review-evidence-task-merge";
|
|
98
|
+
export const REVIEW_EVIDENCE_HOOK_TASK_FINISH = "require-review-evidence-task-finish";
|
|
70
99
|
// Exported (review round 2, F5) so `src/cli/validate/checks.ts` can check a
|
|
71
100
|
// declared hook's `match`/`bash_match` against the EXACT surface the
|
|
72
101
|
// derivation binds to, instead of trusting the hook name alone. See
|
|
@@ -78,6 +107,25 @@ export const MERGE_MCP_MATCH = "mcp__agent-tasks__pull_requests_merge";
|
|
|
78
107
|
// by tests/runtime/workflow-policies.test.ts's parity assertion so the
|
|
79
108
|
// two cannot silently drift apart).
|
|
80
109
|
export const MERGE_BASH_MATCH = "(^|\\n|;|\\||&|\\()\\s*(\\w+=\\S+\\s+)*gh pr merge\\b";
|
|
110
|
+
// The two task-scoped agent-tasks merge surfaces (task 2699b476), pinned
|
|
111
|
+
// here the same way `MERGE_MCP_MATCH` / `MERGE_BASH_MATCH` are and held
|
|
112
|
+
// byte-identical to templates.ts by this module's parity assertion in
|
|
113
|
+
// tests/runtime/workflow-policies.test.ts.
|
|
114
|
+
export const TASK_MERGE_MCP_MATCH = "mcp__agent-tasks__task_merge";
|
|
115
|
+
export const TASK_FINISH_MCP_MATCH = "mcp__agent-tasks__task_finish";
|
|
116
|
+
/**
|
|
117
|
+
* The `trigger.input_match` predicate that separates the merging mode of
|
|
118
|
+
* `task_finish` from the ordinary one. Both auto-merge modes the MCP
|
|
119
|
+
* server documents (soloMode work claim, review claim + approve) carry
|
|
120
|
+
* `autoMerge: true`; a plain finish omits the argument entirely, and a
|
|
121
|
+
* missing path never satisfies an `input_match` entry, so the gate stays
|
|
122
|
+
* out of the way of the non-merging call.
|
|
123
|
+
*/
|
|
124
|
+
export const TASK_FINISH_AUTOMERGE_INPUT_MATCH = {
|
|
125
|
+
"toolArgs.autoMerge": true,
|
|
126
|
+
};
|
|
127
|
+
/** `toolArgs.taskId` is the only identifier either task-scoped verb carries. */
|
|
128
|
+
export const TASK_ID_EXTRACT = { TASK_ID: "toolArgs.taskId" };
|
|
81
129
|
/**
|
|
82
130
|
* True when `workflow.steps` contains a `review_subagent` step with
|
|
83
131
|
* `spawn: "required"` at an index earlier than some `merge` step
|
|
@@ -118,9 +166,34 @@ function triggerSurfaceKey(policy) {
|
|
|
118
166
|
event: policy.trigger.event,
|
|
119
167
|
match: policy.trigger.match ?? null,
|
|
120
168
|
bash_match: policy.trigger.bash_match ?? null,
|
|
169
|
+
input_match: inputMatchKey(policy),
|
|
121
170
|
ledger_tag: policy.requires?.ledger_tag ?? null,
|
|
122
171
|
});
|
|
123
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Canonical form of `trigger.input_match` for the surface key: key-sorted
|
|
175
|
+
* so authoring order does not change identity, `null` when the policy
|
|
176
|
+
* declares none.
|
|
177
|
+
*
|
|
178
|
+
* `input_match` is part of the SURFACE, not of the extract comparison
|
|
179
|
+
* (task 2699b476): two policies on `mcp__agent-tasks__task_finish` that
|
|
180
|
+
* disagree about which `autoMerge` value they gate intercept DIFFERENT
|
|
181
|
+
* tool calls, so they are no more interchangeable than a policy on a
|
|
182
|
+
* different tool name would be. Leaving it out of the key would let a
|
|
183
|
+
* hand-authored `input_match: { toolArgs.autoMerge: false }` policy dedupe
|
|
184
|
+
* the derived `autoMerge: true` gate away and leave the merging call
|
|
185
|
+
* ungated while the manifest still reads as covered.
|
|
186
|
+
*/
|
|
187
|
+
function inputMatchKey(policy) {
|
|
188
|
+
const inputMatch = policy.trigger.input_match;
|
|
189
|
+
if (inputMatch === undefined)
|
|
190
|
+
return null;
|
|
191
|
+
const sorted = {};
|
|
192
|
+
for (const key of Object.keys(inputMatch).sort()) {
|
|
193
|
+
sorted[key] = inputMatch[key];
|
|
194
|
+
}
|
|
195
|
+
return sorted;
|
|
196
|
+
}
|
|
124
197
|
/**
|
|
125
198
|
* Canonical form of `trigger.extract` for equality: key-sorted so two
|
|
126
199
|
* maps that declare the same variables from the same paths compare equal
|
|
@@ -264,6 +337,76 @@ function buildBashMergeGatePolicy(workflowName) {
|
|
|
264
337
|
},
|
|
265
338
|
};
|
|
266
339
|
}
|
|
340
|
+
/**
|
|
341
|
+
* The two task-scoped merge gates (task 2699b476), structurally identical
|
|
342
|
+
* to templates.ts's `review-before-task-merge` /
|
|
343
|
+
* `review-before-task-finish-automerge` apart from name and description.
|
|
344
|
+
* They key on `review:${TASK_ID}` rather than the PR number because both
|
|
345
|
+
* verbs derive owner/repo/PR from the task, so `toolArgs.taskId` is the
|
|
346
|
+
* only identifier in the payload; `harness record review --pr <pr> --task
|
|
347
|
+
* <id>` writes both tag families in ONE fact so a single recorded review
|
|
348
|
+
* opens every merge surface.
|
|
349
|
+
*/
|
|
350
|
+
function buildTaskMergeGatePolicy(workflowName) {
|
|
351
|
+
return {
|
|
352
|
+
name: `workflow:${workflowName}:review-before-task-merge`,
|
|
353
|
+
description: `Derived from workflows[] (workflow "${workflowName}"): a review_subagent step ` +
|
|
354
|
+
`with spawn: "required" precedes a merge step, so block agent-tasks task_merge ` +
|
|
355
|
+
"unless a ledger entry tagged review:<task-id> exists for this session.",
|
|
356
|
+
trigger: {
|
|
357
|
+
event: "PreToolUse",
|
|
358
|
+
match: TASK_MERGE_MCP_MATCH,
|
|
359
|
+
extract: { ...TASK_ID_EXTRACT },
|
|
360
|
+
},
|
|
361
|
+
requires: { ledger_tag: "review:${TASK_ID}" },
|
|
362
|
+
hook: REVIEW_EVIDENCE_HOOK_TASK_MERGE,
|
|
363
|
+
enforcement: "block",
|
|
364
|
+
producers: [
|
|
365
|
+
{
|
|
366
|
+
kind: "mcp",
|
|
367
|
+
verb: "mcp__grounding-mcp__ledger_add",
|
|
368
|
+
example: '{sessionId:"${SESSION_ID}", type:"fact", content:"review:${TASK_ID}: <verdict + key findings + nits>", source:"Agent(general-purpose) review"}',
|
|
369
|
+
description: "Spawn a review subagent against the PR diff, capture its verdict, then persist a ledger entry tagged with the task id. Mirror of the review-before-merge producer for the task-scoped merge surface.",
|
|
370
|
+
},
|
|
371
|
+
],
|
|
372
|
+
ux: {
|
|
373
|
+
cannot: "You cannot merge the PR for task ${TASK_ID} yet.",
|
|
374
|
+
required: ["a recorded review of task ${TASK_ID}"],
|
|
375
|
+
run: ['harness record review --pr <pr> --task ${TASK_ID} "<summary>"'],
|
|
376
|
+
},
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
function buildTaskFinishAutoMergeGatePolicy(workflowName) {
|
|
380
|
+
return {
|
|
381
|
+
name: `workflow:${workflowName}:review-before-task-finish-automerge`,
|
|
382
|
+
description: `Derived from workflows[] (workflow "${workflowName}"): a review_subagent step ` +
|
|
383
|
+
`with spawn: "required" precedes a merge step, so block agent-tasks task_finish ` +
|
|
384
|
+
"in its auto-merge mode unless a ledger entry tagged review:<task-id> exists for " +
|
|
385
|
+
"this session.",
|
|
386
|
+
trigger: {
|
|
387
|
+
event: "PreToolUse",
|
|
388
|
+
match: TASK_FINISH_MCP_MATCH,
|
|
389
|
+
input_match: { ...TASK_FINISH_AUTOMERGE_INPUT_MATCH },
|
|
390
|
+
extract: { ...TASK_ID_EXTRACT },
|
|
391
|
+
},
|
|
392
|
+
requires: { ledger_tag: "review:${TASK_ID}" },
|
|
393
|
+
hook: REVIEW_EVIDENCE_HOOK_TASK_FINISH,
|
|
394
|
+
enforcement: "block",
|
|
395
|
+
producers: [
|
|
396
|
+
{
|
|
397
|
+
kind: "mcp",
|
|
398
|
+
verb: "mcp__grounding-mcp__ledger_add",
|
|
399
|
+
example: '{sessionId:"${SESSION_ID}", type:"fact", content:"review:${TASK_ID}: <verdict + key findings + nits>", source:"Agent(general-purpose) review"}',
|
|
400
|
+
description: "Spawn a review subagent against the PR diff, capture its verdict, then persist a ledger entry tagged with the task id. Same evidence the task_merge gate reads, so one recorded review opens both.",
|
|
401
|
+
},
|
|
402
|
+
],
|
|
403
|
+
ux: {
|
|
404
|
+
cannot: "You cannot finish task ${TASK_ID} with autoMerge yet.",
|
|
405
|
+
required: ["a recorded review of task ${TASK_ID}"],
|
|
406
|
+
run: ['harness record review --pr <pr> --task ${TASK_ID} "<summary>"'],
|
|
407
|
+
},
|
|
408
|
+
};
|
|
409
|
+
}
|
|
267
410
|
// F7 (review round 2): a registry of every `Policy` object this module has
|
|
268
411
|
// ever handed back from `deriveWorkflowGatePolicies`. `WeakSet` keys on
|
|
269
412
|
// object identity, not value equality, deliberately: two DIFFERENT
|
|
@@ -306,6 +449,7 @@ function deriveWorkflowGates(manifest) {
|
|
|
306
449
|
if (!hasWiredMergeGateHooks(manifest))
|
|
307
450
|
return empty;
|
|
308
451
|
const hand = handAuthoredPolicies(manifest);
|
|
452
|
+
const declaredHookNames = new Set(manifest.hooks.map((h) => h.name));
|
|
309
453
|
const bySurface = new Map();
|
|
310
454
|
for (const policy of hand) {
|
|
311
455
|
const key = triggerSurfaceKey(policy);
|
|
@@ -327,8 +471,21 @@ function deriveWorkflowGates(manifest) {
|
|
|
327
471
|
const candidates = [
|
|
328
472
|
{ policy: buildMcpMergeGatePolicy(workflow.name), surface: MERGE_MCP_MATCH },
|
|
329
473
|
{ policy: buildBashMergeGatePolicy(workflow.name), surface: "`gh pr merge` (Bash)" },
|
|
474
|
+
{ policy: buildTaskMergeGatePolicy(workflow.name), surface: TASK_MERGE_MCP_MATCH },
|
|
475
|
+
{
|
|
476
|
+
policy: buildTaskFinishAutoMergeGatePolicy(workflow.name),
|
|
477
|
+
surface: `${TASK_FINISH_MCP_MATCH} (autoMerge: true)`,
|
|
478
|
+
},
|
|
330
479
|
];
|
|
331
480
|
for (const { policy: candidate, surface } of candidates) {
|
|
481
|
+
// A candidate whose own hook is not declared is skipped rather than
|
|
482
|
+
// derived (task 2699b476): see REVIEW_EVIDENCE_HOOK_TASK_MERGE's
|
|
483
|
+
// doc for why an unwired hook makes a derived gate inert rather
|
|
484
|
+
// than enforcing. `hasWiredMergeGateHooks` above already guarantees
|
|
485
|
+
// this holds for the two pull_requests_merge / gh pr merge
|
|
486
|
+
// candidates, so their behaviour is unchanged.
|
|
487
|
+
if (!declaredHookNames.has(candidate.hook))
|
|
488
|
+
continue;
|
|
332
489
|
const key = triggerSurfaceKey(candidate);
|
|
333
490
|
if (seen.has(key))
|
|
334
491
|
continue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-policies.js","sourceRoot":"","sources":["../../src/runtime/workflow-policies.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"workflow-policies.js","sourceRoot":"","sources":["../../src/runtime/workflow-policies.ts"],"names":[],"mappings":"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"}
|