Skip to content

ci(studio-pack): publish the studio pack as a pinned OCI image - #1

Merged
vjan-nie merged 1 commit into
mainfrom
ci/studio-pack
Oct 7, 2026
Merged

vjan-nie merged 1 commit into
mainfrom
ci/studio-pack

Conversation

@vjan-nie

@vjan-nie vjan-nie commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Draft. Not for merge yet, and nothing gets dispatched or published from this PR.

Heads-up @LESdylan: this is additive packaging only. It adds 3 new files and changes no existing file, engine code or workflow.

What it adds

  • .github/workflows/studio-pack.yml runs on workflow_dispatch only. Its one input is commit, which must be a full lowercase 40-hex sha reachable from origin/develop or origin/main. It publishes ghcr.io/univers42/graph-studio-pack:sha-<commit>. There is no :latest, and a tag that already exists fails the run. Permissions are contents: read and packages: write, and the only secret is GITHUB_TOKEN.
  • packaging/studio-pack.Dockerfile builds a FROM scratch image with the six pack files under /pack/. Labels: org.opencontainers.image.{revision,source,created}, plus org.univers42.graph-studio-pack.recipe-rev (the workflow's own sha). Base images are pinned by digest: debian:trixie-slim@sha256:a99cfc51… and node:22.23.3-slim@sha256:43ac6c60…. rustup-init 1.29.1 is sha256-checked and installs Rust 1.98.1.
  • packaging/studio-pack-manifest.sh writes pack.json and verifies it. It ports scripts/studio-pack.sh's write_manifest and verify (same line format), runs the commit's own scripts/worker-form.sh, and checks that the pack has exactly the six files.

The build context is git archive <commit>, so the workflow can pack commits older than itself, such as 77b68d9. The Dockerfile mirrors studio-pack.sh rather than running it. That script starts docker itself and builds ge-rust FROM debian:trixie-slim without a digest.

Gates before anything is pushed

  1. Recipe drift guard: the sha256 of the commit's studio-pack.sh, wasm-threads.sh, rust.Dockerfile, wasm-threads.Dockerfile and vite.pack.config.ts must equal their values at 77b68d9. Also, studio.sh's build_wasm line must be unchanged and image.sh's node pin must match.
  2. Two builds, the second with --no-cache, must give byte-identical packs (diff -r).
  3. The pack must be byte-identical to the commit's own scripts/studio-pack.sh output (diff -r).
  4. After the push, the image is pulled back by digest and its /pack must equal build 1.

The job summary lists the commit, recipe_rev, image@digest, and the bytes and sha256 of each file.

Local evidence (77b68d9, no push)

  • actionlint 1.7.7 (with shellcheck), yamllint, hadolint 2.12.0 and shellcheck 0.10.0 all exit 0.
  • Cold build: 84 s. --no-cache rebuild: 74 s, using a 3 GB-capped BuildKit builder on 6 cores. diff -r A vs B exits 0.
  • Upstream scripts/studio-pack.sh target/pack on a clean detached worktree took 145 s. diff -r of its output against the Dockerfile's pack exits 0.
  • The first attempt was not identical: graph_wasm.wasm was 377 bytes longer. With rust-src installed, rustc embedded /opt/rustup/…/library/… panic paths instead of /rustc/48a229ce…/. That is why rust-src now exists only in the threads stage, matching upstream's ge-rust / ge-wasm-threads split.
d7e4d78752ac60e88f7ee67898b75a6564efa6964509028af0fe44637920768c  graph-studio.js          1078009
1c30c2edfa239dc7c0c0fbbfaca4d760e6adee2e6be4d97b67f4930b51aeb25b  graph_wasm.wasm          1747732
eaca898979e6b405832d5bf30cd6c134d8b102a4ee008c829f5319042e05b0ef  graph_wasm_threads.wasm  1863406
98b92f4bc41107044348aaf351589c1190fbf4e7201d18f31c644600c92aa1ed  helper.js                   2441
d0fa3632c3b61c805d92fd08d84c18ad5e52f8b95df042802bb65c6ac0ae28bb  pack.json                    729
c3e6a15a13953ee9d3659d435e9e7700495d23e1ac36f3835c3c5dc040c06675  worker.js                 205819

Known limits and open items

  • apt packages are not pinned. Two builds on the same day cannot show drift between days.
  • The tag-existence check reads GHCR's error text. Any answer it does not recognise as "absent" fails the run (fail-closed). What GHCR returns under GITHUB_TOKEN for a package that does not exist yet has not been verified.
  • It is not known whether the org lets GITHUB_TOKEN create a new package. A new GHCR package is private by default.

Merge policy: merge commit (--merge), branch deleted after merge.

workflow_dispatch with a full commit sha (reachable from develop or main)
builds the pack from git archive <commit> with a digest-pinned Dockerfile
that mirrors scripts/studio-pack.sh, and pushes
ghcr.io/univers42/graph-studio-pack:sha-<commit> (FROM scratch, /pack/).
Nothing is pushed unless a --no-cache rebuild and the commit's own
studio-pack.sh produce byte-identical packs. Additive: no existing file
changes.
@vjan-nie
vjan-nie marked this pull request as ready for review October 7, 2026 21:26
@vjan-nie
vjan-nie merged commit ece6dd5 into main Oct 7, 2026
3 checks passed
@vjan-nie
vjan-nie deleted the ci/studio-pack branch October 10, 2026 17:16
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.

1 participant