feat(cloud-environment): add canonical cloud environment setup script - #388
Conversation
Admit the shared Claude Code cloud environment baseline as a component so the claude.ai/code setup script lands here by reviewed PR instead of by hand-editing an account-scoped UI field. The environment field keeps only a three-line bootstrap that curls this script from raw.githubusercontent.com (default allowlist; public repo, no credentials). Folds in the 2026-08-14 live verification findings (melodic-software/claude-code-plugins#2654): - Blocker 1: document Custom network access (+ dot.net, aka.ms, builds.dotnet.microsoft.com, download.visualstudio.microsoft.com) as a hard prerequisite — Trusted 403-blocks the .NET installer redirect. - Blocker 2: timestamped step logging to /var/log/melodic-env-setup.log and a completion stamp (/opt/melodic-env-setup.done) written strictly last, so an interrupted cache build is detectable instead of silent. Admission evidence: live consumer is the Melodic environment plus claude-code-plugins docs/CLOUD-FLEET-SETUP.md (bootstrap + verification checklist reference this path); acceptance is the stamp check in that checklist; rollback is reverting and forcing a cache rebuild (README). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AXaqhrFZeGTzbCJun12Ngx
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Claude finished @kyle-sexton's task in 2m 56s —— View job Code review complete
Scope note: FindingsOne nit posted inline on Otherwise the script held up well under a correctness read:
I wasn't able to execute |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 270ba5c703
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Claude has reviewed this PR 1 time. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
#2668) No linked issue ## Summary Folds the 2026-08-14 live verification of the Melodic cloud environment (#2654) into `docs/CLOUD-FLEET-SETUP.md`, and swaps the guide's embedded environment setup script for a three-line bootstrap that curls the canonical script from the new `cloud-environment` component in standards (melodic-software/standards#388) — so environment behavior changes land by reviewed PR instead of hand-edits to an account-scoped UI field. ## Fix - **Step 1 network access**: the Custom allowlist (default package managers + `dot.net`, `aka.ms`, `builds.dotnet.microsoft.com`, `download.visualstudio.microsoft.com`) is now documented as the requirement, not a fallback — #2654 Blocker 1 reproduced the .NET installer's `403` under Trusted, overturning the 2026-08-13 probe-based optimism. - **Setup script section**: embedded script replaced by the bootstrap + pointers to the standards component and its README; documents the per-step timestamped log (`/var/log/melodic-env-setup.log`), the completion stamp (`/opt/melodic-env-setup.done`, written strictly last), and the cache-rebuild lifecycle (a merged standards change reaches environments only on a forced rebuild or ~7-day expiry). - **Verification checklist**: new item 0 checks the stamp first — a missing stamp is the #2654 Blocker 2 signature (cache build interrupted ~13 s in; PowerShell and the baked-in bootstrap never ran). The .NET item now points at confirming the allowlist rather than "applying the fallback". - **Findings + audit table**: the "bootstrap is unwired" finding is marked resolved — #2631 registered the SessionStart hook and enabled the 65-plugin catalog, #2657 closed the cp311 pyyaml hash gap the hook died on (verified against PyPI's published digests; coverage gap, not tampering). Remaining #2654 actions are environment-side (apply the allowlist, rebuild the cache, re-run the checklist). ## Verification - `markdownlint-cli2 docs/CLOUD-FLEET-SETUP.md` — 0 issues - All referenced anchors (`#step-1--the-shared-environment-claudeai-ui-one-time`, `#verification-checklist`) unchanged and resolvable - Claims cross-checked against the primary sources: #2654 (live run forensics), #2631 / #2657 diffs on `main`, and the component content in melodic-software/standards#388 ## Related - Refs #2654 — the verification report this folds in (left open: the environment-side actions — Custom allowlist + cache rebuild + checklist re-run — are still pending) - Refs #2631, #2657 — the repo-side fixes the Findings section now records - Refs melodic-software/standards#388 — the canonical setup script this guide now bootstraps from - Refs #2613 — the original fleet guide PR this follows up 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01AXaqhrFZeGTzbCJun12Ngx --- _Generated by [Claude Code](https://claude.ai/code/session_01AXaqhrFZeGTzbCJun12Ngx)_ Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
…skip case Addresses both review findings on this PR: - Codex P2: the contract test was not executed by CI — every run-tests.sh invocation in ci.yml names explicit files, so a stamp-ordering or bootstrap-URL regression could merge green. Adds a cloud-environment lane that runs it, wired into the ci-status aggregate gate (both the needs list and the results expression, per actionlint). - Claude review nit: the hook-baking step was the one step with no else branch, so a missing "baked" line could not be told apart from the CWD not being the repo checkout. Logs the skip explicitly, matching the script's every-step-logs contract. Verified: shellcheck -x -P SCRIPTDIR clean, run-tests.sh 1 passed, actionlint clean on ci.yml. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AXaqhrFZeGTzbCJun12Ngx
…ugins (#391) Run the checked-out repo's committed .claude/cloud-bootstrap.sh as the setup script's final repo step (CLAUDE_CODE_REMOTE=true, CLAUDE_PROJECT_DIR at the checkout root; one name, no fallback paths), then a generic data-driven plugin stage: register extraKnownMarketplaces entries and install enabledPlugins entries from the checkout's .claude/settings.json, best-effort, skipping cleanly when claude/jq or plugin keys are absent. Claude Code builds its plugin registry at process start and never re-reads it, so installs must be snapshot-baked to load at a session's first turn. The README documents the frozen calling contract: exact entry-point path and env vars, best-effort and exit-0 semantics, and the warm-cache vs correctness-guarantee division. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UHbdXDm8B4yj81uQBy8M3M
…390) ## Summary Cloud sessions (web, `claude --cloud`, mobile, routines) start on a fresh Ubuntu VM shipping Node 20/21/22 with no `node_modules`, so a session here runs the component contract tests and lint gates on the wrong Node against missing tooling. The fleet-wide verification run confirmed this class of failure (melodic-software/claude-code-plugins#2654). This is **this repository as a consumer**, and is deliberately separate from #388, which adds the shared-environment component this repository *owns*. Same rollout, opposite side of the boundary: #388 is the org's generic warm cache, this is the exact pin only a hook can read. No linked issue ## Changes - **`.claude/hooks/cloud-bootstrap.sh`** (new) — Node from `.node-version` via the VM's nvm, then `npm ci` when the lockfile is newer than the installed tree, exported through `$CLAUDE_ENV_FILE` (dedup-guarded, since SessionStart fires on resume too). - **`.claude/settings.json`** — registers it ahead of the existing plugin-install hook. Cloud-only (`CLAUDE_CODE_REMOTE=true`), idempotent, warn-and-continue. **Local sessions are unaffected** — the guard exits 0 before the hook does anything. ## Verification - `shellcheck -x -P SCRIPTDIR` clean under this repo's `.shellcheckrc` - `.claude/settings.json` parses Not claimed: I have not run this hook inside a live cloud session. Its logic is the fleet template, exercised by a 12-case suite in the medley sibling PR (melodic-software/medley#1818); the Node and npm cases there cover exactly the two blocks in this copy. Scope note: only the root lockfile is synced. `distribution/` has its own lockfile and is left to its existing `npm ci --prefix distribution` flow rather than being synced speculatively on every session. ## Related - Refs #388 — the shared cloud-environment component this repository owns (the other half of the same rollout) - Refs melodic-software/claude-code-plugins#2654 — the live verification run this responds to - Refs melodic-software/claude-code-plugins#2668 — the fleet guide whose hook template this follows - Refs melodic-software/medley#1818 — the sibling rollout carrying the tested reference implementation 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01AXaqhrFZeGTzbCJun12Ngx --- _Generated by [Claude Code](https://claude.ai/code/session_01AXaqhrFZeGTzbCJun12Ngx)_ Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
No linked issue ## Summary Cloud sessions (web, `claude --cloud`, mobile, routines) start on a fresh Ubuntu VM with **no .NET at all**, so a session here cannot build or analyze the .NET surface these actions target. The fleet-wide verification run confirmed this class of failure (melodic-software/claude-code-plugins#2654). This is the last of six repos in that rollout: the shared environment installs a generic warm cache, and each repo owns its exact pins in a committed, cloud-guarded SessionStart hook — the environment cannot read a repo it isn't running in, so only the hook can honor `global.json`. ## Changes - **`.claude/hooks/cloud-bootstrap.sh`** (new) — the exact `global.json` SDK (10.0.400) into a repo-local `.dotnet`, with `DOTNET_ROOT` and PATH exported through `$CLAUDE_ENV_FILE` (dedup-guarded, since SessionStart fires on resume as well as startup). - **`.claude/settings.json`** — registers it ahead of the existing plugin-install hook. - **`.gitignore`** — `.dotnet/`, so the install never appears as a large untracked tree. Cloud-only (`CLAUDE_CODE_REMOTE=true`), idempotent, warn-and-continue. **Local sessions are unaffected** — the guard exits 0 before the hook does anything. Two hardening details are carried over from review of the sibling PRs rather than rediscovered here: - the download is validated with a size **and shebang** check before it is executed, because the cloud egress proxy can return an error body with HTTP 200 from `dot.net` and `curl -f` only trips on HTTP ≥ 400; - the installed-version check uses `grep -qF` — the version is a literal whose dots would otherwise act as regex wildcards. A failed fetch names the four hosts an environment must allowlist: that install is 403-blocked under Trusted network access (#2654 Blocker 1). ## Verification - `shellcheck -x -P SCRIPTDIR` clean under this repo's `.shellcheckrc` - `shfmt -d` clean under this repo's `.editorconfig` (note: this repo's continuation style is the opposite of medley's, which sets `binary_next_line` — formatted per this repo) - `.claude/settings.json` parses; `git check-ignore` confirms `.dotnet/` is ignored Not claimed: I have not run this hook inside a live cloud session on this repo. Its logic is the fleet template, exercised by a 12-case suite in melodic-software/medley#1818 — including the SDK install-and-export path and the blocked-download warn path. This repo has no shell test harness to host that suite. ## Related - Refs melodic-software/claude-code-plugins#2654 — the live verification run this responds to - Refs melodic-software/claude-code-plugins#2668 — the fleet guide whose hook template this follows - Refs melodic-software/standards#388 — the canonical shared-environment setup script this pairs with - Refs melodic-software/medley#1818 — the sibling rollout carrying the tested reference implementation 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01AXaqhrFZeGTzbCJun12Ngx --- _Generated by [Claude Code](https://claude.ai/code/session_01AXaqhrFZeGTzbCJun12Ngx)_ Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
## Summary Collapses the fleet's twelve hand-copied, drifted `.claude/cloud-bootstrap.sh` generations into one standards-owned component, distributed by exact materialization with the standard tri-mode lever: take (`managed`), enrich (a repo's own never-synced `.claude/cloud-bootstrap.local.sh`, run by the canonical script), or customize (`locally-owned`). ## Fix - **New component `components/cloud-bootstrap/`** — the canonical script is generic by construction: no repo names, marketplace identifiers, or pinned versions. Node from `.node-version`, `npm ci` from the root lockfile, .NET exactly as `global.json` pins, marketplaces and plugins from `.claude/settings.json` (every declared marketplace; every `enabledPlugins: true` entry, whichever marketplace it names — which also removes the previous hardcoded-marketplace second code path). Adds an environment-snapshot stamp log line (per-account build visibility) and shallow-clone repair (`origin/main` resolvable for base-ref diffs). - **`distribution/sync-manifest.yml`** — `managed` for `.github`, `ci-runner`, `ci-workflows`, `github-iac`, `provisioning`; `locally-owned` with recorded reasons for `claude-code-plugins` (directory-source dogfooding) and `medley` (repo-specific toolchain; converge later); `dotfiles` excluded pending its cloud adoption. - **Contract tests** — `cloud-bootstrap.test.sh` (parse, generic-by-construction, calling-contract landmarks, stamp-path lockstep with cloud-environment, byte-equality with this repo's own materialized copy); `setup.test.sh` now lockstep-tests the cloud-environment Node warm-cache pin against `.node-version`. - **`distribution/check-plugin-baseline.sh`** — report-only fleet drift check of each target's plugin catalog against this repository's own settings file (the dogfooded fleet baseline), with an offline `--compare` mode under test. - CI: the cloud-environment job now runs both cloud contract tests. ## Verification - `harness/shell/run-tests.sh` over the three touched test files: 3 passed. - `distribution/sync-manifest.sh validate`: `Manifest valid: 38 components, 8 targets`; `plan --targets melodic-software/ci-runner` renders `100755 components/cloud-bootstrap/cloud-bootstrap.sh -> .claude/cloud-bootstrap.sh`. - shellcheck + shfmt clean on all new/changed shell; markdownlint clean on changed docs; lefthook pre-commit green. - `sync-manifest.test.sh`: engine fixture cases pass except the two symlink-rejection cases, which fail only on Windows (symlink creation degrades to a regular file there); they are fixture-local and unaffected by this change — CI's Ubuntu run is authoritative. - Post-merge follow-ups (deliberate, not in this PR): the provisioning fan-out PR needs its repo-specific toolchain re-added as `.claude/cloud-bootstrap.local.sh` (extraction prepared); a live cloud verification per the cloud-environment README's stamp checklist. No linked issue ## Related - Builds on #388/#389/#390 (canonical environment script; bootstrap split; Node toolchain). - Node-pin lockstep follows the #394 precedent for hand-duplicated-value drift. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_012tKxg98B3QySqEPf8UqwX3 --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Summary
Admits the shared Claude Code cloud environment baseline as a component (
components/cloud-environment/), so the claude.ai/code setup script lands here by reviewed PR instead of by hand-editing an account-scoped UI field. The environment's script field keeps only a three-line bootstrap that curlssetup.shfromraw.githubusercontent.com(on the platform's default allowlist; this repo is public, so no credentials are involved).No linked issue
Changes
components/cloud-environment/setup.sh— the canonical script: parallel tracks forgh+ PowerShell (apt), .NET SDKs 10.0.302/10.0.400 (fleetglobal.jsonpins), and Node 24.18.0 (fleet.node-versionpin), then bakes the checked-out repo's own SessionStart hook into the snapshot. Always exits 0; stays under the ~5-minute cache-build budget.components/cloud-environment/README.md— bootstrap snippet, network prerequisite, verification stamp, update/rollback lifecycle (including the cache caveat: a merged change reaches environments only on a forced rebuild or ~7-day expiry).components/cloud-environment/setup.test.sh— harness-discovered contract test: script parses, endsexit 0, stamp write is ordered after thewaitbarrier, and the README's documented stamp path + bootstrap URL match what the script implements.Verification findings folded in (2026-08-14 live run)
From melodic-software/claude-code-plugins#2654:
dot.net,aka.ms,builds.dotnet.microsoft.com,download.visualstudio.microsoft.com) is now documented as a hard prerequisite, not a fallback./var/log/melodic-env-setup.logand writes/opt/melodic-env-setup.done(version + timestamp) strictly last, so verification can start at the stamp.Admission evidence (per
docs/component-lifecycle.md)docs/CLOUD-FLEET-SETUP.md, whose Step 1 and verification checklist reference this exact path (guide update in flight on that repo).Test plan
shellcheck -x -P SCRIPTDIRclean on both scripts under the repo rcfileharness/shell/run-tests.sh components/cloud-environment/setup.test.sh— 1 passedmarkdownlint-cli2— 0 issuesRelated
🤖 Generated with Claude Code
https://claude.ai/code/session_01AXaqhrFZeGTzbCJun12Ngx