Skip to content

fix(validate-hosted): name the derivative whose approval is missing - #417

Merged
abrichr merged 2 commits into
mainfrom
fix/sanitized-approval-destination
Aug 28, 2026
Merged

fix(validate-hosted): name the derivative whose approval is missing#417
abrichr merged 2 commits into
mainfrom
fix/sanitized-approval-destination

Conversation

@abrichr

@abrichr abrichr commented Aug 28, 2026

Copy link
Copy Markdown
Member

What broke

The openadapt-cloud job "Requalify managed synthetic workflow" has failed since 2026-08-18 with this pair of lines:

Approved immutable archive sha256=e4f45f... size=2955 bytes.
validate-hosted failed: Sanitized artifact has not been approved. Review it locally, then approve it.

That reads as the bundle it just approved being rejected. It is not. validate-hosted loads two approved derivatives, the --recording one first, and both failure paths used the same sentence with no path in it. The unapproved artifact was the recording.

The workflow materializes its recording by downloading recording.approved.zip and unzipping it. approve-sanitized cannot put the approval inside that archive, because the approval binds the archive's own SHA-256, so the extracted tree is a valid derivative with no approval. Flow was right to refuse it. It just refused illegibly, and the misread cost nine days.

What this changes

  • create_runtime_validation_attestation loads the recording and the bundle in separate try blocks, and prefixes each refusal with the flag and the path that carried it.
  • load_valid_approval names the destination. When the approval is absent but the sibling <derivative>.approved.zip is present, it says so: that combination is the fingerprint of a tree rebuilt by extracting an approved archive.
  • docs/SANITIZED_ARTIFACTS.md states where the approval lives and how to move an approved derivative.

The gate itself is untouched. An extracted archive is still unapproved, nothing auto-approves, and no check is skipped.

Tests

tests/test_runtime_validation.py gains two cases. The first rebuilds the cloud sequence exactly: approve a recording, extract its .approved.zip into a fresh directory, place the archive beside it, and call create_runtime_validation_attestation. It asserts the refusal names --recording, the path, .openadapt-approval.json, and the archive. The second deletes a bundle approval and asserts the refusal names --bundle and not --recording.

Both fail on main (the message is the bare sentence above) and pass here.

The production fix is not in this repo

This PR makes the failure diagnosable. It does not unblock the deploy. The runner needs a genuine approval record for that recording, and Cloud does not have one: push sends the archive plus the ingest envelope, and /api/ingest stores artifact_sha256, storage_path, and sanitization_manifest. The .openadapt-approval.json never leaves the approving operator's machine. Unblocking the job needs a decision on the Cloud side about persisting and materializing that record, or a portable-approval feature here. Flagged separately.

abrichr and others added 2 commits August 27, 2026 20:30
An approval refusal from `validate-hosted` did not say which of its two
derivatives failed, and the refusal itself did not name a path. A hosted
requalification run therefore read

    Approved immutable archive sha256=... size=2955 bytes.
    validate-hosted failed: Sanitized artifact has not been approved.

as the bundle it had just approved being rejected, when the unapproved
artifact was the recording passed to --recording.

Name the flag and the path on each of the two loads, and name the
destination in the underlying SanitizationError. When the derivative has
no approval but its sibling `<derivative>.approved.zip` is present, say
so: that is the fingerprint of a tree rebuilt by extracting an approved
archive, which cannot carry the approval because the approval binds the
archive's own SHA-256.

The approval gate is unchanged. An extracted archive is still unapproved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@abrichr
abrichr merged commit 4ab4155 into main Aug 28, 2026
15 checks passed
@abrichr
abrichr deleted the fix/sanitized-approval-destination branch August 28, 2026 01:49
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