Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions docs/SANITIZED_ARTIFACTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,35 @@ the review, and `compile`, `validate-hosted`, and `push` all read that copy as
unapproved. To move an approved derivative, copy the whole directory, hidden
approval file included, next to its sibling ZIP.

Where only the archive travels -- a CI runner that downloads it from object
storage, for example -- carry the approval record beside it and rebuild the
pair with `materialize-approved`:

```bash
openadapt-flow materialize-approved \
--archive recording.approved.zip \
--approval recording.approval.json \
--out recording/ \
--expect-archive-sha256 <digest the caller already trusts>
```

It extracts the archive into a new empty directory, places the record, and runs
the same approval gate `push` runs. It approves nothing: the record must
already exist and must match the extracted bytes. `--approval` takes either the
derivative's `.openadapt-approval.json` or the
[`openadapt.sanitization/v1`](../schemas/sanitization-ingest-v1.json) ingest
envelope a deployment persisted for that artifact. The envelope carries every
field that holds authority -- archive SHA-256 and size, reviewer, approval
time, approval method -- while the two tree hashes are functions of the
extracted bytes that the archive SHA-256 already binds, so they are recomputed
rather than transported. An envelope recording an automatic approval must carry
its policy key id and MAC, and the MAC is verified wherever
`OPENADAPT_SANITIZATION_POLICY_KEY` is configured.

The record is unsigned, exactly as it is on the reviewing machine. It is
therefore only as trustworthy as the channel that delivered it, and that
channel should be the one that already delivers the archive.

## Destination trust

Execution lane and egress destination are independent:
Expand Down
60 changes: 60 additions & 0 deletions openadapt_flow/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4320,6 +4320,30 @@ def _cmd_approve_sanitized(args: argparse.Namespace) -> int:
return 0


def _cmd_materialize_approved(args: argparse.Namespace) -> int:
from openadapt_flow.sanitized_artifact import (
SanitizationError,
materialize_approved_derivative,
)

try:
approval = materialize_approved_derivative(
Path(args.archive),
approval=Path(args.approval),
destination=Path(args.out),
expected_archive_sha256=args.expect_archive_sha256,
)
except SanitizationError as e:
print(f"materialize failed: {e}")
return 1
print(
f"Materialized the approved derivative into {args.out}; "
f"reviewer={approval['reviewer']} "
f"sha256={approval['approved_derivative_sha256']}."
)
return 0


def _cmd_report_break(args: argparse.Namespace) -> int:
"""Emit a PHI-free break diagnostic from a halted run's ``report.json``.

Expand Down Expand Up @@ -6524,6 +6548,42 @@ def _repair_store_flag(rp: argparse.ArgumentParser) -> None:
)
p.set_defaults(func=_cmd_review_sanitized)

p = sub.add_parser(
"materialize-approved",
help="Rebuild an approved derivative from its archive and approval record",
description=(
"Approval binds the archive's own SHA-256, so the archive cannot "
"carry it and an archive unzipped elsewhere reads as unapproved. "
"This places the reviewer's existing approval record beside the "
"extracted bytes and then runs the unchanged approval gate. It "
"approves nothing."
),
)
p.add_argument(
"--archive", required=True, help="Approved immutable archive (.approved.zip)"
)
p.add_argument(
"--approval",
required=True,
help=(
"Existing approval record: either the derivative's "
".openadapt-approval.json or the openadapt.sanitization/v1 ingest "
"envelope a deployment persisted for it"
),
)
p.add_argument(
"--out", required=True, help="New, empty derivative directory to materialize"
)
p.add_argument(
"--expect-archive-sha256",
default=None,
help=(
"Pin the archive to a digest the caller already trusts, checked "
"independently of the approval record"
),
)
p.set_defaults(func=_cmd_materialize_approved)

p = sub.add_parser(
"approve-sanitized",
help="Approve and freeze the exact reviewed derivative as an immutable archive",
Expand Down
Loading