Skip to content

docs: sign the packaged payload, not the checkout - #79

Open
DeepDiver1975 wants to merge 1 commit into
mainfrom
fix/spec-sign-packaged-payload
Open

DeepDiver1975 wants to merge 1 commit into
mainfrom
fix/spec-sign-packaged-payload

Conversation

@DeepDiver1975

Copy link
Copy Markdown
Contributor

Why

spec-attestation-and-crl-workflows.md §2 — the copy-paste reference signing
workflow developers put in their app repo — ran:

ocsign --path . --key <secret> --cert leaf.crt --chain intermediate.crt

In a GitHub Actions job . is the actions/checkout tree. In app mode the
manifest hashes everything under --path bar appinfo/signature.json and OS
cruft, so that signs .git, tests/, .github/ and build scratch as part of
the app
— and it verifies, because the manifest genuinely describes the tree
that was signed. Nothing downstream can catch it.

Not hypothetical: files_antivirus v1.3.1
shipped as a ~1 MB archive (vs ~165 KB for prior releases) containing the whole
checkout, with a manifest over 537 paths including .git/config and .git/index
— while the correct payload built by make appstore sat unsigned inside that
same archive. owncloud/ocsign#21 now refuses such a --path, so §2 as written
exits 1.

While fixing it: the "full YAML" §2 pointed at did not exist. The same
reference workflow is promised in developer-documentation spec §9 and design §16
— three dangling pointers. It is now written.

What changed

  • attestation/CRL spec §2 — steps reordered to package → sign staging dir →
    tar the signed tree, with the payload rule stated normatively: the signed tree
    and the shipped tree must be the same tree; a staging dir inside the checkout
    (build/artifacts/appstore/<app>) is fine because the guard only looks for
    .git under --path; --allow-vcs MUST NOT appear in a release pipeline.
  • developer-documentation spec §4.1 (new) — the reference workflow YAML, in
    the correct order, plus a --path warning on §4 and the §1/§9 cross-references.
  • developer-guide.md §4.1 (new) — the same section in the published guide, plus
    the --path warning and the §8 link. YAML is byte-identical to the spec's bar
    one comment (see §5 vs ITEM #2).
  • design §16 — its "reference workflow provided" promise now names §4.1.

Workflow design notes: only actions/checkout is used, pinned to a full SHA
(3d3c42e5… v7.0.1, same pin as .github/workflows/validate.yml); the release
upload uses the pre-installed gh rather than a third-party action, so there is
exactly one SHA for developers to keep current. ocsign install pins the release
tag and verifies against that release's SHA256SUMS. The --attest step ships
commented out, pointing at ITEM #2.

Verification

  • All four YAML blocks in the touched docs parse (yaml.safe_load); the two issue
    forms are undisturbed.
  • Install step checked against the real artifacts: SHA256SUMS entries are ./-
    prefixed and the archive member is ./ocsign, so sha256sum --ignore-missing --check and tar -xzf "$archive" ./ocsign are what actually work (a bare
    ocsign member name fails; verified). --ignore-missing is non-vacuous — it
    exits 1 when no file was verified.
  • Every flag used exists in ocsign v0.3.0 --help.
  • End-to-end against ocsign v0.3.0 in a real git checkout: signing
    build/artifacts/appstore/example-app exits 0 and writes
    appinfo/signature.json; the old --path . form exits 1. The tarball rolled by
    the last step contains only example-app/{appinfo,lib} — no .git, no
    tests/, no .github/.
  • go test ./... green (docs-only change).
  • grep sweep: every "reference workflow" pointer now resolves to §4.1.

Out of scope: spec-go-signing-tool.md §2's missing --allow-vcs/--version
flags and the new exit-1 condition — that is #78.

Closes #77

🤖 Generated with Claude Code

The reference developer signing workflow in attestation/CRL spec §2 ran
`ocsign --path .`, which in a GitHub Actions job is the actions/checkout
tree. In app mode the manifest hashes everything under --path bar
appinfo/signature.json and OS cruft, so that command signs .git, tests/
and .github/ as part of the app -- and the result verifies, because the
manifest genuinely describes the tree that was signed.

files_antivirus v1.3.1 shipped exactly this: a ~1 MB archive carrying the
whole checkout, manifest over 537 paths including .git/config. ocsign now
refuses such a --path (owncloud/ocsign#21), so §2 as written exits 1.

§2 now packages first (staging dir, e.g. build/artifacts/appstore/<app>),
signs that directory, and rolls the tarball from the signed tree, with the
payload rule stated normatively: the signed tree and the shipped tree must
be the same tree, and --allow-vcs must never appear in a release pipeline.

The "full YAML" §2 pointed at did not exist -- the same reference workflow
was promised in developer-documentation spec §9 and design §16 as well. It
is now written, as §4.1 of both the developer-documentation spec and the
published developer guide, in the correct package -> sign -> tar order.
Verified against ocsign v0.3.0: the documented invocation exits 0 and the
old `--path .` form exits 1; the resulting archive holds only the payload.

Closes #77

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Thomas Müller <1005065+DeepDiver1975@users.noreply.github.com>
@DeepDiver1975
DeepDiver1975 requested a review from a team as a code owner August 21, 2026 09:27
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.

spec §2 reference signing workflow signs the checkout, not the packaged payload

1 participant