@ouro.bot/cli 0.1.0-alpha.840 → 0.1.0-alpha.841
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 +6 -0
- package/deploy/unraid/sanctuary-butler-upgrade.mjs +16 -1
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +1 -1
- package/deploy/unraid/sanctuary.xml +1 -1
- package/dist/heart/daemon/sanctuary-authority-root-lifecycle.js +14 -4
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/changelog.json
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
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.841",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Sanctuary: the root lifecycle accepts the host keeper as the boot owner (D-045), so staging and retirement no longer refuse on a keeper-managed Unraid host; the upgrade orchestrator prunes old Butler images after a successful upgrade, keeping the live and rollback images (D-046: docker.img had reached 88%)."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
4
10
|
{
|
|
5
11
|
"version": "0.1.0-alpha.840",
|
|
6
12
|
"changes": [
|
|
@@ -823,6 +823,21 @@ function pinTemplate(version) {
|
|
|
823
823
|
ok(`DockerMan template pins ${image(version)}`)
|
|
824
824
|
}
|
|
825
825
|
|
|
826
|
+
// Every release pulls a ~1 GB Butler image, and Unraid's docker.img filled to 88% with
|
|
827
|
+
// twenty of them (D-046). After a successful upgrade keep only the live image and the
|
|
828
|
+
// authority's recorded rollback image; Docker itself refuses to remove an image in use.
|
|
829
|
+
function pruneButlerImages() {
|
|
830
|
+
const activation = JSON.parse(readFileSync(`${ROOT}/activation.json`, "utf8"))
|
|
831
|
+
const keep = new Set([activation.targetImageId, activation.rollbackImageId])
|
|
832
|
+
let removed = 0
|
|
833
|
+
for (const line of docker(["images", "--no-trunc", "--format", "{{.ID}} {{.Tag}}", "ghcr.io/ourostack/ouroboros-butler"]).trim().split("\n").filter(Boolean)) {
|
|
834
|
+
const [id, tag] = line.split(" ")
|
|
835
|
+
if (keep.has(id) || !tag || tag === "<none>") continue
|
|
836
|
+
try { docker(["rmi", `ghcr.io/ourostack/ouroboros-butler:${tag}`], { stdio: ["ignore", "pipe", "pipe"] }); removed += 1 } catch { /* in use */ }
|
|
837
|
+
}
|
|
838
|
+
ok(`pruned ${removed} old Butler image(s); kept the live and rollback images`)
|
|
839
|
+
}
|
|
840
|
+
|
|
826
841
|
function lifecycleFailure(e) {
|
|
827
842
|
const detail = [e.stderr, e.stdout].map((x) => (x ? String(x).trim() : "")).filter(Boolean).join(" | ")
|
|
828
843
|
let last = ""
|
|
@@ -871,7 +886,7 @@ function upgrade(version, rehearse) {
|
|
|
871
886
|
resumeSupervision()
|
|
872
887
|
fail(`ROLLBACK FAILED: ${lifecycleFailure(e)}\nThe journal is kept; the next authority boot (or \`upgrade-rollback\`) retries it.`)
|
|
873
888
|
}
|
|
874
|
-
} else pinTemplate(version)
|
|
889
|
+
} else { pinTemplate(version); pruneButlerImages() }
|
|
875
890
|
resumeSupervision()
|
|
876
891
|
say("preservation")
|
|
877
892
|
docker(["inspect", "jellyfin", "--format", "{{.Id}}|{{.Image}}|{{.RestartCount}}|{{.State.StartedAt}}"]).trim() === jellyfinBefore ? ok("jellyfin unchanged") : fail("JELLYFIN CHANGED")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<?xml version="1.0"?>
|
|
2
2
|
<Container version="2">
|
|
3
3
|
<Name>ouro-butler</Name>
|
|
4
|
-
<Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.
|
|
4
|
+
<Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.841</Repository>
|
|
5
5
|
<Registry>https://github.com/ourostack/ouroboros/pkgs/container/ouroboros-butler</Registry>
|
|
6
6
|
<Network>host</Network>
|
|
7
7
|
<Shell>sh</Shell>
|
|
@@ -34,7 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
var _a;
|
|
36
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
-
exports.SanctuaryAuthorityRootLifecycle = exports.SANCTUARY_UPGRADE_STEPS = void 0;
|
|
37
|
+
exports.SanctuaryAuthorityRootLifecycle = exports.SANCTUARY_UPGRADE_STEPS = exports.SANCTUARY_KEEPER_BOOT_LINES = void 0;
|
|
38
38
|
exports.recordSanctuaryRootLifecycleFailure = recordSanctuaryRootLifecycleFailure;
|
|
39
39
|
exports.runSanctuaryAuthorityRootCli = runSanctuaryAuthorityRootCli;
|
|
40
40
|
const node_child_process_1 = require("node:child_process");
|
|
@@ -58,6 +58,16 @@ const STAGING = "/var/lib/ouro-authority/staging";
|
|
|
58
58
|
const CGROUP = "/sys/fs/cgroup/ouro-authority";
|
|
59
59
|
const BOOT = "/boot/config/custom/ouro-authority/start.sh";
|
|
60
60
|
const BOOT_LINE = `/bin/sh ${BOOT} --boot & # ouro-authority`;
|
|
61
|
+
// On Unraid the host keeper owns boot instead (it runs BOOT --boot itself, D-032), and the
|
|
62
|
+
// upgrade orchestrator installs exactly these lines in place of BOOT_LINE (D-045).
|
|
63
|
+
const KEEPER_SUPERVISOR = "/boot/config/custom/ouro-authority/gateway-supervisor.sh";
|
|
64
|
+
const KEEPER_WATCHDOG = "/boot/config/custom/ouro-authority/gateway-keeper-watchdog.sh";
|
|
65
|
+
exports.SANCTUARY_KEEPER_BOOT_LINES = {
|
|
66
|
+
supervisor: `setsid /bin/sh ${KEEPER_SUPERVISOR} >/dev/null 2>&1 & # ouro-authority-gateway`,
|
|
67
|
+
watchdog: `(crontab -l 2>/dev/null | grep -v gateway-keeper-watchdog; echo "*/2 * * * * /bin/sh ${KEEPER_WATCHDOG} # ouro-authority-gateway-watchdog") | crontab - # ouro-authority-gateway-watchdog`,
|
|
68
|
+
};
|
|
69
|
+
const BOOT_OWNERS = [BOOT_LINE, exports.SANCTUARY_KEEPER_BOOT_LINES.supervisor];
|
|
70
|
+
const KNOWN_BOOT_LINES = [...BOOT_OWNERS, exports.SANCTUARY_KEEPER_BOOT_LINES.watchdog];
|
|
61
71
|
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
62
72
|
// The gateway verifies every pinned package file before it reports ready. With a cold
|
|
63
73
|
// page cache on Unraid's array that takes minutes, so readiness gets a generous budget
|
|
@@ -293,7 +303,7 @@ class SanctuaryAuthorityRootLifecycle {
|
|
|
293
303
|
return false;
|
|
294
304
|
this.#record(`${this.#epochRoot()}/stage.json`, { packageDigest: this.#request.packageDigest });
|
|
295
305
|
this.#verifyPackage(undefined, hostExecution);
|
|
296
|
-
if (this.#bootScript().text.split("\n").filter((line) => line
|
|
306
|
+
if (this.#bootScript().text.split("\n").filter((line) => BOOT_OWNERS.includes(line)).length !== 1
|
|
297
307
|
|| digest(this.#private(BOOT)) !== digest(fs.readFileSync(this.#p(`${ROOT}/package/deploy/unraid/sanctuary-authority-service.sh`))))
|
|
298
308
|
throw new Error("Sanctuary installed boot lifecycle changed");
|
|
299
309
|
return true;
|
|
@@ -379,10 +389,10 @@ class SanctuaryAuthorityRootLifecycle {
|
|
|
379
389
|
}
|
|
380
390
|
this.#verifyPackage(undefined, hostExecution);
|
|
381
391
|
const { text: boot, mode: bootMode } = this.#bootScript();
|
|
382
|
-
if (boot.split("\n").some((line) => line.includes("ouro-authority") && line
|
|
392
|
+
if (boot.split("\n").some((line) => line.includes("ouro-authority") && !KNOWN_BOOT_LINES.includes(line)))
|
|
383
393
|
throw new Error("Sanctuary boot ownership is ambiguous");
|
|
384
394
|
this.#write(BOOT, fs.readFileSync(this.#p(`${ROOT}/package/deploy/unraid/sanctuary-authority-service.sh`), "utf8"));
|
|
385
|
-
if (!boot.split("\n").includes(
|
|
395
|
+
if (!boot.split("\n").some((line) => BOOT_OWNERS.includes(line)))
|
|
386
396
|
this.#write("/boot/config/go", `${boot}${boot.endsWith("\n") ? "" : "\n"}${BOOT_LINE}\n`, bootMode);
|
|
387
397
|
this.#write(`${this.#epochRoot()}/stage.json`, JSON.stringify({ packageDigest: this.#request.packageDigest }));
|
|
388
398
|
}
|
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.841",
|
|
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.841",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
12
12
|
"@azure/identity": "^4.13.0",
|