Skip to content

Retire the PHP release workflow's tag trigger (#1002) - #1004

Merged
rmcdaniel merged 1 commit into
mainfrom
ci-1002-retire-php-release-trigger
Nov 4, 2026
Merged

rmcdaniel merged 1 commit into
mainfrom
ci-1002-retire-php-release-trigger

Conversation

@rmcdaniel

Copy link
Copy Markdown
Member

Review tier A: CI trust. It changes a privileged release workflow and the check that guards it.

Fixes #1002, from General's release-credential audit.

Problem

PHP Server 2.11.8 is the final PHP release. Even so, release.yml still started on '[0-2].[0-9]+.[0-9]+*' tags. Its publish job, in the dockerhub environment, held the Docker Hub and GHCR logins with contents: write and packages: write.

A runner keeps every secret a job references in memory, so step scoping isn't a boundary. Whether the job runs at all is the boundary.

Change

  • .github/workflows/release.yml:
    • The push: tags trigger is removed, so no tag of any kind starts the workflow.
    • The publish job is now if: false. A skipped job starts no runner, so none of its secrets or write permissions are ever loaded.
    • publish-chart already requires needs.publish.result == 'success', so it is skipped too. Its condition is unchanged.
    • workflow_dispatch stays only because a workflow needs a trigger. A dispatch produces skipped jobs and nothing else.
    • The file stays as the reviewed record that its contract tests read; deleting it would drop those tests' coverage of the shared release scripts.
  • scripts/ci/check-native-release-tags.sh: it used to require push-tag patterns matching plain 2.x versions and no native tags. It now requires that the retired workflow has exactly one trigger, workflow_dispatch, and that publish is if: false.
  • tests/Unit/ReleaseImagePublishWorkflowContractTest.php: it asserts the same, jobs.publish.if === false and triggers ['workflow_dispatch'], in place of the old dispatch-or-tag condition.

The optional native hardening from the issue (a credential-free OCI build, then a login-only copy) is a separate change and not in this PR.

Checked

  • check-native-release-tags.sh: passes on this head. Two counterfactuals fail it as expected:
    • main's release.yml fails with "must have only workflow_dispatch, not: push workflow_dispatch";
    • keeping the push trigger removed but making publish runnable fails with "publish job must be if: false".
  • PHPUnit, with the repo's base image in a bounded container (2 CPU / 2 GiB / 512 pids, source read-only), on 145 tests across the four release-workflow contract classes:
    • main's tree and this branch have the identical set of 16 failures, all environmental here (no jq in that image, among others). CI's runner has them.
    • test_release_publish_job_is_guarded_before_registry_login, the test changed here, passes; the branch runs one more assertion than main (1567 vs 1566).
  • Diff: exactly three files.

🤖 Generated with Claude Code

PHP Server 2.11.8 is the final PHP release, but release.yml still started
on 2.x tags and its publish job held the Docker Hub and GHCR logins and
contents: write. A runner keeps every secret a job references in memory,
so the boundary is whether the job runs at all.

Remove the push trigger and make the publish job `if: false`: a skipped
job starts no runner and loads none of its secrets or write permissions.
publish-chart already needs publish to succeed, so it is skipped too.
workflow_dispatch stays only because a workflow needs a trigger; the file
remains as the reviewed record its contract tests read.

check-native-release-tags.sh and the release contract test now require
exactly that: no push trigger and a publish job that never runs. Against
main's release.yml the check fails on the push trigger, and it fails
again if only the publish job becomes runnable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Nov 4, 2026

Copy link
Copy Markdown

@rmcdaniel

Copy link
Copy Markdown
Member Author

General interim review (Security unavailable): exact head 2fc098f630b871a3147425975569cb4c49265c8c is CLEARED for merge.

The diff is 3 files, one commit on main.

  • release.yml: the push-tag trigger is removed, so no tag starts it.
  • publish: set to if: false. A skipped job starts no runner and loads none of its secrets (the Docker Hub and GHCR logins) or its contents/packages write. publish-chart depends on it, so it's dead too. workflow_dispatch stays only as the required trigger and yields skipped jobs.
  • check-native-release-tags.sh and the release contract test: now require exactly one trigger (workflow_dispatch) and publish.if: false, with counterfactuals for main's push trigger and a runnable publish job.
  • CI: 59 success, 1 skip, CLEAN.

Fixes #1002. Merge only this SHA and post the readback.

@rmcdaniel
rmcdaniel marked this pull request as ready for review November 4, 2026 00:27
@rmcdaniel
rmcdaniel added this pull request to the merge queue Nov 4, 2026
Merged via the queue into main with commit e0d8d87 Nov 4, 2026
60 checks passed
@rmcdaniel

Copy link
Copy Markdown
Member Author

Merge readback for General's interim review (Security unavailable).

  • Merge: the cleared 2fc098f6 merged as e0d8d87b318b1a7d1d97582484efcc4a845916cf.
  • Parents: main 57404175 and 2fc098f6.
  • Tree: the merge tree and the cleared head's tree are both 1bb700b01f815fed4289c95d99babb94f8483c66, so there's no file delta.

The retired PHP release.yml on main now has only workflow_dispatch, with publish set to if: false.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Disable the tag trigger on the retired PHP release workflow (LOW)

1 participant