Skip to content

Accept and expose package attestation bundles - #9545

Open
mosuem wants to merge 9 commits into
mainfrom
accept-and-serve-attestations
Open

mosuem wants to merge 9 commits into
mainfrom
accept-and-serve-attestations

Conversation

@mosuem

@mosuem mosuem commented Aug 19, 2026

Copy link
Copy Markdown
Member

First PR in stack for package attestation support:

  • Adds AssetKind.attestation for storing attestation bundles as PackageVersionAsset entities in Datastore.
  • GET /api/packages/versions/new now returns an attestationUrl, pointing at POST /api/packages/versions/newUploadAttestation/<uploadId>. Repositories that do not support publishing with attestations omit the property, which is how pub detects support before uploading the archive (Support uploading package attestations during publish --from-archive pub#4876).
  • The new endpoint requires an authenticated client, validates that the upload id is a uuid, that the bundle is at most maxAttestationContentLength (128 KB), and that it parses as a JSON object, and then stores it as tmp/<guid>.attestation.json in the incoming bucket.
  • In packageBackend.publishUploadedBlob, reads that object if it is present, saves it as an attestation asset, and removes it together with the other temporary objects.
  • newUploadFinish remains a GET-only endpoint.
  • Attestations are not passed through capContent(): oversized bundles are rejected when they are uploaded rather than silently truncated, since a truncated bundle could never be verified.
  • Exposes GET /api/packages/<package>/versions/<version>/attestation endpoint for client retrieval.
  • Updates PubApiClientExt and adds unit tests in upload_test.dart.

Since the attestation is uploaded to the app server, publishing with an attestation does not require a second signed upload policy, and therefore no extra iam.signBlob call per publish.

Verifying the bundle against the uploaded archive (digest and provenance) follows in the next PR in the stack.

- Adds `AssetKind.attestation` for storing attestation bundles as `PackageVersionAsset` entities in Datastore.
- In `packageBackend.publishUploadedBlob`, checks for accompanying `tmp/<guid>.sigstore.json` in the incoming bucket, reads it, and saves it as an attestation asset.
- Exposes `GET /api/packages/<package>/versions/<version>/attestation` endpoint for client retrieval.
- Updates `PubApiClientExt` and adds unit tests in `upload_test.dart`.
@mosuem
mosuem force-pushed the accept-and-serve-attestations branch from 8d92052 to 8cae402 Compare August 20, 2026 08:45
@mosuem
mosuem marked this pull request as ready for review August 28, 2026 12:42
@mosuem
mosuem requested a review from sigurdm August 28, 2026 12:42
@mosuem
mosuem requested a review from jonasfj September 4, 2026 08:00
- Revert attestationUrl and attestationFields in UploadInfo, UploadSignerService, and FakeUploadSignerService.
- Support POST requests on /api/packages/versions/newUploadFinish and /api/packages/versions/newUploadFinish/<uploadId> to receive {'attestation': <bundle>} JSON body.
- Update PackageBackend.publishUploadedBlob to accept attestationContent directly rather than reading a separate object from Cloud Storage.
- Expose Client and sendRaw in api_builder to facilitate sending raw and POST finalize requests.
- Update PubApiClientExt.uploadPackageBytes to send attestation bundle in POST finalization request.
- Run codegen and update tests.
'/api/packages/versions/new' now returns an 'attestationUrl' pointing at
'/api/packages/versions/newUploadAttestation/<uploadId>', where the
client POSTs the attestation bundle before uploading the archive. The
bundle is stored in the incoming bucket next to the archive, and read,
stored and (later) verified when the upload is finished.

'newUploadFinish' is a GET endpoint again.

Also:
 * reject attestations over maxAttestationContentLength instead of
   silently truncating them with capContent(), as a truncated bundle
   could never be verified, and
 * validate that the upload id is a uuid before deriving an object name
   from it.
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