@lannguyensi/harness 0.49.0 → 0.51.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 +791 -0
- package/dist/cli/add/index.js +15 -3
- package/dist/cli/add/index.js.map +1 -1
- package/dist/cli/apply/apply.js +19 -3
- package/dist/cli/apply/apply.js.map +1 -1
- package/dist/cli/approve/risk.d.ts +28 -2
- package/dist/cli/approve/risk.js +14 -4
- package/dist/cli/approve/risk.js.map +1 -1
- package/dist/cli/approve/understanding.d.ts +51 -0
- package/dist/cli/approve/understanding.js +17 -2
- package/dist/cli/approve/understanding.js.map +1 -1
- package/dist/cli/diff/index.js +22 -1
- package/dist/cli/diff/index.js.map +1 -1
- package/dist/cli/doctor/claude-mcp.d.ts +14 -0
- package/dist/cli/doctor/claude-mcp.js +7 -1
- package/dist/cli/doctor/claude-mcp.js.map +1 -1
- package/dist/cli/doctor/format.js +48 -3
- package/dist/cli/doctor/format.js.map +1 -1
- package/dist/cli/doctor/index.d.ts +20 -0
- package/dist/cli/doctor/index.js +66 -2
- package/dist/cli/doctor/index.js.map +1 -1
- package/dist/cli/doctor/settings-drift.d.ts +19 -0
- package/dist/cli/doctor/settings-drift.js +189 -0
- package/dist/cli/doctor/settings-drift.js.map +1 -0
- package/dist/cli/doctor/types.d.ts +52 -0
- package/dist/cli/doctor/types.js.map +1 -1
- package/dist/cli/doctor/ug-auto-approvals.d.ts +40 -0
- package/dist/cli/doctor/ug-auto-approvals.js +116 -0
- package/dist/cli/doctor/ug-auto-approvals.js.map +1 -0
- package/dist/cli/doctor/understanding-mode-env.d.ts +10 -0
- package/dist/cli/doctor/understanding-mode-env.js +12 -0
- package/dist/cli/doctor/understanding-mode-env.js.map +1 -1
- package/dist/cli/explain-policy.d.ts +4 -1
- package/dist/cli/explain-policy.js +12 -2
- package/dist/cli/explain-policy.js.map +1 -1
- package/dist/cli/export.js +12 -1
- package/dist/cli/export.js.map +1 -1
- package/dist/cli/index.js +40 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init/templates.d.ts +1 -1
- package/dist/cli/init/templates.js +65 -1
- package/dist/cli/init/templates.js.map +1 -1
- package/dist/cli/list.js +6 -0
- package/dist/cli/list.js.map +1 -1
- package/dist/cli/loader.js +15 -0
- package/dist/cli/loader.js.map +1 -1
- package/dist/cli/pack/auto-approve-path.d.ts +118 -0
- package/dist/cli/pack/auto-approve-path.js +347 -0
- package/dist/cli/pack/auto-approve-path.js.map +1 -0
- package/dist/cli/pack/hook-codex-pre-tool-use.d.ts +9 -0
- package/dist/cli/pack/hook-codex-pre-tool-use.js +129 -10
- package/dist/cli/pack/hook-codex-pre-tool-use.js.map +1 -1
- package/dist/cli/pack/hook-post-tool-use.d.ts +6 -4
- package/dist/cli/pack/hook-post-tool-use.js.map +1 -1
- package/dist/cli/pack/hook-pre-tool-use.d.ts +11 -0
- package/dist/cli/pack/hook-pre-tool-use.js +90 -23
- package/dist/cli/pack/hook-pre-tool-use.js.map +1 -1
- package/dist/cli/remove/index.d.ts +12 -0
- package/dist/cli/remove/index.js +89 -0
- package/dist/cli/remove/index.js.map +1 -1
- package/dist/cli/validate/checks.d.ts +48 -0
- package/dist/cli/validate/checks.js +312 -0
- package/dist/cli/validate/checks.js.map +1 -1
- package/dist/cli/validate/index.js +11 -0
- package/dist/cli/validate/index.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.d.ts +136 -0
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js +224 -0
- package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js.map +1 -0
- package/dist/policy-packs/builtin/understanding-before-execution/index.d.ts +3 -2
- package/dist/policy-packs/builtin/understanding-before-execution/index.js +35 -28
- package/dist/policy-packs/builtin/understanding-before-execution/index.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/markers.js +2 -2
- package/dist/policy-packs/builtin/understanding-before-execution/markers.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.d.ts +29 -0
- package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js +82 -0
- package/dist/policy-packs/builtin/understanding-before-execution/measured-permission-modes.js.map +1 -0
- package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.d.ts +69 -8
- package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js +100 -12
- package/dist/policy-packs/builtin/understanding-before-execution/persisted-reports.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js +6 -3
- package/dist/policy-packs/builtin/understanding-before-execution/post-tool-use-boundary.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution.d.ts +23 -0
- package/dist/policy-packs/builtin/understanding-before-execution.js +36 -9
- package/dist/policy-packs/builtin/understanding-before-execution.js.map +1 -1
- package/dist/runtime/approval-signing.d.ts +22 -0
- package/dist/runtime/approval-signing.js +55 -1
- package/dist/runtime/approval-signing.js.map +1 -1
- package/dist/runtime/command-normalize.d.ts +112 -0
- package/dist/runtime/command-normalize.js +169 -55
- package/dist/runtime/command-normalize.js.map +1 -1
- package/dist/runtime/deletion-target-resolve.d.ts +28 -0
- package/dist/runtime/deletion-target-resolve.js +1055 -0
- package/dist/runtime/deletion-target-resolve.js.map +1 -0
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/intercept.js +17 -1
- package/dist/runtime/intercept.js.map +1 -1
- package/dist/runtime/kubectl-target-parse.d.ts +16 -0
- package/dist/runtime/kubectl-target-parse.js +9 -1
- package/dist/runtime/kubectl-target-parse.js.map +1 -1
- package/dist/runtime/read-only-bash.d.ts +11 -0
- package/dist/runtime/read-only-bash.js +288 -7
- package/dist/runtime/read-only-bash.js.map +1 -1
- package/dist/runtime/risk-classifier.js +14 -1
- package/dist/runtime/risk-classifier.js.map +1 -1
- package/dist/runtime/when-eval.d.ts +11 -2
- package/dist/runtime/when-eval.js +25 -0
- package/dist/runtime/when-eval.js.map +1 -1
- package/dist/runtime/workflow-policies.d.ts +164 -0
- package/dist/runtime/workflow-policies.js +439 -0
- package/dist/runtime/workflow-policies.js.map +1 -0
- package/dist/schema/index.d.ts +24 -0
- package/dist/schema/policies.d.ts +25 -0
- package/dist/schema/policies.js +29 -0
- package/dist/schema/policies.js.map +1 -1
- package/dist/schema/risk.d.ts +6 -0
- package/dist/schema/risk.js +80 -0
- package/dist/schema/risk.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// Settings-drift half of ADR docs/decisions/2026-08-27-ug-auto-mode-approval.md
|
|
2
|
+
// slice 1 (agent-tasks 74b4b17d), threat model (c): "The permission mode
|
|
3
|
+
// itself is settings-derived, and settings files are agent-editable
|
|
4
|
+
// after approval" and "The same settings write also reaches the hook
|
|
5
|
+
// roster, which supplies key two." A post-approval agent can plant
|
|
6
|
+
// `permissions.defaultMode: "bypassPermissions"` (key one) and/or a
|
|
7
|
+
// `UserPromptSubmit`/`SessionStart` hook entry that mints a report for
|
|
8
|
+
// every later session (key two) into a Claude Code settings file, and
|
|
9
|
+
// nothing named that plant before this check: `harness diff
|
|
10
|
+
// --since-apply` only re-hashes the whole `--target` file as a lock
|
|
11
|
+
// entry, so it flags SOME change without naming which key moved.
|
|
12
|
+
//
|
|
13
|
+
// What this module actually has to compare against, verified against
|
|
14
|
+
// the real `apply()` code path (not assumed from the ADR prose):
|
|
15
|
+
//
|
|
16
|
+
// - `.last-apply` (`src/io/last-apply.ts`) stores exactly ONE
|
|
17
|
+
// `files["settings.json"]` entry: harness's own GENERATED
|
|
18
|
+
// settings.json content (`buildExpectedFiles` in apply.ts), keyed by
|
|
19
|
+
// basename, not by which `--target` path it was merged into. Harness
|
|
20
|
+
// never writes `permissions.defaultMode` itself
|
|
21
|
+
// (`generate-settings.ts` has no such key), and `--merge` replaces
|
|
22
|
+
// `hooks` WHOLESALE (`src/io/merge-settings.ts`'s module header: "harness
|
|
23
|
+
// owns whichever top-level keys appear in the generated output...
|
|
24
|
+
// hooks stays wholesale-owned"). So this one snapshot is, for every
|
|
25
|
+
// settings file harness has ever targeted, an accurate "what harness
|
|
26
|
+
// itself put there at apply time" baseline: defaultMode absent
|
|
27
|
+
// (harness never owns it) and hooks exactly the generated roster (no
|
|
28
|
+
// operator hand-added hook entry survives a `--merge`).
|
|
29
|
+
// - `harness.lock` (`src/io/harness-lock.ts`) records which absolute
|
|
30
|
+
// path(s) were an actual `--target` write, as a `kind: "target"`
|
|
31
|
+
// entry. This is how a live settings file is told apart from one
|
|
32
|
+
// harness has never touched: matching against this lock entry is
|
|
33
|
+
// the "SAME path" mapping the file was written under.
|
|
34
|
+
//
|
|
35
|
+
// A file whose absolute path has no `target` lock entry never received
|
|
36
|
+
// harness's baseline at all, so it gets the EMPTY baseline (everything
|
|
37
|
+
// in it reads as "absent at last apply") rather than the shared
|
|
38
|
+
// generated-settings.json baseline.
|
|
39
|
+
//
|
|
40
|
+
// Warnings only, never a block; this is the compensating control named
|
|
41
|
+
// in the ADR, not an enforcement (the enforcing lever is the managed
|
|
42
|
+
// setting in operator decision 7).
|
|
43
|
+
import * as fs from "node:fs";
|
|
44
|
+
import * as path from "node:path";
|
|
45
|
+
import { readLastApply } from "../../io/last-apply.js";
|
|
46
|
+
import { readLock } from "../../io/harness-lock.js";
|
|
47
|
+
import { safeJsonParse } from "../../io/safe-json-parse.js";
|
|
48
|
+
import { resolveSettingsPath as resolveUserSettingsPath } from "./claude-mcp.js";
|
|
49
|
+
function isRecord(v) {
|
|
50
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
51
|
+
}
|
|
52
|
+
function hookIdentityKey(h) {
|
|
53
|
+
return JSON.stringify([h.event, h.matcher, h.type, h.command]);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Enumerate every `hooks[event][].hooks[]` entry in a parsed settings
|
|
57
|
+
* object as an identity tuple. Mirrors the group-parsing convention
|
|
58
|
+
* `collectOwnedHookGroups`/`classifyHookGroup` use in
|
|
59
|
+
* `src/cli/uninstall/index.ts` for the same on-disk shape. Malformed
|
|
60
|
+
* groups/entries are skipped rather than throwing — a live settings.json
|
|
61
|
+
* this check does not own may carry shapes this parser has no opinion
|
|
62
|
+
* about.
|
|
63
|
+
*/
|
|
64
|
+
function collectHookIdentities(hooksValue) {
|
|
65
|
+
const out = [];
|
|
66
|
+
if (!isRecord(hooksValue))
|
|
67
|
+
return out;
|
|
68
|
+
for (const event of Object.keys(hooksValue)) {
|
|
69
|
+
const groups = hooksValue[event];
|
|
70
|
+
if (!Array.isArray(groups))
|
|
71
|
+
continue;
|
|
72
|
+
for (const group of groups) {
|
|
73
|
+
if (!isRecord(group))
|
|
74
|
+
continue;
|
|
75
|
+
const matcher = typeof group["matcher"] === "string" ? group["matcher"] : "";
|
|
76
|
+
const inner = group["hooks"];
|
|
77
|
+
if (!Array.isArray(inner))
|
|
78
|
+
continue;
|
|
79
|
+
for (const h of inner) {
|
|
80
|
+
if (!isRecord(h))
|
|
81
|
+
continue;
|
|
82
|
+
const type = typeof h["type"] === "string" ? h["type"] : "";
|
|
83
|
+
const command = typeof h["command"] === "string" ? h["command"] : "";
|
|
84
|
+
out.push({ event, matcher, type, command });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
function defaultModeOf(settings) {
|
|
91
|
+
const permissions = settings["permissions"];
|
|
92
|
+
if (!isRecord(permissions))
|
|
93
|
+
return undefined;
|
|
94
|
+
const mode = permissions["defaultMode"];
|
|
95
|
+
return typeof mode === "string" ? mode : undefined;
|
|
96
|
+
}
|
|
97
|
+
function checkOneFile(file, baseline, targetAbsPaths, warnings) {
|
|
98
|
+
// Plain read, no readRegularFileRejectingSymlink: this is a live
|
|
99
|
+
// Claude Code settings file (project or user scope), not one of
|
|
100
|
+
// harness's own generated artefacts, and doctor's existing reader for
|
|
101
|
+
// this exact file class (`findDeadSettingsMcpNames` in claude-mcp.ts)
|
|
102
|
+
// already reads it the same way — a missing file resolves to "nothing
|
|
103
|
+
// to report" here too, not a symlink-defense case.
|
|
104
|
+
let raw;
|
|
105
|
+
try {
|
|
106
|
+
raw = fs.readFileSync(file.absolutePath, "utf8");
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const parsed = safeJsonParse(raw);
|
|
112
|
+
if (!isRecord(parsed)) {
|
|
113
|
+
warnings.push(`${file.displayLabel}: unreadable settings JSON`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const live = parsed;
|
|
117
|
+
const hasSnapshot = targetAbsPaths.has(path.resolve(file.absolutePath));
|
|
118
|
+
const effectiveBaseline = hasSnapshot ? baseline : {};
|
|
119
|
+
const suffix = hasSnapshot ? "" : " (no apply snapshot for this file)";
|
|
120
|
+
const liveMode = defaultModeOf(live);
|
|
121
|
+
const baselineMode = defaultModeOf(effectiveBaseline);
|
|
122
|
+
if (liveMode !== undefined && liveMode !== baselineMode) {
|
|
123
|
+
if (baselineMode === undefined) {
|
|
124
|
+
warnings.push(`permissions.defaultMode set in ${file.displayLabel} but absent at last apply: ${liveMode}${suffix}`);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
warnings.push(`permissions.defaultMode set in ${file.displayLabel} changed from ${baselineMode} to ${liveMode}${suffix}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const liveHooks = collectHookIdentities(live["hooks"]);
|
|
131
|
+
const baselineHookKeys = new Set(collectHookIdentities(effectiveBaseline["hooks"]).map(hookIdentityKey));
|
|
132
|
+
for (const h of liveHooks) {
|
|
133
|
+
if (baselineHookKeys.has(hookIdentityKey(h)))
|
|
134
|
+
continue;
|
|
135
|
+
warnings.push(`hook entries in ${file.displayLabel} absent at last apply: ${h.event}/${h.matcher || "*"}${suffix}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/** `~`-relativize `absPath` under `home` for display; never leak the raw absolute path. */
|
|
139
|
+
function tildeize(absPath, home) {
|
|
140
|
+
const resolvedHome = path.resolve(home);
|
|
141
|
+
const resolvedPath = path.resolve(absPath);
|
|
142
|
+
if (resolvedPath === resolvedHome)
|
|
143
|
+
return "~";
|
|
144
|
+
const withSep = resolvedHome.endsWith(path.sep) ? resolvedHome : `${resolvedHome}${path.sep}`;
|
|
145
|
+
if (resolvedPath.startsWith(withSep)) {
|
|
146
|
+
return path.join("~", resolvedPath.slice(withSep.length));
|
|
147
|
+
}
|
|
148
|
+
return absPath;
|
|
149
|
+
}
|
|
150
|
+
export function buildSettingsDrift(opts) {
|
|
151
|
+
const notes = [];
|
|
152
|
+
const warnings = [];
|
|
153
|
+
const lastApply = readLastApply(opts.generatedDir);
|
|
154
|
+
if (lastApply === null) {
|
|
155
|
+
notes.push("no apply snapshot; settings drift not checked");
|
|
156
|
+
return { notes, warnings };
|
|
157
|
+
}
|
|
158
|
+
const baselineRaw = lastApply.files["settings.json"]?.content;
|
|
159
|
+
let baseline = {};
|
|
160
|
+
if (baselineRaw !== undefined) {
|
|
161
|
+
const parsed = safeJsonParse(baselineRaw);
|
|
162
|
+
if (isRecord(parsed))
|
|
163
|
+
baseline = parsed;
|
|
164
|
+
}
|
|
165
|
+
const lockEntries = readLock(opts.lockPath) ?? [];
|
|
166
|
+
const targetAbsPaths = new Set(lockEntries
|
|
167
|
+
.filter((e) => e.kind === "target")
|
|
168
|
+
.map((e) => path.resolve(e.path)));
|
|
169
|
+
const userSettingsPath = resolveUserSettingsPath(opts.home, opts.env);
|
|
170
|
+
const candidates = [
|
|
171
|
+
{
|
|
172
|
+
absolutePath: path.resolve(opts.cwd, ".claude", "settings.json"),
|
|
173
|
+
displayLabel: ".claude/settings.json",
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
absolutePath: path.resolve(opts.cwd, ".claude", "settings.local.json"),
|
|
177
|
+
displayLabel: ".claude/settings.local.json",
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
absolutePath: path.resolve(userSettingsPath),
|
|
181
|
+
displayLabel: tildeize(userSettingsPath, opts.home),
|
|
182
|
+
},
|
|
183
|
+
];
|
|
184
|
+
for (const c of candidates) {
|
|
185
|
+
checkOneFile(c, baseline, targetAbsPaths, warnings);
|
|
186
|
+
}
|
|
187
|
+
return { notes, warnings };
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=settings-drift.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settings-drift.js","sourceRoot":"","sources":["../../../src/cli/doctor/settings-drift.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,8 @@ import type { NpmBinReport } from "./npm-bin-path.js";
|
|
|
9
9
|
import type { RogueLedgerDb } from "./rogue-ledger.js";
|
|
10
10
|
import type { UnderstandingModeEnvDivergence } from "./understanding-mode-env.js";
|
|
11
11
|
import type { ToolchainParitySection } from "./toolchain-parity.js";
|
|
12
|
+
import type { UgAutoApprovalsSection } from "./ug-auto-approvals.js";
|
|
13
|
+
import type { SettingsDriftSection } from "./settings-drift.js";
|
|
12
14
|
/**
|
|
13
15
|
* Phase 6 #6 follow-up — doctor target identifier. Distinct from
|
|
14
16
|
* `Runtime` (which gates `harness apply --runtime`): doctor only adds
|
|
@@ -114,6 +116,14 @@ export interface PolicyEntryReport {
|
|
|
114
116
|
caveat: string;
|
|
115
117
|
/** Present when this policy has an unproduced freshness-gated tag. */
|
|
116
118
|
producerGap?: PolicyProducerGap;
|
|
119
|
+
/**
|
|
120
|
+
* True when this policy object was derived from `workflows[]`
|
|
121
|
+
* (`isDerivedPolicy`, F7, review round 2) rather than hand-authored
|
|
122
|
+
* under `policies:`. Rendered as "(derived from workflows[])" so an
|
|
123
|
+
* operator reading `harness doctor` output can tell provenance apart
|
|
124
|
+
* without cross-referencing `workflows:` themselves.
|
|
125
|
+
*/
|
|
126
|
+
derived?: boolean;
|
|
117
127
|
}
|
|
118
128
|
/**
|
|
119
129
|
* A declared policy pack whose `source` or builtin name does not
|
|
@@ -229,6 +239,24 @@ export interface WorkflowsSectionReport {
|
|
|
229
239
|
declared: number;
|
|
230
240
|
templates: number;
|
|
231
241
|
entries: WorkflowEntryReport[];
|
|
242
|
+
/**
|
|
243
|
+
* `checkWorkflowGateWiring` errors (F3, review round 2, 99f47307 Slice
|
|
244
|
+
* 1): a `spawn: "required"` review-then-merge workflow whose runtime
|
|
245
|
+
* merge gate is not correctly wired (a missing evidence hook, or one
|
|
246
|
+
* declared under the right name but the wrong trigger surface/command).
|
|
247
|
+
* `harness doctor` previously imported checks selectively and never ran
|
|
248
|
+
* this one, so it showed green on exactly this misconfiguration.
|
|
249
|
+
* Delegates to the shared validate check, mirroring `templateDrift`.
|
|
250
|
+
* Each rolls into `errorCount`.
|
|
251
|
+
*/
|
|
252
|
+
errors: string[];
|
|
253
|
+
/**
|
|
254
|
+
* `checkWorkflowGateWeakOverlap` warnings (F1, review round 2): a
|
|
255
|
+
* hand-authored policy sharing a derived gate's trigger surface but
|
|
256
|
+
* weaker than it (does not suppress the derived gate, just worth
|
|
257
|
+
* flagging). Each rolls into `warningCount`.
|
|
258
|
+
*/
|
|
259
|
+
warnings: string[];
|
|
232
260
|
}
|
|
233
261
|
/**
|
|
234
262
|
* Phase 7 #6 — Risk Gate wiring health. Reports whether the three Risk
|
|
@@ -353,6 +381,28 @@ export interface DoctorReport {
|
|
|
353
381
|
* `understanding-mode-env.ts` for the full rationale.
|
|
354
382
|
*/
|
|
355
383
|
understandingModeEnv?: UnderstandingModeEnvDivergence;
|
|
384
|
+
/**
|
|
385
|
+
* Auto-approval listing + last-N metric (ADR
|
|
386
|
+
* docs/decisions/2026-08-27-ug-auto-mode-approval.md slice 1,
|
|
387
|
+
* agent-tasks 74b4b17d, "Audit and doctor"). Present only when the
|
|
388
|
+
* `understanding-before-execution` pack is declared and enabled
|
|
389
|
+
* (mirrors `understandingModeEnv`'s gate) — a manifest that never
|
|
390
|
+
* uses the pack has no `.approvals/` markers this listing owns an
|
|
391
|
+
* opinion about. Purely informational (`ℹ`); never rolls into
|
|
392
|
+
* `warningCount`.
|
|
393
|
+
*/
|
|
394
|
+
ugAutoApprovals?: UgAutoApprovalsSection;
|
|
395
|
+
/**
|
|
396
|
+
* Settings-drift compensating control (same ADR, threat model (c)): a
|
|
397
|
+
* `permissions.defaultMode` or hook entry present in a live Claude
|
|
398
|
+
* Code settings file but absent from harness's own last-apply
|
|
399
|
+
* snapshot. Present only when the understanding-gate pack is enabled
|
|
400
|
+
* AND `harness apply` has run at least once for this manifest
|
|
401
|
+
* (`harness.generated/` exists) — otherwise there is no baseline to
|
|
402
|
+
* compare against and nothing to say. `warnings` roll into
|
|
403
|
+
* `warningCount`; `notes` never do.
|
|
404
|
+
*/
|
|
405
|
+
settingsDrift?: SettingsDriftSection;
|
|
356
406
|
memory: MemoryReport;
|
|
357
407
|
hooks: HookEntryReport[];
|
|
358
408
|
policies: PolicyEntryReport[];
|
|
@@ -452,5 +502,7 @@ export interface DoctorReport {
|
|
|
452
502
|
export type { NpmBinReport } from "./npm-bin-path.js";
|
|
453
503
|
export type { ClaudeMcpRegistrationSection, ClaudeMcpEntryReport } from "./claude-mcp.js";
|
|
454
504
|
export type { UnderstandingModeEnvDivergence } from "./understanding-mode-env.js";
|
|
505
|
+
export type { UgAutoApprovalsSection, AutoApprovalListingEntry } from "./ug-auto-approvals.js";
|
|
506
|
+
export type { SettingsDriftSection } from "./settings-drift.js";
|
|
455
507
|
export type { ToolchainParitySection, ToolchainParityPeerReport } from "./toolchain-parity.js";
|
|
456
508
|
export type { Manifest, McpProbeResult, MemoryReport, StaleMemory, CodexTargetReport, RogueLedgerDb, };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/cli/doctor/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/cli/doctor/types.ts"],"names":[],"mappings":"AAcA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,OAAO,EAAE,UAAU,CAAU,CAAC;AAGnE,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,oBAA0C,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAClG,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Default doctor window when `--recent-sessions` is not passed. */
|
|
2
|
+
export declare const DEFAULT_RECENT_SESSIONS = 20;
|
|
3
|
+
export interface AutoApprovalListingEntry {
|
|
4
|
+
sessionId: string;
|
|
5
|
+
mode: string;
|
|
6
|
+
harness: string;
|
|
7
|
+
approvedAt: string;
|
|
8
|
+
}
|
|
9
|
+
export interface UgAutoApprovalsSection {
|
|
10
|
+
/** Whether `<generatedDir>/.approvals/` exists at all. */
|
|
11
|
+
approvalsDirPresent: boolean;
|
|
12
|
+
/** The `recentSessions` window that was applied. */
|
|
13
|
+
windowSize: number;
|
|
14
|
+
/** Auto approvals among the newest `windowSize` session markers. */
|
|
15
|
+
autoApprovedCount: number;
|
|
16
|
+
/** Per-mode breakdown of `autoApprovedCount` (e.g. `{bypassPermissions: 3}`). */
|
|
17
|
+
byMode: Record<string, number>;
|
|
18
|
+
/** Per-harness breakdown of `autoApprovedCount` (e.g. `{"claude-code": 3}`). */
|
|
19
|
+
byHarness: Record<string, number>;
|
|
20
|
+
/** `(sessionId, mode, approvedAt)` for each auto approval in the window, newest first. */
|
|
21
|
+
entries: AutoApprovalListingEntry[];
|
|
22
|
+
/**
|
|
23
|
+
* Session markers whose body could not be read as JSON with a
|
|
24
|
+
* parseable `approvedAt` (corrupt file, non-JSON content, missing
|
|
25
|
+
* `approvedAt`). Excluded from the window (there is no timestamp to
|
|
26
|
+
* sort them by) and never counted as auto approvals; surfaced as a
|
|
27
|
+
* single summary count instead of per-file noise.
|
|
28
|
+
*/
|
|
29
|
+
unreadableCount: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Build the auto-approval listing + last-N metric. Pure filesystem read;
|
|
33
|
+
* never throws for ordinary "nothing to see" states (missing
|
|
34
|
+
* `.approvals/`, empty directory, every marker unreadable) — those all
|
|
35
|
+
* resolve to an empty-ish section rather than an exception, mirroring
|
|
36
|
+
* the rest of doctor's read-only checks.
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildUgAutoApprovals(generatedDir: string, opts: {
|
|
39
|
+
recentSessions: number;
|
|
40
|
+
}): UgAutoApprovalsSection;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Doctor visibility half of ADR docs/decisions/2026-08-27-ug-auto-mode-approval.md
|
|
2
|
+
// slice 1 (agent-tasks 74b4b17d): the "auto approvals in the last N
|
|
3
|
+
// sessions" listing named in the ADR's "Audit and doctor" section and
|
|
4
|
+
// slice 1 acceptance criterion 7.
|
|
5
|
+
//
|
|
6
|
+
// Scans `<generatedDir>/.approvals/` for SESSION markers (skips the
|
|
7
|
+
// per-task markers named `task-<id>` and the branch-protection markers
|
|
8
|
+
// named `branch-protection-<sid>`, neither of which is a session
|
|
9
|
+
// approval), sorts the readable ones newest-first by `approvedAt`,
|
|
10
|
+
// takes the newest `recentSessions` of them, and reports how many of
|
|
11
|
+
// THOSE were minted by the auto path (`approvedBy` starting with
|
|
12
|
+
// `auto-mode:`, see auto-approve.ts's `parseAutoApprovedBy`).
|
|
13
|
+
//
|
|
14
|
+
// This is an AUDIT SURFACE, not a security check: it never verifies a
|
|
15
|
+
// marker's HMAC signature (that is `checkApprovalMarker`'s job at gate
|
|
16
|
+
// time; a forged marker still gets rejected there regardless of what
|
|
17
|
+
// this listing shows) and it never blocks or writes anything.
|
|
18
|
+
import * as fs from "node:fs";
|
|
19
|
+
import * as path from "node:path";
|
|
20
|
+
import { readRegularFileRejectingSymlink } from "../../io/read-regular-file.js";
|
|
21
|
+
import { safeJsonParse } from "../../io/safe-json-parse.js";
|
|
22
|
+
import { BRANCH_PROTECTION_MARKER_PREFIX } from "../../policy-packs/builtin/branch-protection-runtime.js";
|
|
23
|
+
import { APPROVAL_MARKER_DIRNAME, APPROVAL_MARKER_TASK_PREFIX, parseAutoApprovedBy, } from "../../policy-packs/builtin/understanding-before-execution/index.js";
|
|
24
|
+
/** Default doctor window when `--recent-sessions` is not passed. */
|
|
25
|
+
export const DEFAULT_RECENT_SESSIONS = 20;
|
|
26
|
+
function emptySection(windowSize) {
|
|
27
|
+
return {
|
|
28
|
+
approvalsDirPresent: false,
|
|
29
|
+
windowSize,
|
|
30
|
+
autoApprovedCount: 0,
|
|
31
|
+
byMode: {},
|
|
32
|
+
byHarness: {},
|
|
33
|
+
entries: [],
|
|
34
|
+
unreadableCount: 0,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build the auto-approval listing + last-N metric. Pure filesystem read;
|
|
39
|
+
* never throws for ordinary "nothing to see" states (missing
|
|
40
|
+
* `.approvals/`, empty directory, every marker unreadable) — those all
|
|
41
|
+
* resolve to an empty-ish section rather than an exception, mirroring
|
|
42
|
+
* the rest of doctor's read-only checks.
|
|
43
|
+
*/
|
|
44
|
+
export function buildUgAutoApprovals(generatedDir, opts) {
|
|
45
|
+
const windowSize = opts.recentSessions;
|
|
46
|
+
const dir = path.join(generatedDir, APPROVAL_MARKER_DIRNAME);
|
|
47
|
+
let dirents;
|
|
48
|
+
try {
|
|
49
|
+
dirents = fs.readdirSync(dir, { withFileTypes: true });
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return emptySection(windowSize);
|
|
53
|
+
}
|
|
54
|
+
const readable = [];
|
|
55
|
+
let unreadableCount = 0;
|
|
56
|
+
for (const d of dirents) {
|
|
57
|
+
const name = d.name;
|
|
58
|
+
if (name.startsWith(APPROVAL_MARKER_TASK_PREFIX))
|
|
59
|
+
continue;
|
|
60
|
+
if (name.startsWith(BRANCH_PROTECTION_MARKER_PREFIX))
|
|
61
|
+
continue;
|
|
62
|
+
const full = path.join(dir, name);
|
|
63
|
+
const read = readRegularFileRejectingSymlink(full);
|
|
64
|
+
// A symlink / non-regular / raced-away entry is not a session marker
|
|
65
|
+
// this listing owns an opinion about; skip silently rather than
|
|
66
|
+
// counting it as "unreadable" (that count is for a FILE we expected
|
|
67
|
+
// to be a marker but could not parse).
|
|
68
|
+
if (read.kind === "symlink" || read.kind === "not-regular" || read.kind === "missing") {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (read.kind === "unreadable") {
|
|
72
|
+
unreadableCount++;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const parsed = safeJsonParse(read.content);
|
|
76
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
77
|
+
unreadableCount++;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const obj = parsed;
|
|
81
|
+
const approvedAt = obj["approvedAt"];
|
|
82
|
+
if (typeof approvedAt !== "string" || Number.isNaN(Date.parse(approvedAt))) {
|
|
83
|
+
unreadableCount++;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
readable.push({ sessionId: name, approvedAt, approvedBy: obj["approvedBy"] });
|
|
87
|
+
}
|
|
88
|
+
readable.sort((a, b) => Date.parse(b.approvedAt) - Date.parse(a.approvedAt));
|
|
89
|
+
const windowed = readable.slice(0, windowSize);
|
|
90
|
+
const byMode = {};
|
|
91
|
+
const byHarness = {};
|
|
92
|
+
const entries = [];
|
|
93
|
+
for (const m of windowed) {
|
|
94
|
+
const parsedAuto = parseAutoApprovedBy(m.approvedBy);
|
|
95
|
+
if (parsedAuto === null)
|
|
96
|
+
continue;
|
|
97
|
+
byMode[parsedAuto.mode] = (byMode[parsedAuto.mode] ?? 0) + 1;
|
|
98
|
+
byHarness[parsedAuto.harness] = (byHarness[parsedAuto.harness] ?? 0) + 1;
|
|
99
|
+
entries.push({
|
|
100
|
+
sessionId: m.sessionId,
|
|
101
|
+
mode: parsedAuto.mode,
|
|
102
|
+
harness: parsedAuto.harness,
|
|
103
|
+
approvedAt: m.approvedAt,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
approvalsDirPresent: true,
|
|
108
|
+
windowSize,
|
|
109
|
+
autoApprovedCount: entries.length,
|
|
110
|
+
byMode,
|
|
111
|
+
byHarness,
|
|
112
|
+
entries,
|
|
113
|
+
unreadableCount,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=ug-auto-approvals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ug-auto-approvals.js","sourceRoot":"","sources":["../../../src/cli/doctor/ug-auto-approvals.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,4 +36,14 @@ export interface UnderstandingModeEnvDivergence {
|
|
|
36
36
|
* warn about.
|
|
37
37
|
* - the normalised env mode differs from the resolved `config.mode`.
|
|
38
38
|
*/
|
|
39
|
+
/**
|
|
40
|
+
* Shared gate for the understanding-gate doctor sub-checks that only
|
|
41
|
+
* make sense when the pack is actually live: this divergence advisory,
|
|
42
|
+
* and (ADR docs/decisions/2026-08-27-ug-auto-mode-approval.md slice 1,
|
|
43
|
+
* agent-tasks 74b4b17d) the auto-approval listing and settings-drift
|
|
44
|
+
* checks. Declared-but-disabled counts as not enabled, mirroring the
|
|
45
|
+
* `p.enabled !== false` gate `checkUnderstandingModeEnvDivergence` uses
|
|
46
|
+
* inline below.
|
|
47
|
+
*/
|
|
48
|
+
export declare function isUnderstandingPackEnabled(manifest: Manifest): boolean;
|
|
39
49
|
export declare function checkUnderstandingModeEnvDivergence(manifest: Manifest, env: NodeJS.ProcessEnv): UnderstandingModeEnvDivergence | undefined;
|
|
@@ -48,6 +48,18 @@ import { isMode, MODE_ENV, PACK_NAME as UNDERSTANDING_PACK_NAME, resolveModeFrom
|
|
|
48
48
|
* warn about.
|
|
49
49
|
* - the normalised env mode differs from the resolved `config.mode`.
|
|
50
50
|
*/
|
|
51
|
+
/**
|
|
52
|
+
* Shared gate for the understanding-gate doctor sub-checks that only
|
|
53
|
+
* make sense when the pack is actually live: this divergence advisory,
|
|
54
|
+
* and (ADR docs/decisions/2026-08-27-ug-auto-mode-approval.md slice 1,
|
|
55
|
+
* agent-tasks 74b4b17d) the auto-approval listing and settings-drift
|
|
56
|
+
* checks. Declared-but-disabled counts as not enabled, mirroring the
|
|
57
|
+
* `p.enabled !== false` gate `checkUnderstandingModeEnvDivergence` uses
|
|
58
|
+
* inline below.
|
|
59
|
+
*/
|
|
60
|
+
export function isUnderstandingPackEnabled(manifest) {
|
|
61
|
+
return manifest.policy_packs.some((p) => p.name === UNDERSTANDING_PACK_NAME && p.enabled !== false);
|
|
62
|
+
}
|
|
51
63
|
export function checkUnderstandingModeEnvDivergence(manifest, env) {
|
|
52
64
|
const pack = manifest.policy_packs.find((p) => p.name === UNDERSTANDING_PACK_NAME && p.enabled !== false);
|
|
53
65
|
if (!pack)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"understanding-mode-env.js","sourceRoot":"","sources":["../../../src/cli/doctor/understanding-mode-env.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,wEAAwE;AACxE,mEAAmE;AACnE,EAAE;AACF,iEAAiE;AACjE,0EAA0E;AAC1E,kEAAkE;AAClE,wEAAwE;AACxE,kEAAkE;AAClE,sEAAsE;AACtE,oEAAoE;AACpE,sEAAsE;AACtE,yEAAyE;AACzE,wEAAwE;AACxE,yEAAyE;AACzE,uDAAuD;AACvD,EAAE;AACF,qEAAqE;AACrE,uEAAuE;AACvE,wEAAwE;AACxE,sEAAsE;AACtE,4DAA4D;AAC5D,wEAAwE;AACxE,yEAAyE;AACzE,wEAAwE;AACxE,qEAAqE;AACrE,yEAAyE;AACzE,+DAA+D;AAC/D,EAAE;AACF,+DAA+D;AAC/D,0EAA0E;AAC1E,kEAAkE;AAClE,2BAA2B;AAE3B,OAAO,EACL,MAAM,EACN,QAAQ,EACR,SAAS,IAAI,uBAAuB,EACpC,qBAAqB,GAEtB,MAAM,8DAA8D,CAAC;AAwBtE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,mCAAmC,CACjD,QAAkB,EAClB,GAAsB;IAEtB,MAAM,IAAI,GAAG,QAAQ,CAAC,YAAY,CAAC,IAAI,CACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,uBAAuB,IAAI,CAAC,CAAC,OAAO,KAAK,KAAK,CACjE,CAAC;IACF,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAE5B,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7B,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC5D,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;QAAE,OAAO,SAAS,CAAC;IAE7C,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACjF,IAAI,aAAa,KAAK,UAAU;QAAE,OAAO,SAAS,CAAC;IAEnD,yEAAyE;IACzE,yEAAyE;IACzE,yEAAyE;IACzE,uEAAuE;IACvE,wEAAwE;IACxE,wEAAwE;IACxE,MAAM,WAAW,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC;IAEhE,OAAO;QACL,OAAO,EAAE,aAAa;QACtB,UAAU;QACV,OAAO,EAAE,GAAG,QAAQ,IAAI,aAAa,8BAA8B,UAAU,EAAE;QAC/E,MAAM,EAAE;YACN,uFAAuF;gBACrF,iFAAiF,aAAa,GAAG;YACnG,yBAAyB,UAAU,GAAG,WAAW,EAAE;YACnD,uDAAuD,QAAQ,wBAAwB;SACxF;KACF,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"understanding-mode-env.js","sourceRoot":"","sources":["../../../src/cli/doctor/understanding-mode-env.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,wEAAwE;AACxE,mEAAmE;AACnE,EAAE;AACF,iEAAiE;AACjE,0EAA0E;AAC1E,kEAAkE;AAClE,wEAAwE;AACxE,kEAAkE;AAClE,sEAAsE;AACtE,oEAAoE;AACpE,sEAAsE;AACtE,yEAAyE;AACzE,wEAAwE;AACxE,yEAAyE;AACzE,uDAAuD;AACvD,EAAE;AACF,qEAAqE;AACrE,uEAAuE;AACvE,wEAAwE;AACxE,sEAAsE;AACtE,4DAA4D;AAC5D,wEAAwE;AACxE,yEAAyE;AACzE,wEAAwE;AACxE,qEAAqE;AACrE,yEAAyE;AACzE,+DAA+D;AAC/D,EAAE;AACF,+DAA+D;AAC/D,0EAA0E;AAC1E,kEAAkE;AAClE,2BAA2B;AAE3B,OAAO,EACL,MAAM,EACN,QAAQ,EACR,SAAS,IAAI,uBAAuB,EACpC,qBAAqB,GAEtB,MAAM,8DAA8D,CAAC;AAwBtE;;;;;;;;;;;;;;;GAeG;AACH;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CAAC,QAAkB;IAC3D,OAAO,QAAQ,CAAC,YAAY,CAAC,IAAI,CAC/B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,uBAAuB,IAAI,CAAC,CAAC,OAAO,KAAK,KAAK,CACjE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mCAAmC,CACjD,QAAkB,EAClB,GAAsB;IAEtB,MAAM,IAAI,GAAG,QAAQ,CAAC,YAAY,CAAC,IAAI,CACrC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,uBAAuB,IAAI,CAAC,CAAC,OAAO,KAAK,KAAK,CACjE,CAAC;IACF,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAE5B,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7B,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAC5D,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAClD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC;QAAE,OAAO,SAAS,CAAC;IAE7C,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACjF,IAAI,aAAa,KAAK,UAAU;QAAE,OAAO,SAAS,CAAC;IAEnD,yEAAyE;IACzE,yEAAyE;IACzE,yEAAyE;IACzE,uEAAuE;IACvE,wEAAwE;IACxE,wEAAwE;IACxE,MAAM,WAAW,GAAG,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC;IAEhE,OAAO;QACL,OAAO,EAAE,aAAa;QACtB,UAAU;QACV,OAAO,EAAE,GAAG,QAAQ,IAAI,aAAa,8BAA8B,UAAU,EAAE;QAC/E,MAAM,EAAE;YACN,uFAAuF;gBACrF,iFAAiF,aAAa,GAAG;YACnG,yBAAyB,UAAU,GAAG,WAAW,EAAE;YACnD,uDAAuD,QAAQ,wBAAwB;SACxF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type EnvironmentResolution, type RiskProfile, type WhenClauseResult } from "../runtime/index.js";
|
|
1
|
+
import { type DeletionTargetVerdict, type EnvironmentResolution, type RiskProfile, type WhenClauseResult } from "../runtime/index.js";
|
|
2
2
|
import type { Manifest } from "../schema/index.js";
|
|
3
3
|
import { type EventInputSeams } from "./event-input.js";
|
|
4
4
|
import { type LoaderOptions } from "./loader.js";
|
|
@@ -28,6 +28,9 @@ interface ExplainPolicyProjection {
|
|
|
28
28
|
};
|
|
29
29
|
classifier: RiskProfile;
|
|
30
30
|
environment: EnvironmentResolution;
|
|
31
|
+
/** Static deletion-target verdict (task d03af8f6); null when the
|
|
32
|
+
* event's command is not a recognized deletion verb. */
|
|
33
|
+
deletion_target: DeletionTargetVerdict | null;
|
|
31
34
|
when: {
|
|
32
35
|
declared: false;
|
|
33
36
|
} | {
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
// LAST recorded decision from the evidence ledger; `explain-policy`
|
|
14
14
|
// evaluates a hypothetical event live and reads nothing from the ledger.
|
|
15
15
|
import { stringify as stringifyYaml } from "yaml";
|
|
16
|
-
import { classifyRisk, evaluateWhen, policyMatchesEvent, resolveEnvironment, resolveKubeContext, } from "../runtime/index.js";
|
|
16
|
+
import { classifyRisk, evaluateWhen, policyMatchesEvent, resolveDeletionTarget, resolveEnvironment, resolveKubeContext, } from "../runtime/index.js";
|
|
17
|
+
import { extractShellCommand } from "../runtime/tool-name-aliases.js";
|
|
18
|
+
import { DEFAULT_SAFE_DELETION_ROOTS } from "../schema/risk.js";
|
|
17
19
|
import { loadEventEnvelope } from "./event-input.js";
|
|
18
20
|
import { EX_USAGE, HarnessExitError } from "./exit-codes.js";
|
|
19
21
|
import { loadManifest } from "./loader.js";
|
|
@@ -43,9 +45,16 @@ export function explainPolicy(policyName, opts) {
|
|
|
43
45
|
kubeContext: kube.context,
|
|
44
46
|
kubeNamespace: kube.namespace,
|
|
45
47
|
});
|
|
48
|
+
// Static deletion-target resolution (task d03af8f6) — same "raw
|
|
49
|
+
// command only, no ambient cwd/env" contract as the runtime's own
|
|
50
|
+
// `enrichEnvelope`. See `deletion-target-resolve.ts`.
|
|
51
|
+
const explainShellCommand = extractShellCommand({ raw_input: envelope.raw_input });
|
|
52
|
+
const deletionTarget = explainShellCommand === null
|
|
53
|
+
? null
|
|
54
|
+
: resolveDeletionTarget(explainShellCommand, manifest.risk.safe_deletion_roots ?? DEFAULT_SAFE_DELETION_ROOTS);
|
|
46
55
|
const triggerMatched = policyMatchesEvent(policy, event);
|
|
47
56
|
const whenEval = policy.when !== undefined
|
|
48
|
-
? evaluateWhen(policy.when, { risk: classifier, environment })
|
|
57
|
+
? evaluateWhen(policy.when, { risk: classifier, environment, deletionTarget })
|
|
49
58
|
: undefined;
|
|
50
59
|
const projection = {
|
|
51
60
|
policy: policy.name,
|
|
@@ -63,6 +72,7 @@ export function explainPolicy(policyName, opts) {
|
|
|
63
72
|
},
|
|
64
73
|
classifier,
|
|
65
74
|
environment,
|
|
75
|
+
deletion_target: deletionTarget,
|
|
66
76
|
when: whenEval
|
|
67
77
|
? {
|
|
68
78
|
declared: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explain-policy.js","sourceRoot":"","sources":["../../src/cli/explain-policy.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,EAAE;AACF,wEAAwE;AACxE,mEAAmE;AACnE,wEAAwE;AACxE,wEAAwE;AACxE,qEAAqE;AACrE,yEAAyE;AACzE,uEAAuE;AACvE,6CAA6C;AAC7C,EAAE;AACF,qEAAqE;AACrE,oEAAoE;AACpE,yEAAyE;AAEzE,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;AAClD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,
|
|
1
|
+
{"version":3,"file":"explain-policy.js","sourceRoot":"","sources":["../../src/cli/explain-policy.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/export.js
CHANGED
|
@@ -2,6 +2,7 @@ import * as os from "node:os";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { stringify as stringifyYaml } from "yaml";
|
|
4
4
|
import { atomicWriteFile } from "../io/atomic-write.js";
|
|
5
|
+
import { withoutDerivedPolicies } from "../runtime/workflow-policies.js";
|
|
5
6
|
import { loadManifest } from "./loader.js";
|
|
6
7
|
const SECRET_KEY_PATTERN = /(?:_|^)(KEY|TOKEN|SECRET|PASSWORD|API_KEY)$/i;
|
|
7
8
|
const REDACTED = "<REDACTED>";
|
|
@@ -10,7 +11,17 @@ export const SANITIZE_FOOTER = "# sanitised: /home/<user>/ paths replaced with ~
|
|
|
10
11
|
"sanitiser does NOT touch secrets in command:[] arrays or in policy " +
|
|
11
12
|
"`requires.ledger_tag` values; review before sharing.";
|
|
12
13
|
export function exportManifest(opts = {}) {
|
|
13
|
-
const { manifest } = loadManifest(opts);
|
|
14
|
+
const { manifest: loaded } = loadManifest(opts);
|
|
15
|
+
// F7 (review round 2, 99f47307 Slice 1): `loadManifest` folds
|
|
16
|
+
// `workflows[]`-derived policies into `manifest.policies` (F2), but
|
|
17
|
+
// `harness export` is meant to emit what the OPERATOR declared, not a
|
|
18
|
+
// computed view — a derived policy re-imported via `harness init
|
|
19
|
+
// --config <exported file>`-style workflows would then be a
|
|
20
|
+
// hand-authored duplicate of something the next `harness apply` would
|
|
21
|
+
// derive again anyway. `withoutDerivedPolicies` (identity-based; see
|
|
22
|
+
// workflow-policies.ts) restores the hand-authored view before
|
|
23
|
+
// projecting; `harness list policies` / `doctor` show the derived pair.
|
|
24
|
+
const manifest = withoutDerivedPolicies(loaded);
|
|
14
25
|
const projection = manifest;
|
|
15
26
|
const projected = opts.sanitize ? sanitize(projection, os.homedir()) : projection;
|
|
16
27
|
let output;
|
package/dist/cli/export.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/cli/export.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,YAAY,EAAsB,MAAM,aAAa,CAAC;AAe/D,MAAM,kBAAkB,GAAG,8CAA8C,CAAC;AAC1E,MAAM,QAAQ,GAAG,YAAY,CAAC;AAE9B,MAAM,CAAC,MAAM,eAAe,GAC1B,0EAA0E;IAC1E,yEAAyE;IACzE,qEAAqE;IACrE,sDAAsD,CAAC;AAEzD,MAAM,UAAU,cAAc,CAAC,OAAsB,EAAE;IACrD,MAAM,EAAE,QAAQ,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/cli/export.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,YAAY,EAAsB,MAAM,aAAa,CAAC;AAe/D,MAAM,kBAAkB,GAAG,8CAA8C,CAAC;AAC1E,MAAM,QAAQ,GAAG,YAAY,CAAC;AAE9B,MAAM,CAAC,MAAM,eAAe,GAC1B,0EAA0E;IAC1E,yEAAyE;IACzE,qEAAqE;IACrE,sDAAsD,CAAC;AAEzD,MAAM,UAAU,cAAc,CAAC,OAAsB,EAAE;IACrD,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAChD,8DAA8D;IAC9D,oEAAoE;IACpE,sEAAsE;IACtE,iEAAiE;IACjE,4DAA4D;IAC5D,sEAAsE;IACtE,qEAAqE;IACrE,+DAA+D;IAC/D,wEAAwE;IACxE,MAAM,QAAQ,GAAa,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC1D,MAAM,UAAU,GAA4B,QAA8C,CAAC;IAC3F,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IAElF,IAAI,MAAc,CAAC;IACnB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,IAAI,CAAC;IAC7C,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,aAAa,CAAC,SAAS,EAAE;YAChC,SAAS,EAAE,CAAC;YACZ,qBAAqB,EAAE,KAAK;SAC7B,CAAC,CAAC;QACH,IAAI,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,eAAe,IAAI,CAAC;IACxD,CAAC;IAED,IAAI,OAAO,GAAkB,IAAI,CAAC;IAClC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC;AACnE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAc,EAAE,OAAe;IACtD,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,IAAI,CAAC,KAAc,EAAE,OAAe,EAAE,QAA6B;IAC1E,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,GAAG,GAA4B,EAAE,CAAC;QACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;YACtE,IAAI,gBAAgB,CAAC,QAAQ,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACtF,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;YAC9C,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,gBAAgB,CAAC,QAA6B;IACrD,yEAAyE;IACzE,2EAA2E;IAC3E,OAAO,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,KAAK,CAAC;AACjD,CAAC;AAED,SAAS,eAAe,CAAC,CAAS,EAAE,OAAe;IACjD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,KAAK,GAAG;QAAE,OAAO,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IAC/D,sEAAsE;IACtE,4EAA4E;IAC5E,sEAAsE;IACtE,mBAAmB;IACnB,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,OAAO,SAAS,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AAC9D,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,QAAQ,EAAE,eAAe,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,CAAC"}
|