Skip to content

Restore bound PHP setup after upstream archive replacement - #404

Draft
rmcdaniel wants to merge 4 commits into
mainfrom
general/restore-php-archives-20261114
Draft

rmcdaniel wants to merge 4 commits into
mainfrom
general/restore-php-archives-20261114

Conversation

@rmcdaniel

@rmcdaniel rmcdaniel commented Nov 14, 2026 •

Copy link
Copy Markdown
Member

Upstream replaced both PHP 8.3 archives used by the bound Ubuntu 24.04/26.04 setup profiles. The old asset IDs return 404 before dependent repository tests start. This repair selects the replacements by exact asset ID, size and SHA-256, and rebuilds their complete archive, normalization and alternatives records.

The source change updates only the two existing profiles. The installer, TLS trust, redirects, regular-file derivation, configuration, extraction bounds and tool selections retain their existing rules. Retired asset identities are rejected before normalization. Shared contract CI pins the reviewed setup predecessor 5c1ddbff59bcfad8a686a72a9b09804b359c382a. Its action role and exact workflow bytes are explicitly recorded; candidate PR action changes do not execute through a local action reference.

Profile Replacement asset Compressed bytes SHA-256
Ubuntu 24.04 x64 PHP 8.3 747287433 43,826,053 c60a4af4c7806c8c123268305b35ba1f7250a8356b195997bd0860359b101784
Ubuntu 26.04 x64 PHP 8.3 747290740 40,600,860 d4959f02ae28e3936ad2ae3bcaca25aff8c2eca38ae11ab53a72a76a3711a7ab

Ubuntu 24.04 retains 3,636 raw members and derives 3,215 regular files plus 373 directories. Ubuntu 26.04 adds 20 members for bundled libtalloc2 and libwbclient0, including two directories and two library links; its 4,006 raw members derive 3,531 regular files plus 393 directories. Every link treatment is regenerated from the held archive. All nine managed alternatives resolve to the same archive member paths; only their metadata binding changes.

Validation completed:

  • 191 PHP setup/archive/normalization/configuration/qualification tests pass, including refusal of both retired IDs before codec execution. The corrected action/workflow policy bindings pass 386 policy/trust controls (one existing skip).
  • Both acquired archives match the official release API and pass sealed-byte normalization followed by the unchanged strict archive inspector. The derived inventories equal the normalizer's inventory, all nine managed targets and the CLI template are present, and sizes remain below the existing 64 MiB bound.
  • The existing offline record generator reproduces both committed records byte for byte. Public-boundary and whitespace checks pass.

The initial hosted run successfully installed the replacement PHP, then refused the unbound local-action workflow change. That initial run remains failed; the exact-source successor corrects the finding.

This PR starts #400's repair. The two original manual qualifiers now change only their six setup/control source literals, retaining the existing main-only/attempt-1 admission, prerequisites, probes, evidence and cleanup. Their exact future workflow identities are bound in the policy runtime. Hosted qualification, the administrator transition below, downstream immutable pin updates and successful affected callers still need completion before that issue closes. Existing failed runs remain failed; no installed qualification is inferred from offline archive inspection.

The final source head is d8826b083063be5f1724c8a1ad3aa88bb757b981 (tree f7b5bec9dca6b4c9262141b71c45706324a1c51b). Setup source is the immutable predecessor 5c1ddbff59bcfad8a686a72a9b09804b359c382a; the enforcer workflow pins policy runtime 2f6445df3c10ed10599001ff7bee6ecc25bac2f4. All four PHP implementation modules and all generated records remain byte-equal to the independently reviewed repair.

The final 380-test source/policy/qualification group passes. Running the full successor enforcer over the 17 actual Git-captured workflow/helper inputs accepts them (input manifest SHA-256 c841f71ce335fa5a9171d5bebc6116eaa20b525cc9630188eca72334d8192df4). The old d477 enforcer refuses those same inputs. Both a foreign setup pin and substitution of a local action remain refused. These are local source controls; fresh hosted accepted/refused events remain required.

The required organization workflow currently selects main and thus the old d477 runtime, which cannot admit its own successor bytes. Current credentials lack admin:org. The proposed administrator action preserves rule 26628397, its Active enforcement, no bypass actors, every existing condition and all other rules. Replace only its sole workflow selector with:

{
  "repository_id": 575230056,
  "path": ".github/workflows/native-policy.yml",
  "sha": "d8826b083063be5f1724c8a1ad3aa88bb757b981"
}

