@sema-agent/core 7.51.0 → 7.51.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +97 -1
- package/dist/agents/subagent.d.ts +5 -0
- package/dist/agents/subagent.js +1 -0
- package/dist/core/allow-entry.d.ts +4 -2
- package/dist/core/allow-entry.js +1 -1
- package/dist/core/engine-capabilities.d.ts +15 -0
- package/dist/core/engine-capabilities.js +1 -0
- package/dist/core/engine-notice.d.ts +8 -5
- package/dist/core/locked-config.d.ts +26 -5
- package/dist/core/locked-config.js +31 -6
- package/dist/core/mcp-server-spec.d.ts +37 -7
- package/dist/core/mcp-server-spec.js +84 -1
- package/dist/core/mcp.js +16 -4
- package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
- package/dist/core/runner/prepare-policy-chain.js +4 -2
- package/dist/core/runner/session-rule-policy.d.ts +3 -1
- package/dist/core/runner/session-rule-policy.js +11 -9
- package/dist/core/runner/tool-output-projection.d.ts +5 -0
- package/dist/core/runner/tool-output-projection.js +3 -3
- package/dist/core/secret-env.d.ts +46 -15
- package/dist/core/secret-env.js +84 -18
- package/dist/core/session-policy-store.d.ts +54 -14
- package/dist/core/session-policy-store.js +83 -20
- package/dist/core/spec-contract.d.ts +5 -3
- package/dist/core/types.d.ts +2 -1
- package/dist/core/types.js +1 -0
- package/dist/engine/execution-env/kill-tree.js +4 -4
- package/dist/engine/execution-env/node-execution-env.d.ts +11 -4
- package/dist/engine/execution-env/node-execution-env.js +9 -4
- package/dist/engine/lsp/node-lsp-manager.d.ts +2 -1
- package/dist/engine/lsp/node-lsp-manager.js +2 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.js +7 -2
- package/dist/stores/file/fs-atomic.js +2 -2
- package/dist/stores/file/session-policy-store.d.ts +3 -3
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +33 -1
- package/wire-changes/core@7.51.1.json +259 -0
- package/wire-changes/core@7.51.2.json +293 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { posix } from "node:path";
|
|
2
2
|
import { isWinFormPath } from "../tools/fs/safety.js";
|
|
3
3
|
import { NAMESPACED_NAME_SHAPES, carriesNamespaceSeparator } from "./protocol-table.js";
|
|
4
|
-
import { compileAllowList, inertEntryPhrase, readRuleEntry, renderListEntry } from "./allow-entry.js";
|
|
4
|
+
import { compileAllowList, compiledEntryName, inertEntryPhrase, readRuleEntry, renderListEntry } from "./allow-entry.js";
|
|
5
5
|
import { valueTypeLabel } from "./tool-name-list.js";
|
|
6
6
|
const SESSION_RULE_BUCKETS = { toolAllow: "allow", toolDeny: "deny", allowDirs: "dirs" };
|
|
7
7
|
const BUCKETS = Object.keys(SESSION_RULE_BUCKETS);
|
|
8
8
|
const ENTRY_FIELDS = BUCKETS.filter((f) => SESSION_RULE_BUCKETS[f] !== "dirs");
|
|
9
|
-
const STORE_STAMPS = new Set(["rev", "gen"]);
|
|
9
|
+
const STORE_STAMPS = new Set(["rev", "gen", "grammar"]);
|
|
10
|
+
export const SESSION_RULES_GRAMMAR = 1;
|
|
10
11
|
export class SessionPolicyError extends Error {
|
|
11
12
|
code;
|
|
12
13
|
detail;
|
|
@@ -49,18 +50,37 @@ function lexWithin(root, p) {
|
|
|
49
50
|
return true;
|
|
50
51
|
return np === nr || np.startsWith(nr + "/");
|
|
51
52
|
}
|
|
53
|
+
function grammarOf(value) {
|
|
54
|
+
const stamp = value.grammar;
|
|
55
|
+
if (stamp === undefined)
|
|
56
|
+
return { grammar: value.rev !== undefined ? 0 : SESSION_RULES_GRAMMAR };
|
|
57
|
+
if (typeof stamp !== "number" || !Number.isInteger(stamp) || stamp < 0) {
|
|
58
|
+
const got = typeof stamp === "number" ? "a number that is not a whole number of 0 or more" : valueTypeLabel(stamp);
|
|
59
|
+
return { got, sentence: `session rules carry a grammar stamp that is ${got} — the stamp is the whole number of the rule grammar the rules were written in (this engine reads grammar ${SESSION_RULES_GRAMMAR})` };
|
|
60
|
+
}
|
|
61
|
+
if (stamp > SESSION_RULES_GRAMMAR) {
|
|
62
|
+
return {
|
|
63
|
+
got: `${stamp}, a grammar newer than this engine's (${SESSION_RULES_GRAMMAR})`,
|
|
64
|
+
sentence: `session rules were written in rule grammar ${stamp}, newer than this engine reads (grammar ${SESSION_RULES_GRAMMAR}) — refusing rather than read their entries in an older grammar; an engine that reads grammar ${stamp} reads them`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return { grammar: stamp };
|
|
68
|
+
}
|
|
52
69
|
export function readSessionRulesShape(value) {
|
|
53
70
|
const fault = (field, got, sentence) => ({ fault: { field, got }, sentence });
|
|
54
71
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
55
72
|
const got = Array.isArray(value) ? "an array" : valueTypeLabel(value);
|
|
56
73
|
return fault("", got, `session rules must be an object of rule buckets (${BUCKETS.join(", ")}), got ${got}`);
|
|
57
74
|
}
|
|
58
|
-
const
|
|
75
|
+
const read = grammarOf(value);
|
|
76
|
+
if ("got" in read)
|
|
77
|
+
return fault("grammar", read.got, read.sentence);
|
|
78
|
+
const rules = { grammar: read.grammar };
|
|
59
79
|
for (const [key, v] of Object.entries(value)) {
|
|
60
80
|
if (STORE_STAMPS.has(key) || v === undefined)
|
|
61
81
|
continue;
|
|
62
82
|
if (!Object.hasOwn(SESSION_RULE_BUCKETS, key)) {
|
|
63
|
-
return fault(key, "not a rule bucket", `session rules hold ${JSON.stringify(key)}, which is not a rule bucket — the buckets are ${BUCKETS.join(", ")}, and a shell command rule is a toolDeny / toolAllow entry written Bash(<command>) (Bash(rm:*)
|
|
83
|
+
return fault(key, "not a rule bucket", `session rules hold ${JSON.stringify(key)}, which is not a rule bucket — the buckets are ${BUCKETS.join(", ")}, and a shell command rule is a toolDeny / toolAllow entry written Bash(<command>) (Bash(rm:*) matches a command whose first word is rm)`);
|
|
64
84
|
}
|
|
65
85
|
const field = key;
|
|
66
86
|
const listed = Array.isArray(v) ? Array.from(v) : undefined;
|
|
@@ -78,34 +98,76 @@ export function readSessionRulesShape(value) {
|
|
|
78
98
|
return { rules };
|
|
79
99
|
}
|
|
80
100
|
export function normalizeRules(rules) {
|
|
101
|
+
return canonicalRules(shapeOrRefuse(rules));
|
|
102
|
+
}
|
|
103
|
+
function shapeOrRefuse(rules) {
|
|
81
104
|
const read = readSessionRulesShape(rules);
|
|
82
105
|
if ("fault" in read)
|
|
83
106
|
throw new SessionPolicyError("invalid_shape", read.sentence, read.fault);
|
|
107
|
+
return read.rules;
|
|
108
|
+
}
|
|
109
|
+
function canonicalRules(read) {
|
|
84
110
|
const out = {};
|
|
85
111
|
for (const field of BUCKETS) {
|
|
86
|
-
const list = read
|
|
112
|
+
const list = read[field];
|
|
87
113
|
if (list === undefined)
|
|
88
114
|
continue;
|
|
89
115
|
out[field] = SESSION_RULE_BUCKETS[field] === "dirs" ? list.map((d) => posix.normalize(d).replace(/\/+$/, "") || "/") : [...list];
|
|
90
116
|
}
|
|
91
117
|
return out;
|
|
92
118
|
}
|
|
93
|
-
function
|
|
94
|
-
return
|
|
119
|
+
function readsAsNothingIn(grammar, field, entry, compiled) {
|
|
120
|
+
return grammar === 0 && SESSION_RULE_BUCKETS[field] === "allow" && compiledEntryName(compiled) !== entry;
|
|
121
|
+
}
|
|
122
|
+
export function compileSessionRuleBucket(rules, field, roster) {
|
|
123
|
+
const list = compileAllowList(rules[field] ?? [], SESSION_RULE_BUCKETS[field], roster);
|
|
124
|
+
const rows = list.rows.filter((r) => !readsAsNothingIn(rules.grammar, field, r.entry, r.compiled));
|
|
125
|
+
if (rows.length === list.rows.length)
|
|
126
|
+
return list;
|
|
127
|
+
const earlier = list.rows.filter((r) => readsAsNothingIn(rules.grammar, field, r.entry, r.compiled)).map((r) => ({ entry: r.entry, reason: "earlier_grammar" }));
|
|
128
|
+
return { rows, inert: [...list.inert, ...earlier] };
|
|
129
|
+
}
|
|
130
|
+
const ADVISORY_ENTRIES_SHOWN = 5;
|
|
131
|
+
export function earlierGrammarAdvisory(sessionId, entries) {
|
|
132
|
+
const one = entries.length === 1;
|
|
133
|
+
const shown = entries.slice(0, ADVISORY_ENTRIES_SHOWN).map(renderListEntry).join(", ");
|
|
134
|
+
const rest = entries.length > ADVISORY_ENTRIES_SHOWN ? ` and ${entries.length - ADVISORY_ENTRIES_SHOWN} more` : "";
|
|
135
|
+
return (`session permission rules of session ${JSON.stringify(sessionId)}: toolAllow ${shown}${rest} ${one ? "was" : "were"} stored before the rule grammar stamp, when session rules compared an entry as a tool name as written, so a parenthesized entry named no tool — ` +
|
|
136
|
+
`${one ? "it admits" : "they admit"} nothing, as when written. To make ${one ? "it an allow rule" : "them allow rules"}, write the session's rules afresh through this engine (an operator write of a value without the stored row's rev; the write stamps grammar ${SESSION_RULES_GRAMMAR}); left as stored, ${one ? "it keeps" : "they keep"} admitting nothing.`);
|
|
137
|
+
}
|
|
138
|
+
export function earlierGrammarAnnouncer(sink) {
|
|
139
|
+
const announced = new Set();
|
|
140
|
+
return (entries) => {
|
|
141
|
+
const key = JSON.stringify(entries);
|
|
142
|
+
if (sink === undefined || entries.length === 0 || announced.has(key))
|
|
143
|
+
return;
|
|
144
|
+
announced.add(key);
|
|
145
|
+
try {
|
|
146
|
+
sink(entries);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function effectiveEntries(rules, field, mountedToolNames) {
|
|
153
|
+
return compileSessionRuleBucket(rules, field, mountedToolNames).rows.map((r) => r.entry);
|
|
95
154
|
}
|
|
96
155
|
function assertEntriesRead(rules, mountedToolNames) {
|
|
97
156
|
for (const field of ENTRY_FIELDS) {
|
|
98
157
|
for (const entry of rules[field] ?? []) {
|
|
99
|
-
const
|
|
158
|
+
const reading = readRuleEntry(entry, SESSION_RULE_BUCKETS[field], mountedToolNames);
|
|
159
|
+
const read = reading.kind === "row" && readsAsNothingIn(rules.grammar, field, entry, reading.compiled) ? { kind: "inert", reason: "earlier_grammar" } : reading;
|
|
100
160
|
if (read.kind === "row")
|
|
101
161
|
continue;
|
|
102
162
|
const { kind: _kind, ...why } = read;
|
|
103
163
|
void _kind;
|
|
104
|
-
const way = why.
|
|
105
|
-
? `
|
|
106
|
-
: why.
|
|
107
|
-
? `
|
|
108
|
-
:
|
|
164
|
+
const way = why.reason === "earlier_grammar"
|
|
165
|
+
? ` These rules are written in grammar ${rules.grammar} (a stored row from before the grammar stamp), in which this entry names no tool. To make it an allow rule, write the rules afresh — a value without the stored row's rev; the write stamps grammar ${SESSION_RULES_GRAMMAR} — or leave the entry out.`
|
|
166
|
+
: why.verdict === "retired"
|
|
167
|
+
? ` If this deployment mounts its own tool under ${renderListEntry(entry)}, declare it in the store's mountedToolNames.`
|
|
168
|
+
: why.currentName === undefined
|
|
169
|
+
? ` An entry is a tool name (Read; a protocol tool is named ${NAMESPACED_NAME_SHAPES}), a protocol namespace (mcp__<server>), or a rule in its tool's own grammar (Bash(<command>), Edit(<path>), Skill(<name>), WebFetch(domain:<host>)).`
|
|
170
|
+
: "";
|
|
109
171
|
const sentence = why.guidance !== undefined ? ` — ${why.guidance}` : "";
|
|
110
172
|
throw new SessionPolicyError("inert_entry", `session rules ${field} holds ${inertEntryPhrase({ entry, ...why })}, which ${SESSION_RULE_BUCKETS[field] === "deny" ? "refuses" : "admits"} nothing as written${sentence}; nothing was written.${way}`, { field, entry, ...why });
|
|
111
173
|
}
|
|
@@ -115,8 +177,9 @@ export function judgeSessionRulesWrite(prior, rules, opts, mountedToolNames = NO
|
|
|
115
177
|
if (opts?.expectedRev !== undefined && (prior?.rev ?? 0) !== opts.expectedRev) {
|
|
116
178
|
throw new SessionPolicyError("conflict", `session rules rev mismatch (expected ${opts.expectedRev}, have ${prior?.rev ?? 0})`);
|
|
117
179
|
}
|
|
118
|
-
const
|
|
119
|
-
|
|
180
|
+
const read = shapeOrRefuse(rules);
|
|
181
|
+
const clean = canonicalRules(read);
|
|
182
|
+
assertEntriesRead(read, mountedToolNames);
|
|
120
183
|
if (prior !== null && opts?.operator !== true) {
|
|
121
184
|
const stored = readSessionRulesShape(prior);
|
|
122
185
|
if ("fault" in stored) {
|
|
@@ -127,7 +190,7 @@ export function judgeSessionRulesWrite(prior, rules, opts, mountedToolNames = NO
|
|
|
127
190
|
throw new SessionPolicyError("loosen_forbidden", `a non-operator session-rule write may only tighten; refused: ${loosens.join("; ")}`);
|
|
128
191
|
}
|
|
129
192
|
}
|
|
130
|
-
return clean;
|
|
193
|
+
return { ...clean, grammar: SESSION_RULES_GRAMMAR };
|
|
131
194
|
}
|
|
132
195
|
export function loosenReasons(priorValue, nextValue, mountedToolNames = NO_DECLARED_TOOLS) {
|
|
133
196
|
const shapeOf = (side, value) => {
|
|
@@ -139,16 +202,16 @@ export function loosenReasons(priorValue, nextValue, mountedToolNames = NO_DECLA
|
|
|
139
202
|
const prior = shapeOf("prior", priorValue);
|
|
140
203
|
const next = shapeOf("next", nextValue);
|
|
141
204
|
const reasons = [];
|
|
142
|
-
const keptDeny = new Set(effectiveEntries("toolDeny",
|
|
143
|
-
for (const x of effectiveEntries("toolDeny",
|
|
205
|
+
const keptDeny = new Set(effectiveEntries(next, "toolDeny", mountedToolNames));
|
|
206
|
+
for (const x of effectiveEntries(prior, "toolDeny", mountedToolNames))
|
|
144
207
|
if (!keptDeny.has(x))
|
|
145
208
|
reasons.push(`removed toolDeny ${renderListEntry(x)}`);
|
|
146
209
|
if (prior.toolAllow !== undefined) {
|
|
147
210
|
if (next.toolAllow === undefined)
|
|
148
211
|
reasons.push("removed toolAllow allowlist (all allowed)");
|
|
149
212
|
else {
|
|
150
|
-
const had = new Set(effectiveEntries("toolAllow",
|
|
151
|
-
for (const x of effectiveEntries("toolAllow",
|
|
213
|
+
const had = new Set(effectiveEntries(prior, "toolAllow", mountedToolNames));
|
|
214
|
+
for (const x of effectiveEntries(next, "toolAllow", mountedToolNames))
|
|
152
215
|
if (!had.has(x))
|
|
153
216
|
reasons.push(`widened toolAllow with ${renderListEntry(x)}`);
|
|
154
217
|
}
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* 任意命令)。它只能来自部署作者/可信代码路径;LLM 生成的 contract 直接喂 runSpec = 不受信输入获得
|
|
8
8
|
* 命令执行权(越红线),禁止。contract 里的 `spec` **文本**才是 DATA-tier(runSpec 恒围栏置入 objective)。
|
|
9
9
|
* 命令可信 ≠ 它跑的代码可信:门跑的测试会加载模型改过的代码,故门子进程的环境缺省经 `scrubSecretEnv`
|
|
10
|
-
* (`OracleGateSpec.inheritEnv`,与 tool shell 同一三态),凭据名只在部署显式列名 / `"all"`
|
|
10
|
+
* (`OracleGateSpec.inheritEnv`,与 tool shell 同一三态),凭据名只在部署显式列名 / `"all"` 时交给它;
|
|
11
|
+
* 部署声明的自有凭据名(`declareWithheldEnv`)在任一形下都不交。
|
|
11
12
|
*
|
|
12
13
|
* 🔴 **oracle 三值(fable-M6)**:每门结果 ∈ {green, red, error} —— 判据不满足 = red;基础设施故障
|
|
13
14
|
* (ENOENT/timeout/maxBuffer/parse 解析不出)= **error 非 red**。假红防线:error 绝不冒充"曾经红过"
|
|
@@ -56,8 +57,9 @@ export interface OracleGateSpec {
|
|
|
56
57
|
* way. Absent / `"scrub"`: the environment without its credential-shaped variables (`scrubSecretEnv`); the command
|
|
57
58
|
* runs code the model wrote, so the credentials are not handed to it by default. `"all"`: the whole environment.
|
|
58
59
|
* A list: exactly the named variables that are set (a strict allow list — `PATH` too, when the command is looked
|
|
59
|
-
* up on it).
|
|
60
|
-
* gate `error`.
|
|
60
|
+
* up on it). Under every form, the deployment's declared own credentials (`declareWithheldEnv`) are withheld, and a
|
|
61
|
+
* list naming one makes the gate `error`. Names only, never values: the contract is serializable data. A value of
|
|
62
|
+
* any other shape makes the gate `error`.
|
|
61
63
|
*/
|
|
62
64
|
inheritEnv?: "all" | "scrub" | string[];
|
|
63
65
|
}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -18,7 +18,8 @@ export type { PermissionMode } from "./ask-origin.js";
|
|
|
18
18
|
export type { ToolEffect, ToolContentOrigin, ReversibilityVerdict, ReadRootGrantCandidate, ToolSpec, ToolReturn, NestedUsage, NestedUsageAccum, ToolExecuteContext } from "./tool-spec.js";
|
|
19
19
|
export type { BeforeWriteRequest, BeforeWriteResult, BeforeWriteHook, TrackEditRequest, TrackEditResult, TrackFileEditHook, FileEditedNotice, FileEditedHook, HandsBandOptions } from "./hands-band.js";
|
|
20
20
|
export type { AgentDefinition, SkillSpec } from "./agent-definition.js";
|
|
21
|
-
export type { McpServerSpec, A2aServerSpec, McpElicitRequest, McpElicitResponse, OnElicit, McpRevocationLedger, McpMountIdentity } from "./mcp-server-spec.js";
|
|
21
|
+
export type { McpServerSpec, A2aServerSpec, McpElicitRequest, McpElicitResponse, OnElicit, McpRevocationLedger, McpMountIdentity, McpToolAxesRead } from "./mcp-server-spec.js";
|
|
22
|
+
export { readMcpToolAxes } from "./mcp-server-spec.js";
|
|
22
23
|
export type { TaskLimits } from "./task-limits.js";
|
|
23
24
|
export type { TaskStatus, RemoteEnvFailureNote, EffectiveMemoryScopes, TaskResult, HumanReviewGateRow } from "./task-result.js";
|
|
24
25
|
export type { TerminalCause, PausedCause } from "./terminal-cause.js";
|
package/dist/core/types.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { MODEL_ROLES } from "./model-seat.js";
|
|
2
|
+
export { readMcpToolAxes } from "./mcp-server-spec.js";
|
|
2
3
|
export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js";
|
|
3
4
|
export { __resetMalformedDelegationSeatAnnouncement, backgroundChildTerminal, deliverDelegationLifecycle, emitsChildRowFrames, taskStartedFrame } from "./delegation-frames.js";
|
|
4
5
|
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn, spawnSync } from "node:child_process";
|
|
2
|
-
import {
|
|
2
|
+
import { inheritedHostEnv } from "../../core/secret-env.js";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
const DEFAULT_GRACE_MS = 3000;
|
|
@@ -145,7 +145,7 @@ function enumerateDescendantsSync(rootPid) {
|
|
|
145
145
|
let out;
|
|
146
146
|
try {
|
|
147
147
|
const result = spawnSync("ps", ["-A", "-o", "pid=", "-o", "ppid=", "-o", "etime="], {
|
|
148
|
-
env:
|
|
148
|
+
env: inheritedHostEnv("scrub"),
|
|
149
149
|
timeout: PS_ENUMERATION_TIMEOUT_MS,
|
|
150
150
|
encoding: "utf8",
|
|
151
151
|
windowsHide: true,
|
|
@@ -211,7 +211,7 @@ function parseEtimeSeconds(etime) {
|
|
|
211
211
|
function runTaskkill(args) {
|
|
212
212
|
try {
|
|
213
213
|
const child = spawn("taskkill", args, {
|
|
214
|
-
env:
|
|
214
|
+
env: inheritedHostEnv("scrub"),
|
|
215
215
|
stdio: "ignore",
|
|
216
216
|
detached: true,
|
|
217
217
|
windowsHide: true,
|
|
@@ -271,7 +271,7 @@ function tryMsysGroupKill(bashPath, pid) {
|
|
|
271
271
|
`[ -n "$g" ] && [ "$g" != "0" ] && kill -9 -"$g" 2>/dev/null; ` +
|
|
272
272
|
`done; exit 0`;
|
|
273
273
|
try {
|
|
274
|
-
const child = spawn(bashPath, ["-c", script], { env:
|
|
274
|
+
const child = spawn(bashPath, ["-c", script], { env: inheritedHostEnv("scrub"), stdio: "ignore", detached: true, windowsHide: true });
|
|
275
275
|
child.on("error", () => { });
|
|
276
276
|
return true;
|
|
277
277
|
}
|
|
@@ -88,6 +88,10 @@ export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCa
|
|
|
88
88
|
/** `ExecutionEnv.cdPath` = the `CDPATH` the shell child receives, read LIVE off the same merge each exec gets (never the
|
|
89
89
|
* engine process's own environment): its entries, `[]` when the child gets none. Residual: a per-exec `env.CDPATH`. */
|
|
90
90
|
get cdPath(): readonly string[];
|
|
91
|
+
/** The environment the next shell child would receive, for a READ (the scrub seat is a no-op: a read reports nothing).
|
|
92
|
+
* `undefined` when no child would be spawned at all — the policy is refused against the own credentials declared
|
|
93
|
+
* since construction, and every spawn throws that reason — so a reader sees "the child gets none", never a throw. */
|
|
94
|
+
private childEnvForRead;
|
|
91
95
|
private shellPath?;
|
|
92
96
|
private shellEnv?;
|
|
93
97
|
private inheritEnv;
|
|
@@ -108,7 +112,9 @@ export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCa
|
|
|
108
112
|
* fail-closed (drop secret-pattern keys, keep PATH/build/locale). `"all"` = full inherit (trusted env);
|
|
109
113
|
* `string[]` = strict allowlist. `shellEnv`/per-exec `env` always pass through. Any other value — an unknown
|
|
110
114
|
* word, a non-string, a list entry that is not a variable name — throws here (`inheritEnvPolicyProblem`'s
|
|
111
|
-
* reason), the same judgment the oracle gate's `inheritEnv` meets.
|
|
115
|
+
* reason), the same judgment the oracle gate's `inheritEnv` meets. Whatever the policy, the deployment's declared
|
|
116
|
+
* own credentials (`declareWithheldEnv`) are withheld from the inherited part; a list naming one throws here when
|
|
117
|
+
* the declaration came first, and every spawn refuses it (`spawn_error` / `spawn_failed`) whenever it came. */
|
|
112
118
|
inheritEnv?: "all" | "scrub" | string[];
|
|
113
119
|
/** design/105: inject a resident scheduler daemon backend (the shell daemon). Absent ⇒ scheduling INERT. */
|
|
114
120
|
scheduler?: SchedulerCapability;
|
|
@@ -125,9 +131,10 @@ export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCa
|
|
|
125
131
|
* deployments (their pre-suspend dispose becomes a no-op too — do not combine).
|
|
126
132
|
*/
|
|
127
133
|
retainBackgroundProcesses?: boolean;
|
|
128
|
-
/** The D1 scrub decision's observation seat: called with every NON-EMPTY finding set
|
|
129
|
-
* "scrub" leg
|
|
130
|
-
*
|
|
134
|
+
/** The D1 scrub decision's observation seat: called with every NON-EMPTY finding set withheld from a
|
|
135
|
+
* shell child — the default "scrub" leg's, and on any leg the declared own credentials the inherited part
|
|
136
|
+
* held (kind `own-credential`). Absent ⇒ a once-per-process console summary (loud enough to notice,
|
|
137
|
+
* quiet enough not to spam). An allow list withholds nothing else, so it reports nothing. */
|
|
131
138
|
onSecretEnvScrub?: (findings: readonly SecretEnvFinding[]) => void;
|
|
132
139
|
/** #1081 — the structured-notice seat for the SAME withheld-keys disclosure (`EngineNotice`,
|
|
133
140
|
* `code: "config.secret_env_scrubbed"`, `detail.names`); independent of `onSecretEnvScrub` (a raw
|
|
@@ -7,7 +7,7 @@ import { isAbsolute, join, resolve } from "node:path";
|
|
|
7
7
|
import { createInterface } from "node:readline";
|
|
8
8
|
import { ExecutionError, err, FileError, ok, toError, } from "../harness/types.js";
|
|
9
9
|
import { killProcessTree, shutdownDebug } from "./kill-tree.js";
|
|
10
|
-
import { __resetSecretEnvScrubNoticeAnnouncement, announceSecretEnvScrub, inheritEnvPolicyProblem, inheritedHostEnv
|
|
10
|
+
import { __resetSecretEnvScrubNoticeAnnouncement, announceSecretEnvScrub, inheritEnvPolicyProblem, inheritedHostEnv } from "../../core/secret-env.js";
|
|
11
11
|
import { physicalPathOfAsync } from "../../core/physical-path.js";
|
|
12
12
|
import { posixModeBitsMeaningful } from "../../core/posix-mode-face.js";
|
|
13
13
|
import { walkSymlinkChain } from "./symlink-chain.js";
|
|
@@ -157,7 +157,7 @@ async function runCommand(command, args, timeoutMs) {
|
|
|
157
157
|
child = spawn(command, args, {
|
|
158
158
|
stdio: ["ignore", "pipe", "ignore"],
|
|
159
159
|
windowsHide: true,
|
|
160
|
-
env:
|
|
160
|
+
env: inheritedHostEnv("scrub"),
|
|
161
161
|
});
|
|
162
162
|
}
|
|
163
163
|
catch {
|
|
@@ -315,12 +315,17 @@ export function openSpoolPair(base) {
|
|
|
315
315
|
export class NodeExecutionEnv {
|
|
316
316
|
cwd;
|
|
317
317
|
get homeDir() {
|
|
318
|
-
return
|
|
318
|
+
return this.childEnvForRead()?.HOME;
|
|
319
319
|
}
|
|
320
320
|
get cdPath() {
|
|
321
|
-
const value =
|
|
321
|
+
const value = this.childEnvForRead()?.CDPATH;
|
|
322
322
|
return value === undefined || value === "" ? [] : value.split(":");
|
|
323
323
|
}
|
|
324
|
+
childEnvForRead() {
|
|
325
|
+
if (inheritEnvPolicyProblem(this.inheritEnv) !== undefined)
|
|
326
|
+
return undefined;
|
|
327
|
+
return getShellEnv(this.inheritEnv, this.shellEnv, undefined, () => { });
|
|
328
|
+
}
|
|
324
329
|
shellPath;
|
|
325
330
|
shellEnv;
|
|
326
331
|
inheritEnv;
|
|
@@ -21,7 +21,8 @@ export interface NodeLspManagerOptions {
|
|
|
21
21
|
/** Injectable spawn (tests supply a fake server; default = {@link defaultLspSpawn} over `child_process.spawn`). */
|
|
22
22
|
spawn?: LspSpawn;
|
|
23
23
|
/** The language server's environment for the default spawn, verbatim. Omitted ⇒ the host environment scrubbed of
|
|
24
|
-
* credential-shaped names (`
|
|
24
|
+
* credential-shaped names and of the declared own credentials (`inheritedHostEnv("scrub")`, a tool child's
|
|
25
|
+
* reading; `declareWithheldEnv`). Unread when {@link spawn} is supplied. */
|
|
25
26
|
env?: Record<string, string>;
|
|
26
27
|
/** #1081 — the withheld-keys notice sink, SAME shared once-per-process latch/code as the shell-exec
|
|
27
28
|
* site's `NodeExecutionEnv.onNotice`. Absent ⇒ console only. Unread when {@link spawn} is supplied. */
|
|
@@ -9,7 +9,7 @@ import { TransportLspSession } from "../../core/lsp-session.js";
|
|
|
9
9
|
import { StdioLspTransport } from "./stdio-lsp-transport.js";
|
|
10
10
|
import { MAX_LSP_FILE_BYTES, SharedAbortScope, settleOnAbort } from "../../core/lsp.js";
|
|
11
11
|
import { asThrownError, thrownText } from "../../core/thrown-value.js";
|
|
12
|
-
import { announceSecretEnvScrub,
|
|
12
|
+
import { announceSecretEnvScrub, inheritedHostEnv } from "../../core/secret-env.js";
|
|
13
13
|
export const DEFAULT_LSP_SERVERS = {
|
|
14
14
|
typescript: "typescript-language-server --stdio",
|
|
15
15
|
javascript: "typescript-language-server --stdio",
|
|
@@ -336,7 +336,7 @@ const lspSpawnWithEnv = (env, onNotice) => (command, args, cwd, signal) => new P
|
|
|
336
336
|
let scrubbedEnv = env;
|
|
337
337
|
if (scrubbedEnv == null) {
|
|
338
338
|
const findings = [];
|
|
339
|
-
scrubbedEnv =
|
|
339
|
+
scrubbedEnv = inheritedHostEnv("scrub", findings);
|
|
340
340
|
announceSecretEnvScrub(onNotice, findings);
|
|
341
341
|
}
|
|
342
342
|
child = spawn(command, args, { ...lspSpawnOptions(cwd), env: scrubbedEnv });
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export type { RunInternals, ResolvedWorkspace } from "./core/runner/prepare-task
|
|
|
11
11
|
export type { RunnerSelfSeat } from "./core/runner/contracts.js";
|
|
12
12
|
export type { BudgetAxis } from "./core/runner/assemble-result.js";
|
|
13
13
|
export { terminalProjection } from "./core/runner/terminal-projection.js";
|
|
14
|
+
export { toolOutputBlockChars } from "./core/runner/tool-output-projection.js";
|
|
14
15
|
export { SESSION_LOG_DIGEST_SCHEME, sessionEntryDigest, sessionLogDigest, sessionLogDigestsComparable, } from "./engine/session/log-digest.js";
|
|
15
16
|
export type { ResumeTaskConfig } from "./core/runner/runtask.js";
|
|
16
17
|
export { defineTool } from "./core/tools.js";
|
|
@@ -75,7 +76,7 @@ export { WORKFLOW_SIZE_GUIDELINE_AGENT_CAPS } from "./orchestration/workflow-siz
|
|
|
75
76
|
export { ENGINE_AUTHORITY_ENVELOPE_TAGS } from "./core/untrusted-text.js";
|
|
76
77
|
export { materializeA2aTools, A2aRpcError, type MaterializedA2a, type A2aPeerStatus, type A2aRefreshResult, type A2aToolAxis } from "./core/a2a.js";
|
|
77
78
|
export { PROTOCOL_TABLE, MCP_NAMESPACE, A2A_NAMESPACE, protocolOf, type ProtocolNamespace, type ProtocolId } from "./core/protocol-table.js";
|
|
78
|
-
export { InMemorySessionPolicyStore, SessionPolicyError, loosenReasons, normalizeRules, judgeSessionRulesWrite, readSessionRulesShape, type SessionPolicyStoreOptions, type SessionRuleShapeRefusal, type SessionRuleEntryRefusal, type SessionRuleEntryField, type SessionPolicyStore, type SessionPermissionRules, type StoredSessionRules, type SessionRulesRecord, type PutRulesOptions, } from "./core/session-policy-store.js";
|
|
79
|
+
export { InMemorySessionPolicyStore, SessionPolicyError, loosenReasons, normalizeRules, judgeSessionRulesWrite, readSessionRulesShape, SESSION_RULES_GRAMMAR, compileSessionRuleBucket, type SessionRulesInGrammar, type SessionPolicyStoreOptions, type SessionRuleShapeRefusal, type SessionRuleEntryRefusal, type SessionRuleEntryField, type SessionPolicyStore, type SessionPermissionRules, type StoredSessionRules, type SessionRulesRecord, type PutRulesOptions, } from "./core/session-policy-store.js";
|
|
79
80
|
export { SAFETY_MERGE_CONFORMANCE_CORPUS, type SafetyMergeVector } from "./core/safety-merge-corpus.js";
|
|
80
81
|
export { SAFETY_AXIS_VOCABULARY } from "./core/safety-axis-vocab.js";
|
|
81
82
|
export { createSessionRulePolicy } from "./core/runner/session-rule-policy.js";
|
|
@@ -98,6 +99,8 @@ export { getShellConfig, isWslBashLauncher } from "./engine/execution-env/node-e
|
|
|
98
99
|
export { walkSymlinkChain, SYMLINK_CHAIN_MAX_HOPS, type SymlinkHopReader } from "./engine/execution-env/symlink-chain.js";
|
|
99
100
|
export { isSecretEnvKey, scrubSecretEnv } from "./core/secret-env.js";
|
|
100
101
|
export type { SecretEnvFinding, SecretEnvFindingKind } from "./core/secret-env.js";
|
|
102
|
+
export { declareWithheldEnv, inheritedHostEnv, inheritEnvPolicyProblem, type InheritEnvPolicy } from "./core/secret-env.js";
|
|
103
|
+
export { ENGINE_CAPABILITIES, type EngineCapability } from "./core/engine-capabilities.js";
|
|
101
104
|
export { MAX_EXEC_OUTPUT_BYTES, RollingTailBuffer, markTruncated } from "./core/exec-output-tail.js";
|
|
102
105
|
export { physicalPathOf, physicalPathOfExisting } from "./core/physical-path.js";
|
|
103
106
|
export type { ExecutionEnv, FileInfo, Result, FileErrorCode, ExecutionErrorCode, WriteExpectation, WriteReceipt, SymlinkChain, BoundFileObject } from "./internal/harness.js";
|
|
@@ -338,12 +341,15 @@ export { untrustedEgressForHuman, redactHostLeaks, redactSecrets, boundedRedacte
|
|
|
338
341
|
export type { Egress, EgressTier } from "./core/untrusted-egress.js";
|
|
339
342
|
export type { RedactionFinding, RedactionReport, RedactionConfidence, RedactionSource, SummarizableFinding, } from "./core/untrusted-egress.js";
|
|
340
343
|
export { summarizeRedactions } from "./core/untrusted-egress.js";
|
|
344
|
+
export { headerOwnershipCollision } from "./core/protocol-http-auth.js";
|
|
345
|
+
export type { ProtocolHttpAuth } from "./core/protocol-http-auth.js";
|
|
341
346
|
export { MemoryRosterStore, FileRosterStore, type RosterStore, type RosterEntry, type RosterAccess, type RosterGcOptions } from "./agents/roster-store.js";
|
|
342
347
|
export { CONFIG_CATALOG_VERSION, describeConfigCatalog, resolveEffectiveConfig, type ConfigKnob, type ConfigOverrideDeclaration, type ConfigProvenance, type EffectiveConfigField, } from "./config/catalog.js";
|
|
343
348
|
export { normalizeAgentName } from "./core/task-registry.js";
|
|
344
349
|
export { DELEGATION_MAX_CONCURRENT_DEFAULT, DELEGATION_MAX_PER_SESSION_DEFAULT, SUBAGENT_TRANSCRIPT_RETENTION_DAYS_DEFAULT, } from "./config/defaults.js";
|
|
345
350
|
export { COORDINATOR_ROLE_PROMPT, TEAMMATE_COMMUNICATION_ADDENDUM } from "./prompts/coordinator.js";
|
|
346
|
-
export
|
|
351
|
+
export type { BuiltinSubagentType } from "./agents/subagent.js";
|
|
352
|
+
export { createSubagentTool, FORK_SUBAGENT_TYPE, BUILTIN_SUBAGENT_TYPES, GENERAL_PURPOSE_SUBAGENT_TYPE, agentWhenToUseText, FORK_DIRECTIVE_FRAME, SUBAGENT_SYSTEM_NOTE, type SubagentToolOptions, resolveDelegationEntryCaps, type ResolvedDelegationEntryCaps, type SubagentSpawnContext, type SubagentSteerHandle, type SubagentStep, type SubagentEditedFile, } from "./agents/subagent.js";
|
|
347
353
|
export { getSessionRetainLedger, releaseSessionRetainLedger, } from "./agents/retain-ledger.js";
|
|
348
354
|
export { createSendMessageTool, createAgentContinuationVerb, SEND_MESSAGE_TOOL_NAME, type SendMessageToolOptions, type AgentContinuationReceipt } from "./agents/send-message-tool.js";
|
|
349
355
|
export { createPeerAdmission, peerAdmissionFor, judgePeerAdmission, resolvePeerLaneConfig, PEER_LANE_DEFAULTS, PEER_HOP_CHAIN_WINDOW, PEER_MESSAGE_NOTICE, createPeerSelfRef, createPeerInboundChainRef, peerAxisToken, appendHopToken, type PeerAdmission, type PeerLaneConfig, type PeerAdmissionOptions, type PeerAdmissionRequest, type PeerAdmissionVerdict, type PeerAdmissionRefusal, type PeerRefusalCode, type PeerAxisTag, type PeerIdentity, type PeerSelfRef, type PeerInboundChainRef, } from "./agents/peer-admission.js";
|
|
@@ -395,3 +401,5 @@ export { RULE_OFFERS_ABSENCES, type RuleOffersAbsence } from "./core/ask-origin.
|
|
|
395
401
|
export { BOUND_GRANT_ABSENCES, type BoundGrantAbsence } from "./core/skill-grant-binding.js";
|
|
396
402
|
export { DISPOSABLE_PROMPT_SECTIONS, type DisposablePromptSection, type PromptSectionEntry, type PromptSectionDisposition, type PromptSectionAuthor, type McpInstructionsEntry } from "./core/prompt-section-seat.js";
|
|
397
403
|
export type { McpRevocationLedger, McpMountIdentity } from "./core/mcp-server-spec.js";
|
|
404
|
+
export { readMcpToolAxes } from "./core/mcp-server-spec.js";
|
|
405
|
+
export type { McpToolAxesRead } from "./core/mcp-server-spec.js";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { Runner, runTask } from "./core/runner/runtask.js";
|
|
2
2
|
export { resolveTaskLimits } from "./core/runner/prepare-task.js";
|
|
3
3
|
export { terminalProjection } from "./core/runner/terminal-projection.js";
|
|
4
|
+
export { toolOutputBlockChars } from "./core/runner/tool-output-projection.js";
|
|
4
5
|
export { SESSION_LOG_DIGEST_SCHEME, sessionEntryDigest, sessionLogDigest, sessionLogDigestsComparable, } from "./engine/session/log-digest.js";
|
|
5
6
|
export { defineTool } from "./core/tools.js";
|
|
6
7
|
export { SKILL_TOOL_NAME } from "./core/runner/synthetic-tools.js";
|
|
@@ -61,7 +62,7 @@ export { WORKFLOW_SIZE_GUIDELINE_AGENT_CAPS } from "./orchestration/workflow-siz
|
|
|
61
62
|
export { ENGINE_AUTHORITY_ENVELOPE_TAGS } from "./core/untrusted-text.js";
|
|
62
63
|
export { materializeA2aTools, A2aRpcError } from "./core/a2a.js";
|
|
63
64
|
export { PROTOCOL_TABLE, MCP_NAMESPACE, A2A_NAMESPACE, protocolOf } from "./core/protocol-table.js";
|
|
64
|
-
export { InMemorySessionPolicyStore, SessionPolicyError, loosenReasons, normalizeRules, judgeSessionRulesWrite, readSessionRulesShape, } from "./core/session-policy-store.js";
|
|
65
|
+
export { InMemorySessionPolicyStore, SessionPolicyError, loosenReasons, normalizeRules, judgeSessionRulesWrite, readSessionRulesShape, SESSION_RULES_GRAMMAR, compileSessionRuleBucket, } from "./core/session-policy-store.js";
|
|
65
66
|
export { SAFETY_MERGE_CONFORMANCE_CORPUS } from "./core/safety-merge-corpus.js";
|
|
66
67
|
export { SAFETY_AXIS_VOCABULARY } from "./core/safety-axis-vocab.js";
|
|
67
68
|
export { createSessionRulePolicy } from "./core/runner/session-rule-policy.js";
|
|
@@ -82,6 +83,8 @@ export { killProcessTree, signalProcessTree } from "./engine/execution-env/kill-
|
|
|
82
83
|
export { getShellConfig, isWslBashLauncher } from "./engine/execution-env/node-execution-env.js";
|
|
83
84
|
export { walkSymlinkChain, SYMLINK_CHAIN_MAX_HOPS } from "./engine/execution-env/symlink-chain.js";
|
|
84
85
|
export { isSecretEnvKey, scrubSecretEnv } from "./core/secret-env.js";
|
|
86
|
+
export { declareWithheldEnv, inheritedHostEnv, inheritEnvPolicyProblem } from "./core/secret-env.js";
|
|
87
|
+
export { ENGINE_CAPABILITIES } from "./core/engine-capabilities.js";
|
|
85
88
|
export { MAX_EXEC_OUTPUT_BYTES, RollingTailBuffer, markTruncated } from "./core/exec-output-tail.js";
|
|
86
89
|
export { physicalPathOf, physicalPathOfExisting } from "./core/physical-path.js";
|
|
87
90
|
export { RemoteExecutionError, hasDestroy, isRemoteExecutionEnv, isSuspendable, isIsolated, canonicalPathIsAuthoritative, missingRestoreSurface, isRetryableRemoteErrorCode, RETRYABLE_REMOTE_ERROR_CODES, } from "./core/remote-env.js";
|
|
@@ -276,12 +279,13 @@ export { A2A_TASK_STATES, toA2ATaskState, fromA2ATaskState, } from "./core/a2a-t
|
|
|
276
279
|
export { InMemoryWorkflowJournalStore, callKeyOrdinal, JOURNAL_OVERSIZE_ERROR_CODE, WorkflowJournalOversizeError, assertJournalEntryFits, } from "./core/workflow-journal-store.js";
|
|
277
280
|
export { untrustedEgressForHuman, redactHostLeaks, redactSecrets, boundedRedactedSummary } from "./core/untrusted-egress.js";
|
|
278
281
|
export { summarizeRedactions } from "./core/untrusted-egress.js";
|
|
282
|
+
export { headerOwnershipCollision } from "./core/protocol-http-auth.js";
|
|
279
283
|
export { MemoryRosterStore, FileRosterStore } from "./agents/roster-store.js";
|
|
280
284
|
export { CONFIG_CATALOG_VERSION, describeConfigCatalog, resolveEffectiveConfig, } from "./config/catalog.js";
|
|
281
285
|
export { normalizeAgentName } from "./core/task-registry.js";
|
|
282
286
|
export { DELEGATION_MAX_CONCURRENT_DEFAULT, DELEGATION_MAX_PER_SESSION_DEFAULT, SUBAGENT_TRANSCRIPT_RETENTION_DAYS_DEFAULT, } from "./config/defaults.js";
|
|
283
287
|
export { COORDINATOR_ROLE_PROMPT, TEAMMATE_COMMUNICATION_ADDENDUM } from "./prompts/coordinator.js";
|
|
284
|
-
export { createSubagentTool, FORK_SUBAGENT_TYPE, GENERAL_PURPOSE_SUBAGENT_TYPE, agentWhenToUseText, FORK_DIRECTIVE_FRAME, SUBAGENT_SYSTEM_NOTE, resolveDelegationEntryCaps, } from "./agents/subagent.js";
|
|
288
|
+
export { createSubagentTool, FORK_SUBAGENT_TYPE, BUILTIN_SUBAGENT_TYPES, GENERAL_PURPOSE_SUBAGENT_TYPE, agentWhenToUseText, FORK_DIRECTIVE_FRAME, SUBAGENT_SYSTEM_NOTE, resolveDelegationEntryCaps, } from "./agents/subagent.js";
|
|
285
289
|
export { getSessionRetainLedger, releaseSessionRetainLedger, } from "./agents/retain-ledger.js";
|
|
286
290
|
export { createSendMessageTool, createAgentContinuationVerb, SEND_MESSAGE_TOOL_NAME } from "./agents/send-message-tool.js";
|
|
287
291
|
export { createPeerAdmission, peerAdmissionFor, judgePeerAdmission, resolvePeerLaneConfig, PEER_LANE_DEFAULTS, PEER_HOP_CHAIN_WINDOW, PEER_MESSAGE_NOTICE, createPeerSelfRef, createPeerInboundChainRef, peerAxisToken, appendHopToken, } from "./agents/peer-admission.js";
|
|
@@ -328,3 +332,4 @@ export { SHADOW_REASON, allowRuleShadowSentence, cardDisclosureOf } from "./core
|
|
|
328
332
|
export { RULE_OFFERS_ABSENCES } from "./core/ask-origin.js";
|
|
329
333
|
export { BOUND_GRANT_ABSENCES } from "./core/skill-grant-binding.js";
|
|
330
334
|
export { DISPOSABLE_PROMPT_SECTIONS } from "./core/prompt-section-seat.js";
|
|
335
|
+
export { readMcpToolAxes } from "./core/mcp-server-spec.js";
|
|
@@ -5,7 +5,7 @@ import { hrtime } from "node:process";
|
|
|
5
5
|
import { basename, dirname, join, resolve as resolvePath } from "node:path";
|
|
6
6
|
import { createHash, randomBytes } from "node:crypto";
|
|
7
7
|
import { execFileSync } from "node:child_process";
|
|
8
|
-
import {
|
|
8
|
+
import { inheritedHostEnv } from "../../core/secret-env.js";
|
|
9
9
|
import { physicalPathOf, physicalPathOfExisting } from "../../core/physical-path.js";
|
|
10
10
|
import { thrownText } from "../../core/thrown-value.js";
|
|
11
11
|
const SAFE_COMPONENT = /^[A-Za-z0-9_.-]+$/;
|
|
@@ -713,7 +713,7 @@ function probeStartTimesOnce(pid) {
|
|
|
713
713
|
encoding: "utf8",
|
|
714
714
|
timeout: START_TIME_PROBE_TIMEOUT_MS,
|
|
715
715
|
stdio: ["ignore", "pipe", "ignore"],
|
|
716
|
-
env: { ...
|
|
716
|
+
env: { ...inheritedHostEnv("scrub"), LC_ALL: "C", LANG: "C" },
|
|
717
717
|
});
|
|
718
718
|
}
|
|
719
719
|
catch (err) {
|
|
@@ -102,9 +102,9 @@ export declare function judgeSessionPolicyRowObject(raw: string): {
|
|
|
102
102
|
*
|
|
103
103
|
* Required: `rev` >= 1 (a rev-0 row would read as the live reader's SYNTHETIC empty seed); `gen`, when present, a
|
|
104
104
|
* whole number (a STRING `rev` poisons the CAS arithmetic); the rules themselves read by the ONE shape reading
|
|
105
|
-
* (`readSessionRulesShape` — every key a bucket, every bucket a list of strings
|
|
106
|
-
* rules (a key that is no bucket) is refused like any malformed row, never read as fewer rules.
|
|
107
|
-
* metadata is STRIPPED so the value is byte-identical to the in-memory twin's.
|
|
105
|
+
* (`readSessionRulesShape` — every key a bucket, every bucket a list of strings, a `grammar` this engine reads), so a row it
|
|
106
|
+
* cannot read as rules (a key that is no bucket, a later grammar) is refused like any malformed row, never read as fewer rules.
|
|
107
|
+
* The `__sid`/`__principal` metadata is STRIPPED so the value is byte-identical to the in-memory twin's.
|
|
108
108
|
*/
|
|
109
109
|
export declare function judgeSessionPolicyRowShape(row: Record<string, unknown>): {
|
|
110
110
|
rules: StoredSessionRules;
|