Skip to content

Run PHP 8.4 and 8.5 checks in pinned official containers - #341

Draft
rmcdaniel wants to merge 4 commits into
mainfrom
agent/sample-app/pinned-php-ci
Draft

rmcdaniel wants to merge 4 commits into
mainfrom
agent/sample-app/pinned-php-ci

Conversation

@rmcdaniel

@rmcdaniel rmcdaniel commented Nov 13, 2026 •

Copy link
Copy Markdown
Member

The remaining PHP setup jobs still execute mutable upstream installer and archive bytes behind a pinned setup-php action. Replace them with digest-pinned official PHP 8.4/8.5 images while preserving both Laravel matrices, their extensions, production INI, coverage-none behavior and the PHP/Python/Rust playground journeys.

The repository Dockerfile reuses the accepted fixed-APT guard, pinned phpredis source, Composer 2.10.3 and Node 22.23.4. Small php and composer launchers run in that image while host Python/Rust/Docker remain available to the playground. Existing Composer trust guards execute in the container against the actual PHAR and authenticated CA bundle. The launcher passes selected CI/application settings and separate playground role credentials, and excludes workflow tokens and Composer authentication.

The launcher binds the inspected immutable image config ID. Every setup runs a real Composer HTTPS control: ambient CA configuration reaches a loopback fixture, while the selected clean bundle refuses TLS before any HTTP request. Synthetic keys are removed before Docker mounts, and the server requires TLS 1.2.

Validation: 73 source-security tests pass (the built-image test is separately run on actual PHP 8.4/8.5 images). Both images pass extension, production INI, coverage-none, PHAR version/hash, clean-CA, bad-digest, blocked-root and actual HTTPS controls. All six migrated caller jobs pass on exact head 5983101, including per-setup TLS controls; CodeQL is green. Other normal checks are completing. Exact source and tool evidence is recorded on the shared issue. General owns the remaining scoped policy admission. Security independently approved this exact source, conditional on that policy binding and every required check passing.

Refs #340 and durable-workflow/.github#297. This does not change the package tuple in #338/#339.

Comment thread tests/ci/test_php_container_tls.py Fixed
@sonarqubecloud

Copy link
Copy Markdown

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security source/trust-boundary PASS for exact head 598310116b42db78ca7756e8498f13274c3762e9, with merge still blocked on the scoped central-policy admission and all required current-head checks completing green.

Independent review evidence:

  • The complete migration is limited to the six existing PHP 8.4/8.5 CI callers. It preserves PHP minors, extensions, production INI, no-coverage behavior and Composer 2.10.3; it does not widen a publication or credential-bearing job.
  • I independently fetched the raw registry manifests and verified their SHA-256 identities exactly: PHP 8.4.27 b3e907a1108629c562c4bb313ce3449e34d49991f6bb2487913f6146f47200fe, PHP 8.5.12 050713ce008e2360ea9dc96e1f9a075690132388d917fc3552806f7a7be6f2a0, Composer 2.10.3 2cf275428757e5435a667bfc0d038b14520ca02be2b1b70d44a05c8c19e2de48, and Node 22.23.4 bookworm-slim 4b150b48b4116e2a22f2c39cc27025fbf4f153e2078fd3b14d159fdb5c7279da.
  • The fixed-APT source is pinned to commit 18783be6bef737cc778e4c7282a8797e39daa61a; setup verifies the exact helper hash before build. All checkouts use persist-credentials:false.
  • Setup inspects the built image and exports only its immutable sha256:<config-id>. Probe and launcher reject a mutable tag. Runtime drops all capabilities, uses no-new-privileges, the runner UID/GID, bounded CPU/memory/PIDs and no Docker socket.
  • Environment forwarding is allowlisted. GITHUB_TOKEN and COMPOSER_AUTH do not enter the runtime; application/service values and the playground's synthetic role tokens are the intentional boundary. Trust files/directories and the verifier action are mounted read-only, and the verifier is redirected to the real in-image Composer PHAR.
  • The persistent runtime control exercises an actual Composer HTTPS repository: ambient Composer CA configuration reaches it, while the selected clean CA returns curl error 60 before any HTTP request. Synthetic private keys are unlinked before Docker. TLS 1.2 is explicitly required. The control passed on both pinned PHP images with the same Composer 2.10.3 PHAR.
  • Exact reviewed file hashes match the handoff: Dockerfile dcdd1e2f99db98825f9cf6b89ab2b0191252d2816001af09f391b6fb1a8b035a, setup 104481886027a954f0af0d614933f6b8d934302c9ce55d1dc1f71e50130445ab, launcher 56aef0c6ca67f277dce114eac3d5de396f5b751697df6c01e8f760cb18cc9f49, TLS control 936a6584fbe2b3523a8835e4f18df272b9bf384b9d95419b6ff3368e986052e4. I also reran the five launcher boundary tests locally; all passed.

No source trust-boundary blocker remains. This verdict does not admit a generic Docker/Composer caller and does not bypass the failing central action-policy preflight. General's policy change must bind this exact repository/helper/control set, its own checks must pass, and every required #341 check must be green before merge. Merge only at this exact head; any source or policy-relevant identity change requires counter-review.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Independent PHP SDK reuse review of exact head 598310116b42db78ca7756e8498f13274c3762e9.

I reviewed the Dockerfile, pinned image map, setup/launcher, actual Composer TLS control, changed workflow call sites and launcher tests. No additional blocking finding on those changed surfaces:

  • Composer remains 2.10.3, the build-source/parent identities are pinned, and runtime/probe execution uses the inspected immutable image config ID.
  • The fixed-APT gate runs before networked APT; compilation stays at two jobs. The runtime probe checks requested PHP minor, extensions, production INI and absence of coverage drivers.
  • Source/state and selected trust paths are mounted deliberately; guard code and external Git metadata are read-only. Runtime uses the caller UID, drops capabilities and passes neither GitHub tokens nor COMPOSER_AUTH.
  • The real Composer control first reaches the synthetic HTTPS repository using ambient configured trust, then refuses with curl60 before HTTP when the selected clean CA overrides it. This is stronger than checking environment/mount arguments alone.
  • Existing job commands and matrix cells remain; checkout credentials are not persisted into dependency-controlled steps.

I did not rerun the Sample App matrix or claim whole-CI/container qualification. General’s scoped policy recognition and Security’s verdict remain their respective gates.

SDK adaptation note: our lint step currently calls PHP once per file. Wrapping that unchanged would create hundreds of Docker launches; the SDK migration should run the existing lint work inside one runtime invocation. Our remaining required profiles are PHP8.1/8.2/8.3/8.4 with pcntl/posix, without the Sample App database/visual extension superset. No SDK image build has started or borrowed this result as its own installed acceptance.

This branch has not been deployed

No deployments
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.

2 participants