# Update package verification response hardening

Audience: AI coding agents first.

**Status:** DONE — implementation `be0eb2c57` and controller receipt `5552b08b5` are published on `origin/master`.

## Outcome

Fail closed unless update verification returns the authenticated backend envelope with an explicit valid verdict, the exact downloaded package SHA-256, and a valid newer release version. Preserve unrelated update downloads and delete rejected plugin packages.

## Task IDs

- `UPV-01` — harden `UpdateChecker` response validation and add focused regressions.

## Source request

Automated security review reported that `verifyPackageSignature()` accepts every HTTP 2xx JSON object because it checks only for a non-null response. Direct inspection confirmed the bypass.

## Acceptance criteria

1. Require `success === true` and an array `data` envelope.
2. Require `data.valid === true`.
3. Require `data.sha256` to be a lowercase SHA-256 string exactly matching the downloaded bytes via `hash_equals()`.
4. Require a syntactically valid backend release version newer than `IPZ_VERSION`.
5. Send the backend’s published `hash` request field; never rely on the obsolete `package_hash` field.
6. Reject malformed, negative, hash-mismatched, replayed/current-version, error-envelope, and unavailable responses; delete rejected downloaded bytes.
7. Preserve HTTPS enforcement, credential transport, unrelated-plugin passthrough, and valid package acceptance.
8. Run focused regression, PHP syntax, PHPStan, project PHPCS baseline, direct review, commit, serialized publication, and exact remote verification.

## Preserved WIP / constraints

- Worktree: `.claude/worktrees/multilingual-all-slices`; preserve all existing all-slices plan edits.
- Allowed production file: `includes/SiteServices/UpdateChecker.php`.
- Allowed focused test: `tests/unit/SiteServices/UpdatePackageVerificationStandaloneTest.php`.
- Allowed plan records: this plan, `docs/plans/INDEX.md`, and the active all-slices plan receipt.
- Security fix MUST NOT be feature-flagged.
- Do not contact dev1 or dev3. Do not invoke Ask Codex or spawn subagents.

## Execution

1. Add failure-first response-shape, verdict, digest, and version regressions.
2. Implement exact fail-closed validation against the published backend contract.
3. Run affected deterministic gates and inspect every warning.
4. Commit and publish through the serialized delivery controller.
5. Resume `SC-ADAPTER-01` immediately after publication.

## Current receipt

2026-08-14: Confirmed fail-open check at `UpdateChecker.php:340`. Published backend integration tests define response as `{success:true,data:{valid,version,sha256,signature,signature_key_id}}` and request digest as `hash`; prior plugin code validated none of those fields and sent `package_hash`.

Implemented failure-first regressions and exact fail-closed envelope, verdict, digest, and newer-version validation. Focused standalone regression passes; PHP syntax passes; PHPStan reports `No errors`; production-file PHPCS occurrence baseline passes; `git diff --check` passes. The broad legacy test runner reports four pre-existing unrelated harness failures in untouched files (`BlockSegmentCodecTest.php`, `AutoPublishStatusTest.php`, `ContentManagerTest.php`, `SettingsIdempotencyTest.php`); its primary PHPUnit suite passes 80 tests / 298 assertions and the focused owned regression passes independently. Passing the standalone test file to the production PHPCS occurrence-baseline tool exposes its pre-existing ungated standalone-fixture style debt, so the applicable production file alone was checked cleanly without suppressions.

The first serialized publication attempt failed at source import because its temporary bundle vanished; the controller retained recovery data but reset the branch to a prior base and removed the local commit. The reviewed diff was reconstructed exactly and reverified. The second attempt published implementation `be0eb2c5716bccadd11f0cb952a365c859f99dcb`; controller receipt `5552b08b5` is verified on `origin/master`. Cleanup completed after the session moved to a fresh continuation worktree. No owner action is required.

## Next executable action

None. `UPV-01` is complete; resume `SC-ADAPTER-01`.
