Skip to content

fix(ci): add PyYAML 6.0.3 cp311 hashes for cloud Python 3.11 - #2657

Merged
kyle-sexton merged 1 commit into
mainfrom
cursor/fix-ci-pyyaml-cp311-hash-f8b0
Aug 15, 2026
Merged

fix(ci): add PyYAML 6.0.3 cp311 hashes for cloud Python 3.11#2657
kyle-sexton merged 1 commit into
mainfrom
cursor/fix-ci-pyyaml-cp311-hash-f8b0

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Closes #2654

Summary

Cloud Melodic SessionStart failed because .github/requirements-ci.txt hash-locked PyYAML 6.0.3 to cp314 wheels while the VM uses Python 3.11, so pip selected a cp311 manylinux wheel whose hash was missing.

Fix

  • Added the cp311 platform hash set for PyYAML 6.0.3 (Linux/macOS/Windows parallels to the existing cp314 list), verified against PyPI — including the blocker Linux x86_64 hash from Melodic cloud environment verification results (2026-08-14) #2654.
  • Noted cp311 coverage in docs/CLOUD-FLEET-SETUP.md verification checklist item 6.

Verification

python3.11 -m pip install --dry-run --require-hashes -r .github/requirements-ci.txt
# selects pyyaml-6.0.3-cp311-…-manylinux…x86_64.whl; exit 0

Related

Refs #2655 — SessionStart registration / enabledPlugins install.

Residual host notes

  1. Blocker 1 — .NET proxy allowlist: switch Melodic to Custom and add dot.net, aka.ms, builds.dotnet.microsoft.com, download.visualstudio.microsoft.com.
  2. Blocker 2 — interrupted env cache build: rebuild the environment cache and re-run the verification checklist.
Open in Web Open in Cursor 

SessionStart pip --require-hashes failed on Melodic cloud VMs because
requirements-ci.txt only listed cp314 wheels while the VM ships 3.11.
Add the matching cp311 platform set (verified against PyPI), including
the Linux x86_64 hash from #2654, and note the coverage in the cloud
fleet setup checklist.

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
@kyle-sexton
kyle-sexton marked this pull request as ready for review August 15, 2026 02:28
@cursor

cursor Bot commented Aug 15, 2026

Copy link
Copy Markdown

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

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 49s —— View job


Security review complete

  • Gather context (PR diff, changed files)
  • Skip-gate check (open PR, security-relevant surface)
  • Review .github/requirements-ci.txt hash changes
  • Review docs/CLOUD-FLEET-SETUP.md changes
  • Post findings / no-issues summary

No security issues found.

This PR is a pip hash-pinning fix: it adds cp311 wheel hashes (Linux/macOS/Windows) for pyyaml==6.0.3 in .github/requirements-ci.txt alongside the existing cp314 set, so pip install --require-hashes succeeds on the cloud VM's system Python 3.11 as well as the CI interpreter (3.14). The accompanying docs/CLOUD-FLEET-SETUP.md change is documentation only.

Notes from the review:

  • The change is purely additive to the pin list — no existing hash was weakened or removed, the package version stays pinned at 6.0.3, and --require-hashes enforcement is untouched. This strengthens supply-chain hash coverage rather than loosening it.
  • No GitHub Actions workflow files, permissions, secrets handling, or authorization logic are touched by this diff.
  • No injection surfaces (command, path, template) are introduced — the changes are static hash literals and prose.
  • Independently re-verifying each hash against PyPI is outside this lane's allowed tools (gh pr diff/view/comment/review, Read, Glob, Grep — no network fetch); the PR description states the author verified them against PyPI and via a local --dry-run --require-hashes install. If that verification is in doubt, a maintainer can re-run the dry-run install locally as a final check.
    · Branch

@github-actions

Copy link
Copy Markdown

Last security-reviewed head: 47c18ee3050ee38a759ae46837989624a950ce66. On the next push, the relevance gate compares only the commits since this SHA; delete this comment to force a full re-review.

@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 2m 3s —— View job


Security review — no findings

  • Gather context (PR diff, changed files)
  • Apply skip gate / assess security-relevant surface
  • Review changed files for security issues
  • Post final findings

Scope reviewed: .github/requirements-ci.txt and docs/CLOUD-FLEET-SETUP.md.

This PR only adds 8 additional --hash=sha256:... entries to the existing pyyaml==6.0.3 pin (covering cp311 wheels alongside the pre-existing cp314 set) and updates a doc comment to explain the new coverage. No logic, permissions, workflow triggers, or untrusted-input handling changed.

