@ouro.bot/cli 0.1.0-alpha.742 → 0.1.0-alpha.744
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.json +32 -0
- package/deploy/unraid/Dockerfile +7 -2
- package/deploy/unraid/README.txt +704 -64
- package/deploy/unraid/migrate-sanctuary-bundle.mjs +21 -0
- package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
- package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
- package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
- package/deploy/unraid/ouro-events/install-usenet-guard.sh +434 -0
- package/deploy/unraid/ouro-events/usenet-health.sh +178 -0
- package/deploy/unraid/sanctuary-acceptance-contract.json +4 -3
- package/deploy/unraid/sanctuary-unit16-host-broker.mjs +5 -1
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +2 -2
- package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +1 -1
- package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +3 -1
- package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +3 -1
- package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +4 -0
- package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +6 -2
- package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +4 -2
- package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
- package/deploy/unraid/sanctuary.ouro/tool-profiles.json +19 -17
- package/deploy/unraid/sanctuary.xml +13 -10
- package/dist/arc/cares.js +171 -37
- package/dist/arc/obligations.js +38 -0
- package/dist/heart/awaiting/await-alert.js +4 -2
- package/dist/heart/awaiting/await-expiry.js +39 -4
- package/dist/heart/awaiting/await-parser.js +8 -0
- package/dist/heart/core.js +37 -7
- package/dist/heart/cross-chat-delivery.js +1 -0
- package/dist/heart/daemon/container-spec-auditor-main.js +11 -7
- package/dist/heart/daemon/container-spec-auditor.js +38 -11
- package/dist/heart/daemon/daemon-entry.js +19 -5
- package/dist/heart/daemon/daemon.js +154 -22
- package/dist/heart/daemon/sanctuary-acceptance-adapter.js +126 -42
- package/dist/heart/daemon/sanctuary-acceptance-harness.js +26 -29
- package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +42 -51
- package/dist/heart/daemon/sanctuary-bundle-migration.js +398 -0
- package/dist/heart/external-events/router.js +1025 -43
- package/dist/heart/session-events.js +23 -5
- package/dist/heart/steward-policy.js +302 -0
- package/dist/heart/tool-approval.js +3 -1
- package/dist/heart/turn-context.js +1 -0
- package/dist/mind/context.js +8 -3
- package/dist/mind/pending.js +25 -0
- package/dist/mind/prompt.js +49 -1
- package/dist/repertoire/guardrails.js +2 -1
- package/dist/repertoire/relationship-authorization.js +194 -0
- package/dist/repertoire/tools-awaiting.js +229 -26
- package/dist/repertoire/tools-base.js +15 -0
- package/dist/repertoire/tools-continuity.js +259 -4
- package/dist/repertoire/tools-notes.js +29 -3
- package/dist/repertoire/tools-session.js +219 -4
- package/dist/repertoire/tools-steward-policy.js +88 -0
- package/dist/repertoire/tools-telegram-contacts.js +37 -0
- package/dist/repertoire/tools-unraid.js +113 -6
- package/dist/repertoire/tools.js +104 -9
- package/dist/repertoire/unraid-restart.js +86 -4
- package/dist/senses/private-runtime-worker.js +36 -3
- package/dist/senses/private-runtime.js +310 -63
- package/dist/senses/sanctuary-health-acceptance-probe.js +8 -6
- package/dist/senses/sanctuary-health-runner.js +47 -103
- package/dist/senses/sanctuary-health.js +53 -105
- package/dist/senses/sanctuary-runtime.js +36 -2
- package/dist/senses/sanctuary-sab.js +80 -0
- package/dist/senses/shared-turn.js +64 -9
- package/dist/senses/telegram-admission.js +684 -0
- package/dist/senses/telegram-approval-runtime.js +46 -6
- package/dist/senses/telegram-client.js +212 -66
- package/dist/senses/telegram-effect-adapter.js +787 -0
- package/dist/senses/telegram.js +728 -48
- package/npm-shrinkwrap.json +6 -6
- package/package.json +2 -2
|
@@ -55,15 +55,20 @@ const node_crypto_1 = require("node:crypto");
|
|
|
55
55
|
const node_fs_1 = require("node:fs");
|
|
56
56
|
const node_net_1 = require("node:net");
|
|
57
57
|
const path = __importStar(require("node:path"));
|
|
58
|
+
const friends_1 = require("@ouro.bot/friends");
|
|
58
59
|
const runtime_1 = require("../../nerves/runtime");
|
|
59
60
|
const telegram_approval_runtime_1 = require("../../senses/telegram-approval-runtime");
|
|
60
61
|
const telegram_client_1 = require("../../senses/telegram-client");
|
|
62
|
+
const telegram_effect_adapter_1 = require("../../senses/telegram-effect-adapter");
|
|
63
|
+
const telegram_admission_1 = require("../../senses/telegram-admission");
|
|
61
64
|
const sanctuary_interactive_control_1 = require("../../senses/sanctuary-interactive-control");
|
|
65
|
+
const shared_turn_1 = require("../../senses/shared-turn");
|
|
62
66
|
const telegram_1 = require("../../senses/telegram");
|
|
63
67
|
const telegram_audit_ledger_1 = require("../../senses/telegram-audit-ledger");
|
|
64
68
|
const sanctuary_runtime_1 = require("../../senses/sanctuary-runtime");
|
|
65
69
|
const sanctuary_grounding_1 = require("../../senses/sanctuary-grounding");
|
|
66
70
|
const tools_1 = require("../../repertoire/tools");
|
|
71
|
+
const relationship_authorization_1 = require("../../repertoire/relationship-authorization");
|
|
67
72
|
const core_1 = require("../core");
|
|
68
73
|
const identity_1 = require("../identity");
|
|
69
74
|
const approval_store_1 = require("../approval-store");
|
|
@@ -104,7 +109,6 @@ const POSTBOOT_HEALTH_FILE = "/run/ouro-acceptance/postboot-health.json";
|
|
|
104
109
|
const BOOT_ID_FILE = "/run/ouro-acceptance/boot-id";
|
|
105
110
|
const TELEGRAM_POLLER_COUNT_FILE = "/run/ouro-acceptance/telegram-poller-count.json";
|
|
106
111
|
const CONTRACT_FILE = "/opt/ouro/deploy/unraid/sanctuary-acceptance-contract.json";
|
|
107
|
-
const SANCTUARY_TOOL_PROFILES_FILE = "/opt/ouro/deploy/unraid/sanctuary.ouro/tool-profiles.json";
|
|
108
112
|
const CLOSED_INVENTORY_FILE = "/run/ouro-acceptance/closed-inventory.json";
|
|
109
113
|
const HOST_BROKER_SOCKET = "/run/ouro-host-acceptance/adapter.sock";
|
|
110
114
|
const MAX_BROKER_RESPONSE = 256 * 1024;
|
|
@@ -118,7 +122,7 @@ const APPROVAL_EVIDENCE_LABELS = new Set([
|
|
|
118
122
|
const HEALTH_ACCEPTANCE_LABELS = new Set([
|
|
119
123
|
"unit-16f-cron-fingerprint",
|
|
120
124
|
"unit-16g-health-transition",
|
|
121
|
-
"unit-16h-
|
|
125
|
+
"unit-16h-acceptance-delivery-probe",
|
|
122
126
|
]);
|
|
123
127
|
const PERMISSION_RESOURCES = new Set([
|
|
124
128
|
"ACTIVATION_CODE", "API_KEY", "ARRAY", "CLOUD", "CONFIG", "CONNECT", "CONNECT__REMOTE_ACCESS",
|
|
@@ -505,6 +509,67 @@ function parsedJson(raw) {
|
|
|
505
509
|
return null;
|
|
506
510
|
return object(JSON.parse(raw), "scenario source");
|
|
507
511
|
}
|
|
512
|
+
async function projectTelegramAdmissions(agentRoot, credentials, identityKey) {
|
|
513
|
+
const admissionsRoot = path.join(agentRoot, "state", "senses", "telegram", "admissions");
|
|
514
|
+
const effectsRoot = path.join(agentRoot, "state", "telegram", "effects");
|
|
515
|
+
if (!(0, node_fs_1.existsSync)(admissionsRoot) || !(0, node_fs_1.existsSync)(effectsRoot) || !identityKey || !/^[A-Za-z0-9_-]{43}$/u.test(identityKey))
|
|
516
|
+
return [];
|
|
517
|
+
const admissionStore = new telegram_admission_1.FileTelegramAdmissionStore(admissionsRoot);
|
|
518
|
+
const effectStore = new telegram_effect_adapter_1.FileTelegramEffectJournal(effectsRoot);
|
|
519
|
+
try {
|
|
520
|
+
const effects = new Map(effectStore.list().map((artifact) => [artifact.id, artifact]));
|
|
521
|
+
const botId = (0, telegram_1.telegramBotIdFromToken)(credentials.botToken);
|
|
522
|
+
const ownerSessionKey = `telegram:${(0, telegram_1.opaqueTelegramSubject)(identityKey, botId, credentials.authorizedUserId, credentials.authorizedChatId)}`;
|
|
523
|
+
const friendsRoot = path.join(agentRoot, "friends");
|
|
524
|
+
const friendStore = (0, node_fs_1.existsSync)(friendsRoot) ? new friends_1.FileFriendStore(friendsRoot) : null;
|
|
525
|
+
const owner = friendStore ? await friendStore.findByExternalId("telegram-user", credentials.authorizedUserId, botId) : null;
|
|
526
|
+
const exactSameBotIdentity = (friend, userId) => {
|
|
527
|
+
const bindings = friend.externalIds.filter((external) => external.provider === "telegram-user" && external.tenantId === botId);
|
|
528
|
+
return bindings.length === 1 && bindings[0].externalId === userId;
|
|
529
|
+
};
|
|
530
|
+
const ownerExact = Boolean(owner && exactSameBotIdentity(owner, credentials.authorizedUserId) && owner.trustLevel === "family" && owner.admissionState === "active"
|
|
531
|
+
&& owner.initiativePolicy === "proactive" && owner.capabilityProfileId === "sanctuary-owner");
|
|
532
|
+
const projections = await Promise.all(admissionStore.list().map(async (record) => {
|
|
533
|
+
const acknowledgement = record.acknowledgementArtifactId ? effects.get(record.acknowledgementArtifactId) : undefined;
|
|
534
|
+
const ownerCard = record.ownerCardArtifactId ? effects.get(record.ownerCardArtifactId) : undefined;
|
|
535
|
+
const expectedButtons = [[
|
|
536
|
+
{ text: "Allow", callbackData: `admit:${record.id}:allow` },
|
|
537
|
+
{ text: "Deny", callbackData: `admit:${record.id}:deny` },
|
|
538
|
+
{ text: "Block", callbackData: `admit:${record.id}:block` },
|
|
539
|
+
]];
|
|
540
|
+
const admittedFriend = friendStore ? await friendStore.findByExternalId("telegram-user", record.userId, record.botId) : null;
|
|
541
|
+
const acknowledgementExact = Boolean(acknowledgement?.idempotencyKey === `ack:${record.id}`
|
|
542
|
+
&& acknowledgement.authorClass === "control" && acknowledgement.target.kind === "admission_gate"
|
|
543
|
+
&& acknowledgement.target.admissionId === record.id && acknowledgement.target.botId === record.botId
|
|
544
|
+
&& acknowledgement.target.userId === record.userId && acknowledgement.target.chatId === record.chatId
|
|
545
|
+
&& acknowledgement.effect.kind === "admission_ack" && acknowledgement.effect.text === telegram_effect_adapter_1.FIXED_ADMISSION_ACKNOWLEDGEMENT
|
|
546
|
+
&& acknowledgement.parts.every((part) => part.state === "accepted" || part.state === "session_recorded"));
|
|
547
|
+
const ownerCardExact = Boolean(ownerExact && owner && ownerCard?.idempotencyKey === `owner-card:${record.id}`
|
|
548
|
+
&& ownerCard.authorClass === "control" && ownerCard.target.kind === "approved_relationship"
|
|
549
|
+
&& ownerCard.target.friendId === owner.id && ownerCard.target.sessionKey === ownerSessionKey && ownerCard.target.requestId === record.id
|
|
550
|
+
&& ownerCard.effect.kind === "card" && ownerCard.effect.text.startsWith("Unknown Telegram contact\n")
|
|
551
|
+
&& ownerCard.effect.text.includes("The message is quarantined and has not been processed.")
|
|
552
|
+
&& JSON.stringify(ownerCard.effect.buttons) === JSON.stringify(expectedButtons)
|
|
553
|
+
&& ownerCard.parts.every((part) => part.state === "session_recorded"));
|
|
554
|
+
return {
|
|
555
|
+
admissionDigest: (0, telegram_1.sanctuaryTelegramTurnReceiptDigest)(identityKey, "sanctuary-telegram-turn-receipt-v3", "admission", `${record.id}\0${record.botId}\0${record.userId}\0${record.chatId}\0${record.updateId}\0${record.messageId}`),
|
|
556
|
+
status: record.status,
|
|
557
|
+
identityExact: record.botId === botId && record.userId === record.chatId && record.userId !== credentials.authorizedUserId,
|
|
558
|
+
acknowledgementExact,
|
|
559
|
+
ownerCardExact,
|
|
560
|
+
contentQuarantined: typeof record.quarantinedText === "string" && (0, node_crypto_1.createHash)("sha256").update(record.quarantinedText).digest("hex") === record.contentDigest,
|
|
561
|
+
relationshipAbsent: record.friendId === null && admittedFriend === null,
|
|
562
|
+
capturedAt: record.createdAt,
|
|
563
|
+
updatedAt: record.updatedAt,
|
|
564
|
+
};
|
|
565
|
+
}));
|
|
566
|
+
return projections.sort((left, right) => left.admissionDigest.localeCompare(right.admissionDigest));
|
|
567
|
+
}
|
|
568
|
+
finally {
|
|
569
|
+
admissionStore.close();
|
|
570
|
+
effectStore.close();
|
|
571
|
+
}
|
|
572
|
+
}
|
|
508
573
|
function canonicalIso(value) {
|
|
509
574
|
return typeof value === "string" && value.length <= 30 && Number.isFinite(Date.parse(value)) && new Date(Date.parse(value)).toISOString() === value;
|
|
510
575
|
}
|
|
@@ -611,10 +676,10 @@ function parseHealthProbeReceipt(raw, label, scenarioHandleDigest, identityKey)
|
|
|
611
676
|
if (Buffer.byteLength(raw) > 128 * 1024)
|
|
612
677
|
throw new Error("Sanctuary health probe receipt exceeds its bound");
|
|
613
678
|
const receipt = object(JSON.parse(raw), "Sanctuary health probe receipt");
|
|
614
|
-
const exactKeys = ["beforeStateDigest", "clockMode", "cronDegradedAfter", "cronDegradedBefore", "cronFingerprintAfter", "cronFingerprintBefore", "cronRegisteredAfter", "cronRegisteredBefore", "deliveryCount", "effectiveNow", "fixtureSequenceDigest", "label", "ownerContainerDigestAfter", "ownerContainerDigestBefore", "ownerImageDigestAfter", "ownerImageDigestBefore", "phases", "privateTurnCount", "productionRestored", "providerInvocationCount", "realCheckEquivalent", "restoredStateDigest", "scenarioHandleDigest", "schedulerReceipt", "schemaVersion", "snapshotAbsent", "socketAbsent", "workspaceAbsent"].sort();
|
|
615
|
-
const supportedLabel = label === "unit-16f-cron-fingerprint" || label === "unit-16g-health-transition" || label === "unit-16h-
|
|
679
|
+
const exactKeys = ["acceptanceOnly", "beforeStateDigest", "clockMode", "cronDegradedAfter", "cronDegradedBefore", "cronFingerprintAfter", "cronFingerprintBefore", "cronRegisteredAfter", "cronRegisteredBefore", "deliveryCount", "effectiveNow", "fixtureSequenceDigest", "label", "ownerContainerDigestAfter", "ownerContainerDigestBefore", "ownerImageDigestAfter", "ownerImageDigestBefore", "phases", "privateTurnCount", "productionRestored", "productionScheduleChanged", "providerInvocationCount", "realCheckEquivalent", "restoredStateDigest", "scenarioHandleDigest", "schedulerReceipt", "schemaVersion", "snapshotAbsent", "socketAbsent", "workspaceAbsent"].sort();
|
|
680
|
+
const supportedLabel = label === "unit-16f-cron-fingerprint" || label === "unit-16g-health-transition" || label === "unit-16h-acceptance-delivery-probe";
|
|
616
681
|
const digestFields = ["ownerImageDigestBefore", "ownerImageDigestAfter", "ownerContainerDigestBefore", "ownerContainerDigestAfter", "beforeStateDigest", "restoredStateDigest", "cronFingerprintBefore", "cronFingerprintAfter", "fixtureSequenceDigest"];
|
|
617
|
-
const booleanFields = ["cronRegisteredBefore", "cronRegisteredAfter", "cronDegradedBefore", "cronDegradedAfter", "workspaceAbsent", "socketAbsent", "snapshotAbsent", "realCheckEquivalent", "productionRestored"];
|
|
682
|
+
const booleanFields = ["acceptanceOnly", "productionScheduleChanged", "cronRegisteredBefore", "cronRegisteredAfter", "cronDegradedBefore", "cronDegradedAfter", "workspaceAbsent", "socketAbsent", "snapshotAbsent", "realCheckEquivalent", "productionRestored"];
|
|
618
683
|
if (!supportedLabel || JSON.stringify(Object.keys(receipt).sort()) !== JSON.stringify(exactKeys) || receipt.schemaVersion !== "sanctuary-health-probe-receipt-v1"
|
|
619
684
|
|| receipt.label !== label || receipt.scenarioHandleDigest !== scenarioHandleDigest || !SHA256.test(scenarioHandleDigest)
|
|
620
685
|
|| !digestFields.every((field) => typeof receipt[field] === "string" && SHA256.test(receipt[field]))
|
|
@@ -689,10 +754,10 @@ function parseHealthProbeReceipt(raw, label, scenarioHandleDigest, identityKey)
|
|
|
689
754
|
if (receipt.ownerImageDigestBefore !== receipt.ownerImageDigestAfter || receipt.ownerContainerDigestBefore !== receipt.ownerContainerDigestAfter
|
|
690
755
|
|| (label !== "unit-16f-cron-fingerprint" && receipt.beforeStateDigest !== receipt.restoredStateDigest) || receipt.cronFingerprintBefore !== receipt.cronFingerprintAfter
|
|
691
756
|
|| receipt.cronRegisteredBefore !== true || receipt.cronRegisteredAfter !== true || receipt.cronDegradedBefore !== false || receipt.cronDegradedAfter !== false
|
|
692
|
-
|| receipt.workspaceAbsent !== true || receipt.socketAbsent !== true || receipt.snapshotAbsent !== true || receipt.realCheckEquivalent !== true || receipt.productionRestored !== true) {
|
|
757
|
+
|| receipt.acceptanceOnly !== true || receipt.productionScheduleChanged !== false || receipt.workspaceAbsent !== true || receipt.socketAbsent !== true || receipt.snapshotAbsent !== true || receipt.realCheckEquivalent !== true || receipt.productionRestored !== true) {
|
|
693
758
|
throw new Error("Sanctuary health probe did not restore its exact production owner and state");
|
|
694
759
|
}
|
|
695
|
-
if (label === "unit-16h-
|
|
760
|
+
if (label === "unit-16h-acceptance-delivery-probe") {
|
|
696
761
|
const effective = new Date(receipt.effectiveNow);
|
|
697
762
|
const parts = new Intl.DateTimeFormat("en-US", { timeZone: "America/Los_Angeles", hour: "2-digit", minute: "2-digit", second: "2-digit", hourCycle: "h23" }).formatToParts(effective);
|
|
698
763
|
const part = (type) => Number(parts.find((entry) => entry.type === type).value);
|
|
@@ -1170,9 +1235,6 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1170
1235
|
identityKey: identityRaw.trim(),
|
|
1171
1236
|
});
|
|
1172
1237
|
const auditEntries = auditLedgerEntries.filter((entry) => entry.meta.scenarioHandleDigest === scenarioHandleDigest);
|
|
1173
|
-
const toolProfiles = parsedJson(optionalFixedFile(deps, SANCTUARY_TOOL_PROFILES_FILE));
|
|
1174
|
-
const profiles = toolProfiles ? object(toolProfiles.profiles, "Sanctuary tool profiles") : null;
|
|
1175
|
-
const telegramProfile = profiles?.["sanctuary-telegram"];
|
|
1176
1238
|
let approvalRecords = [];
|
|
1177
1239
|
const approvalDatabasePath = pathFor(agentRoot, "state/approvals/approvals.sqlite");
|
|
1178
1240
|
if ((0, node_fs_1.existsSync)(approvalDatabasePath))
|
|
@@ -1254,30 +1316,6 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1254
1316
|
throw new Error("Telegram audit lifecycle MAC is invalid");
|
|
1255
1317
|
}
|
|
1256
1318
|
}
|
|
1257
|
-
if (label === "unit-16d-2-unauthorized") {
|
|
1258
|
-
const expectedAuthorizedIdentityDigest = (0, telegram_1.sanctuaryTelegramTurnReceiptDigest)(identityKey, auditSchema, "sender-identity", credentials.authorizedUserId);
|
|
1259
|
-
for (const entry of auditEntries.filter((candidate) => candidate.event === "telegram.update_dropped")) {
|
|
1260
|
-
const binding = {
|
|
1261
|
-
scenarioHandleDigest: entry.meta.scenarioHandleDigest,
|
|
1262
|
-
updateDigest: entry.meta.updateDigest,
|
|
1263
|
-
senderIdentityDigest: entry.meta.senderIdentityDigest,
|
|
1264
|
-
authorizedIdentityDigest: entry.meta.authorizedIdentityDigest,
|
|
1265
|
-
senderDistinct: entry.meta.senderDistinct,
|
|
1266
|
-
nextOffsetDigest: entry.meta.nextOffsetDigest,
|
|
1267
|
-
};
|
|
1268
|
-
if (typeof binding.updateDigest !== "string" || !SHA256.test(binding.updateDigest)
|
|
1269
|
-
|| typeof binding.senderIdentityDigest !== "string" || !SHA256.test(binding.senderIdentityDigest)
|
|
1270
|
-
|| typeof binding.authorizedIdentityDigest !== "string" || !SHA256.test(binding.authorizedIdentityDigest)
|
|
1271
|
-
|| typeof binding.nextOffsetDigest !== "string" || !SHA256.test(binding.nextOffsetDigest)
|
|
1272
|
-
|| binding.nextOffsetDigest !== (0, telegram_1.sanctuaryTelegramTurnReceiptDigest)(identityKey, auditSchema, "next-update-id", String(telegramNextUpdateId))
|
|
1273
|
-
|| binding.authorizedIdentityDigest !== expectedAuthorizedIdentityDigest
|
|
1274
|
-
|| binding.senderIdentityDigest === binding.authorizedIdentityDigest
|
|
1275
|
-
|| binding.senderDistinct !== true || entry.meta.distinctAccount !== true
|
|
1276
|
-
|| typeof entry.meta.dropMac !== "string" || !SHA256.test(entry.meta.dropMac)
|
|
1277
|
-
|| entry.meta.dropMac !== (0, telegram_1.sanctuaryTelegramUnauthorizedDropMac)(identityKey, auditSchema, binding))
|
|
1278
|
-
throw new Error("Telegram unauthorized sender binding MAC is invalid");
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
1319
|
const approvalEvidenceKeys = {
|
|
1282
1320
|
"senses.telegram_approval_prompt_bound": [["actionDigest", "approvalId", "boundAt", "checkpointDigest", "evidenceMac", "messageIdDigest", "scenarioHandleDigest", "suspendedSessionRevisionDigest", "targetDigest"]],
|
|
1283
1321
|
"telegram.callback_settled": [["accepted", "acknowledged", "acknowledgementState", "actionDigest", "approvalId", "boundAt", "callbackAt", "checkpointDigest", "decisionAttemptDigest", "evidenceMac", "messageIdDigest", "reason", "scenarioHandleDigest", "suspendedSessionRevisionDigest", "targetDigest"]],
|
|
@@ -1446,7 +1484,7 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1446
1484
|
}
|
|
1447
1485
|
}
|
|
1448
1486
|
let containment;
|
|
1449
|
-
if (label === "unit-16e-containment-audit" || label === "unit-16d-2-
|
|
1487
|
+
if (label === "unit-16e-containment-audit" || label === "unit-16d-2-unknown-admission") {
|
|
1450
1488
|
const inventoryEnvelope = object(await dependency(deps.hostRequest, "Sanctuary host broker")({ operation: "inventory_keys", targetServerId: TARGET_SERVER_ID }), "containment key inventory");
|
|
1451
1489
|
if (!Array.isArray(inventoryEnvelope.keys))
|
|
1452
1490
|
throw new Error("containment key inventory is invalid");
|
|
@@ -1460,9 +1498,12 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1460
1498
|
})).sort((left, right) => left.name.localeCompare(right.name));
|
|
1461
1499
|
const readRecord = inventory.find((record) => record.name === "Butler RO");
|
|
1462
1500
|
const writeRecord = inventory.find((record) => record.name === "Butler RW");
|
|
1463
|
-
const
|
|
1464
|
-
const
|
|
1465
|
-
const
|
|
1501
|
+
const relationshipRegistry = (0, relationship_authorization_1.loadRelationshipCapabilityRegistry)(agentRoot);
|
|
1502
|
+
const telegramProfile = relationshipRegistry.profiles["sanctuary-owner"];
|
|
1503
|
+
const privateProfile = relationshipRegistry.profiles["sanctuary-event"];
|
|
1504
|
+
const telegramNames = telegramProfile?.toolNames ?? [];
|
|
1505
|
+
const privateNames = privateProfile?.toolNames ?? [];
|
|
1506
|
+
const relationshipProfilesExact = telegramNames.length > 0 && privateNames.length > 0;
|
|
1466
1507
|
const flowSchemas = new Map([tools_1.ponderTool, tools_1.settleTool, tools_1.speakTool, tools_1.restTool].map((tool) => [tool.function.name, tool]));
|
|
1467
1508
|
const schemasFor = (names) => names.flatMap((name) => {
|
|
1468
1509
|
const schema = (0, tools_1.resolveToolDefinition)(name)?.tool ?? flowSchemas.get(name);
|
|
@@ -1471,12 +1512,18 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1471
1512
|
const telegramSchemas = schemasFor(telegramNames);
|
|
1472
1513
|
const privateSchemas = schemasFor(privateNames);
|
|
1473
1514
|
const handlerResolves = (name) => typeof (0, tools_1.resolveToolDefinition)(name)?.handler === "function" || flowSchemas.has(name);
|
|
1515
|
+
const resolvedHandlerCount = [...telegramNames, ...privateNames].filter(handlerResolves).length;
|
|
1516
|
+
const handlersExact = resolvedHandlerCount === telegramNames.length + privateNames.length;
|
|
1474
1517
|
const excludedNames = ["shell", "read_file", "edit_file", "vault_get", "mcp_call", "exec", "credential_get"];
|
|
1475
1518
|
const excludedSchemaIntersection = excludedNames.filter((name) => telegramNames.includes(name) || privateNames.includes(name));
|
|
1476
1519
|
const productionBoundaryReceipts = await dependency(deps.runProductionBoundaryProbe, "production tool boundary probe")(telegramSchemas);
|
|
1477
1520
|
const excludedAttempts = productionBoundaryReceipts.filter((receipt) => excludedNames.includes(receipt.name));
|
|
1478
1521
|
const restartDefinition = (0, tools_1.resolveToolDefinition)("unraid_restart_container");
|
|
1479
1522
|
const writeApprovalPolicy = restartDefinition.approvalPolicy({ container: "calibre-web" });
|
|
1523
|
+
const writeApprovalPolicyExact = writeApprovalPolicy.kind === "required"
|
|
1524
|
+
&& writeApprovalPolicy.policyId === "sanctuary.unraid.restart.v1"
|
|
1525
|
+
&& writeApprovalPolicy.actionClass === "unraid.container.restart"
|
|
1526
|
+
&& writeApprovalPolicy.requiresSoleCall === true;
|
|
1480
1527
|
let lifecycleBalance = 0;
|
|
1481
1528
|
let lifecyclePairs = 0;
|
|
1482
1529
|
for (const entry of auditLedgerEntries) {
|
|
@@ -1502,7 +1549,9 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1502
1549
|
privateToolCount: privateNames.length,
|
|
1503
1550
|
privateProfileDigest: (0, node_crypto_1.createHash)("sha256").update(JSON.stringify(privateNames)).digest("hex"),
|
|
1504
1551
|
privateSchemaDigest: (0, node_crypto_1.createHash)("sha256").update(JSON.stringify(privateSchemas)).digest("hex"),
|
|
1505
|
-
resolvedHandlerCount
|
|
1552
|
+
resolvedHandlerCount,
|
|
1553
|
+
relationshipProfilesExact,
|
|
1554
|
+
handlersExact,
|
|
1506
1555
|
excludedToolCount: excludedNames.length,
|
|
1507
1556
|
excludedSchemaIntersectionCount: excludedSchemaIntersection.length,
|
|
1508
1557
|
fabricatedHandlerInvocationCount: excludedSchemaIntersection.filter(handlerResolves).length,
|
|
@@ -1528,10 +1577,14 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1528
1577
|
rawWriteMaterialFieldCount,
|
|
1529
1578
|
typedWriteExecutorCount: telegramNames.filter((name) => name === "unraid_restart_container" && writeApprovalPolicy.kind === "required").length,
|
|
1530
1579
|
writeApprovalPolicyDigest: (0, node_crypto_1.createHash)("sha256").update(JSON.stringify(writeApprovalPolicy)).digest("hex"),
|
|
1580
|
+
writeApprovalPolicyExact,
|
|
1531
1581
|
sensitiveMaterialObserved: auditContainsSensitiveMaterial(auditRaw ?? "", deps.telegramCredentials?.()) || rawWriteMaterialFieldCount > 0 || container?.writableKeyExposure === true,
|
|
1532
1582
|
stopDenied, restartDenied, denialAuditCount, denialStateUnchanged, denialProbeCompleted,
|
|
1533
1583
|
};
|
|
1534
1584
|
}
|
|
1585
|
+
const telegramAdmissions = label === "unit-16d-2-unknown-admission"
|
|
1586
|
+
? await projectTelegramAdmissions(agentRoot, dependency(deps.telegramCredentials, "Telegram credentials")(), identityRaw?.trim() ?? null)
|
|
1587
|
+
: [];
|
|
1535
1588
|
const sourceValues = {
|
|
1536
1589
|
"identity-key": identityRaw, "telegram-audit": auditEntries, "telegram-offset": offsetRaw,
|
|
1537
1590
|
"approval-journal": approvals, "approval-checkpoints": checkpointsRaw, "container-inspect": container,
|
|
@@ -1539,6 +1592,7 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1539
1592
|
"digest-runtime": health, "reboot-checkpoint": rebootCheckpoint, "telegram-turn-receipts": telegramTurns, "read-only-denial-receipt": denialReceipt ?? null,
|
|
1540
1593
|
"identity-surface-audit": identity ? { inspectedRecordCount: identity.inspectedRecordCount, opaqueSubjectCount: identity.opaqueSubjectCount, mismatchCount: identity.mismatchCount, rawLeakCount: identity.rawLeakCount, canonicalSessionCount: identity.canonicalSessionCount, canonicalFriendCount: identity.canonicalFriendCount, sessionSurfaceDigest: identity.sessionSurfaceDigest, friendSurfaceDigest: identity.friendSurfaceDigest, surfaceDigest: identity.surfaceDigest } : null,
|
|
1541
1594
|
"containment-audit": containment ?? null,
|
|
1595
|
+
"telegram-admission-evidence": telegramAdmissions,
|
|
1542
1596
|
"health-probe-receipt": healthProbe ?? null,
|
|
1543
1597
|
"scheduler-liveness-receipt": healthProbe?.schedulerReceipt ?? null,
|
|
1544
1598
|
"interactive-driver-receipt": parsedJson(interactiveDriverRaw),
|
|
@@ -1570,6 +1624,7 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1570
1624
|
approvals,
|
|
1571
1625
|
restartAttempts,
|
|
1572
1626
|
telegramTurns,
|
|
1627
|
+
telegramAdmissions,
|
|
1573
1628
|
telegramNextUpdateId,
|
|
1574
1629
|
zeroWork,
|
|
1575
1630
|
liveGrounding,
|
|
@@ -1578,7 +1633,7 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1578
1633
|
exactImage: typeof expectedImageId === "string" && SHA256.test(expectedImageId) && container.imageId === `sha256:${expectedImageId}`, running: container.running === true,
|
|
1579
1634
|
healthy: container.health === "healthy", user: text(container.user, "container user"), readOnlyRoot: container.readOnlyRoot === true,
|
|
1580
1635
|
mountCount: Number(container.mountCount), publishedPortCount: Number(container.publishedPortCount), restartPolicy: text(container.restartPolicy, "restart policy"), restartCount: Number(container.restartCount),
|
|
1581
|
-
autostartExact: container.autostartExact === true, updaterDisabled: container.updaterDisabled === true,
|
|
1636
|
+
autostartExact: container.autostartExact === true, mountsExact: container.mountsExact === true, updaterDisabled: container.updaterDisabled === true,
|
|
1582
1637
|
vaultUnlocked: container.vaultUnlocked === true, manualAuthRequired: container.manualAuthRequired === true,
|
|
1583
1638
|
} : undefined,
|
|
1584
1639
|
provider: liveProvider,
|
|
@@ -1591,10 +1646,10 @@ async function readDefaultSanctuaryScenarioFacts(label, scenarioHandleDigest, de
|
|
|
1591
1646
|
reboot,
|
|
1592
1647
|
containment: containment ?? {
|
|
1593
1648
|
schemaVersion: "sanctuary-containment-audit-v1", keyCount: 0, keyInventoryDigest: "", readScopeDigest: "", writeScopeDigest: "", keyRoleAssignmentCount: 0,
|
|
1594
|
-
telegramToolCount: 0, telegramProfileDigest: "", telegramSchemaDigest: "", privateToolCount: 0, privateProfileDigest: "", privateSchemaDigest: "", resolvedHandlerCount: 0,
|
|
1649
|
+
telegramToolCount: 0, telegramProfileDigest: "", telegramSchemaDigest: "", privateToolCount: 0, privateProfileDigest: "", privateSchemaDigest: "", resolvedHandlerCount: 0, relationshipProfilesExact: false, handlersExact: false,
|
|
1595
1650
|
excludedToolCount: 0, excludedSchemaIntersectionCount: 0, fabricatedHandlerInvocationCount: 0, excludedToolAttemptCount: 0, excludedToolRejectedCount: 0, excludedToolInvokedCount: 0, excludedToolSideEffectCount: 0, globallyResolvableExcludedToolCount: 0, auditPathDigest: "", auditLedgerDigest: "", auditRecordCount: 0, auditLifecyclePairCount: 0,
|
|
1596
1651
|
containerUser: "", liveProcessUser: "", mountCount: 0, publishedPortCount: 0, networkMode: "", readOnlyRoot: false, mountsExact: false, securityExact: false, updaterDisabled: false,
|
|
1597
|
-
writableKeyExposure: container?.writableKeyExposure === true, rawWriteMaterialFieldCount: 0, typedWriteExecutorCount: 0, writeApprovalPolicyDigest: "",
|
|
1652
|
+
writableKeyExposure: container?.writableKeyExposure === true, rawWriteMaterialFieldCount: 0, typedWriteExecutorCount: 0, writeApprovalPolicyDigest: "", writeApprovalPolicyExact: false,
|
|
1598
1653
|
sensitiveMaterialObserved: auditContainsSensitiveMaterial(auditRaw ?? "") || container?.writableKeyExposure === true,
|
|
1599
1654
|
stopDenied, restartDenied, denialAuditCount, denialStateUnchanged, denialProbeCompleted,
|
|
1600
1655
|
},
|
|
@@ -2288,6 +2343,25 @@ async function executeSanctuaryAcceptanceRevokedProbe(keyIdValue, endpointValue,
|
|
|
2288
2343
|
fetch: deps.fetch,
|
|
2289
2344
|
});
|
|
2290
2345
|
}
|
|
2346
|
+
function createAcceptanceProbeEffects(input) {
|
|
2347
|
+
const store = new telegram_effect_adapter_1.FileTelegramEffectJournal(path.join(input.agentRoot, "state", "telegram", "effects"));
|
|
2348
|
+
const target = { kind: "approved_relationship", friendId: `telegram-user:${input.subject}`, sessionKey: `telegram:${input.subject}` };
|
|
2349
|
+
const execute = (0, telegram_effect_adapter_1.createTelegramAuthorizedEffectExecutor)({
|
|
2350
|
+
store,
|
|
2351
|
+
api: input.api,
|
|
2352
|
+
authorize: ({ target: candidate }) => JSON.stringify(candidate) === JSON.stringify(target)
|
|
2353
|
+
? { allowed: true, receiptId: `configured-owner:${input.subject}`, expiresAt: new Date(Date.now() + 5 * 60_000).toISOString(), transport: { chatId: input.chatId } }
|
|
2354
|
+
: { allowed: false, reason: "effect target is not the configured owner relationship" },
|
|
2355
|
+
});
|
|
2356
|
+
const sessionPath = (0, shared_turn_1.getSenseSessionPath)(TARGET_ID, target.friendId, "telegram", target.sessionKey, input.agentRoot);
|
|
2357
|
+
const port = (0, telegram_effect_adapter_1.createTelegramApprovalEffectPort)({
|
|
2358
|
+
target,
|
|
2359
|
+
chatId: input.chatId,
|
|
2360
|
+
execute,
|
|
2361
|
+
record: async (artifact) => { await (0, telegram_effect_adapter_1.recordTelegramEffectsInSession)({ store, sessionPath, artifacts: [artifact] }); },
|
|
2362
|
+
});
|
|
2363
|
+
return { port, close: () => store.close() };
|
|
2364
|
+
}
|
|
2291
2365
|
exports.proveAttemptedRecoveryWithoutRetry = sanctuary_interactive_control_1.proveSanctuaryAttemptedRecoveryWithoutRetry;
|
|
2292
2366
|
async function executeSanctuaryInteractiveRuntimeOperation(rawPayload, supplied) {
|
|
2293
2367
|
exactKeys(rawPayload, ["operation", "label", "scenarioHandleDigest"], "interactive runtime payload");
|
|
@@ -2312,6 +2386,7 @@ async function executeSanctuaryAcceptanceCallbackProbe(rawUpdate, _replay, deps
|
|
|
2312
2386
|
createApi: telegram_client_1.createTelegramBotApi,
|
|
2313
2387
|
createRuntime: telegram_approval_runtime_1.createTelegramApprovalRuntime,
|
|
2314
2388
|
toolContext: sanctuary_runtime_1.createSanctuaryToolContext,
|
|
2389
|
+
effects: createAcceptanceProbeEffects,
|
|
2315
2390
|
}) {
|
|
2316
2391
|
const update = callbackUpdate(rawUpdate);
|
|
2317
2392
|
const refreshed = await deps.refresh(TARGET_ID);
|
|
@@ -2321,6 +2396,13 @@ async function executeSanctuaryAcceptanceCallbackProbe(rawUpdate, _replay, deps
|
|
|
2321
2396
|
const identityKey = deps.identityKey((0, identity_1.getAgentRoot)(TARGET_ID));
|
|
2322
2397
|
const subject = (0, telegram_1.opaqueTelegramSubject)(identityKey, credentials.botToken, credentials.authorizedUserId, credentials.authorizedChatId);
|
|
2323
2398
|
const api = deps.createApi({ token: credentials.botToken });
|
|
2399
|
+
const effectBoundary = deps.effects?.({ agentRoot: (0, identity_1.getAgentRoot)(TARGET_ID), api, subject, chatId: credentials.authorizedChatId });
|
|
2400
|
+
const unavailableEffects = {
|
|
2401
|
+
sendText: async () => { throw new Error("Telegram acceptance probe effect boundary is unavailable"); },
|
|
2402
|
+
sendCard: async () => { throw new Error("Telegram acceptance probe effect boundary is unavailable"); },
|
|
2403
|
+
edit: async () => { throw new Error("Telegram acceptance probe effect boundary is unavailable"); },
|
|
2404
|
+
acknowledge: async () => { throw new Error("Telegram acceptance probe effect boundary is unavailable"); },
|
|
2405
|
+
};
|
|
2324
2406
|
const runtime = deps.createRuntime({
|
|
2325
2407
|
agentName: TARGET_ID,
|
|
2326
2408
|
api,
|
|
@@ -2329,6 +2411,7 @@ async function executeSanctuaryAcceptanceCallbackProbe(rawUpdate, _replay, deps
|
|
|
2329
2411
|
subject,
|
|
2330
2412
|
identityKey,
|
|
2331
2413
|
toolContext: deps.toolContext(TARGET_ID),
|
|
2414
|
+
effects: effectBoundary?.port ?? unavailableEffects,
|
|
2332
2415
|
});
|
|
2333
2416
|
try {
|
|
2334
2417
|
const result = await runtime.transport.handleUpdate(update);
|
|
@@ -2340,6 +2423,7 @@ async function executeSanctuaryAcceptanceCallbackProbe(rawUpdate, _replay, deps
|
|
|
2340
2423
|
}
|
|
2341
2424
|
finally {
|
|
2342
2425
|
runtime.close();
|
|
2426
|
+
effectBoundary?.close();
|
|
2343
2427
|
api.stop();
|
|
2344
2428
|
}
|
|
2345
2429
|
}
|
|
@@ -333,13 +333,13 @@ exports.SANCTUARY_UNIT_16_EVIDENCE_LABELS = [
|
|
|
333
333
|
"unit-16c-provider-readiness",
|
|
334
334
|
"unit-16d-whats-up",
|
|
335
335
|
"unit-16d-1-space",
|
|
336
|
-
"unit-16d-2-
|
|
336
|
+
"unit-16d-2-unknown-admission",
|
|
337
337
|
"unit-16e-containment-audit",
|
|
338
338
|
"unit-16e-1-stop-denial",
|
|
339
339
|
"unit-16e-2-restart-denial",
|
|
340
340
|
"unit-16f-cron-fingerprint",
|
|
341
341
|
"unit-16g-health-transition",
|
|
342
|
-
"unit-16h-
|
|
342
|
+
"unit-16h-acceptance-delivery-probe",
|
|
343
343
|
"unit-16i-delayed-approval",
|
|
344
344
|
"unit-16j-denial",
|
|
345
345
|
"unit-16k-timeout-stale",
|
|
@@ -370,7 +370,7 @@ function sanctuaryScenarioTimeoutBudget(label) {
|
|
|
370
370
|
return 125_000;
|
|
371
371
|
if (label === "unit-15c-1-no-callback-terminalization")
|
|
372
372
|
return 365_000;
|
|
373
|
-
if (label === "unit-16h-
|
|
373
|
+
if (label === "unit-16h-acceptance-delivery-probe")
|
|
374
374
|
return 1_025_000;
|
|
375
375
|
if (label === "unit-16f-cron-fingerprint")
|
|
376
376
|
return 1_025_000;
|
|
@@ -435,10 +435,10 @@ function validateSanctuaryUnit16EvidenceAssertions(label, raw) {
|
|
|
435
435
|
opaqueDigest(value.processBindingDigest, `${label} processBindingDigest`);
|
|
436
436
|
break;
|
|
437
437
|
case "unit-16b-runtime-vault-containment":
|
|
438
|
-
exact(["autostartExact", "exactImage", "manualAuthRequired", "mountCount", "nonRootUid", "publishedPortCount", "readOnlyRoot", "updaterDisabled", "vaultUnlocked"]);
|
|
439
|
-
allTrue(["autostartExact", "exactImage", "readOnlyRoot", "updaterDisabled", "vaultUnlocked"]);
|
|
438
|
+
exact(["autostartExact", "exactImage", "manualAuthRequired", "mountCount", "mountsExact", "nonRootUid", "publishedPortCount", "readOnlyRoot", "updaterDisabled", "vaultUnlocked"]);
|
|
439
|
+
allTrue(["autostartExact", "exactImage", "mountsExact", "readOnlyRoot", "updaterDisabled", "vaultUnlocked"]);
|
|
440
440
|
requiredFalse(value, "manualAuthRequired", label);
|
|
441
|
-
requiredInteger(value, "mountCount",
|
|
441
|
+
requiredInteger(value, "mountCount", 4, label);
|
|
442
442
|
requiredInteger(value, "nonRootUid", 10001, label);
|
|
443
443
|
requiredInteger(value, "publishedPortCount", 0, label);
|
|
444
444
|
break;
|
|
@@ -458,19 +458,19 @@ function validateSanctuaryUnit16EvidenceAssertions(label, raw) {
|
|
|
458
458
|
requiredInteger(value, "responseCount", 1, label);
|
|
459
459
|
requiredInteger(value, "mutationCount", 0, label);
|
|
460
460
|
break;
|
|
461
|
-
case "unit-16d-2-
|
|
462
|
-
exact(["
|
|
463
|
-
allTrue(["
|
|
464
|
-
allZero(["mutationCount", "providerInvocationCount", "responseCount", "workItemCount"]);
|
|
461
|
+
case "unit-16d-2-unknown-admission":
|
|
462
|
+
exact(["acknowledgementSent", "agentTurnCount", "distinctAccount", "mutationCount", "ownerCardSent", "providerInvocationCount", "quarantined", "responseCount", "workItemCount"]);
|
|
463
|
+
allTrue(["acknowledgementSent", "distinctAccount", "ownerCardSent", "quarantined"]);
|
|
464
|
+
allZero(["agentTurnCount", "mutationCount", "providerInvocationCount", "responseCount", "workItemCount"]);
|
|
465
465
|
break;
|
|
466
466
|
case "unit-16e-containment-audit":
|
|
467
467
|
exact([
|
|
468
468
|
"schemaVersion", "keyCount", "keyInventoryDigest", "readScopeDigest", "writeScopeDigest", "keyRoleAssignmentCount",
|
|
469
|
-
"telegramToolCount", "telegramProfileDigest", "telegramSchemaDigest", "privateToolCount", "privateProfileDigest", "privateSchemaDigest", "resolvedHandlerCount",
|
|
469
|
+
"telegramToolCount", "telegramProfileDigest", "telegramSchemaDigest", "privateToolCount", "privateProfileDigest", "privateSchemaDigest", "resolvedHandlerCount", "relationshipProfilesExact", "handlersExact",
|
|
470
470
|
"excludedToolCount", "excludedSchemaIntersectionCount", "fabricatedHandlerInvocationCount", "excludedToolAttemptCount", "excludedToolRejectedCount", "excludedToolInvokedCount", "excludedToolSideEffectCount", "globallyResolvableExcludedToolCount",
|
|
471
471
|
"auditPathDigest", "auditLedgerDigest", "auditRecordCount", "auditLifecyclePairCount",
|
|
472
472
|
"containerUser", "liveProcessUser", "mountCount", "publishedPortCount", "networkMode", "readOnlyRoot", "mountsExact", "securityExact", "updaterDisabled", "writableKeyExposure",
|
|
473
|
-
"rawWriteMaterialFieldCount", "typedWriteExecutorCount", "writeApprovalPolicyDigest", "sensitiveMaterialObserved", "mutationCount",
|
|
473
|
+
"rawWriteMaterialFieldCount", "typedWriteExecutorCount", "writeApprovalPolicyDigest", "writeApprovalPolicyExact", "sensitiveMaterialObserved", "mutationCount",
|
|
474
474
|
]);
|
|
475
475
|
if (text(value.schemaVersion, `${label} schemaVersion`) !== "sanctuary-containment-audit-v1")
|
|
476
476
|
throw new Error(`${label} schemaVersion is invalid`);
|
|
@@ -479,20 +479,16 @@ function validateSanctuaryUnit16EvidenceAssertions(label, raw) {
|
|
|
479
479
|
for (const [key, expected] of Object.entries({
|
|
480
480
|
readScopeDigest: "9914469afdcb574937d1020a03faa82e3c02d767169d3eccae4b81863dafa06e",
|
|
481
481
|
writeScopeDigest: "1de873b2bc3c7769010c32c69fcc8ea55343a5647cfdb0294769e831142945ec",
|
|
482
|
-
telegramProfileDigest: "a7f26934c5e60737582b9d13c78944b8bcbb941366899d82d58c01ca296e14e2",
|
|
483
|
-
telegramSchemaDigest: "3c66299a5f70ec82f8795cae47659284e6dbc691ef49002c2fb22edba76c59b6",
|
|
484
|
-
privateProfileDigest: "a100ffcaf436842bf9fceaf3d2fd1a1b766c04238300487474d6e9fcb7946369",
|
|
485
|
-
privateSchemaDigest: "61b137b2467acbcf22ca7443ee01e71ed970a62728c42aabffbdcb562f4a6a70",
|
|
486
482
|
auditPathDigest: "1cb8f1a00c544a5d10b0577090dbf070a07a5b6a99de13ccd27c11a257f84b75",
|
|
487
|
-
writeApprovalPolicyDigest: "24b1726edf1a2bbd524e9be63d3f0f726d996a8a009425462e01a5c4916ef42b",
|
|
488
483
|
}))
|
|
489
484
|
if (value[key] !== expected)
|
|
490
485
|
throw new Error(`${label} ${key} does not match the canonical contract`);
|
|
491
486
|
requiredInteger(value, "keyCount", 2, label);
|
|
492
487
|
requiredInteger(value, "keyRoleAssignmentCount", 0, label);
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
488
|
+
const telegramToolCount = integer(value.telegramToolCount, `${label} telegramToolCount`, 1);
|
|
489
|
+
const privateToolCount = integer(value.privateToolCount, `${label} privateToolCount`, 1);
|
|
490
|
+
if (integer(value.resolvedHandlerCount, `${label} resolvedHandlerCount`, 1) !== telegramToolCount + privateToolCount)
|
|
491
|
+
throw new Error(`${label} handler count does not match the live relationship profiles`);
|
|
496
492
|
requiredInteger(value, "excludedToolCount", 7, label);
|
|
497
493
|
requiredInteger(value, "excludedToolAttemptCount", 7, label);
|
|
498
494
|
requiredInteger(value, "excludedToolRejectedCount", 7, label);
|
|
@@ -504,9 +500,9 @@ function validateSanctuaryUnit16EvidenceAssertions(label, raw) {
|
|
|
504
500
|
integer(value.auditLifecyclePairCount, `${label} auditLifecyclePairCount`, 1);
|
|
505
501
|
if (text(value.containerUser, `${label} containerUser`) !== "10001:10001" || text(value.liveProcessUser, `${label} liveProcessUser`) !== "10001:10001" || text(value.networkMode, `${label} networkMode`) !== "host")
|
|
506
502
|
throw new Error(`${label} container identity or network is invalid`);
|
|
507
|
-
requiredInteger(value, "mountCount",
|
|
503
|
+
requiredInteger(value, "mountCount", 4, label);
|
|
508
504
|
requiredInteger(value, "typedWriteExecutorCount", 1, label);
|
|
509
|
-
allTrue(["readOnlyRoot", "mountsExact", "securityExact", "updaterDisabled"]);
|
|
505
|
+
allTrue(["relationshipProfilesExact", "handlersExact", "writeApprovalPolicyExact", "readOnlyRoot", "mountsExact", "securityExact", "updaterDisabled"]);
|
|
510
506
|
break;
|
|
511
507
|
case "unit-16e-1-stop-denial":
|
|
512
508
|
case "unit-16e-2-restart-denial":
|
|
@@ -526,9 +522,10 @@ function validateSanctuaryUnit16EvidenceAssertions(label, raw) {
|
|
|
526
522
|
allTrue(["productionRestored", "transitionObserved"]);
|
|
527
523
|
requiredInteger(value, "alertCount", 3, label);
|
|
528
524
|
break;
|
|
529
|
-
case "unit-16h-
|
|
530
|
-
exact(["firedWithinMs", "messageCount", "productionRestored", "
|
|
531
|
-
allTrue(["
|
|
525
|
+
case "unit-16h-acceptance-delivery-probe":
|
|
526
|
+
exact(["acceptanceOnly", "deliveryPathObserved", "firedWithinMs", "messageCount", "productionRestored", "productionScheduleChanged"]);
|
|
527
|
+
allTrue(["acceptanceOnly", "deliveryPathObserved", "productionRestored"]);
|
|
528
|
+
requiredFalse(value, "productionScheduleChanged", label);
|
|
532
529
|
requiredInteger(value, "messageCount", 1, label);
|
|
533
530
|
if (integer(value.firedWithinMs, `${label} firedWithinMs`, 0) > 960_000)
|
|
534
531
|
throw new Error(`${label} fired outside the 16-minute bound`);
|
|
@@ -644,13 +641,13 @@ exports.SANCTUARY_SCENARIO_GATES = {
|
|
|
644
641
|
"unit-16c-provider-readiness": "none",
|
|
645
642
|
"unit-16d-whats-up": "authorized-telegram-message",
|
|
646
643
|
"unit-16d-1-space": "authorized-telegram-message",
|
|
647
|
-
"unit-16d-2-
|
|
644
|
+
"unit-16d-2-unknown-admission": "unknown-telegram-admission",
|
|
648
645
|
"unit-16e-containment-audit": "none",
|
|
649
646
|
"unit-16e-1-stop-denial": "none",
|
|
650
647
|
"unit-16e-2-restart-denial": "none",
|
|
651
648
|
"unit-16f-cron-fingerprint": "none",
|
|
652
649
|
"unit-16g-health-transition": "none",
|
|
653
|
-
"unit-16h-
|
|
650
|
+
"unit-16h-acceptance-delivery-probe": "none",
|
|
654
651
|
"unit-16i-delayed-approval": "telegram-delayed-approve",
|
|
655
652
|
"unit-16j-denial": "telegram-deny",
|
|
656
653
|
"unit-16k-timeout-stale": "telegram-stale-callback",
|
|
@@ -668,13 +665,13 @@ exports.SANCTUARY_SCENARIO_SOURCES = {
|
|
|
668
665
|
"unit-16c-provider-readiness": ["provider-live-check"],
|
|
669
666
|
"unit-16d-whats-up": ["telegram-audit", "telegram-offset", "telegram-turn-receipts", "live-grounding-read"],
|
|
670
667
|
"unit-16d-1-space": ["telegram-audit", "telegram-offset", "telegram-turn-receipts", "restart-attempt-ledger", "container-inspect", "live-grounding-read"],
|
|
671
|
-
"unit-16d-2-
|
|
668
|
+
"unit-16d-2-unknown-admission": ["identity-key", "telegram-audit", "telegram-offset", "telegram-turn-receipts", "telegram-admission-evidence", "approval-journal", "restart-attempt-ledger", "container-inspect", "containment-audit"],
|
|
672
669
|
"unit-16e-containment-audit": ["telegram-audit", "container-inspect", "containment-audit"],
|
|
673
670
|
"unit-16e-1-stop-denial": ["read-only-denial-receipt", "container-inspect"],
|
|
674
671
|
"unit-16e-2-restart-denial": ["read-only-denial-receipt", "container-inspect"],
|
|
675
672
|
"unit-16f-cron-fingerprint": ["health-probe-receipt", "scheduler-liveness-receipt", "cron-runtime", "telegram-audit", "container-inspect"],
|
|
676
673
|
"unit-16g-health-transition": ["health-probe-receipt", "telegram-audit", "container-inspect"],
|
|
677
|
-
"unit-16h-
|
|
674
|
+
"unit-16h-acceptance-delivery-probe": ["health-probe-receipt", "cron-runtime", "telegram-audit", "container-inspect"],
|
|
678
675
|
"unit-16i-delayed-approval": ["identity-key", "telegram-audit", "approval-journal", "approval-checkpoints", "restart-attempt-ledger", "container-inspect"],
|
|
679
676
|
"unit-16j-denial": ["identity-key", "telegram-audit", "approval-journal", "approval-checkpoints", "restart-attempt-ledger", "container-inspect"],
|
|
680
677
|
"unit-16k-timeout-stale": ["identity-key", "telegram-audit", "approval-journal", "approval-checkpoints", "restart-attempt-ledger", "container-inspect", "interactive-driver-receipt"],
|