@ouro.bot/cli 0.1.0-alpha.745 → 0.1.0-alpha.747

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 CHANGED
@@ -1,6 +1,20 @@
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.747",
6
+ "changes": [
7
+ "Create every nested host-backup directory as root-private before provenance verification.",
8
+ "Accept a missing OCI source label only on Sanctuary's exact historical alpha.742 image while retaining strict source provenance for every other image."
9
+ ]
10
+ },
11
+ {
12
+ "version": "0.1.0-alpha.746",
13
+ "changes": [
14
+ "Run packaged Sanctuary auditors with constrained root privileges so root-private inspection and staged policy inputs remain readable without widening file permissions.",
15
+ "Audit immutable container image identity from Docker's resolved top-level Image and validate the portable effective root Mounts contract, including private bind propagation, across real Docker inspect output."
16
+ ]
17
+ },
4
18
  {
5
19
  "version": "0.1.0-alpha.745",
6
20
  "changes": [
@@ -42,6 +42,7 @@ Effective-spec audit helper:
42
42
  docker image inspect "$AUDIT_EXPECTED_IMAGE" >"$INSPECT_DIR/image.json" || return $?
43
43
  chmod 0600 "$INSPECT_DIR/container.json" "$INSPECT_DIR/image.json" || return $?
44
44
  docker run --rm --pull=never --network=none \
45
+ --user 0:0 --read-only --cap-drop=ALL --security-opt=no-new-privileges \
45
46
  --entrypoint /opt/ouro/deploy/unraid/audit-container-spec.sh \
46
47
  --mount "type=bind,src=$INSPECT_DIR/container.json,dst=/audit/container.json,readonly" \
47
48
  --mount "type=bind,src=$INSPECT_DIR/image.json,dst=/audit/image.json,readonly" \
@@ -310,7 +311,9 @@ Effective-spec audit helper:
310
311
  const image = JSON.parse(fs.readFileSync(imagePath, "utf8"));
311
312
  if (!Array.isArray(container) || container.length !== 1 || !container[0] || container[0].Image !== imageId) process.exit(1);
312
313
  if (!Array.isArray(image) || image.length !== 1 || !image[0] || image[0].Id !== imageId) process.exit(1);
313
- if (image[0].Config?.Labels?.["org.opencontainers.image.source"] !== "https://github.com/ourostack/ouroboros") process.exit(1);
314
+ const source = image[0].Config?.Labels?.["org.opencontainers.image.source"];
315
+ const legacyAlpha742 = "sha256:681449ad47a2621705cd339b481e6339236b31dc65e195b1cf5025d0f2191d7d";
316
+ if (source !== "https://github.com/ourostack/ouroboros" && !(source === undefined && imageId === legacyAlpha742)) process.exit(1);
314
317
  const expected = ["custom/usenet_health.sh", "custom/ouro-events/bootstrap-spool.sh", "custom/ouro-events/emit-event.mjs", "custom/ouro-events/emit-usenet-event.sh", "custom/ouro-events/install-usenet-guard.sh", "go.butler-lines", "crontab.butler-lines", "global-state"];
315
318
  const expectedUid = 0;
316
319
  const expectedGid = 0;
@@ -1444,6 +1447,7 @@ Update:
1444
1447
  audit the staged template and runtime policy with the packaged auditor, then
1445
1448
  remove the private stage before any Butler mutation:
1446
1449
  docker run --rm --pull=never --network=none \
1450
+ --user 0:0 --read-only --cap-drop=ALL --security-opt=no-new-privileges \
1447
1451
  --entrypoint /opt/ouro/deploy/unraid/audit-container-spec.sh \
1448
1452
  --mount "type=bind,src=$STAGED_TEMPLATE,dst=/audit/sanctuary.xml,readonly" \
1449
1453
  --mount "type=bind,src=$STAGED_RUNTIME_POLICY,dst=/audit/container-runtime.json,readonly" \
@@ -1784,7 +1788,7 @@ Backup:
1784
1788
  if docker stop ouro-butler \
1785
1789
  && test "$(docker inspect --format '{{.State.Running}}' ouro-butler)" = false \
1786
1790
  && install -d -m 0700 -o 0 -g 0 "$BACKUP_TMP" "$BACKUP_TMP/runtime" "$BACKUP_TMP/agent" "$BACKUP_TMP/host" "$BACKUP_TMP/provenance" \
1787
- && install -d -m 0700 -o 0 -g 0 "$BACKUP_TMP/host/custom/ouro-events" \
1791
+ && install -d -m 0700 -o 0 -g 0 "$BACKUP_TMP/host/custom" "$BACKUP_TMP/host/custom/ouro-events" \
1788
1792
  && install -m 0600 -o 0 -g 0 /dev/null "$BACKUP_TMP/host/inventory" \
1789
1793
  && backup_host_file /boot/config/custom/usenet_health.sh custom/usenet_health.sh \
1790
1794
  && backup_host_file /boot/config/custom/ouro-events/bootstrap-spool.sh custom/ouro-events/bootstrap-spool.sh \
@@ -1,5 +1,5 @@
1
1
  {
2
- "runtimeVersion": "0.1.0-alpha.745",
2
+ "runtimeVersion": "0.1.0-alpha.747",
3
3
  "bundleSchemaVersion": 3,
4
4
  "lastUpdated": "2026-08-30T00:00:00.000Z"
5
5
  }
@@ -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.745</Repository>
4
+ <Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.747</Repository>
5
5
  <Registry>https://github.com/ourostack/ouroboros/pkgs/container/ouroboros-butler</Registry>
6
6
  <Network>host</Network>
7
7
  <Shell>sh</Shell>
@@ -10,13 +10,12 @@ const EXPECTED_BINDS = [
10
10
  "/mnt/user/appdata/sabnzbd/sabnzbd.ini:/run/sanctuary/sabnzbd.ini:ro",
11
11
  ];
12
12
  const EXPECTED_MOUNTS = [
13
- ["/mnt/user/appdata/ouro-butler/runtime/.ouro-cli", "/home/ouro/.ouro-cli", true],
14
- ["/mnt/user/appdata/ouro-butler/agent/sanctuary.ouro", "/home/ouro/AgentBundles/sanctuary.ouro", true],
15
- ["/boot/config/custom/ouro-events/spool", "/run/ouro-events", false],
16
- ["/mnt/user/appdata/sabnzbd/sabnzbd.ini", "/run/sanctuary/sabnzbd.ini", false],
13
+ ["/mnt/user/appdata/ouro-butler/runtime/.ouro-cli", "/home/ouro/.ouro-cli", true, "rprivate"],
14
+ ["/mnt/user/appdata/ouro-butler/agent/sanctuary.ouro", "/home/ouro/AgentBundles/sanctuary.ouro", true, "rprivate"],
15
+ ["/boot/config/custom/ouro-events/spool", "/run/ouro-events", false, "rprivate"],
16
+ ["/mnt/user/appdata/sabnzbd/sabnzbd.ini", "/run/sanctuary/sabnzbd.ini", false, "rprivate"],
17
17
  ];
18
18
  const LEGACY_ALPHA742_IMAGE = "sha256:681449ad47a2621705cd339b481e6339236b31dc65e195b1cf5025d0f2191d7d";
19
- const LEGACY_ALPHA742_BINDS = EXPECTED_BINDS.slice(0, 2);
20
19
  const LEGACY_ALPHA742_MOUNTS = EXPECTED_MOUNTS.slice(0, 2);
21
20
  const EXPECTED_EXTRA_PARAMS = "--restart=unless-stopped --user=10001:10001";
22
21
  function record(value) {
@@ -46,9 +45,8 @@ function auditSanctuaryContainerSpec(value, options) {
46
45
  const mountContract = options.mountContract ?? "canonical";
47
46
  if (mountContract === "legacy-alpha742" && options.expectedImage !== LEGACY_ALPHA742_IMAGE)
48
47
  violations.push("legacy mount exception requires the pinned alpha.742 image ID");
49
- const expectedBinds = mountContract === "legacy-alpha742" ? LEGACY_ALPHA742_BINDS : EXPECTED_BINDS;
50
48
  const expectedMounts = mountContract === "legacy-alpha742" ? LEGACY_ALPHA742_MOUNTS : EXPECTED_MOUNTS;
51
- if (config.Image !== options.expectedImage)
49
+ if (root.Image !== options.expectedImage)
52
50
  violations.push("image does not match the reviewed exact local Docker image ID");
53
51
  if (root.Path !== "node")
54
52
  violations.push("effective container path must be node");
@@ -92,14 +90,11 @@ function auditSanctuaryContainerSpec(value, options) {
92
90
  violations.push("container must not publish all exposed ports");
93
91
  if (!isEmptyRecord(network?.Ports))
94
92
  violations.push("effective network ports must be empty");
95
- const binds = stringArray(host.Binds);
96
- if (!binds || JSON.stringify([...binds].sort()) !== JSON.stringify([...expectedBinds].sort()))
97
- violations.push("bind set does not match the selected Sanctuary mount contract");
98
93
  const mounts = Array.isArray(root.Mounts) ? root.Mounts : [];
99
94
  const normalizedMounts = mounts.map((mount) => {
100
95
  const item = record(mount);
101
- return item && item.Type === "bind" && typeof item.RW === "boolean" && typeof item.Source === "string" && typeof item.Destination === "string"
102
- ? [item.Source, item.Destination, item.RW]
96
+ return item && item.Type === "bind" && typeof item.RW === "boolean" && typeof item.Source === "string" && typeof item.Destination === "string" && item.Propagation === "rprivate"
97
+ ? [item.Source, item.Destination, item.RW, item.Propagation]
103
98
  : null;
104
99
  });
105
100
  if (normalizedMounts.some((mount) => mount === null)
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.745",
3
+ "version": "0.1.0-alpha.747",
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.745",
9
+ "version": "0.1.0-alpha.747",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.78.0",
12
12
  "@azure/identity": "^4.13.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.745",
3
+ "version": "0.1.0-alpha.747",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },