Skip to content

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

Merged
rmcdaniel merged 4 commits into
mainfrom
agent/sample-app/pinned-php-ci
Nov 13, 2026
Merged

rmcdaniel merged 4 commits into
mainfrom
agent/sample-app/pinned-php-ci

Conversation

@rmcdaniel

@rmcdaniel rmcdaniel commented Nov 13, 2026 •

Copy link
Copy Markdown
Member

The six existing PHP CI jobs executed mutable upstream installer/archive bytes behind a pinned setup-php action. They now run through digest-pinned official PHP 8.4/8.5 containers, preserving both Laravel matrices, extensions, production INI, coverage-none behavior, Composer 2.10.3 and the PHP/Python/Rust playground journeys.

The launchers bind the inspected immutable image config ID, keep host Python/Rust/Docker available, filter the runtime environment and run the existing Composer verifier against the actual in-container PHAR and authenticated CA bundle. Every setup runs a real Composer HTTPS control: ambient CA configuration reaches the loopback fixture, while selected clean trust refuses TLS before HTTP. The TLS server requires 1.2 and synthetic keys are removed before Docker mounts.

Validation: all 34 exact-head checks pass, including all six migrated callers, source-security tests, CodeQL, both native image qualifications and existing SDK experiments. Actual PHP 8.4/8.5 controls cover image identity, extensions/INI, clean-CA acceptance, bad-digest/blocked-root refusal and HTTPS isolation. Security approved exact head 5983101. The scoped shared policy is delivered through .github#377, accepted main 33548140, and the failed policy/aggregate jobs passed on rerun without a consumer source change. Exact source/tool evidence.

Refs #340 and durable-workflow/.github#297. The package tuple remains separate in #338/#339. This CI-only change needs no package release or developer-image publication; those follow the tuple update. Keep #340 open through actual-main verification.

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.

@rmcdaniel
rmcdaniel marked this pull request as ready for review November 13, 2026 10:37
@rmcdaniel
rmcdaniel merged commit c680ef9 into main Nov 13, 2026
39 of 41 checks passed
@rmcdaniel

Copy link
Copy Markdown
Member Author

Delivered through PR #341, merged as c680ef92d578ee837d2d960c4235d5919d890134. The signed merge has the reviewed source tree and ordered parents, and main still selects that commit.

Actual-main verification passes for all six migrated callers: the PHP 8.4/8.5 application and microservice cells, committed lock audit, and real PHP/Python/Rust playground journeys. Application CI, lock audit, playground journeys, polyglot smoke and native embedded smoke pass. All three protected main checks pass. The two unchanged broader SDK timer experiments are still running; no result is attributed to them here.

Security independently approved exact source 5983101, the shared policy correction passed independent review and actual-main verification in .github#377, and all 34 PR checks passed before the ordinary merge. Every setup exercises the actual Composer HTTPS accept/refuse control; image ID, extensions, production INI, coverage none and Composer trust are preserved. No owned containers remain.

This completes the requested CI-only migration. It needs no package release or developer-image publication because runtime packages and the shipped tuple are unchanged in this PR. The package update remains in #338/#339; shared .github#297 remains open for other callers.

@rmcdaniel

Copy link
Copy Markdown
Member Author

The two remaining unchanged SDK timer experiments on the accepted merge c680ef92d578ee837d2d960c4235d5919d890134 have now completed successfully: timer upgrades and timers. Together with the previously recorded application, audit, playground, smoke and polyglot results, all seven actual-main workflows are successful. This completes the pending verification readback for this CI-only change.

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