@lannguyensi/harness 0.30.1 → 0.32.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 +31 -0
- package/README.md +1 -0
- package/dist/cli/index.js +59 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init/templates.d.ts +1 -1
- package/dist/cli/init/templates.js +15 -0
- package/dist/cli/init/templates.js.map +1 -1
- package/dist/cli/pack/hook-branch-protection.js +2 -1
- package/dist/cli/pack/hook-branch-protection.js.map +1 -1
- package/dist/cli/pack/hook-codex-pre-tool-use.js +4 -3
- package/dist/cli/pack/hook-codex-pre-tool-use.js.map +1 -1
- package/dist/cli/pack/hook-codex-stop.js +1 -0
- package/dist/cli/pack/hook-codex-stop.js.map +1 -1
- package/dist/cli/pack/hook-post-tool-use.js +1 -0
- package/dist/cli/pack/hook-post-tool-use.js.map +1 -1
- package/dist/cli/pack/hook-pre-tool-use.js +3 -2
- package/dist/cli/pack/hook-pre-tool-use.js.map +1 -1
- package/dist/cli/pack/hook-runtime-reality.d.ts +50 -0
- package/dist/cli/pack/hook-runtime-reality.js +160 -0
- package/dist/cli/pack/hook-runtime-reality.js.map +1 -0
- package/dist/cli/pack/hook-solution-acceptance-writeguard.d.ts +26 -0
- package/dist/cli/pack/hook-solution-acceptance-writeguard.js +187 -0
- package/dist/cli/pack/hook-solution-acceptance-writeguard.js.map +1 -0
- package/dist/cli/pack/hook-solution-acceptance.d.ts +26 -0
- package/dist/cli/pack/hook-solution-acceptance.js +237 -0
- package/dist/cli/pack/hook-solution-acceptance.js.map +1 -0
- package/dist/cli/pause/index.d.ts +17 -3
- package/dist/cli/pause/index.js +30 -6
- package/dist/cli/pause/index.js.map +1 -1
- package/dist/cli/policy/intercept.js +7 -1
- package/dist/cli/policy/intercept.js.map +1 -1
- package/dist/cli/session-start/branch-check.js +4 -2
- package/dist/cli/session-start/branch-check.js.map +1 -1
- package/dist/cli/session-start/index.js +4 -2
- package/dist/cli/session-start/index.js.map +1 -1
- package/dist/cli/validate/checks.js +38 -0
- package/dist/cli/validate/checks.js.map +1 -1
- package/dist/policy-packs/builtin/solution-acceptance-runtime.d.ts +119 -0
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js +289 -0
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js.map +1 -0
- package/dist/policy-packs/builtin/solution-acceptance.d.ts +44 -0
- package/dist/policy-packs/builtin/solution-acceptance.js +185 -0
- package/dist/policy-packs/builtin/solution-acceptance.js.map +1 -0
- package/dist/policy-packs/registry.d.ts +1 -1
- package/dist/policy-packs/registry.js +10 -0
- package/dist/policy-packs/registry.js.map +1 -1
- package/dist/runtime/risk-classifier.js +64 -0
- package/dist/runtime/risk-classifier.js.map +1 -1
- package/dist/runtime/session-id.d.ts +4 -3
- package/dist/runtime/session-id.js +17 -5
- package/dist/runtime/session-id.js.map +1 -1
- package/package.json +3 -1
- package/scripts/runtime-reality-docker-probe.mjs +71 -0
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
// default; this module's job is only to report the unclassified state
|
|
17
17
|
// honestly.
|
|
18
18
|
//
|
|
19
|
+
// The one built-in exception is harness's own benign meta-commands (see
|
|
20
|
+
// BENIGN_HARNESS_COMMAND below): leaving them unclassified would let the
|
|
21
|
+
// fail-close gate deny `harness preflight` — a command other harness
|
|
22
|
+
// gates require — so they get a recognized `low`-severity floor.
|
|
23
|
+
//
|
|
19
24
|
// Design source: lava-ice-logs/2026-04-30/harness-risk-gate-extension.md
|
|
20
25
|
// (design phase B).
|
|
21
26
|
import { RiskSeveritySchema } from "../schema/index.js";
|
|
@@ -32,6 +37,50 @@ const SEVERITY_ORDER = RiskSeveritySchema.options;
|
|
|
32
37
|
// caution. A genuinely destructive-but-reversible action simply should
|
|
33
38
|
// not be tagged `destructive` by its classifier author.
|
|
34
39
|
const IRREVERSIBLE_CATEGORIES = new Set(["irreversible_action", "data_loss", "destructive"]);
|
|
40
|
+
// Built-in benign-harness-command floor.
|
|
41
|
+
//
|
|
42
|
+
// harness's own read-only and gate-producer subcommands are benign: they
|
|
43
|
+
// read state, record evidence, or print diagnostics, and several
|
|
44
|
+
// (`harness preflight`, `harness session-start`) are REQUIRED by other
|
|
45
|
+
// harness gates (require-preflight-evidence et al). Leaving them
|
|
46
|
+
// unclassified lets the "unknown is not safe" fail-close treat them as
|
|
47
|
+
// risk-bearing, so a `when: { risk.severity_at_least: critical,
|
|
48
|
+
// environment.name: production }` policy HARD-DENIES `harness preflight`
|
|
49
|
+
// the moment a session resolves to production (a main / release branch)
|
|
50
|
+
// — deadlocking against the very gate that demands it. So we recognize
|
|
51
|
+
// these as a `low`-severity floor.
|
|
52
|
+
//
|
|
53
|
+
// Floor, not override: the contribution composes with operator
|
|
54
|
+
// classifiers under the same highest-severity-wins rule, so
|
|
55
|
+
// `harness preflight && rm -rf /var` still classifies `critical` (the
|
|
56
|
+
// dangerous-shell tail wins) and an operator pattern can only RAISE the
|
|
57
|
+
// severity, never sink below this floor. Mutating subcommands (`apply`,
|
|
58
|
+
// `init`, `add`, `adopt`, `remove`, `pack`, `uninstall`, `migrate-home`,
|
|
59
|
+
// `smoke`, `gate`, `pause`, `resume`) are deliberately excluded — they
|
|
60
|
+
// stay classifiable. Anchored at the command head, so `cd /x && harness
|
|
61
|
+
// preflight` does NOT match and stays unclassified (fail-safe = denied):
|
|
62
|
+
// a benign prefix must not launder a non-harness command.
|
|
63
|
+
const BENIGN_HARNESS_SUBCOMMANDS = [
|
|
64
|
+
"preflight",
|
|
65
|
+
"session-start",
|
|
66
|
+
"approve",
|
|
67
|
+
"doctor",
|
|
68
|
+
"validate",
|
|
69
|
+
"describe",
|
|
70
|
+
"list",
|
|
71
|
+
"diff",
|
|
72
|
+
"explain",
|
|
73
|
+
"explain-action",
|
|
74
|
+
"explain-policy",
|
|
75
|
+
"test-risk",
|
|
76
|
+
"resolve-env",
|
|
77
|
+
"audit",
|
|
78
|
+
"session-export",
|
|
79
|
+
"dry-run",
|
|
80
|
+
"export",
|
|
81
|
+
"help",
|
|
82
|
+
];
|
|
83
|
+
const BENIGN_HARNESS_COMMAND = new RegExp(`^\\s*harness\\s+(?:${BENIGN_HARNESS_SUBCOMMANDS.join("|")})\\b`);
|
|
35
84
|
// Hot-path ReDoS guard (Phase 7 #6). As of Phase 7 #5/#6 the classifier
|
|
36
85
|
// runs operator-authored regexes against tool input on EVERY PreToolUse
|
|
37
86
|
// call inside `harness policy intercept`. Catastrophic-backtracking cost
|
|
@@ -121,6 +170,21 @@ export function classifyRisk(envelope, classifiers) {
|
|
|
121
170
|
`severity ${pat.severity}, categories [${pat.categories.join(", ")}]`);
|
|
122
171
|
}
|
|
123
172
|
}
|
|
173
|
+
// Built-in benign-harness floor (see BENIGN_HARNESS_COMMAND above).
|
|
174
|
+
// Folded in AFTER the operator loop so it composes by the same
|
|
175
|
+
// highest-severity-wins rule: it only raises an otherwise-unclassified
|
|
176
|
+
// action up to `low`, and never sinks an operator match (a dangerous
|
|
177
|
+
// tail in `harness preflight && rm -rf /var` keeps the higher
|
|
178
|
+
// severity). Gated on a real shell command so a non-shell tool whose
|
|
179
|
+
// serialized input happens to start with "harness" cannot match.
|
|
180
|
+
const shellCommand = extractShellCommand({ raw_input: envelope.raw_input });
|
|
181
|
+
if (shellCommand !== null && BENIGN_HARNESS_COMMAND.test(subject)) {
|
|
182
|
+
const lowIdx = SEVERITY_ORDER.indexOf("low");
|
|
183
|
+
if (lowIdx > severityIdx) {
|
|
184
|
+
severityIdx = lowIdx;
|
|
185
|
+
reasons.push("built-in: benign harness meta-command recognized (severity low)");
|
|
186
|
+
}
|
|
187
|
+
}
|
|
124
188
|
if (severityIdx === -1) {
|
|
125
189
|
return {
|
|
126
190
|
classified: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"risk-classifier.js","sourceRoot":"","sources":["../../src/runtime/risk-classifier.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"risk-classifier.js","sourceRoot":"","sources":["../../src/runtime/risk-classifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -38,9 +38,10 @@ export interface ResolveReadSessionOptions extends DiscoverSessionOptions {
|
|
|
38
38
|
*
|
|
39
39
|
* Precedence:
|
|
40
40
|
* 1. explicit value (the `--session` flag)
|
|
41
|
-
* 2. `$
|
|
42
|
-
* 3.
|
|
43
|
-
* 4.
|
|
41
|
+
* 2. `$CLAUDE_CODE_SESSION_ID` env (the var Claude Code actually exports)
|
|
42
|
+
* 3. `$CLAUDE_SESSION_ID` env (legacy fallback)
|
|
43
|
+
* 4. newest Claude Code transcript (the live session)
|
|
44
|
+
* 5. literal `"default"`
|
|
44
45
|
*
|
|
45
46
|
* The WRITE path keeps `resolveSessionId`: it always has
|
|
46
47
|
* `event.session_id`, so it never reaches the discovery tier, and a
|
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
// WRITE path (`policy intercept`), which always carries a concrete
|
|
14
14
|
// `event.session_id`:
|
|
15
15
|
// 1. explicit value (the runtime's `event.session_id`)
|
|
16
|
-
// 2. `$
|
|
17
|
-
// 3.
|
|
16
|
+
// 2. `$CLAUDE_CODE_SESSION_ID` env (the var Claude Code actually exports)
|
|
17
|
+
// 3. `$CLAUDE_SESSION_ID` env (legacy fallback)
|
|
18
|
+
// 4. literal `"default"`
|
|
18
19
|
//
|
|
19
20
|
// The READ path (`audit`, `explain --trace/--last`) needs more. The
|
|
20
21
|
// Phase 5 #2 fix assumed `$CLAUDE_SESSION_ID` is exported into the
|
|
@@ -25,6 +26,10 @@
|
|
|
25
26
|
// the active session id off the newest Claude Code transcript JSONL.
|
|
26
27
|
// That is the programmatic form of the heuristic `harness approve`'s
|
|
27
28
|
// own help text recommends to humans.
|
|
29
|
+
//
|
|
30
|
+
// Both resolvers also accept `$CLAUDE_CODE_SESSION_ID` as a higher-priority
|
|
31
|
+
// env tier than the legacy `$CLAUDE_SESSION_ID`, mirroring the
|
|
32
|
+
// `harness approve` verbs (`src/cli/approve/{risk,understanding}.ts`).
|
|
28
33
|
import * as fs from "node:fs";
|
|
29
34
|
import * as os from "node:os";
|
|
30
35
|
import * as path from "node:path";
|
|
@@ -41,6 +46,9 @@ const FALLBACK = "default";
|
|
|
41
46
|
export function resolveSessionId(explicit) {
|
|
42
47
|
if (typeof explicit === "string" && explicit.length > 0)
|
|
43
48
|
return explicit;
|
|
49
|
+
const envCode = process.env.CLAUDE_CODE_SESSION_ID;
|
|
50
|
+
if (typeof envCode === "string" && envCode.length > 0)
|
|
51
|
+
return envCode;
|
|
44
52
|
const env = process.env.CLAUDE_SESSION_ID;
|
|
45
53
|
if (typeof env === "string" && env.length > 0)
|
|
46
54
|
return env;
|
|
@@ -102,9 +110,10 @@ export function discoverNewestSessionId(opts = {}) {
|
|
|
102
110
|
*
|
|
103
111
|
* Precedence:
|
|
104
112
|
* 1. explicit value (the `--session` flag)
|
|
105
|
-
* 2. `$
|
|
106
|
-
* 3.
|
|
107
|
-
* 4.
|
|
113
|
+
* 2. `$CLAUDE_CODE_SESSION_ID` env (the var Claude Code actually exports)
|
|
114
|
+
* 3. `$CLAUDE_SESSION_ID` env (legacy fallback)
|
|
115
|
+
* 4. newest Claude Code transcript (the live session)
|
|
116
|
+
* 5. literal `"default"`
|
|
108
117
|
*
|
|
109
118
|
* The WRITE path keeps `resolveSessionId`: it always has
|
|
110
119
|
* `event.session_id`, so it never reaches the discovery tier, and a
|
|
@@ -113,6 +122,9 @@ export function discoverNewestSessionId(opts = {}) {
|
|
|
113
122
|
export function resolveReadSessionId(explicit, opts = {}) {
|
|
114
123
|
if (typeof explicit === "string" && explicit.length > 0)
|
|
115
124
|
return explicit;
|
|
125
|
+
const envCode = process.env.CLAUDE_CODE_SESSION_ID;
|
|
126
|
+
if (typeof envCode === "string" && envCode.length > 0)
|
|
127
|
+
return envCode;
|
|
116
128
|
const env = process.env.CLAUDE_SESSION_ID;
|
|
117
129
|
if (typeof env === "string" && env.length > 0)
|
|
118
130
|
return env;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-id.js","sourceRoot":"","sources":["../../src/runtime/session-id.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,EAAE;AACF,uEAAuE;AACvE,iEAAiE;AACjE,qEAAqE;AACrE,8DAA8D;AAC9D,wEAAwE;AACxE,iEAAiE;AACjE,oEAAoE;AACpE,aAAa;AACb,EAAE;AACF,uEAAuE;AACvE,mEAAmE;AACnE,sBAAsB;AACtB,yDAAyD;AACzD,
|
|
1
|
+
{"version":3,"file":"session-id.js","sourceRoot":"","sources":["../../src/runtime/session-id.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lannguyensi/harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "Declarative control plane for agent harnesses — one YAML for grounding, tools, memory, and hooks.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/LanNguyenSi/harness",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"types": "./dist/index.d.ts",
|
|
28
28
|
"files": [
|
|
29
29
|
"dist",
|
|
30
|
+
"scripts/runtime-reality-docker-probe.mjs",
|
|
30
31
|
"README.md",
|
|
31
32
|
"CHANGELOG.md",
|
|
32
33
|
"LICENSE"
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
},
|
|
44
45
|
"dependencies": {
|
|
45
46
|
"@inquirer/prompts": "^8.4.3",
|
|
47
|
+
"@lannguyensi/runtime-reality-checker": "^0.2.0",
|
|
46
48
|
"chalk": "^5.3.0",
|
|
47
49
|
"commander": "^12.1.0",
|
|
48
50
|
"diff": "^9.0.0",
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Docker probe for the runtime-reality PreToolUse hook.
|
|
3
|
+
//
|
|
4
|
+
// Contract (see `harness pack hook runtime-reality`): print a JSON array
|
|
5
|
+
// of ActualProcessState `{ name, running, startup_mode, port }` on stdout,
|
|
6
|
+
// one entry per running/known container. The hook spawns this via
|
|
7
|
+
// RUNTIME_REALITY_PROBE_CMD, parses stdout, and compares it against the
|
|
8
|
+
// keyword's expectations file. A non-zero exit or non-JSON output is
|
|
9
|
+
// treated by the hook as "probe failed" (fail-open unless
|
|
10
|
+
// RUNTIME_REALITY_PROBE_FAIL_BLOCK=1) — so this script must either emit a
|
|
11
|
+
// valid array or exit non-zero, never print partial garbage.
|
|
12
|
+
//
|
|
13
|
+
// Host-coupling lives here on purpose: the agent-grounding package stays
|
|
14
|
+
// probe-agnostic; this is the harness-side concrete probe. Copy/adapt it
|
|
15
|
+
// for systemd or pm2 hosts.
|
|
16
|
+
|
|
17
|
+
import { execFileSync } from "node:child_process";
|
|
18
|
+
|
|
19
|
+
/** Pull the first published host port out of a `docker ps` Ports string,
|
|
20
|
+
* e.g. "0.0.0.0:3001->3001/tcp, :::3001->3001/tcp" -> 3001. Returns
|
|
21
|
+
* undefined when the container publishes no host port. */
|
|
22
|
+
function firstHostPort(ports) {
|
|
23
|
+
if (typeof ports !== "string") return undefined;
|
|
24
|
+
const m = ports.match(/:(\d+)->/);
|
|
25
|
+
if (!m) return undefined;
|
|
26
|
+
const n = Number.parseInt(m[1], 10);
|
|
27
|
+
return Number.isFinite(n) ? n : undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function main() {
|
|
31
|
+
let raw;
|
|
32
|
+
try {
|
|
33
|
+
raw = execFileSync("docker", ["ps", "--format", "{{json .}}"], {
|
|
34
|
+
encoding: "utf8",
|
|
35
|
+
timeout: 8000,
|
|
36
|
+
maxBuffer: 4 * 1024 * 1024,
|
|
37
|
+
});
|
|
38
|
+
} catch (err) {
|
|
39
|
+
process.stderr.write(`docker-probe: docker ps failed: ${String(err)}\n`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const states = [];
|
|
44
|
+
for (const line of raw.split("\n")) {
|
|
45
|
+
const trimmed = line.trim();
|
|
46
|
+
if (!trimmed) continue;
|
|
47
|
+
let row;
|
|
48
|
+
try {
|
|
49
|
+
row = JSON.parse(trimmed);
|
|
50
|
+
} catch {
|
|
51
|
+
// A single malformed line shouldn't sink the whole probe; skip it.
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
// `docker ps` may join multiple names with commas; the first is the
|
|
55
|
+
// canonical container name expectations are written against.
|
|
56
|
+
const name = String(row.Names ?? "").split(",")[0].trim();
|
|
57
|
+
if (!name) continue;
|
|
58
|
+
const state = {
|
|
59
|
+
name,
|
|
60
|
+
running: row.State === "running",
|
|
61
|
+
startup_mode: "docker",
|
|
62
|
+
};
|
|
63
|
+
const port = firstHostPort(row.Ports);
|
|
64
|
+
if (port !== undefined) state.port = port;
|
|
65
|
+
states.push(state);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
process.stdout.write(JSON.stringify(states) + "\n");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
main();
|