molecule-core/.github/workflows
Hongming Wang a089712cef feat(cascade): verify wheel content sha256 against just-built dist
Closes #132. Extends the cascade propagation probe (added in #2197
and clarified in #2198) with a content-integrity check.

The previous probe verified pip can RESOLVE the version we just
published (catches surface 1+2 propagation lag — metadata + simple
index). It did NOT verify pip can DOWNLOAD bytes that match what we
uploaded — leaving a window where a Fastly stale-content scenario
(rare but PyPI has had it: e.g. 2026-04-01 incident where a CDN node
served a previous version's wheel under the new version's URL for
~90s after upload) would pass the probe and ship corrupt builds to
all 8 receiver templates.

Two-stage check, both must pass before the cascade fans out:

  (a) `pip install --no-cache-dir PACKAGE==VERSION` succeeds —
      version is resolvable. (Existing, unchanged.)

  (b) `pip download` of the same wheel + `sha256sum` matches the
      hash captured pre-upload from `dist/*.whl`. (New.)

Captured BEFORE upload via a new `wheel_hash` step that exposes
`steps.wheel_hash.outputs.wheel_sha256`, bubbled up as
`needs.publish.outputs.wheel_sha256`, and consumed by the cascade
probe via the EXPECTED_SHA256 env var.

`pip download` is the right primitive: it writes the actual .whl
file (vs `pip install` which unpacks and discards), so we can
sha256sum it directly. Combined with --no-cache-dir + a wiped
/tmp/probe-dl per poll, every poll re-fetches from the live Fastly
edge — no local-cache mask.

Per-poll cost: ~3-5s pip install + ~3s pip download + 4s sleep.
30-poll budget = ~5-6 min wall on a slow runner (vs the previous
~4-5 min for resolve-only). Well within the cascade's tolerance for
a known-rare CDN issue, and the overwhelming-common case (Fastly
serves matching bytes immediately) exits on the first poll.

Verified locally: pip download of the current PyPI-latest
(molecule-ai-workspace-runtime 0.1.29) produced
sha256=7e782b2d50812257…, exactly matching PyPI's own metadata
endpoint. The mismatch path is exercised inline (different builds
of the same version produce different hashes by definition — the
build_runtime_package.py output is timestamp-deterministic only
within a single CI invocation).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 10:53:50 -07:00
..
auto-promote-staging.yml ci: canary-verify graceful-skip + draft auto-promote staging→main 2026-04-22 22:39:23 +00:00
auto-tag-runtime.yml feat(platform/admin): /admin/workspace-images/refresh + Docker SDK + GHCR auth 2026-04-26 10:17:21 -07:00
block-internal-paths.yml fix(ci): block-internal-paths handle merge_group + shallow-clone BASE 2026-04-26 23:54:00 -07:00
canary-staging.yml Merge branch 'staging' into ci/cicd-review-quick-wins 2026-04-27 13:27:16 -07:00
canary-verify.yml ci: canary-verify graceful-skip + draft auto-promote staging→main 2026-04-22 22:39:23 +00:00
check-merge-group-trigger.yml ci: add linter that fails when required workflow lacks merge_group trigger 2026-04-24 00:33:05 -07:00
ci.yml test(workspace): centralize pytest-cov config + 92% floor (closes #1817) 2026-04-26 06:21:22 -07:00
codeql.yml ci: add merge_group trigger to ci + codeql 2026-04-23 21:24:53 -07:00
e2e-api.yml test(e2e): claude-code + hermes priority-runtimes happy path 2026-04-26 23:48:54 -07:00
e2e-staging-canvas.yml fix(ci): sweep prior UTC day in e2e safety nets (midnight-rollover) 2026-04-26 19:23:36 -07:00
e2e-staging-saas.yml Merge branch 'staging' into ci/cicd-review-quick-wins 2026-04-27 13:27:16 -07:00
e2e-staging-sanity.yml fix(e2e): CP DELETE /cp/admin/tenants body uses 'confirm', not 'confirm_token' 2026-04-21 04:50:28 -07:00
pr-guards.yml ci: add pr-guards caller that disables auto-merge on push 2026-04-27 06:39:31 -07:00
promote-latest.yml perf(ci): move all public-repo workflows to ubuntu-latest 2026-04-22 12:56:49 -07:00
publish-canvas-image.yml perf(ci): move all public-repo workflows to ubuntu-latest 2026-04-22 12:56:49 -07:00
publish-runtime.yml feat(cascade): verify wheel content sha256 against just-built dist 2026-04-28 10:53:50 -07:00
publish-workspace-server-image.yml ci(publish-image): also tag :staging-latest so CP auto-picks up new builds 2026-04-24 00:29:55 -07:00
redeploy-tenants-on-main.yml ci(redeploy): fire post-main tenant fleet redeploy via CP admin endpoint 2026-04-24 14:34:28 -07:00
retarget-main-to-staging.yml ci(retarget): handle 422 'duplicate PR' by closing redundant main-PR (closes #1884) 2026-04-26 00:53:55 -07:00
runtime-pin-compat.yml ci(runtime-pin-compat): test the PR-built wheel, not the PyPI-latest one 2026-04-27 17:39:00 -07:00
secret-scan.yml chore(secret-scan): add sk-cp- MiniMax pattern (F1088 retroactive fix) 2026-04-26 21:43:22 -07:00
sweep-cf-orphans.yml fix(ci): stop sweep-cf-orphans noise — drop merge_group + soft-skip when secrets unset 2026-04-26 08:05:53 -07:00
sweep-stale-e2e-orgs.yml ci: hourly sweep of stale e2e-* orgs on staging 2026-04-24 23:07:57 -07:00
test-ops-scripts.yml refactor(ops): apply simplify findings on #2027 PR 2026-04-26 00:28:15 -07:00