Skip to content

ci: build on native arm64 runners, pin actions to SHAs#10

Merged
loks0n merged 18 commits into
mainfrom
separate-arm-runners
May 12, 2026
Merged

ci: build on native arm64 runners, pin actions to SHAs#10
loks0n merged 18 commits into
mainfrom
separate-arm-runners

Conversation

@loks0n
Copy link
Copy Markdown
Contributor

@loks0n loks0n commented May 12, 2026

Summary

  • Switch arm64 builds (and structure tests) from QEMU emulation to native ubuntu-24.04-arm runners by matrixing on arch and runner OS, mirroring appwrite/docker-base.
  • Build/push each arch as …-amd64 / …-arm64 tag, then a manifest job assembles the multi-arch tag per PHP version.
  • Pin actions/checkout, docker/login-action, and plexsystems/container-structure-test-action to commit SHAs with version comments.

Test plan

  • Open PR — confirm test.yml runs the matrix on both ubuntu-24.04 and ubuntu-24.04-arm and all PHP versions pass structure tests.
  • On a release, verify per-arch images are pushed and the multi-arch manifest resolves with docker buildx imagetools inspect appwrite/utopia-base:php-<ver>-<tag>.

🤖 Generated with Claude Code

Use ubuntu-24.04-arm runners for arm64 builds (and tests) instead of
QEMU emulation, mirroring appwrite/docker-base. Each arch is built and
pushed separately, then a manifest job assembles the multi-arch tag.

Pin all third-party actions to commit SHAs with version comments.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 12, 2026

Greptile Summary

This PR replaces the single QEMU-based build-and-push workflow with a four-workflow pipeline: ci.yml (build + test on native runners), publish.yml (push + manifest on merge), release.yml (promote-only on tag), and cleanup.yml (daily pruning of stale SHA tags). All actions are pinned to commit SHAs, tools are installed with checksum verification, and fail-fast: false is set throughout.

  • Native arm64 runners: the matrix now targets ubuntu-24.04 / ubuntu-24.04-arm per arch, eliminating QEMU for both structure tests and image builds.
  • Promote-don't-rebuild release flow: release.yml uses docker buildx imagetools create to retag the already-pushed SHA manifest, sharing the build-<sha> concurrency group with ci.yml and publish.yml so a release automatically queues behind any in-flight CI.
  • PHP 8.2 dropped: the PHP 8.2 Dockerfile and tests are removed; the matrix now covers 8.3, 8.4, and 8.5 only.

Confidence Score: 5/5

Safe to merge — the CI/CD redesign is structurally sound and the only finding is a defensive edge-case guard in the cleanup script.

All four new workflows follow correct patterns: native arm64 runners replace QEMU, artifacts are exchanged by name with matching upload/download keys, the promote-not-rebuild release flow correctly shares the concurrency group, and fail-fast: false is applied throughout. The one finding is a null-guard in the daily cleanup loop that would only fire if Docker Hub returned an unexpected null for a CI tag — an unlikely edge case that does not affect builds or releases.

No files require special attention.

Important Files Changed

Filename Overview
.github/workflows/ci.yml New CI workflow replacing test.yml; builds per (php x arch), uploads artifacts, then runs structure tests on native runners, dive and Trivy on amd64. SHA-pinned actions, checksum-verified tool installs, correct artifact name matching between upload and download.
.github/workflows/publish.yml New publish workflow triggered by CI workflow_run; downloads artifacts from the CI run, pushes per-arch tags, then assembles a multi-arch manifest via docker buildx imagetools create. Uses fail-fast: false on both matrices.
.github/workflows/release.yml New release workflow that promotes the existing SHA-tagged manifest to a release tag using docker buildx imagetools create - no image rebuild. Shares the build-sha concurrency group with ci.yml and publish.yml.
.github/workflows/cleanup.yml New daily cleanup workflow that prunes CI SHA tags from Docker Hub older than 14 days. Correctly paginates through the Hub API and skips release tags via regex. A null tag_last_pushed value for a matched tag would abort the script mid-run.
.dive-ci.yml New dive configuration file; referenced correctly via --ci-config .dive-ci.yml in ci.yml. Thresholds (90% efficiency, 128 MB wasted, 10% wasted ratio) look reasonable.
README.md Substantially expanded README documenting supported PHP versions, tag naming conventions, CI/CD pipeline overview, and local dev workflow. Accurate reflection of the new four-workflow design.

Reviews (10): Last reviewed commit: "ci: point --ci-config at the real filena..." | Re-trigger Greptile

Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/test.yml Outdated
loks0n and others added 4 commits May 12, 2026 16:26
Trivy scans built images for CRITICAL/HIGH CVEs and uploads SARIF to the
GitHub Security tab. Runs on push, PR, and a weekly cron so newly-disclosed
CVEs in already-shipped base images get flagged.

Dive enforces layer-efficiency thresholds via .dive-ci.yml to catch
Dockerfile regressions (e.g. uncleared apt caches).

Both workflows fan out per PHP version.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
PHP 8.2 reaches end-of-life on 2026-12-31; drop it now to focus on
8.3/8.4/8.5.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three separate workflow files each created their own check rows and the
push+pull_request triggers fired duplicate runs on every PR commit.
Merge into one workflow with three jobs and limit triggers to push-on-main
plus PRs (cron retained for Trivy CVE refresh).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Trigger is `release: published`; matching the filename to the trigger
makes intent obvious at a glance.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread .github/workflows/release.yml Outdated
Previously each of structure-test/dive/trivy rebuilt the same Dockerfile,
amounting to 12 builds per CI run for 3 Dockerfiles. Split into a single
build job per (php, arch) that saves the image as an artifact; downstream
jobs load it instead of rebuilding (3 amd64 builds reused twice each, plus
the 3 arm64 builds for structure-test).

Add concurrency group keyed on ref so superseded commits' runs cancel
instead of stacking up.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread .github/workflows/release.yml Outdated
loks0n and others added 8 commits May 12, 2026 16:44
CI now pushes per-commit images on main (php-X.Y-<sha>[-arch]) after
tests pass and assembles the multi-arch manifest with
buildx imagetools create. Tagging is driven by docker/metadata-action.

Release workflow drops its build/push matrix entirely — it just calls
buildx imagetools create to retag the already-tested per-commit manifest
to the release tag. Server-side, no rebuild, takes seconds.

Add cleanup.yml: daily scheduled job that deletes CI tags matching
php-X.Y-<sha>[-arch] older than TTL_DAYS via the Docker Hub API. Released
semver tags don't match the regex and are never touched.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
If a release is cut before CI finishes pushing the per-commit image,
buildx imagetools create would fail with manifest-not-found. Add a
wait-for-ci job that polls the CI run for github.sha until it succeeds
(or times out at 30min), then runs the promote matrix.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the polling wait-for-ci job with a shared per-commit concurrency
group ('build-<sha>'). CI and release on the same commit can't run
concurrently; release queues until CI's group slot is free.

PR runs use a separate group keyed on ref so superseded PR commits keep
cancelling earlier runs as before.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Audit pass on workflow names: unify 'Checkout the repo' / 'Checkout code'
to 'Checkout', shorten verbose Trivy/manifest/promote step names, and
rename 'Cleanup stale CI tags' workflow to 'Cleanup' for consistency
with 'CI' / 'Release'. Standardize on 'Docker Hub' (two words).

Replace plexsystems/container-structure-test-action with a direct binary
install: the action is a Docker action that hardcodes the amd64 binary,
so it fails with 'exec format error' on the ubuntu-24.04-arm runners.
Install the matching linux-<arch> binary instead.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Job-level 'if' on a matrix job displays the unrendered '\${{ matrix.* }}'
string in skipped check rows. Move push/manifest into a separate
publish-sha workflow that triggers via workflow_run on CI success on
main, so PRs no longer see skipped placeholder rows.

The new workflow downloads CI's image artifact by run-id and pushes
per-arch tags + assembles the multi-arch manifest. Concurrency group is
still 'build-<sha>', shared with ci.yml and release.yml.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pipeline reads as CI -> publish -> release; -sha suffix leaked the tag
format into the filename.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The 'deleted' counter in cleanup.yml was incremented inside a piped
subshell so the outer scope never saw it — pure dead code; remove it
and use a process substitution loop instead so the body runs in the
parent shell. While here, switch all curl invocations (cleanup HTTP
calls + structure-test binary download) to '-fsS' / '-fsSL' so HTTP
errors surface as a non-zero exit instead of being silently saved as
the response body.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Floating on 'latest' makes builds non-reproducible — pin the version so
upgrades are explicit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-advanced-security
Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

loks0n and others added 3 commits May 12, 2026 17:19
…ADME

The storage.googleapis.com bucket only hosts a 'latest/' path, not
versioned ones — pinned URL 404'd. Switch to the GitHub release asset
URL which exposes per-version downloads.

Expand README with supported PHP versions, tag scheme, and a description
of the four workflows.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Download checksums.txt from the same release and run sha256sum -c against
the per-arch asset. Catches a corrupted download or a tampered mirror.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The yuichielectric/dive-action wraps dive v0.9, which doesn't yet
support --ci-config — invocation failed with 'unknown flag: --ci-config'.
Install dive v0.13.1 directly with checksum verification.

Capture the dive report to the GitHub Actions step summary so the layer
breakdown and efficiency metrics are visible on every run instead of
buried in raw step logs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread .github/workflows/ci.yml Outdated
dive's --ci-config is passed verbatim to viper.SetConfigFile, so it
needs the literal path including extension. The committed file is
.dive-ci.yml.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@loks0n loks0n merged commit 2f97c35 into main May 12, 2026
20 checks passed
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.

2 participants