Skip to content

fix(composer-update): don't abort PR when all unhandled packages are no-widen#30

Merged
oxyc merged 1 commit into
masterfrom
fix/composer-update-no-widen-abort
May 21, 2026
Merged

fix(composer-update): don't abort PR when all unhandled packages are no-widen#30
oxyc merged 1 commit into
masterfrom
fix/composer-update-no-widen-abort

Conversation

@oxyc
Copy link
Copy Markdown
Member

@oxyc oxyc commented May 21, 2026

Problem

When the vulnerability scan finds packages it can't update within their composer.json constraints (Step 2 / widen), and every one of them is listed in extra.vuln-scan.no-widen, they all get skipped and TARGETS ends up empty. The dedupe line then runs:

TARGETS=$(echo "$TARGETS" | tr ' ' '\n' | grep -v '^$' | sort -u | tr '\n' ' ')

grep -v '^$' over empty input matches nothing and exits 1. Composite-action steps run with set -eo pipefail, so that non-zero exit propagates and kills the whole "Update packages" step — aborting PR creation entirely, even when Step 1 already updated other vulnerable packages within their constraints.

Real-world impact

Seen on generoi/solarplexius: the scan flagged 4 safely-updatable symfony/* CVEs and 3 deliberately-pinned (no-widen) WooCommerce plugins. The 3 pins were correctly skipped — but the empty-TARGETS grep then exited 1, so the step failed and no security PR was opened at all. The safe symfony fixes were silently dropped along with the intentionally-skipped ones. (I raised that repo's symfony PR manually in the meantime: generoi/solarplexius#83.)

Fix

Add || true to the dedupe pipeline so the empty-match exit is swallowed and the step falls through to the existing git diff check — which still sees Step 1's changes and raises a PR for whatever updated.

Also hardened find_direct_ancestors, whose final grep -v '^$' has the identical "empty result is a valid outcome, not an error" property and is consumed in $(...)/pipe contexts under pipefail (latent sibling of the same bug).

Verification

Reproduced the failure and confirmed the fix with a minimal harness mirroring the Step 2 path under set -eo pipefail:

  • Before: empty TARGETSgrep -v '^$' → step exits 1 (PR aborted).
  • After: step survives (exit 0), reaches the git diff / changed=true branch, PR is created for the packages that did update.

Note for release

The scheduled scans consume this via composer-update@v2 (and vulnerability-scan.yml@v2). The v2 tag needs to be re-pointed to include this commit for the fix to take effect in running workflows.

🤖 Generated with Claude Code

…no-widen

When the constraint-blocked set (Step 2) consists entirely of packages
listed in `extra.vuln-scan.no-widen`, they're all skipped and `TARGETS`
ends up empty. The dedupe line then runs `grep -v '^$'` over empty input,
which exits 1 on no match. Composite-action shells run with
`set -eo pipefail`, so that non-zero exit propagated and killed the whole
"Update packages" step — aborting PR creation even when Step 1 had already
updated other vulnerable packages within their constraints.

Real-world effect: a repo with safely-updatable symfony CVEs *and* a few
deliberately pinned (no-widen) WooCommerce plugins got NO security PR at
all — the safe fixes were silently dropped along with the skipped ones.

Swallow the empty-match exit on the dedupe line so the step falls through
to the git-diff check and still raises a PR for whatever updated. Apply
the same `|| true` guard to find_direct_ancestors, whose final
`grep -v '^$'` has the identical "empty result is valid, not an error"
property and is consumed in pipefail contexts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@oxyc oxyc merged commit 7705c4c into master May 21, 2026
@oxyc oxyc deleted the fix/composer-update-no-widen-abort branch May 21, 2026 11:47
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