Skip to content

Publish the production image instead of the Xdebug variant - #78

Merged
abnegate merged 1 commit into
mainfrom
fix/publish-final-not-xdebug
Aug 7, 2026
Merged

Publish the production image instead of the Xdebug variant#78
abnegate merged 1 commit into
mainfrom
fix/publish-final-not-xdebug

Conversation

@abnegate

@abnegate abnegate commented Aug 7, 2026

Copy link
Copy Markdown
Member

Problem

Every workflow builds with docker image build ... . and no --target. Docker defaults to the last stage, and the last stage is xdebug:

$ BUILDX_EXPERIMENTAL=1 docker buildx build --print=outline .
TARGET: xdebug

So every published appwrite/base image has shipped Xdebug since the variant was introduced in 1.2.0. Trivy and dive were also measuring that image rather than the one users actually run.

This is pre-existing on main, not introduced by the SHA-pinning work.

Why not reorder the stages instead

xdebug is FROM final, so it must be declared after final — which necessarily makes it last. Forward stage references don't resolve; Docker reinterprets the name as an external image:

ERROR: failed to solve: final: failed to resolve source metadata for
docker.io/library/final:latest: pull access denied, repository does not exist

An explicit --target is the only reliable control, so the README now documents it as required for local builds too.

Why CI never caught it

tests.yaml only ever asserted module presence. The Xdebug image satisfies every one of those assertions, so CI stayed green while shipping the wrong artifact. This PR adds an excludedOutput guard so the production image cannot silently regain Xdebug.

tests-xdebug.yaml has existed since 1.2.0 with no workflow consuming it; it is now wired into the structure-test workflow.

Why the variant is published rather than dropped

Downstream consumers do depend on the base providing xdebug.so. Appwrite's development stage copies a dev/xdebug.ini containing zend_extension=xdebug but never installs the extension itself, while its base/production stages strip Xdebug back out — compensating for this bug from both directions.

Nothing tracks a floating tag (consumers pin 1.4.4, 1.2.1, 1.2.0, 0.11.3, 0.5.0…), so this changes nothing retroactively. The variant is now published as <sha>-xdebug / <tag>-xdebug so those consumers have a real image to pin when they bump.

Changes

  • --target final in all four build workflows (build-and-push, structure-test, dive, trivy)
  • Build and push the Xdebug variant under -xdebug tags, per-arch plus manifests
  • Wire tests-xdebug.yaml into structure-test.yml
  • tests.yaml: assert Xdebug is absent
  • README: document --target final as required

Verification

Both variants built locally on arm64:

Build php -m
--target final no xdebug; all 56 expected modules present
--target xdebug xdebug present

Follow-up (not in this PR)

appwrite/appwrite should point its development stage at appwrite/base:<version>-xdebug before bumping its pin, otherwise --build-arg DEBUG=true builds will fail to load the extension.

🤖 Generated with Claude Code

@greptile-apps

greptile-apps Bot commented Aug 7, 2026

Copy link
Copy Markdown

Greptile Summary

The PR explicitly targets the production Docker stage throughout CI while separately building, testing, and publishing the Xdebug variant.

  • Adds --target final to production builds used for publishing, structure tests, Dive, and Trivy
  • Publishes architecture-specific and multi-architecture Xdebug tags
  • Tests both variants and asserts that Xdebug is absent from production
  • Documents the required explicit build target and records the release changes

Confidence Score: 5/5

The PR appears safe to merge because no blocking failure remains within the scope of this follow-up review.

No blocking failure remains.

Important Files Changed

Filename Overview
.github/workflows/build-and-push.yml Production publishing now targets final, while Xdebug receives separate per-architecture images and manifests.
.github/workflows/dive.yml Dive now measures the explicitly selected production stage.
.github/workflows/structure-test.yml Structure tests now build and validate production and Xdebug images independently.
.github/workflows/trivy.yml Trivy now scans the explicitly selected production stage.
tests.yaml The production-image test suite now rejects images that expose the Xdebug module.
README.md Local build documentation now requires an explicit production or Xdebug target.
CHANGES.md The changelog documents the corrected production artifact and newly published Xdebug variant.

Reviews (2): Last reviewed commit: "(fix): publish production image instead ..." | Re-trigger Greptile

Comment thread .github/workflows/dependencies.yml Outdated
Every build workflow ran `docker image build ... .` with no --target, and
Docker defaults to the last stage. The last stage is `xdebug`, so every
published appwrite/base image has shipped Xdebug since the variant was
added in 1.2.0 — and Trivy and dive were scanning that image rather than
the one users actually run.

Reordering the stages cannot fix this: `xdebug` is `FROM final`, so it
has to be declared after `final`, which necessarily makes it last.
Forward stage references do not resolve — Docker reinterprets the name
as an external image and fails the pull — so an explicit --target is the
only reliable control.

tests.yaml only ever asserted module presence, so the xdebug image
satisfied it and CI stayed green while shipping the wrong artifact. Add
an excludedOutput guard so the production image cannot silently regain
Xdebug, and wire up tests-xdebug.yaml, which had no consumer since 1.2.0.

Publish the variant under -xdebug rather than dropping it. Appwrite's
development image supplies an ini expecting xdebug.so to already exist in
the base, so consumers that want Xdebug need a real image to pin.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@abnegate
abnegate force-pushed the fix/publish-final-not-xdebug branch from d72022e to 9b1702e Compare August 7, 2026 02:22
@abnegate
abnegate merged commit de49207 into main Aug 7, 2026
12 checks passed
@abnegate
abnegate deleted the fix/publish-final-not-xdebug branch August 7, 2026 02:32
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