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

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,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.746",
6
+ "changes": [
7
+ "Run packaged Sanctuary auditors with constrained root privileges so root-private inspection and staged policy inputs remain readable without widening file permissions.",
8
+ "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."
9
+ ]
10
+ },
4
11
  {
5
12
  "version": "0.1.0-alpha.745",
6
13
  "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" \
@@ -1444,6 +1445,7 @@ Update:
1444
1445
  audit the staged template and runtime policy with the packaged auditor, then
1445
1446
  remove the private stage before any Butler mutation:
1446
1447
  docker run --rm --pull=never --network=none \
1448
+ --user 0:0 --read-only --cap-drop=ALL --security-opt=no-new-privileges \
1447
1449
  --entrypoint /opt/ouro/deploy/unraid/audit-container-spec.sh \
1448
1450
  --mount "type=bind,src=$STAGED_TEMPLATE,dst=/audit/sanctuary.xml,readonly" \
1449
1451
  --mount "type=bind,src=$STAGED_RUNTIME_POLICY,dst=/audit/container-runtime.json,readonly" \
@@ -1,5 +1,5 @@
1
1
  {
2
- "runtimeVersion": "0.1.0-alpha.745",
2
+ "runtimeVersion": "0.1.0-alpha.746",
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.746</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.746",
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.746",
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.746",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },