Skip to content

Plugin Directory: Baseline security scans on the served release - #806

Closed
obenland wants to merge 3 commits into
WordPress:trunkfrom
obenland:gandalf-clean-baseline
Closed

Plugin Directory: Baseline security scans on the served release#806
obenland wants to merge 3 commits into
WordPress:trunkfrom
obenland:gandalf-clean-baseline

Conversation

@obenland

Copy link
Copy Markdown
Member

The release block introduced in #777 is deliberately scoped to one release, so an author can ship a genuine fix without reviewer intervention. But the scan's diff baseline (previous_zip_url) came from the last_stable_tag/last_version post meta, which updates on every import — including the import of a blocked version. Re-tagging a blocked payload under a new version therefore diffed against the blocked release itself: an empty diff, a clean verdict, and the block circumvented. Splitting a payload across several small releases exploited the same chained baseline.

Builds on #777.

What it does

  • The scan dispatch now prefers the release currently served by the update API (update_source) as the diff baseline. A blocked or cooling-down release never reaches that row, so a follow-up release is always diffed against the last version that actually shipped — or that a reviewer force-released, which is clean by definition. The payload of a re-tagged blocked release shows up in its own diff, every time, until a reviewer clears it.
  • The baseline is existing, authoritative state: no new bookkeeping, and force-release naturally advances it.
  • When the row already carries the scanned version — imports without a cooldown write it before the scan dispatches, and rebuilds of the current stable serve it already — the last-import meta remains the baseline as before. In that regime a block cannot exist (block_release() refuses served versions), so the fallback reopens nothing.
  • Trunk-served releases carry no baseline, as before: the previous trunk build is overwritten, so the scanner falls back to a full scan — the conservative direction.
  • API_Update_Updater::get_served_release() returns the served row's version and stable_tag (zips are named by tag, not by the version header); get_served_version() now delegates to it.

Testing

tests/Gandalf_Scan_Baseline_Test.php (4 tests) captures the dispatched scan request and covers: the served release winning as baseline while a newer version is held (the circumvention case), the fallback when the row already serves the scanned version, the fallback without an update_source row, and the trunk-served case dispatching with no baseline.

🤖 Generated with Claude Code

A blocked or cooling-down release never reaches update_source, so diffing
against the served release keeps a re-tagged blocked payload from becoming
its own scan baseline. When the row already carries the scanned version
(imports without a cooldown write it before the scan dispatches), the
last-import meta remains the baseline, where a block cannot exist.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 13, 2026 19:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props obenland.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

obenland and others added 2 commits August 13, 2026 14:52
Review fixes: drop the baseline when the candidate release is blocked
(reachable through the last-import fallback when no update_source row
exists), normalize empty served row columns to null, type the test HTTP
mock, and remove an unread stable_tag fixture.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@bazza bazza closed this in 330dffa Aug 13, 2026
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.

2 participants