This uses the ruleset's documented immutable workflow SHA field, replacing the moving ref. The selected workflow bytes have SHA-256 9c285c0e00605e0a8be85e1f601c96234616ade9d4b855ba8a273a359150f360 and execute only the earlier pinned runtime. No organization write, enforcement reduction, bypass, credential scope expansion, merge or manual qualification has occurred. After independent source/transition review and actual admin selection, verify fresh accepted/refused policy events and merge through the protected path with every required check passing.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Independent review: the two replacement asset bindings and generated records are sound. I fetched assets 747287433 and 747290740, matched their API size/SHA-256 identities, and reproduced both committed archive and normalization records byte-for-byte with php_linux_profile_records.py. The focused archive/setup tests pass.

Blocking finding: .github/workflows/ci.yml now uses ./.github/actions/setup-php-linux. That makes every future pull request's action implementation executable in the ordinary PR job before the exact-source policy controls. The workflow bytes can remain unchanged while a later PR changes the local composite action, so approving this workflow would not bind the setup source that executes. It also causes the current protected-policy failure; my focused policy run reproduces two InputRefused errors for the changed CI workflow.

Bind the hosted check to this reviewed predecessor commit instead: durable-workflow/.github/.github/actions/setup-php-linux@5c1ddbff59bcfad8a686a72a9b09804b359c382a. Add that exact action pin and the resulting exact CI-workflow identity to the existing policy/context controls. A successor can consume 5c1ddbff without a self-referential hash, preserving exact-source execution while qualifying the new archives.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security source re-review PASS for exact 3d0652e0811d34b5c54bd1772a7337c23f3386e7, scoped before protected-policy activation and hosted qualification.

The earlier PR-controlled local-action finding is closed: CI now invokes the immutable reviewed predecessor durable-workflow/.github/.github/actions/setup-php-linux@5c1ddbff59bcfad8a686a72a9b09804b359c382a, the bound-linux-php pin is closed in policy, the exact CI bytes are recorded as d43a91ff…, and the fixture is byte-identical. I independently reproduced the two replacement archive records at the prior head; this successor does not alter installer/trust/extraction semantics. Focused policy/workflow/archive/setup tests pass locally (169 tests), and the workflow/hash commitments recompute exactly.

The current Validate native policy subject failure remains expected and material: active rule runtime d4770e… cannot admit these successor workflow/pin bytes. Do not merge by bypassing or disabling that rule. The separately proposed administrator transition to an immutable reviewed workflow SHA while the ruleset stays Active is the required next review boundary; after it is approved/applied, require a fresh accepted policy event plus ordinary hosted setup/contract qualification. This PASS does not itself authorize that org-admin transition or promote old installed evidence.

@sonarqubecloud

Copy link
Copy Markdown

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security source review PASS for exact d8826b083063be5f1724c8a1ad3aa88bb757b981 / tree f7b5bec9dca6b4c9262141b71c45706324a1c51b, with the organization-rule mutation still HOLD pending an authorized exact preflight.

Source findings are closed:

  • the setup/record implementation remains byte-equal to reviewed 5c1ddbff…;
  • CI invokes that immutable action, never PR-controlled local action code;
  • both original qualification workflows change exactly their six source/control literals and their complete bytes recompute to afebd85c… / 71db64b8…;
  • the required workflow bytes recompute to 9c285c0e… and pin earlier ancestor runtime 2f6445df…, which contains the exact CI/qualifier registries;
  • focused policy/workflow/archive/setup controls pass locally (208 tests), including absence of the successor registries and rejection of local/foreign action substitutions.

I independently checked the current GitHub REST schema: a required-workflow selector supports sha, so pinning the reviewed workflow commit is a valid way to keep enforcement Active without a bypass or Evaluate/disabled window. However, the update operation is PUT /orgs/{org}/rulesets/{ruleset_id}, and changing the nested workflow rule requires submitting rule data. The present packet provides only the replacement selector; our credentials cannot read the live ruleset, so we cannot independently prove that every other live field will be preserved.

Before the one admin write, the already-authorized administrator must:

  1. GET exact rule 26628397 and retain the complete response (including the write-visible bypass actors), rejecting if it is not Active, has any bypass actor, differs from the expected target/conditions, or does not contain exactly the expected sole moving selector.
  2. Build and review the complete PUT body from that captured object. Canonical before/after diff must replace only {repository_id:575230056,path:.github/workflows/native-policy.yml,ref:refs/heads/main} with {repository_id:575230056,path:.github/workflows/native-policy.yml,sha:d8826b083063be5f1724c8a1ad3aa88bb757b981}. Name, target, Active enforcement, empty bypass list, all conditions, do_not_enforce_on_create, and every other rule must be byte/structurally unchanged.
  3. Apply it once using existing admin authority, immediately GET and reconcile the returned rule, then trigger fresh accepted and refused PR events. The accepted event must execute workflow SHA 9c285c0e… and runtime 2f6445df…; a foreign pin/local action/malformed subject must still fail.

No merge or manual qualification is cleared until that transition evidence and all ordinary required checks are terminal. This is an exact external-authority precondition, not a request to broaden the current credential or weaken enforcement.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant