@ouro.bot/cli 0.1.0-alpha.767 → 0.1.0-alpha.768
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 +7 -0
- package/deploy/unraid/sanctuary-acceptance-contract.json +1 -1
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +1 -1
- package/deploy/unraid/sanctuary.xml +1 -1
- package/dist/heart/daemon/sanctuary-acceptance-adapter.js +49 -7
- package/dist/heart/daemon/sanctuary-acceptance-harness.js +4 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.768",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Fix Sanctuary acceptance cursor snapshots for authenticated genesis and concurrent audit writes.",
|
|
8
|
+
"Cover fail-closed cursor schema, authority, and offset validation."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
4
11
|
{
|
|
5
12
|
"version": "0.1.0-alpha.767",
|
|
6
13
|
"changes": [
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"fixed": {
|
|
103
103
|
"allowedRoot": "/evidence",
|
|
104
104
|
"evidencePath": "/evidence/cursor-snapshot.json",
|
|
105
|
-
"adapters": [{ "schema": "telegram-cursor-v1", "executable": "/opt/ouro/deploy/unraid/sanctuary-acceptance-adapter.sh" }]
|
|
105
|
+
"adapters": [{ "schema": "telegram-cursor-v1", "executable": "/opt/ouro/deploy/unraid/sanctuary-acceptance-adapter.sh", "allowGenesis": false }]
|
|
106
106
|
}
|
|
107
107
|
},
|
|
108
108
|
"cursor-delta": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<?xml version="1.0"?>
|
|
2
2
|
<Container version="2">
|
|
3
3
|
<Name>Mendelow Cloud Butler</Name>
|
|
4
|
-
<Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.
|
|
4
|
+
<Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.768</Repository>
|
|
5
5
|
<Registry>https://github.com/ourostack/ouroboros/pkgs/container/ouroboros-butler</Registry>
|
|
6
6
|
<Network>host</Network>
|
|
7
7
|
<Shell>sh</Shell>
|
|
@@ -99,6 +99,7 @@ const NETWORK_TIMEOUT_MS = 10_000;
|
|
|
99
99
|
const KEY_DIRECTORY = "/boot/config/plugins/dynamix.my.servers/keys";
|
|
100
100
|
const SELECTED_KEY_RECORD = "/run/ouro-acceptance/unraid-key.json";
|
|
101
101
|
const TELEGRAM_OFFSET = "/home/ouro/AgentBundles/sanctuary.ouro/state/senses/telegram/offset.json";
|
|
102
|
+
const TELEGRAM_IDENTITY_KEY = "/home/ouro/AgentBundles/sanctuary.ouro/state/senses/telegram/identity.key";
|
|
102
103
|
const TELEGRAM_AUDIT = `/home/ouro/AgentBundles/sanctuary.ouro/${telegram_audit_ledger_1.TELEGRAM_ACCEPTANCE_AUDIT_RELATIVE_PATH}`;
|
|
103
104
|
const TELEGRAM_AUDIT_HEAD = `/home/ouro/AgentBundles/sanctuary.ouro/${telegram_audit_ledger_1.TELEGRAM_ACCEPTANCE_AUDIT_HEAD_RELATIVE_PATH}`;
|
|
104
105
|
const IMAGE_DIGEST_FILE = "/run/ouro-acceptance/image-digest";
|
|
@@ -1848,16 +1849,52 @@ async function storeTelegramBootstrap(payload, deps) {
|
|
|
1848
1849
|
}
|
|
1849
1850
|
return { stored: true };
|
|
1850
1851
|
}
|
|
1851
|
-
function cursorSnapshot(deps) {
|
|
1852
|
+
function cursorSnapshot(payload, deps) {
|
|
1853
|
+
exactKeys(payload, ["allowGenesis", "operation", "schema"], "Telegram cursor snapshot request");
|
|
1854
|
+
if (payload.schema !== "telegram-cursor-v1" || typeof payload.allowGenesis !== "boolean")
|
|
1855
|
+
throw new Error("Telegram cursor snapshot request is invalid");
|
|
1852
1856
|
const offsetRaw = fixedFile(deps, TELEGRAM_OFFSET);
|
|
1853
|
-
const
|
|
1854
|
-
|
|
1857
|
+
const identityKey = fixedFile(deps, TELEGRAM_IDENTITY_KEY).trim();
|
|
1858
|
+
if (!/^[A-Za-z0-9_-]{43}$/u.test(identityKey) || Buffer.from(identityKey, "base64url").length !== 32) {
|
|
1859
|
+
throw new Error("Telegram identity key is invalid");
|
|
1860
|
+
}
|
|
1855
1861
|
const offset = object(JSON.parse(offsetRaw), "Telegram offset");
|
|
1856
1862
|
if (!Number.isSafeInteger(offset.nextUpdateId) || offset.nextUpdateId < 0)
|
|
1857
1863
|
throw new Error("Telegram offset is invalid");
|
|
1864
|
+
let auditCursorDigest;
|
|
1865
|
+
let verificationFailure;
|
|
1866
|
+
let observedAuditState = false;
|
|
1867
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
1868
|
+
const headBefore = optionalFixedFile(deps, TELEGRAM_AUDIT_HEAD);
|
|
1869
|
+
const auditRaw = optionalFixedFile(deps, TELEGRAM_AUDIT);
|
|
1870
|
+
const headAfter = optionalFixedFile(deps, TELEGRAM_AUDIT_HEAD);
|
|
1871
|
+
if (headBefore === null && auditRaw === null && headAfter === null) {
|
|
1872
|
+
if (payload.allowGenesis !== true)
|
|
1873
|
+
throw new Error("Telegram audit genesis is not authorized for this snapshot");
|
|
1874
|
+
if (!observedAuditState) {
|
|
1875
|
+
auditCursorDigest = sha256("ouroboros.telegram.acceptance.cursor.v1\0genesis");
|
|
1876
|
+
break;
|
|
1877
|
+
}
|
|
1878
|
+
continue;
|
|
1879
|
+
}
|
|
1880
|
+
observedAuditState = true;
|
|
1881
|
+
if (headBefore !== null && auditRaw !== null && headAfter !== null && headBefore === headAfter) {
|
|
1882
|
+
try {
|
|
1883
|
+
(0, telegram_audit_ledger_1.verifyTelegramAuditLedger)({ ledgerRaw: auditRaw, headRaw: headAfter, identityKey });
|
|
1884
|
+
auditCursorDigest = sha256(`ouroboros.telegram.acceptance.cursor.v1\0present\0${auditRaw}\0${headAfter}`);
|
|
1885
|
+
break;
|
|
1886
|
+
}
|
|
1887
|
+
catch (error) {
|
|
1888
|
+
verificationFailure = error;
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
if (auditCursorDigest === undefined) {
|
|
1893
|
+
throw new Error(`Telegram acceptance audit state could not be captured consistently${verificationFailure ? `: ${verificationFailure.message}` : ""}`, verificationFailure ? { cause: verificationFailure } : undefined);
|
|
1894
|
+
}
|
|
1858
1895
|
return {
|
|
1859
1896
|
offsetDigest: sha256(JSON.stringify({ nextUpdateId: offset.nextUpdateId })),
|
|
1860
|
-
auditCursorDigest
|
|
1897
|
+
auditCursorDigest,
|
|
1861
1898
|
};
|
|
1862
1899
|
}
|
|
1863
1900
|
function telegramPollerQuiescence(payload, deps) {
|
|
@@ -2065,7 +2102,7 @@ function provenance(payload, deps) {
|
|
|
2065
2102
|
const containerDigest = fixedFile(deps, CONTAINER_DIGEST_FILE).trim();
|
|
2066
2103
|
if (!SHA256.test(imageDigest) || !SHA256.test(containerDigest))
|
|
2067
2104
|
throw new Error("live provenance digest is invalid");
|
|
2068
|
-
const cursor = cursorSnapshot(deps);
|
|
2105
|
+
const cursor = cursorSnapshot({ operation: "snapshot", schema: "telegram-cursor-v1", allowGenesis: false }, deps);
|
|
2069
2106
|
return { imageDigest, containerDigest, cursorDigest: sha256(`${cursor.offsetDigest}\0${cursor.auditCursorDigest}`) };
|
|
2070
2107
|
}
|
|
2071
2108
|
function evidenceSnapshot(payload, deps) {
|
|
@@ -2078,7 +2115,11 @@ function evidenceSnapshot(payload, deps) {
|
|
|
2078
2115
|
const imageDigest = fixedFile(deps, IMAGE_DIGEST_FILE).trim();
|
|
2079
2116
|
if (!SHA256.test(imageDigest))
|
|
2080
2117
|
throw new Error("container image digest is invalid");
|
|
2081
|
-
return {
|
|
2118
|
+
return {
|
|
2119
|
+
healthy: health.healthy,
|
|
2120
|
+
containerImageDigest: imageDigest,
|
|
2121
|
+
telegramOffsetDigest: cursorSnapshot({ operation: "snapshot", schema: "telegram-cursor-v1", allowGenesis: false }, deps).offsetDigest,
|
|
2122
|
+
};
|
|
2082
2123
|
}
|
|
2083
2124
|
function bootId(deps) {
|
|
2084
2125
|
const value = fixedFile(deps, BOOT_ID_FILE).trim();
|
|
@@ -2147,6 +2188,7 @@ function materializeConfig(payload, deps) {
|
|
|
2147
2188
|
if (phase !== "before" && phase !== "after")
|
|
2148
2189
|
throw new Error("cursor snapshot phase is invalid");
|
|
2149
2190
|
config.evidencePath = `/evidence/cursor-${phase}.json`;
|
|
2191
|
+
config.adapters = config.adapters.map((adapter) => ({ ...adapter, allowGenesis: phase === "before" }));
|
|
2150
2192
|
}
|
|
2151
2193
|
else if (command === "unraid-key-rotate") {
|
|
2152
2194
|
const closed = object(JSON.parse(fixedFile(deps, CLOSED_INVENTORY_FILE)), "closed Unraid inventory");
|
|
@@ -2188,7 +2230,7 @@ async function executeSanctuaryAcceptanceAdapter(rawPayload, deps = createSanctu
|
|
|
2188
2230
|
result = telegramPollerQuiescence(payload, deps);
|
|
2189
2231
|
break;
|
|
2190
2232
|
case "snapshot":
|
|
2191
|
-
result = cursorSnapshot(deps);
|
|
2233
|
+
result = cursorSnapshot(payload, deps);
|
|
2192
2234
|
break;
|
|
2193
2235
|
case "inject_callbacks_concurrently":
|
|
2194
2236
|
result = await concurrentCallbackProbe(payload, deps);
|
|
@@ -1011,7 +1011,10 @@ async function cursorSnapshot(config, deps) {
|
|
|
1011
1011
|
throw new Error("snapshot adapter schemas must be unique");
|
|
1012
1012
|
schemas.add(schema);
|
|
1013
1013
|
const executable = adapter(spec.executable, "snapshot adapter executable");
|
|
1014
|
-
const
|
|
1014
|
+
const allowGenesis = spec.allowGenesis === undefined ? false : boolean(spec.allowGenesis, "snapshot adapter allowGenesis");
|
|
1015
|
+
if (allowGenesis && evidencePath !== path.join(root, "cursor-before.json"))
|
|
1016
|
+
throw new Error("snapshot adapter genesis authority is only valid for cursor-before evidence");
|
|
1017
|
+
const payload = await deps.runAdapter(executable, { operation: "snapshot", schema, allowGenesis });
|
|
1015
1018
|
const selected = fixedEvidenceValues(schema, payload);
|
|
1016
1019
|
for (const [name, value] of Object.entries(selected))
|
|
1017
1020
|
values[`${schema}.${name}`] = value;
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ouro.bot/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.768",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@ouro.bot/cli",
|
|
9
|
-
"version": "0.1.0-alpha.
|
|
9
|
+
"version": "0.1.0-alpha.768",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
12
12
|
"@azure/identity": "^4.13.0",
|