From a supply-chain-security lens (the one angle this kind of change can affect):

  • The change tightens the existing --require-hashes pin rather than loosening it — no unpinned or floating versions were introduced.
  • I visually verified all 8 new hashes are well-formed 64-character hex sha256 digests with no duplicates against the existing set (lines 34–41).
  • I was not able to independently cross-check these digests against PyPI's published wheel hashes for pyyaml==6.0.3 — this sandbox has no outbound network access. This is a soft limitation, not a blocking risk: pip install --require-hashes fails closed on any mismatch, so an incorrect hash here would break the CI install rather than allow an unexpected/malicious artifact to install silently.

No CRITICAL, IMPORTANT, or SUGGESTION findings.
· branch

@kyle-sexton
kyle-sexton enabled auto-merge (squash) August 15, 2026 02:34
@kyle-sexton
kyle-sexton merged commit 1eea04d into main Aug 15, 2026
45 checks passed
@kyle-sexton
kyle-sexton deleted the cursor/fix-ci-pyyaml-cp311-hash-f8b0 branch August 15, 2026 02:35
cursor Bot pushed a commit that referenced this pull request Aug 15, 2026
Rely on #2657's cp311 PyYAML hashes so SessionStart always runs
`--require-hashes` without an interpreter-mismatch skip or unpinned
ruff fallback. A digest mismatch stays fatal.

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
@claude

claude Bot commented Aug 15, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 3m 37s —— View job


Claude Code Review

  • Gather context (diff, CLAUDE.md, changed files)
  • Review .github/requirements-ci.txt changes
  • Review docs/CLOUD-FLEET-SETUP.md changes
  • Verify hash correctness / installability claims
  • Post findings

Summary

