fix(validate-hosted): name the derivative whose approval is missing - #417
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What broke
The openadapt-cloud job "Requalify managed synthetic workflow" has failed since 2026-08-18 with this pair of lines:
That reads as the bundle it just approved being rejected. It is not.
validate-hostedloads two approved derivatives, the--recordingone 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.zipand unzipping it.approve-sanitizedcannot 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_attestationloads the recording and the bundle in separatetryblocks, and prefixes each refusal with the flag and the path that carried it.load_valid_approvalnames the destination. When the approval is absent but the sibling<derivative>.approved.zipis present, it says so: that combination is the fingerprint of a tree rebuilt by extracting an approved archive.docs/SANITIZED_ARTIFACTS.mdstates 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.pygains two cases. The first rebuilds the cloud sequence exactly: approve a recording, extract its.approved.zipinto a fresh directory, place the archive beside it, and callcreate_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--bundleand 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:
pushsends the archive plus the ingest envelope, and/api/ingeststoresartifact_sha256,storage_path, andsanitization_manifest. The.openadapt-approval.jsonnever 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.