@sema-agent/server 7.103.2 → 7.105.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/MIGRATION.md +378 -2
- package/README.md +6 -1
- package/README.zh-CN.md +5 -1
- package/USAGE.md +320 -16
- package/deploy/sema-up/README.md +57 -7
- package/deploy/sema-up/cluster-up.sh +18 -4
- package/deploy/sema-up/kube-up.sh +16 -0
- package/deploy/sema-up/lib/dataroot.sh +142 -0
- package/deploy/sema-up/lib/flagshape.sh +69 -0
- package/deploy/sema-up/lib/lanes.py +14 -4
- package/deploy/sema-up/lib/shell-access.sh +41 -0
- package/deploy/sema-up/preflight.sh +14 -1
- package/deploy/sema-up/sema-up.sh +134 -37
- package/deploy/sema-up/smoke.sh +5 -0
- package/dist/auto-mode-face.js +3 -4
- package/dist/boot/budget-tracing.js +1 -1
- package/dist/boot/config-center.d.ts +6 -2
- package/dist/boot/config-center.js +5 -59
- package/dist/boot/execution-env.d.ts +11 -0
- package/dist/boot/execution-env.js +14 -0
- package/dist/boot/execution-lane.d.ts +25 -0
- package/dist/boot/execution-lane.js +95 -0
- package/dist/boot/memory-consolidation.d.ts +185 -9
- package/dist/boot/memory-consolidation.js +192 -32
- package/dist/boot/resolve-spec.d.ts +2 -0
- package/dist/boot/resolve-spec.js +28 -24
- package/dist/boot/runner-deps.d.ts +6 -2
- package/dist/boot/runner-deps.js +6 -1
- package/dist/boot/session-faces.d.ts +5 -0
- package/dist/boot/session-faces.js +18 -2
- package/dist/boot/session-incarnation-seat.d.ts +41 -0
- package/dist/boot/session-incarnation-seat.js +69 -0
- package/dist/boot/stage-01-config.js +2 -2
- package/dist/boot/stage-02-registry-pull.js +3 -1
- package/dist/boot/stage-04-stores.d.ts +2 -0
- package/dist/boot/stage-04-stores.js +3 -1
- package/dist/boot/stage-05-execution-env.d.ts +4 -0
- package/dist/boot/stage-05-execution-env.js +2 -2
- package/dist/boot/stage-06-runners.d.ts +4 -1
- package/dist/boot/stage-06-runners.js +7 -14
- package/dist/boot/stage-07-capability-layer.d.ts +4 -1
- package/dist/boot/stage-08-reapers.d.ts +4 -1
- package/dist/boot/stage-09-leader.d.ts +6 -1
- package/dist/boot/stage-09-leader.js +2 -1
- package/dist/boot/stage-10-http-server.d.ts +6 -1
- package/dist/boot/stage-10-http-server.js +4 -1
- package/dist/brain.d.ts +1 -1
- package/dist/config-catalog.d.ts +16 -1
- package/dist/config-catalog.js +9 -9
- package/dist/config-center/restart-signal.d.ts +4 -4
- package/dist/config-invariants.d.ts +7 -1
- package/dist/config-invariants.js +37 -6
- package/dist/config-provider.d.ts +42 -10
- package/dist/config-provider.js +18 -16
- package/dist/config-types.d.ts +37 -16
- package/dist/config-types.js +1 -0
- package/dist/config.d.ts +28 -30
- package/dist/config.js +95 -77
- package/dist/env-facts.d.ts +13 -3
- package/dist/env-facts.js +15 -3
- package/dist/execution-lane-caps.d.ts +15 -0
- package/dist/execution-lane-caps.js +8 -0
- package/dist/file-history-capture.d.ts +42 -35
- package/dist/file-history-capture.js +15 -10
- package/dist/file-history-disclosure.d.ts +7 -31
- package/dist/file-history-disclosure.js +12 -0
- package/dist/fleet/fleet-bus.d.ts +5 -1
- package/dist/http/admission.d.ts +12 -5
- package/dist/http/admission.js +5 -1
- package/dist/http/dispatch.d.ts +18 -0
- package/dist/http/dispatch.js +19 -6
- package/dist/http/principal-gate.d.ts +22 -0
- package/dist/http/principal-gate.js +20 -0
- package/dist/http/resume-legs.d.ts +1 -1
- package/dist/http/resume-legs.js +9 -5
- package/dist/http/route-table.d.ts +15 -4
- package/dist/http/route-table.js +6 -5
- package/dist/http/routes/agents-roster.d.ts +7 -0
- package/dist/http/routes/agents-roster.js +6 -2
- package/dist/http/routes/approvals-assistant.d.ts +48 -19
- package/dist/http/routes/approvals-assistant.js +117 -50
- package/dist/http/routes/capabilities.js +3 -2
- package/dist/http/routes/config-catalog.js +1 -0
- package/dist/http/routes/fleet.d.ts +3 -2
- package/dist/http/routes/images.js +0 -1
- package/dist/http/routes/memory-consolidation.d.ts +3 -2
- package/dist/http/routes/memory-policy.js +3 -3
- package/dist/http/routes/rules.js +2 -2
- package/dist/http/routes/runs.js +29 -10
- package/dist/http/routes/session-sync.js +14 -15
- package/dist/http/routes/sessions-list.js +3 -2
- package/dist/http/routes/sessions.js +49 -25
- package/dist/http/routes/shared-memory.js +2 -2
- package/dist/http/routes/side-query.js +8 -1
- package/dist/http/routes/tasks.js +22 -19
- package/dist/http/routes/trace-usage.d.ts +2 -0
- package/dist/http/routes/trace-usage.js +8 -13
- package/dist/http/send.d.ts +12 -0
- package/dist/http/send.js +12 -1
- package/dist/http/server.d.ts +30 -8
- package/dist/http/server.js +11 -5
- package/dist/http/sse-lifecycle.d.ts +1 -1
- package/dist/http/sse-log.d.ts +12 -9
- package/dist/http/sse-log.js +1 -8
- package/dist/http/sync-submit-body.d.ts +43 -0
- package/dist/http/sync-submit-body.js +4 -0
- package/dist/http/wire-types.d.ts +23 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/leader/merge.d.ts +8 -3
- package/dist/memory-incident-sink.js +2 -1
- package/dist/model-select.d.ts +9 -0
- package/dist/model-select.js +5 -1
- package/dist/observability/corrupt-read-seat.d.ts +151 -16
- package/dist/observability/corrupt-read-seat.js +158 -15
- package/dist/observability/fail-open.d.ts +17 -1
- package/dist/observability/fail-open.js +17 -1
- package/dist/observability/metrics.js +1 -1
- package/dist/observability/run-terminal.d.ts +60 -10
- package/dist/observability/run-terminal.js +119 -9
- package/dist/parked-decide.d.ts +8 -3
- package/dist/parked-decide.js +56 -20
- package/dist/parked-revive-surface.d.ts +14 -7
- package/dist/parked-revive-surface.js +5 -1
- package/dist/plugins/approval-ask-store-file.d.ts +4 -1
- package/dist/plugins/approval-ask-store-file.js +9 -12
- package/dist/plugins/approval-ask-store-sql.d.ts +4 -0
- package/dist/plugins/approval-ask-store-sql.js +4 -1
- package/dist/plugins/approval-exemption-store.d.ts +21 -1
- package/dist/plugins/approval-exemption-store.js +36 -7
- package/dist/plugins/approval-nonce-store.d.ts +16 -2
- package/dist/plugins/approval-nonce-store.js +17 -7
- package/dist/plugins/caching-session-store.d.ts +5 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/file-resume-anchor-store.d.ts +7 -2
- package/dist/plugins/file-resume-anchor-store.js +19 -5
- package/dist/plugins/file-run-store.d.ts +21 -8
- package/dist/plugins/file-run-store.js +60 -38
- package/dist/plugins/image-bake-store-sql.d.ts +0 -2
- package/dist/plugins/image-bake-store-sql.js +0 -5
- package/dist/plugins/local-session-store.d.ts +22 -0
- package/dist/plugins/local-session-store.js +74 -11
- package/dist/plugins/memory-run-store.d.ts +7 -5
- package/dist/plugins/memory-run-store.js +11 -4
- package/dist/plugins/one-time-migrations.d.ts +38 -1
- package/dist/plugins/one-time-migrations.js +143 -15
- package/dist/plugins/permission-rule-store-file.d.ts +9 -2
- package/dist/plugins/permission-rule-store-file.js +37 -51
- package/dist/plugins/pg-session-storage.d.ts +3 -0
- package/dist/plugins/pg-session-storage.js +19 -10
- package/dist/plugins/retention-store-sql.js +1 -0
- package/dist/plugins/run-store-sql.d.ts +15 -6
- package/dist/plugins/run-store-sql.js +15 -13
- package/dist/plugins/schema-indexes.js +1 -0
- package/dist/plugins/send-file-ledger.d.ts +5 -1
- package/dist/plugins/send-file-ledger.js +11 -6
- package/dist/plugins/session-event-payload.d.ts +14 -4
- package/dist/plugins/session-event-payload.js +5 -2
- package/dist/plugins/session-policy-store-sql.js +18 -5
- package/dist/plugins/store-backend.d.ts +13 -7
- package/dist/plugins/store-backend.js +10 -6
- package/dist/plugins/store-contracts.d.ts +7 -2
- package/dist/plugins/tidb-pool.js +12 -5
- package/dist/plugins/tidb-session-store.d.ts +6 -1
- package/dist/plugins/tidb-session-store.js +17 -10
- package/dist/project-identity.d.ts +4 -6
- package/dist/read-face-posture.d.ts +21 -0
- package/dist/read-face-posture.js +9 -0
- package/dist/request-key-closure.js +1 -1
- package/dist/request-value-closure.d.ts +72 -3
- package/dist/request-value-closure.js +12 -4
- package/dist/roster-bound-http-status.d.ts +6 -0
- package/dist/roster-bound-http-status.js +6 -0
- package/dist/rules-consent.js +0 -11
- package/dist/run-local.js +22 -27
- package/dist/runs.d.ts +22 -2
- package/dist/runs.js +29 -7
- package/dist/sealed-key.d.ts +31 -4
- package/dist/sealed-key.js +9 -0
- package/dist/security.d.ts +5 -1
- package/dist/session-children-retire.d.ts +92 -0
- package/dist/session-children-retire.js +85 -0
- package/dist/session-error-wire.d.ts +58 -0
- package/dist/session-error-wire.js +38 -0
- package/dist/session-incarnation.d.ts +61 -0
- package/dist/session-incarnation.js +43 -0
- package/dist/session-policy-wire.d.ts +98 -12
- package/dist/session-policy-wire.js +71 -8
- package/dist/session-records-skipped-notice.d.ts +20 -0
- package/dist/session-records-skipped-notice.js +27 -0
- package/dist/tool-approval.d.ts +65 -0
- package/dist/tool-approval.js +36 -9
- package/dist/trace/core-keyset-guard.d.ts +8 -7
- package/dist/trace/engine-notice-wire.d.ts +3 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/project.d.ts +11 -6
- package/dist/trace/project.js +12 -3
- package/dist/trace/redact.d.ts +7 -0
- package/dist/trace/redact.js +153 -61
- package/dist/trace/wire-projection-faces.d.ts +10 -3
- package/dist/trace/wire-projection-faces.js +8 -2
- package/package.json +2 -2
- package/dist/plugins/memory-session-policy-store.d.ts +0 -46
- package/dist/plugins/memory-session-policy-store.js +0 -52
package/dist/trace/redact.js
CHANGED
|
@@ -486,13 +486,12 @@ function deriveLiteralHead(re) {
|
|
|
486
486
|
function scanResumeAfterHit(start, end, back) {
|
|
487
487
|
return Math.max(start + 1, end - back);
|
|
488
488
|
}
|
|
489
|
-
const spanOffset = (a, m) => (a.outside === 1 ? m[1].length : 0);
|
|
490
489
|
function collectRegexSpans(a, text, out) {
|
|
491
490
|
const g = a.g;
|
|
492
491
|
g.lastIndex = 0;
|
|
493
492
|
for (let m = g.exec(text); m !== null; m = g.exec(text)) {
|
|
494
493
|
const end = m.index + m[0].length;
|
|
495
|
-
out.push({ start: m.index
|
|
494
|
+
out.push({ start: m.index, end, repl: a.repl, rank: a.rank, order: a.order });
|
|
496
495
|
g.lastIndex = scanResumeAfterHit(m.index, end, a.back);
|
|
497
496
|
}
|
|
498
497
|
}
|
|
@@ -585,7 +584,7 @@ function collectStickySpans(a, text, at, out) {
|
|
|
585
584
|
if (m === null)
|
|
586
585
|
continue;
|
|
587
586
|
const end = p + m[0].length;
|
|
588
|
-
out.push({ start: p
|
|
587
|
+
out.push({ start: p, end, repl, rank, order });
|
|
589
588
|
pos = scanResumeAfterHit(p, end, back);
|
|
590
589
|
}
|
|
591
590
|
}
|
|
@@ -935,6 +934,47 @@ function collectSsh2FenceSpans(text, span) {
|
|
|
935
934
|
from = scanResumeAfterHit(fence, end, SSH2_FENCE_OPEN.length);
|
|
936
935
|
}
|
|
937
936
|
}
|
|
937
|
+
const PEM_END_OPEN = "-----END";
|
|
938
|
+
const PEM_FENCE_BODY_MAX = 8192;
|
|
939
|
+
function pemFenceLineEnd(text, labelFrom) {
|
|
940
|
+
const close = text.indexOf(PEM_FENCE_CLOSE, labelFrom);
|
|
941
|
+
return close >= 0 && isPemFenceLabel(text, labelFrom, close) ? close + PEM_FENCE_CLOSE.length : -1;
|
|
942
|
+
}
|
|
943
|
+
function collectPemFenceSpans(text, span) {
|
|
944
|
+
let endFrom = -1;
|
|
945
|
+
let endAt = -1;
|
|
946
|
+
let endAfter = -1;
|
|
947
|
+
const earliestEndFence = (from) => {
|
|
948
|
+
if (endFrom >= 0 && from >= endFrom && (endAt < 0 || endAt >= from))
|
|
949
|
+
return;
|
|
950
|
+
let b = text.indexOf(PEM_END_OPEN, from);
|
|
951
|
+
let after = -1;
|
|
952
|
+
while (b >= 0 && (after = pemFenceLineEnd(text, b + PEM_END_OPEN.length)) < 0)
|
|
953
|
+
b = text.indexOf(PEM_END_OPEN, b + 1);
|
|
954
|
+
endFrom = from;
|
|
955
|
+
endAt = b;
|
|
956
|
+
endAfter = after;
|
|
957
|
+
};
|
|
958
|
+
for (let from = 0;;) {
|
|
959
|
+
const fence = text.indexOf(PEM_FENCE_OPEN, from);
|
|
960
|
+
if (fence < 0)
|
|
961
|
+
return;
|
|
962
|
+
const bodyFrom = pemFenceLineEnd(text, fence + PEM_FENCE_OPEN.length);
|
|
963
|
+
if (bodyFrom < 0) {
|
|
964
|
+
from = fence + 1;
|
|
965
|
+
continue;
|
|
966
|
+
}
|
|
967
|
+
earliestEndFence(bodyFrom);
|
|
968
|
+
if (endAt < 0)
|
|
969
|
+
return;
|
|
970
|
+
if (endAt - bodyFrom > PEM_FENCE_BODY_MAX) {
|
|
971
|
+
from = fence + 1;
|
|
972
|
+
continue;
|
|
973
|
+
}
|
|
974
|
+
span(fence, endAfter);
|
|
975
|
+
from = scanResumeAfterHit(fence, endAfter, PEM_FENCE_OPEN.length);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
938
978
|
function collectPemFragmentSpans(text, json, span) {
|
|
939
979
|
let cur = findPemFence(text, 0);
|
|
940
980
|
let inherited = false;
|
|
@@ -1145,6 +1185,18 @@ const SSH2_FENCE_PATTERN = (() => {
|
|
|
1145
1185
|
throw new Error("redact: SSH2 fence rule missing from FULL_ARM_PATTERNS");
|
|
1146
1186
|
return row;
|
|
1147
1187
|
})();
|
|
1188
|
+
const PEM_FENCE_PATTERN = (() => {
|
|
1189
|
+
const row = FULL_ARM_PATTERNS.find(([re]) => re.source.startsWith(PEM_FENCE_OPEN));
|
|
1190
|
+
if (row === undefined)
|
|
1191
|
+
throw new Error("redact: PEM fence rule missing from FULL_ARM_PATTERNS");
|
|
1192
|
+
return row;
|
|
1193
|
+
})();
|
|
1194
|
+
const JSON_SECRET_FIELD_PATTERN = (() => {
|
|
1195
|
+
const rows = FULL_ARM_PATTERNS.filter(([, repl]) => repl === '$1"«redacted»"');
|
|
1196
|
+
if (rows.length !== 1)
|
|
1197
|
+
throw new Error(`redact: expected exactly one JSON secret-field rule (replacement '$1"«redacted»"') in FULL_ARM_PATTERNS, found ${rows.length}`);
|
|
1198
|
+
return rows[0];
|
|
1199
|
+
})();
|
|
1148
1200
|
const isRegexSpace = (c) => c === 32 || (c >= 9 && c <= 13) || c === 0xa0 || c === 0x1680 || (c >= 0x2000 && c <= 0x200a) || c === 0x2028 || c === 0x2029 || c === 0x202f || c === 0x205f || c === 0x3000 || c === 0xfeff;
|
|
1149
1201
|
const isLineTerminator = (c) => c === 10 || c === 13 || c === 0x2028 || c === 0x2029;
|
|
1150
1202
|
const isControlCode = (c) => c < 0x20 || c === 0x7f;
|
|
@@ -1360,6 +1412,78 @@ function collectUrlCredentialSpans(text, json, span) {
|
|
|
1360
1412
|
i = valueEnd - 1;
|
|
1361
1413
|
}
|
|
1362
1414
|
}
|
|
1415
|
+
const JSON_FIELD_ANCHOR = '"';
|
|
1416
|
+
const CREDENTIAL_NAME_MAX = Math.max(...CREDENTIAL_NAME_WORDS.map((w) => w.length));
|
|
1417
|
+
function jsonSecretFieldValueQuoteAt(text, p) {
|
|
1418
|
+
const n = text.length;
|
|
1419
|
+
let name = "";
|
|
1420
|
+
let i = p + 1;
|
|
1421
|
+
for (; i < n; i++) {
|
|
1422
|
+
let c = text.charCodeAt(i);
|
|
1423
|
+
if (c === CH_QUOTE)
|
|
1424
|
+
break;
|
|
1425
|
+
if (i - p > CREDENTIAL_NAME_MAX)
|
|
1426
|
+
return -1;
|
|
1427
|
+
if (c >= CH_A && c <= CH_Z)
|
|
1428
|
+
c += 32;
|
|
1429
|
+
if (!((c >= CH_a && c <= CH_z) || (c >= CH_0 && c <= CH_9) || c === CH_UNDERSCORE || c === CH_MINUS))
|
|
1430
|
+
return -1;
|
|
1431
|
+
name += String.fromCharCode(c);
|
|
1432
|
+
}
|
|
1433
|
+
if (i >= n || !CREDENTIAL_NAME_SET.has(name))
|
|
1434
|
+
return -1;
|
|
1435
|
+
i += 1;
|
|
1436
|
+
while (i < n && isRegexSpace(text.charCodeAt(i)))
|
|
1437
|
+
i += 1;
|
|
1438
|
+
if (text.charCodeAt(i) !== CH_COLON)
|
|
1439
|
+
return -1;
|
|
1440
|
+
i += 1;
|
|
1441
|
+
while (i < n && isRegexSpace(text.charCodeAt(i)))
|
|
1442
|
+
i += 1;
|
|
1443
|
+
return text.charCodeAt(i) === CH_QUOTE ? i : -1;
|
|
1444
|
+
}
|
|
1445
|
+
function jsonStringEndAt(text, q) {
|
|
1446
|
+
const n = text.length;
|
|
1447
|
+
for (let i = q + 1; i < n;) {
|
|
1448
|
+
const c = text.charCodeAt(i);
|
|
1449
|
+
if (c === CH_QUOTE)
|
|
1450
|
+
return i + 1;
|
|
1451
|
+
if (c === CH_BACKSLASH) {
|
|
1452
|
+
if (i + 1 < n && !isLineTerminator(text.charCodeAt(i + 1))) {
|
|
1453
|
+
i += 2;
|
|
1454
|
+
continue;
|
|
1455
|
+
}
|
|
1456
|
+
return -1;
|
|
1457
|
+
}
|
|
1458
|
+
i += 1;
|
|
1459
|
+
}
|
|
1460
|
+
return -1;
|
|
1461
|
+
}
|
|
1462
|
+
function collectJsonSecretFieldSpans(text, span) {
|
|
1463
|
+
for (let p = text.indexOf(JSON_FIELD_ANCHOR); p >= 0;) {
|
|
1464
|
+
const q = jsonSecretFieldValueQuoteAt(text, p);
|
|
1465
|
+
const end = q < 0 ? -1 : jsonStringEndAt(text, q);
|
|
1466
|
+
if (end < 0) {
|
|
1467
|
+
p = text.indexOf(JSON_FIELD_ANCHOR, p + 1);
|
|
1468
|
+
continue;
|
|
1469
|
+
}
|
|
1470
|
+
span(q, end);
|
|
1471
|
+
p = text.indexOf(JSON_FIELD_ANCHOR, scanResumeAfterHit(p, end, JSON_FIELD_ANCHOR.length));
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
export function structuralScannerForTest(arm) {
|
|
1475
|
+
const collect = (scan) => (text) => {
|
|
1476
|
+
const out = [];
|
|
1477
|
+
scan(text, (start, end) => out.push([start, end]));
|
|
1478
|
+
return out;
|
|
1479
|
+
};
|
|
1480
|
+
switch (arm) {
|
|
1481
|
+
case "json-secret-field":
|
|
1482
|
+
return { declared: new RegExp(JSON_SECRET_FIELD_PATTERN[0].source, JSON_SECRET_FIELD_PATTERN[0].flags), spans: collect(collectJsonSecretFieldSpans) };
|
|
1483
|
+
case "pem-fence":
|
|
1484
|
+
return { declared: new RegExp(PEM_FENCE_PATTERN[0].source, PEM_FENCE_PATTERN[0].flags), spans: collect(collectPemFenceSpans) };
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1363
1487
|
let ppkScanBytes = 0;
|
|
1364
1488
|
export function ppkScanBytesForTest() { return ppkScanBytes; }
|
|
1365
1489
|
export function resetPpkScanBytesForTest() { ppkScanBytes = 0; }
|
|
@@ -1462,56 +1586,19 @@ const armPool = (() => {
|
|
|
1462
1586
|
throw new Error(`redact: arm-pool replacement ${JSON.stringify(token)} may only use a leading $1 (the run kept outside the span)`);
|
|
1463
1587
|
return body;
|
|
1464
1588
|
};
|
|
1465
|
-
const
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
let out = "";
|
|
1469
|
-
for (; i < src.length; i++) {
|
|
1470
|
-
const c = src[i];
|
|
1471
|
-
if (c === "\\") {
|
|
1472
|
-
const e = src[i + 1];
|
|
1473
|
-
if (e === undefined || !HEAD_LITERAL_ESCAPES.has(e))
|
|
1474
|
-
break;
|
|
1475
|
-
if ("*+?{".includes(src[i + 2] ?? ""))
|
|
1476
|
-
break;
|
|
1477
|
-
out += src.slice(i, i + 2);
|
|
1478
|
-
i += 1;
|
|
1479
|
-
continue;
|
|
1480
|
-
}
|
|
1481
|
-
if ("([{|).^$*+?".includes(c))
|
|
1482
|
-
break;
|
|
1483
|
-
if ("*+?{".includes(src[i + 1] ?? ""))
|
|
1484
|
-
break;
|
|
1485
|
-
out += c;
|
|
1486
|
-
}
|
|
1487
|
-
if (out.length === 0)
|
|
1488
|
-
throw new Error(`redact: structural arm /${src}/ has no literal anchor head — its same-arm rewind amount cannot be derived`);
|
|
1489
|
-
return out;
|
|
1490
|
-
};
|
|
1491
|
-
const regexMember = ([re, token], rank, order, structural) => {
|
|
1589
|
+
const regexMember = ([re, token], rank, order) => {
|
|
1590
|
+
if (token.startsWith("$1"))
|
|
1591
|
+
throw new Error(`redact: regex arm /${re.source}/ cannot carry an outside-span $1 prefix — that form belongs to the structural scanners`);
|
|
1492
1592
|
const repl = spanRepl(token);
|
|
1493
|
-
const outside = token.startsWith("$1") ? 1 : 0;
|
|
1494
1593
|
const y = VALUE_ARM_STICKY.get(re);
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
headFirst = undefined;
|
|
1502
|
-
}
|
|
1503
|
-
else {
|
|
1504
|
-
const d = deriveLiteralHead(re);
|
|
1505
|
-
back = Math.max(d.len - 1, 0);
|
|
1506
|
-
headSrc = d.src;
|
|
1507
|
-
headFirst = d.first;
|
|
1508
|
-
if (y !== undefined && (d.len === 0 || headSrc === undefined || headFirst === undefined)) {
|
|
1509
|
-
throw new Error(`redact: boundary arm /${re.source}/ has a zero-length structural head — the bounded head screen would admit every candidate position`);
|
|
1510
|
-
}
|
|
1594
|
+
const d = deriveLiteralHead(re);
|
|
1595
|
+
const back = Math.max(d.len - 1, 0);
|
|
1596
|
+
const headSrc = d.src;
|
|
1597
|
+
const headFirst = d.first;
|
|
1598
|
+
if (y !== undefined && (d.len === 0 || headSrc === undefined || headFirst === undefined)) {
|
|
1599
|
+
throw new Error(`redact: boundary arm /${re.source}/ has a zero-length structural head — the bounded head screen would admit every candidate position`);
|
|
1511
1600
|
}
|
|
1512
|
-
|
|
1513
|
-
throw new Error(`redact: value arm /${re.source}/ cannot carry an outside-span $1 prefix`);
|
|
1514
|
-
const arm = { g: re, y, back, headSrc, headFirst, repl, rank, order, outside };
|
|
1601
|
+
const arm = { g: re, y, back, headSrc, headFirst, repl, rank, order };
|
|
1515
1602
|
const boundary = y === undefined || headSrc === undefined || headFirst === undefined ? undefined : { ...arm, y, headSrc, headFirst };
|
|
1516
1603
|
return {
|
|
1517
1604
|
token,
|
|
@@ -1541,24 +1628,29 @@ const armPool = (() => {
|
|
|
1541
1628
|
headFirst: undefined,
|
|
1542
1629
|
};
|
|
1543
1630
|
};
|
|
1631
|
+
const structuralScannerMember = (row, order) => {
|
|
1632
|
+
if (row === PEM_FENCE_PATTERN)
|
|
1633
|
+
return scannerMember(row[1], order, 1, (text, _json, _observe, span) => collectPemFenceSpans(text, span));
|
|
1634
|
+
if (row === SSH2_FENCE_PATTERN)
|
|
1635
|
+
return scannerMember(row[1], order, 2, (text, _json, _observe, span) => collectSsh2FenceSpans(text, span));
|
|
1636
|
+
if (row === URL_CREDENTIAL_PATTERN)
|
|
1637
|
+
return scannerMember(row[1], order, 2, (text, json, _observe, span) => collectUrlCredentialSpans(text, json, span));
|
|
1638
|
+
if (row === JSON_SECRET_FIELD_PATTERN)
|
|
1639
|
+
return scannerMember(row[1], order, 1, (text, _json, _observe, span) => collectJsonSecretFieldSpans(text, span));
|
|
1640
|
+
throw new Error(`redact: structural row /${row[0].source}/ has no hand-written scanner — structural grammars are declared as regexes but never executed as one (S-102 / S-265)`);
|
|
1641
|
+
};
|
|
1544
1642
|
const members = [];
|
|
1545
|
-
for (const row of STRUCTURAL_SECRET_PATTERNS)
|
|
1546
|
-
|
|
1547
|
-
members.push(row === URL_CREDENTIAL_PATTERN
|
|
1548
|
-
? scannerMember(row[1], order, 2, (text, json, _observe, span) => collectUrlCredentialSpans(text, json, span))
|
|
1549
|
-
: row === SSH2_FENCE_PATTERN
|
|
1550
|
-
? scannerMember(row[1], order, 2, (text, _json, _observe, span) => collectSsh2FenceSpans(text, span))
|
|
1551
|
-
: regexMember(row, ARM_RANK.structural, order, true));
|
|
1552
|
-
}
|
|
1643
|
+
for (const row of STRUCTURAL_SECRET_PATTERNS)
|
|
1644
|
+
members.push(structuralScannerMember(row, members.length));
|
|
1553
1645
|
members.push(scannerMember(PPK_CONTAINER_TOKEN, members.length, 2, (text, _json, observe, span) => collectPpkContainerSpans(text, observe, span)));
|
|
1554
1646
|
members.push(scannerMember(PEM_FRAGMENT_TOKEN, members.length, 2, (text, json, _observe, span) => collectPemFragmentSpans(text, json, span)));
|
|
1555
1647
|
members.push(scannerMember(HEADLESS_PPK_TOKEN, members.length, 2, (text, _json, _observe, span) => collectHeadlessPpkSpans(text, span)));
|
|
1556
1648
|
for (const row of KEYWORD_SECRET_PATTERNS)
|
|
1557
|
-
members.push(regexMember(row, ARM_RANK.keyword, members.length
|
|
1649
|
+
members.push(regexMember(row, ARM_RANK.keyword, members.length));
|
|
1558
1650
|
for (const row of SHAPE_SECRET_PATTERNS)
|
|
1559
|
-
members.push(regexMember(row, ARM_RANK.shape, members.length
|
|
1651
|
+
members.push(regexMember(row, ARM_RANK.shape, members.length));
|
|
1560
1652
|
for (const row of FRAGMENT_SECRET_PATTERNS)
|
|
1561
|
-
members.push(regexMember(row, ARM_RANK.fragment, members.length
|
|
1653
|
+
members.push(regexMember(row, ARM_RANK.fragment, members.length));
|
|
1562
1654
|
for (const [re] of KEYWORD_SECRET_PATTERNS) {
|
|
1563
1655
|
if (!LEXICAL_KEYWORD_ARMS.has(re))
|
|
1564
1656
|
throw new Error(`redact: keyword arm /${re.source}/ is not registered as lexical — build it with keywordArm() so the bounded-unit scope can exclude it`);
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
* `NotificationExcluded` 直接读成本表这一行的 `excluded`,于是「哪几个键有意不上 wire」全仓**只有一个写者**。
|
|
17
17
|
* 旧形是两个:守卫文件一簿、`test/wire-whitelist-exhaustiveness.test.ts` 的 `KnownExcluded` 一簿,那份门注
|
|
18
18
|
* 自己写着「两处必须同时改」—— 而「必须同时改」正是 [ref] 要下线的东西(对账门不算替代,单写者才算)。
|
|
19
|
-
*
|
|
19
|
+
* 本表是纯数据、无行为(唯一的派生是 `wiring_manifest_operator` 行的 `excluded` 取值器 = 租户行减具名常量,S-724),
|
|
20
|
+
* 被守卫文件以 `typeof import(...)` 的**类型查询**读取(编译期擦除,零运行期边)。
|
|
20
21
|
*
|
|
21
22
|
* ## 门在哪里
|
|
22
23
|
* `test/wire-whitelist-exhaustiveness.test.ts`:对每一行喂一枚 core 型全键 fixture,真的跑一遍构造器,
|
|
@@ -54,6 +55,12 @@ export interface WireProjectionFace {
|
|
|
54
55
|
export declare const FRAME_ENVELOPE_KEYS: readonly ["type", "sourceTaskId", "bgAgentId"];
|
|
55
56
|
/** 探针文件要从 `@sema-agent/core` 具名导入的类型(`coreType` 表达式里用到的全部名字)。 */
|
|
56
57
|
export declare const WIRE_PROJECTION_CORE_IMPORTS: readonly ["TaskEvent", "TaskNotificationPayload", "WiringManifest", "EngineNotice", "MemoryImportReport", "OriginClearanceRow", "OriginClearanceEvent", "MemoryEntryOrigin"];
|
|
58
|
+
/**
|
|
59
|
+
* `wiring_manifest` 的 **operator 面多投的那几段**(`wiringManifestOperatorEventData` 在租户形之上加的段)。
|
|
60
|
+
* operator 行的 `excluded` = 租户行减本常量(派生);四段各自的受众裁定在 `core-keyset-guard.ts` ⑥b。
|
|
61
|
+
* operator 构造器新投一段 ⇒ 同批加进本常量(否则 operator 行会把它登记成「不投」,键集等式门当场红)。
|
|
62
|
+
*/
|
|
63
|
+
export declare const WIRING_MANIFEST_OPERATOR_ONLY_SECTIONS: readonly ["governance", "configFingerprint", "autoConsolidation", "readDeny"];
|
|
57
64
|
/**
|
|
58
65
|
* 全部帧投影面。键 = 面名(门的报错文案与负控都按它称呼这一行)。
|
|
59
66
|
*
|
|
@@ -161,14 +168,14 @@ export declare const WIRE_PROJECTION_FACES: {
|
|
|
161
168
|
readonly wiring_manifest_tenant: {
|
|
162
169
|
readonly projector: "wiringManifestEventData";
|
|
163
170
|
readonly coreType: `WiringManifest & ${string}`;
|
|
164
|
-
readonly excluded: readonly ["governance", "configFingerprint", "autoConsolidation", "readDeny", "peerPresence"
|
|
171
|
+
readonly excluded: readonly ["governance", "configFingerprint", "autoConsolidation", "readDeny", "peerPresence"];
|
|
165
172
|
readonly unwrapped: readonly ["manifest"];
|
|
166
173
|
readonly minted: readonly [];
|
|
167
174
|
};
|
|
168
175
|
readonly wiring_manifest_operator: {
|
|
169
176
|
readonly projector: "wiringManifestOperatorEventData";
|
|
170
177
|
readonly coreType: `WiringManifest & ${string}`;
|
|
171
|
-
readonly excluded: readonly [
|
|
178
|
+
readonly excluded: readonly string[];
|
|
172
179
|
readonly unwrapped: readonly ["manifest"];
|
|
173
180
|
readonly minted: readonly [];
|
|
174
181
|
};
|
|
@@ -10,6 +10,10 @@ export const WIRE_PROJECTION_CORE_IMPORTS = [
|
|
|
10
10
|
"MemoryEntryOrigin",
|
|
11
11
|
];
|
|
12
12
|
const arm = (name) => `Extract<TaskEvent, { type: "${name}" }>`;
|
|
13
|
+
export const WIRING_MANIFEST_OPERATOR_ONLY_SECTIONS = ["governance", "configFingerprint", "autoConsolidation", "readDeny"];
|
|
14
|
+
function withoutSections(all, drop) {
|
|
15
|
+
return all.filter((k) => !drop.includes(k));
|
|
16
|
+
}
|
|
13
17
|
export const WIRE_PROJECTION_FACES = {
|
|
14
18
|
task_progress: { projector: "taskProgressEventData", coreType: arm("task_progress"), excluded: [], minted: [] },
|
|
15
19
|
tool_start: { projector: "toolStartEventData", coreType: arm("tool_start"), excluded: [], minted: [] },
|
|
@@ -36,14 +40,16 @@ export const WIRE_PROJECTION_FACES = {
|
|
|
36
40
|
wiring_manifest_tenant: {
|
|
37
41
|
projector: "wiringManifestEventData",
|
|
38
42
|
coreType: `WiringManifest & ${arm("wiring_manifest")}`,
|
|
39
|
-
excluded: ["governance", "configFingerprint", "autoConsolidation", "readDeny", "peerPresence"
|
|
43
|
+
excluded: ["governance", "configFingerprint", "autoConsolidation", "readDeny", "peerPresence"],
|
|
40
44
|
unwrapped: ["manifest"],
|
|
41
45
|
minted: [],
|
|
42
46
|
},
|
|
43
47
|
wiring_manifest_operator: {
|
|
44
48
|
projector: "wiringManifestOperatorEventData",
|
|
45
49
|
coreType: `WiringManifest & ${arm("wiring_manifest")}`,
|
|
46
|
-
excluded
|
|
50
|
+
get excluded() {
|
|
51
|
+
return withoutSections(WIRE_PROJECTION_FACES.wiring_manifest_tenant.excluded, WIRING_MANIFEST_OPERATOR_ONLY_SECTIONS);
|
|
52
|
+
},
|
|
47
53
|
unwrapped: ["manifest"],
|
|
48
54
|
minted: [],
|
|
49
55
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.105.0",
|
|
4
4
|
"description": "Sema Server — the server/API implementation layer for Sema, wiring core, registry, model providers, and cloud agent execution. Built on @sema-agent/core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"sharp": "^0.35.3"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
|
-
"@sema-agent/sdk": "
|
|
80
|
+
"@sema-agent/sdk": "12.0.1",
|
|
81
81
|
"@types/libsodium-wrappers": "^0.7.14",
|
|
82
82
|
"@types/node": "22.10.2",
|
|
83
83
|
"@types/pg": "^8.20.0",
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* In-memory SessionPolicyStore + the service's `deleteBySession` extension (E21 purge / 2c overwrite-dst wipe).
|
|
3
|
-
*
|
|
4
|
-
* WHY THIS EXISTS (and not core's `InMemorySessionPolicyStore`): core's in-memory/file policy stores implement only
|
|
5
|
-
* the core interface (getRules/putRules/listBySession) — they have NO deletion seam, so neither the E21 session purge
|
|
6
|
-
* nor the 2c `overwrite-dst` subsystem wipe can remove policy rows on a backend that uses them (the SQL twins carry
|
|
7
|
-
* `deleteBySession` as a service extension; see session-policy-store-sql.ts). This store is the delete-capable
|
|
8
|
-
* in-memory twin. The seam itself is also requested upstream (core: optional `deleteBySession?` on the interface +
|
|
9
|
-
* the File/InMemory impls) — if core lands it, this class can retire in favor of core's.
|
|
10
|
-
*
|
|
11
|
-
* BYTE-MATCH DISCIPLINE: getRules/putRules/listBySession replicate core's `InMemorySessionPolicyStore` semantics
|
|
12
|
-
* exactly (same key shape, same CAS `conflict` on expectedRev mismatch, same tighten-only `loosen_forbidden` gate via
|
|
13
|
-
* core's exported `normalizeRules`/`loosenReasons`/`stripRev`, same rev start/bump). Any divergence is a bug here.
|
|
14
|
-
* S-529 起同样钉住 `@contract session_policy.rev_survives_delete`:`deleteBySession` 保留每把键的 rev 高水位
|
|
15
|
-
* **并给那把键的世代(`gen`)+1**(见 {@link MemorySessionPolicyStore.deleteBySession});共用试剂盒
|
|
16
|
-
* `test/helpers/session-policy-rev-line-contract.ts` 与 SQL 双生、以及 core 自己的 `InMemorySessionPolicyStore`
|
|
17
|
-
* (7.25.0 起带这条契约,已作为第三只引擎接进同一只试剂盒当 oracle)跑同一段剧本。
|
|
18
|
-
*/
|
|
19
|
-
import { type PutRulesOptions, type SessionPermissionRules, type SessionPolicyStore, type SessionRulesRecord, type StoredSessionRules } from "@sema-agent/core";
|
|
20
|
-
export declare class MemorySessionPolicyStore implements SessionPolicyStore {
|
|
21
|
-
private readonly map;
|
|
22
|
-
/** S-529 —— 每把键的 rev **高水位 + 世代**(`@contract session_policy.rev_survives_delete`):`deleteBySession`
|
|
23
|
-
* 抹掉规则行时把它那条 rev 线的终点留在这里,于是删后首写 stamp 的是 `max(当前行 rev, 记号.rev) + 1`,
|
|
24
|
-
* 而不是从 1 重来;同时把 `gen` +1 —— **抹除终结的是那一行的血统**,下一次写开的是新世代,读侧因此能把
|
|
25
|
-
* 「重建的行」与「它正在执行的那一行的延续」分开,无论新行的 rev 有多大(core 7.25.0 [ref] 判词:
|
|
26
|
-
* 没有世代时读侧只能靠「亲眼看见行消失」那条弱守卫,于是两道门之间未被观察到的 erase+重建抓不住,
|
|
27
|
-
* 而一次瞬时读 null 会把该腿永久闩在旧行上)。
|
|
28
|
-
* 与 SQL 双生的 `session_policy_rev_mark` 表、core File 店的 `<stem>.hwm.json` 侧车是同一条律的三个实现体
|
|
29
|
-
* (SQL 那边的表注写了为什么不留墓碑行)。本表只增不减、条目是两个整数 —— 与 `map` 同为进程内结构,
|
|
30
|
-
* 随进程亡;跨副本的持久面在 SQL 双生那半。 */
|
|
31
|
-
private readonly marks;
|
|
32
|
-
private key;
|
|
33
|
-
getRules(sessionId: string, principal?: string): Promise<StoredSessionRules | null>;
|
|
34
|
-
putRules(sessionId: string, principal: string | undefined, rules: SessionPermissionRules, opts?: PutRulesOptions): Promise<StoredSessionRules>;
|
|
35
|
-
listBySession(sessionId: string): Promise<SessionRulesRecord[]>;
|
|
36
|
-
/** Purge ALL policy rows for a session, across every principal — KEEPING each key's rev high-water mark.
|
|
37
|
-
* Scoped by session_id alone — the caller (E21 route / importSession overwrite-dst) already proved ownership.
|
|
38
|
-
* Shape = core 1.423's optional `SessionPolicyStore.deleteBySession?` seam (`Promise<void>` — the count was
|
|
39
|
-
* incidental; nothing consumed it).
|
|
40
|
-
*
|
|
41
|
-
* S-529:规则本身死,rev 线不死(`@contract session_policy.rev_survives_delete`)。记号只升不降(`Math.max`),
|
|
42
|
-
* 所以反复抹除不会把线走回头;从没写过的键不留记号(没有线就不凭空抬)。**抹除同时终结那一行的血统**:
|
|
43
|
-
* `gen` +1,于是下一次写开的是新世代 —— 数字继续爬,但读侧按世代判「这不是我在执行的那一行的延续」。 */
|
|
44
|
-
deleteBySession(sessionId: string): Promise<void>;
|
|
45
|
-
}
|
|
46
|
-
//# sourceMappingURL=memory-session-policy-store.d.ts.map
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { normalizeRules, loosenReasons, stripRev, SessionPolicyError, } from "@sema-agent/core";
|
|
2
|
-
export class MemorySessionPolicyStore {
|
|
3
|
-
map = new Map();
|
|
4
|
-
marks = new Map();
|
|
5
|
-
key(sessionId, principal) {
|
|
6
|
-
return JSON.stringify([sessionId, principal ?? null]);
|
|
7
|
-
}
|
|
8
|
-
async getRules(sessionId, principal) {
|
|
9
|
-
const r = this.map.get(this.key(sessionId, principal));
|
|
10
|
-
return r ? structuredClone(r) : null;
|
|
11
|
-
}
|
|
12
|
-
async putRules(sessionId, principal, rules, opts) {
|
|
13
|
-
const key = this.key(sessionId, principal);
|
|
14
|
-
const prior = this.map.get(key);
|
|
15
|
-
if (opts?.expectedRev !== undefined && (prior?.rev ?? 0) !== opts.expectedRev) {
|
|
16
|
-
throw new SessionPolicyError("conflict", `session rules rev mismatch (expected ${opts.expectedRev}, have ${prior?.rev ?? 0})`);
|
|
17
|
-
}
|
|
18
|
-
const clean = normalizeRules(stripRev(rules));
|
|
19
|
-
if (prior && opts?.operator !== true) {
|
|
20
|
-
const loosens = loosenReasons(prior, clean);
|
|
21
|
-
if (loosens.length > 0) {
|
|
22
|
-
throw new SessionPolicyError("loosen_forbidden", `a non-operator session-rule write may only tighten; refused: ${loosens.join("; ")}`);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
const mark = this.marks.get(key) ?? { rev: 0, gen: 0 };
|
|
26
|
-
const gen = prior?.gen ?? mark.gen;
|
|
27
|
-
const next = { ...structuredClone(clean), rev: Math.max(prior?.rev ?? 0, mark.rev) + 1, gen };
|
|
28
|
-
this.map.set(key, next);
|
|
29
|
-
this.marks.set(key, { rev: next.rev, gen });
|
|
30
|
-
return structuredClone(next);
|
|
31
|
-
}
|
|
32
|
-
async listBySession(sessionId) {
|
|
33
|
-
const out = [];
|
|
34
|
-
for (const [k, rules] of this.map) {
|
|
35
|
-
const [sid, principal] = JSON.parse(k);
|
|
36
|
-
if (sid === sessionId)
|
|
37
|
-
out.push({ principal: principal ?? undefined, rules: structuredClone(rules) });
|
|
38
|
-
}
|
|
39
|
-
return out;
|
|
40
|
-
}
|
|
41
|
-
async deleteBySession(sessionId) {
|
|
42
|
-
for (const [k, rules] of [...this.map]) {
|
|
43
|
-
const [sid] = JSON.parse(k);
|
|
44
|
-
if (sid !== sessionId)
|
|
45
|
-
continue;
|
|
46
|
-
const mark = this.marks.get(k) ?? { rev: 0, gen: 0 };
|
|
47
|
-
this.marks.set(k, { rev: Math.max(mark.rev, rules.rev), gen: mark.gen + 1 });
|
|
48
|
-
this.map.delete(k);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
//# sourceMappingURL=memory-session-policy-store.js.map
|