Skip to content

build(composer): raise dev-tool lower bounds past advisory-affected versions (Ref #69) - #74

Merged
megyptm merged 1 commit into
mainfrom
fix/69-dev-dependency-floors
Oct 23, 2026
Merged

megyptm merged 1 commit into
mainfrom
fix/69-dev-dependency-floors

Conversation

@megyptm

@megyptm megyptm commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Dev-only fix for #69 (investigation: report, Lead disposition: F69-01). require-dev still allowed advisory-affected lower bounds; hosted CI only passes because Composer 2.10.2 filters them (audit.block-insecure, default since 2.9).

-    "phpunit/phpunit": "^11.5"
+    "phpunit/phpunit": "^11.5.50",
+    "symfony/process": "^5.4.51 || ^6.4.33 || ~7.3.11 || ^7.4.5 || ^8.0.5"

Only composer.json require-dev changes. No change to require, php >=8.2, config.platform.php, src/, tests/, CI, standards, audit policy; no audit ignores / --no-audit; no lockfile.

Why a direct symfony/process constraint (parent-first was checked)

SECURITY.md step 4 asks to fix a transitive finding through its parent first. I inspected every friendsofphp/php-cs-fixer release on Packagist: the latest, v3.95.27, still requires symfony/process ^5.4.47 || ^6.4.24 || ^7.2 || ^8.0, i.e. it admits affected versions on every branch (5.4.47, 6.4.24–32, 7.3.0–10, 7.4.0–4, 8.0.0–4). No parent release can remediate it, so a dev-only constraint is the minimum. It is one OR-ed term per maintained branch, so it never forces a branch and ~7.3.11 stops 7.3 from reaching 7.4.0–7.4.4 (^7.3.11 would not).

Advisory ranges (Packagist API): CVE-2026-24739 >=8.0,<8.0.5|>=7.4,<7.4.5|>=7.3,<7.3.11|>=6.4,<6.4.33|<5.4.51; CVE-2026-24765 >=11.0.0,<11.5.50; older CVE-2024-51736 (<5.4.46, <6.4.14, <7.1.7) is also excluded.

Baseline

  • Base: main@3fe55d7d3a779fed93d8f4419d512390dcc803bf, tree be13452ad666ee07eaa94e5897c42f465d0ef94d
  • HEAD: ba609cb6bb633d140fef6d5e036f2c14b3c67acf, tree 1a7beb6871698010a4727b2b9f52da0d9fd3fedf

RED → GREEN (isolated dirs, own COMPOSER_HOME/cache; --prefer-lowest --prefer-stable, then composer audit --locked --abandoned=fail)

Composer 2.10.2 = official phar, sha256 5ee7125f…8027 matched getcomposer.org's published sum. config.platform.php=8.2.0 in all cells.

PHP Composer composer.json phpunit symfony/process audit exit
8.4.4 2.8.6 base (RED) 11.5.0 v5.4.47 1 (2 advisories)
8.2.34 2.8.6 base (RED) 11.5.0 v5.4.47 1
8.4.4 2.10.2, audit.block-insecure=false (scratch only) base (RED) 11.5.0 v5.4.47 1 — proves the mechanism directly
8.4.4 / 8.2.34 2.10.2 default base 11.5.50 v5.4.51 0 (masked by Composer, not by constraints)
8.4.4 2.8.6 this PR (GREEN) 11.5.50 v5.4.51 0
8.2.34 2.8.6 this PR 11.5.50 v5.4.51 0
8.4.4 / 8.2.34 2.10.2 default this PR 11.5.50 v5.4.51 0
8.4.4 2.10.2, block-insecure=false this PR 11.5.50 v5.4.51 0

Every affected Symfony branch (composer update --prefer-lowest --with symfony/process:~X, platform 8.4 in scratch so 8.x resolves)

branch base, Composer 2.8.6 this PR, 2.8.6 this PR, 2.10.2
5.4 v5.4.47 (affected) v5.4.51 v5.4.51
6.4 v6.4.24 (affected) v6.4.33 v6.4.33
7.3 — v7.3.11 v7.3.11
7.4 v7.4.0 (affected) v7.4.5 v7.4.5
8.0 v8.0.0 (affected) v8.0.5 v8.0.5

All audit-clean. Additionally, a composer/semver check of every published stable symfony/process version that the parent allows (48 versions, 17 advisory-affected): 0 affected versions remain allowed by the new constraint.

Full gates on real MySQL 8.4.10 (dedicated disposable container; PHP 8.4.4 locally)

For each of {lowest, latest} × {Composer 2.8.6, 2.10.2}: validate --strict, update, check-platform-reqs, audit --abandoned=fail, dump-autoload --optimize --strict-psr, check:syntax, PHPStan ([OK] No errors), php-cs-fixer --dry-run, unit (383 tests), regression (97), integration ×2 (223 each), consumer harness, check:residue, check:whitespace — all 4 combinations passed, audit "No security vulnerability advisories found" in each. Lowest resolves phpunit 11.5.50 / process v5.4.51 on both Composer versions; latest resolves phpunit 11.5.57 / process v7.4.21.

Not run locally: the suites on PHP 8.2 (no local 8.2 with pdo_mysql); PHP 8.2 resolution/audit was proven in Docker php:8.2-cli. The PHP 8.2 test runs are covered by this PR's CI.

Notes

  • #69 should stay open for post-merge reconciliation; hence "Ref", not "Fixes".
  • Future maatify/php-persistence (^8.4) must not copy the old constraints; this PR leaves that for its own WU.

🤖 Generated with Claude Code

Follow Chart — Technical Lead

flowchart TD
    A[Confirm baseline and advisory ranges] --> B[Reproduce vulnerable lowest resolution RED]
    B --> C{Can the direct parent remove vulnerable versions?}
    C -->|Yes| D[Use safe parent constraint]
    C -->|No, validated| E[Add minimal dev-only security bounds]
    D --> F[Verify all Symfony branches and PHPUnit floor]
    E --> F
    F --> G[GREEN: Composer 2.8 and 2.10 resolutions plus audit]
    G --> H[Full local quality and real-MySQL tests]
    H --> I[GitHub 10/10 CI on exact HEAD]
    I --> J[Independent Technical Lead fresh full review]
    J --> K{Lead MERGE GO and Owner approval?}
    K -->|No| L[Remediate or keep PR open]
    K -->|Yes| M[Owner merges the reviewed HEAD]
    M --> N[Post-merge main tree, CI and issue reconciliation]
Loading

Technical Lead status: exact-tree CI and independent final acceptance pending; this chart does not authorize merge or release.

…ersions (Ref #69)

require-dev allowed advisory-affected lower bounds, so a supported
`--prefer-lowest` resolution under Composer < 2.9 (no default
audit.block-insecure) selected phpunit/phpunit 11.5.0 (CVE-2026-24765)
and symfony/process 5.4.47 (CVE-2026-24739) and failed `composer audit`.
Hosted CI (Composer 2.10.2) only passed because it filters them out.

- phpunit/phpunit ^11.5 -> ^11.5.50
- add dev-only symfony/process constraint that excludes every affected
  branch (5.4<5.4.51, 6.4<6.4.33, 7.3<7.3.11, 7.4<7.4.5, 8.0<8.0.5). No
  friendsofphp/php-cs-fixer release (latest v3.95.27) narrows the parent
  constraint, so the parent cannot remediate it.

No change to require, php >=8.2, config.platform, src, tests or CI.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

megyptm commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator Author

Technical Lead — independent Fresh Full Re-Review (current disposition: CODE ACCEPTED; MERGE NO-GO until exact-HEAD CI completed)

Identity & scope checked independently: PR #74, Base main@3fe55d7d3a779fed93d8f4419d512390dcc803bf / Tree be13452ad666ee07eaa94e5897c42f465d0ef94d, HEAD ba609cb6bb633d140fef6d5e036f2c14b3c67acf / Tree 1a7beb6871698010a4727b2b9f52da0d9fd3fedf, direct parent of HEAD is the exact reviewed base. One commit, one file, cumulative +2/−1: composer.json require-dev only. No changes to PHP >=8.2, config.platform.php, Runtime src/, public types/API, scripts, tracked lockfiles, CI, security policy, source standards, tags/releases.

Audit of code/standards:

  • phpunit/phpunit: ^11.5.50 covers the first fixed PHPUnit 11.x version for GHSA-vvj3-c3rp-c85p, is an open caret lower floor, not an exact patch pin.
  • symfony/process: ^5.4.51 || ^6.4.33 || ~7.3.11 || ^7.4.5 || ^8.0.5 matches the five published fixed-version thresholds of GHSA-r39x-jcww-82v6. The ~7.3.11 clause specifically does not admit 7.4.0–7.4.4; ^7.4.5 starts after that unsafe gap. ^8.0.5 does not back-open 8.0.0–8.0.4. Independently verified the released friendsofphp/php-cs-fixer v3.95.27 still declares symfony/process ^5.4.47 || ^6.4.24 || ^7.2 || ^8.0; moving the direct parent cannot guarantee a safe lowest resolution. A root-only direct dev constraint is therefore justified despite the normal parent-first policy.
  • Composer field sorting, stable constraints, root-only require-dev, no unauthorized PHP-minimum change, no audit ignores, and SECURITY.md:96–110 fail-closed remediation align with pinned COMPOSER_PACKAGE_STANDARD §§15–17 and CI_WORKFLOW_STANDARD §9. Pin policy that forbids permanently hard-pinning a tool to one patch is not breached by a security-motivated open lower bound that allows later patched releases. No runtime dependency added, consumers remain unaffected by dev-only packages.
  • RED/GREEN 2.8.6 vs 2.10.2, branch-forced Symfony matrix and four real-MySQL gate combinations are executor-supplied evidence in the PR description, not independently rerun by Lead; consistent with exact patch and published advisory thresholds.

CI blocker is procedural, not demonstrated code failure: exact HEAD GitHub Actions run 39867801298 currently queued with conclusion null (nine non-final jobs reported; the tenth aggregation gate has not completed). Do not claim 10/10, MERGE GO or authorize Owner merge until all ten actual jobs complete SUCCESS on this HEAD, with inspectable Quality, Lowest, PHP 8.2–8.5 tests, real-MySQL Integration and final CI Gate. GitHub queueing is not proof of code failure; do not make a no-op commit or enable auto-merge to clear it.

Decision: No blocking code findings in the one-file patch; MERGE NO-GO (CI PENDING). The English Mermaid Follow Chart has been added to the PR description by the Technical Lead. Once exact-HEAD CI resolves, independently verify all jobs and post a final MERGE GO/NO-GO. #69 stays OPEN for post-merge main tree/CI and issue reconciliation. Owner's separate approval remains necessary for merge; absolutely no new repo, package migration, tag or release here.

megyptm commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator Author

Technical Lead — FINAL Fresh Full Re-Review: MERGE GO (exact HEAD / Tree)

Identity and merge preflight verified directly against GitHub (2026-10-23):

  • PR #74: OPEN, ready-for-review, mergeable true, not merged.
  • Base main@3fe55d7d3a779fed93d8f4419d512390dcc803bf, Tree be13452ad666ee07eaa94e5897c42f465d0ef94d; main remains on the reviewed Base.
  • HEAD ba609cb6bb633d140fef6d5e036f2c14b3c67acf, Tree 1a7beb6871698010a4727b2b9f52da0d9fd3fedf; exact parent = reviewed Base; only one file composer.json require-dev +2/−1. No changes to PHP >=8.2, config.platform.php, src/, public contracts, CI, standards, tests, or tracked lockfile.
  • English Mermaid Follow Chart added by Lead to PR description in previous review.

Final gate — independently verified from GitHub Actions logs

Run #39867801298 attempt 1 on exact HEAD: COMPLETED / SUCCESS; all 10/10 check-runs and jobs COMPLETED / SUCCESS, including Workflow lint, Quality PHP 8.2, Unit/Regression PHP 8.2/8.3/8.4/8.5, Lowest PHP 8.2/MySQL 8.4.10, real-MySQL Integration PHP 8.2 and 8.5, and stable CI Gate.

Relevant independently read logs:

  • Lowest job 120134298405: Composer 2.10.2, resolved phpunit 11.5.50, symfony/process 5.4.51; 0 security advisories, PHPStan no errors, Unit 383/2688 assertions, Regression 97/1085 assertions, Integration 223 tests twice (1688, 1689 assertions), MySQL residue clean.
  • Quality job 120134298370: latest resolved phpunit 11.5.57, symfony/process 7.4.21, audit clean, PHPStan no errors.
  • Integration jobs 120134298411 (PHP 8.2) and 120134298422 (PHP 8.5): each passed Consumer Verification Harness two clean runs, 223 Integration tests twice, and residue verification clean.
  • Final CI Gate 120155341248: CI Gate passed: all required jobs concluded with success.

Architectural/security conclusion

The previously accepted one-file remediation has no open blocking findings. PHPUnit security floor ^11.5.50 and complete branch-aware Symfony Process security floors ^5.4.51 || ^6.4.33 || ~7.3.11 || ^7.4.5 || ^8.0.5 exclude documented affected ranges, including the 7.3→7.4 gap. Direct dev-only constraint is justified because the current stable friendsofphp/php-cs-fixer dependency ranges still admit affected lower versions; no runtime dependency, audit waiver, hard pin or API break introduced. The executor's extensive local RED/GREEN and four Composer/version test matrices remain executor-attributed; Lead independently examined source, exact cumulative patch and the actual GitHub CI results, not a separate local reproduction.

Decision: FINAL MERGE GO for exact HEAD ba609cb6bb633d140fef6d5e036f2c14b3c67acf and Tree 1a7beb6871698010a4727b2b9f52da0d9fd3fedf, subject to separate explicit Owner merge authorization. No new commit/no-op/rerun needed. PR must not move before merge; if it does, obtain fresh verification. NOT MERGED by Lead.

Mandatory after Owner merges: confirm actual squash merge SHA and merged Tree matching 1a7beb6871698010a4727b2b9f52da0d9fd3fedf (or reconcile divergent main), main-push 10/10 CI, update/close #69 with causal resolution evidence, record in release tracker #37, then proceed to bounded harness fix #68. No Tag/Release, PHP minimum raise or new php-persistence extraction authorized by this GO.

@megyptm
megyptm merged commit a486cc7 into main Oct 23, 2026
10 checks passed
@megyptm
megyptm deleted the fix/69-dev-dependency-floors branch October 23, 2026 09:27
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