Scope: adds 8 cp311 sha256 hashes for PyYAML 6.0.3 to .github/requirements-ci.txt (fixing the cloud SessionStart failure from #2654, where pip on the VM's Python 3.11 couldn't find a hash for the resolved wheel) and updates docs/CLOUD-FLEET-SETUP.md's verification checklist item 6 to mention cp311 coverage.

Checks performed:

  • All 8 new hashes are well-formed 64-char lowercase hex (sha256), and none duplicate each other or the existing 6 cp314 hashes.
  • Line-continuation formatting in the pip requirements block is syntactically correct.
  • docs/CLOUD-FLEET-SETUP.md change is accurate and consistent with how .claude/hooks/session-start.sh invokes pip install --require-hashes -r .github/requirements-ci.txt.
  • CI (ci workflow run) is green, but note it only exercises the cp314 install path (hook-exec-form-gate pins Python 3.14) — it does not install/verify the new cp311 hashes.

One suggestion posted inline on .github/requirements-ci.txt (permalink): since no CI job installs against Python 3.11, a future mis-pin of a cp311 hash wouldn't be caught until it re-breaks cloud SessionStart. Worth codifying the manual python3.11 --dry-run --require-hashes check from the PR description as a lightweight CI step.

Limitation: this review lane has no outbound network access, so I could only validate hash format (well-formed, non-duplicate) — not the hash values against PyPI's published digests for the cp311 wheels. The PR description states these were verified against PyPI manually.

No correctness or security issues found in the diff itself.

--hash=sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e \
--hash=sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824 \
--hash=sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf \
--hash=sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion (maintainability): the 8 new cp311 hashes are structurally well-formed (64-char lowercase hex, no duplicates against each other or the existing cp314 set) and the file's --require-hashes install fails closed if a hash is wrong — so this can't silently install the wrong wheel. But nothing in .github/workflows/ci.yml actually exercises the cp311 branch: hook-exec-form-gate only sets up Python 3.14 (ci.yml#L505), so a typo'd cp311 hash here wouldn't be caught until it breaks cloud SessionStart again — the exact failure mode this PR fixes (#2654). Consider codifying the manual verification command from the PR description (python3.11 -m pip install --dry-run --require-hashes -r .github/requirements-ci.txt) as a cheap CI step (e.g. an extra setup-python@… + dry-run install with python-version: '3.11') so a future re-pin can't regress this silently.

I wasn't able to independently verify the hash values against PyPI (no outbound network access in this review lane) — only their format.

@github-actions

Copy link
Copy Markdown

Claude has reviewed this PR 1 time. The lane skips further automatic reviews after 5; deleting this comment resets the count.

kyle-sexton added a commit that referenced this pull request Aug 15, 2026
…ins (#2655)

No linked issue

## Summary

Cloud sessions on this repo started with zero plugins loaded and no
bootstrap at all: every `/plugin` command unknown, no plugin skill
available, an empty `~/.claude/plugins/installed_plugins.json`, and none
of the CI-parity tooling `.claude/hooks/session-start.sh` exists to
provide. Three independent causes, all fixed here.

## Fix

**1. The SessionStart hook was never registered.**
`.claude/settings.json` had no `hooks` key. The script has carried a
header comment claiming it was registered since it was added in 39fe757,
and `docs/CLOUD-SESSIONS.md` documented the registration, but `git log
-p --all -- .claude/settings.json` shows the key was never committed —
so the bootstrap had never run in a cloud session. Registered with
matcher `startup|resume`, pointing at the script via
`$CLAUDE_PROJECT_DIR`.

**2. Declaring a marketplace is not installing it.** [What runs before
you trust a
folder](https://code.claude.com/docs/en/permissions#what-runs-before-you-trust-a-folder)
groups `extraKnownMarketplaces` entries with content that needs *this
exact folder* trusted, while hooks and the `env` block are used whether
or not it is. A cloud session on this repo had `hasTrustDialogAccepted`
false, an empty plugin registry, and no plugin loaded — while the same
settings file's `env` block *had* applied, exactly the split that table
predicts. A hook is the durable fix because hooks run untrusted.

The hook registers the checkout by absolute path and installs every
plugin `enabledPlugins` sets to `true`, computed from the tracked
settings file with `jq` so it cannot drift from the catalog. It
deliberately never calls `claude plugin marketplace remove` — that
subcommand deletes the marketplace's entry from `.claude/settings.json`,
so a hook using it to force a re-add would silently mutate tracked
repository config. (Observed directly while diagnosing this.)

It also repairs same-version commit drift. A directory-source cache is
keyed by the semver in `plugin.json` rather than the commit
(`docs/MIGRATION-PLAYBOOK.md`, #2061), so a presence check alone would
keep serving whichever commit installed first — defeating the reason
this repo uses a directory source. The hook compares the `gitCommitSha`
recorded at install time against `HEAD` and runs the documented
uninstall/install/enable cycle for the plugins whose own directory
changed, so an ordinary resume stays cheap.

**3. The Python install aborted the bootstrap.**
`.github/requirements-ci.txt` was hash-locked against CI's Python 3.14
wheels only; the cloud VM ships 3.11.15 and resolves a different
`pyyaml` wheel, so `--require-hashes` refused it and `set -e` aborted
before the hygiene binaries and git-history steps ever ran. That
surfaced #2654, fixed on `main` by #2657, which added the cp311 hash
set.

This branch is rebased onto that fix and keeps the install
**fail-closed**: SessionStart always runs the hash-locked install and a
failure stays fatal. An earlier revision of this branch fell back to a
ruff-only install on an interpreter-version mismatch; that was removed,
because it both weakened the one control that catches a tampered wheel
and — once #2657 landed — would have skipped an install that now
succeeds, leaving `pyyaml`/`pytest` permanently absent.

`docs/CLOUD-SESSIONS.md` is corrected in the same change: it previously
claimed the hook was registered and described the directory source as
installing at session start.

## Verification

Verified live rather than by inspection — the session restarted
mid-change and the newly registered hook fired on its own:

```
SessionStart:resume hook success: session-start: plugins 65 enabled, 26 newly installed, 0 failed
session-start: bootstrap complete in /home/user/claude-code-plugins
```

All 65 plugin skill sets became available in-session
(`/claude-config:audit`, the command that surfaced this, among them),
and `markdown-format` and `hardcoded-path-check` hooks then fired on
subsequent edits — confirming plugin hooks load, not just skills.

The fail-closed install, checked on a real cloud VM at `8773eae5`:

```
$ python3 -V
Python 3.11.15
$ python3 -m pip install --user --only-binary=:all: --require-hashes -r .github/requirements-ci.txt
EXIT=0   (2.4s)
```

Full CI-parity inventory now present, all three previously absent or
wrong: `ruff` 0.16.2 (CI's exact pin, against the VM image's 0.15.8),
`pytest` 9.1.1, `pyyaml` 6.0.3.

Other post-run state:

- `claude plugin list --json | jq length` → 103 (65 enabled + 38
auto-installed dependencies)
- `claude plugin marketplace list --json` →
`{"name":"melodic-software","source":"directory","path":"<repo-root>"}`
— resolved from the checkout, so a session exercises branch code rather
than published `main`
- Refresh predicate selects `repo-fleet-hygiene` (10 files changed since
the recorded SHA) and skips `session-flow`, `adhd`, `claude-config` (0
changed); an uninstalled id falls through to the install path

Gates, all clean: `shellcheck` (with the repo's
`check-set-e-suppressed`), `shfmt -d`, `bash -n`, `markdownlint-cli2`,
`typos`, `editorconfig-checker`, `check-jsonschema` against the settings
schema, and both repo-local hook tests (17/17). Empty-array handling
under `set -u` checked against the VM's bash 5.2.21.

Not verified: whether a `github`-source marketplace auto-installs at
session start without a hook. That is the path consumer repos should
use, and it resolves fine here (`claude plugin marketplace add
melodic-software/claude-code-plugins` clones through the proxy), but
confirming the no-hook auto-install needs a fresh cloud session on a
consumer repo.

Follow-up, not blocking: the strict path is load-bearing on
`requirements-ci.txt` covering whatever `python3` the cloud image ships.
If that image moves to a minor with no wheel hashes, session start
aborts rather than degrades — worth generating hashes per supported
interpreter instead of reactively, as #2654#2657 just did.

## Related

Refs #2061 (same-version commit drift), #2654 / #2657 (cp311 wheel
hashes), and the plugin-enablement setup in `docs/CLOUD-SESSIONS.md` and
`docs/CLOUD-FLEET-SETUP.md`.

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
kyle-sexton added a commit that referenced this pull request Aug 15, 2026
#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>
kyle-sexton added a commit that referenced this pull request Aug 15, 2026
…ste-once rollout kit (#2677)

No linked issue

## Summary

Cloud sessions could never use this repo's plugins on turn one: the
SessionStart hook installs the full catalog, but Claude Code builds its
plugin/command registry at process start — before hook effects land —
and never re-reads it. This PR records that finding with its evidence
and fix, and adds the copy-paste rollout kit for moving the whole fleet
(and every account environment) onto the layout that works.

## Fix

- `docs/CLOUD-SESSIONS.md`: document the same-session limit observed
2026-08-15 (hook completed `65 enabled, 65 newly installed, 0 failed`
with the on-disk registry fully populated, yet the same session resolved
no plugin command or skill), plus the confirmation that a stop/resume
restarts the process and loads everything; reframe the environment
setup-script one-liner from a performance lever to the required
pre-launch slot for plugin liveness.
- `.claude/hooks/session-start.sh`: state the timing limit in the header
— hook-time installs serve the *next* process start, so the environment
setup script must run this bootstrap at cache build for a session to
start with plugins loaded.
- `docs/CLOUD-FLEET-SETUP.md`: refresh the stale "bootstrap is currently
unwired" finding (settings.json registers the hook on `main` and it
ran), fix the verification step that relied on `/plugin` (unavailable in
cloud sessions), and point step 1 at the rollout kit.
- `prompts/cloud-bootstrap-rollout.md` (new): the paste-once account
environment stub, the prompt for creating the shared
`cloud/env-setup.sh` in `melodic-software/standards`, and the per-repo
migration prompt that renames `.claude/hooks/session-start.sh` to
`.claude/cloud-bootstrap.sh` — one script, two callers (environment
setup script pre-launch; SessionStart hook for per-session drift repair)
— and settles on one Default environment per account.

## Verification

- `markdownlint-cli2`, `typos`, and `editorconfig-checker` pass on all
touched files; `shellcheck` and `shfmt -d` pass on the hook
(comment-only change).
- Empirical basis verified live in the cloud session that produced this
PR: installed-on-disk vs empty session registry, a failed mid-session
skill probe, and full catalog loading after resume (this repo's own
commit-convention hook began enforcing mid-session once loaded).
- Official-docs basis: hooks reference documents no same-session pickup;
`/plugin` and `--plugin-dir` are unavailable in cloud sessions; the
setup script runs after clone and before the session process.

## Related

`docs/CLOUD-SESSIONS.md` §"Plugins in sessions on this repo",
`docs/CLOUD-FLEET-SETUP.md`, `docs/MIGRATION-PLAYBOOK.md` (same-version
commit drift), #2061, #2539, #2657

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_018NhKrvZ4Jz1qK2wWDWXiZd

---
_Generated by [Claude
Code](https://claude.ai/code/session_018NhKrvZ4Jz1qK2wWDWXiZd)_

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Melodic cloud environment verification results (2026-08-14)

1 participant