Skip to content

feat: artifact and signature download endpoints - #262

Open
taleodor wants to merge 3 commits into
CycloneDX:mainfrom
relizaio:2026-08-artifact-direct-download
Open

feat: artifact and signature download endpoints#262
taleodor wants to merge 3 commits into
CycloneDX:mainfrom
relizaio:2026-08-artifact-direct-download

Conversation

@taleodor

Copy link
Copy Markdown
Contributor

Adds endpoints to download TEA Artifact and signature contents.

Signed-off-by: Pavel Shukhman <pavel@reliza.io>
@Mehrn0ush

Copy link
Copy Markdown
Contributor

Hi,

Following up from the meeting — latest/download and {artifactVersion}/download currently share the same artifact-content response component, which means they both get Cache-Control: public, max-age=31536000, immutable. That's fine for the versioned endpoint since a revision never changes, but not for latest, since that's exactly the endpoint whose target does change over time. Right now a cache could hang onto a year-old copy and never revalidate, even after a new revision is published. Same problem on the signature side (latest/signature/download / artifact-signature-content).
I think latest/* needs its own cache policy, no immutable, probably no-cache or a short max-age instead.

@Mehrn0ush

Copy link
Copy Markdown
Contributor

One more question:
artifact-format.mediaType — mentions a media type MUST appear at most once across a revision's formats, which is good, but mediaType itself isn't marked required on the schema. If a format can be published without one, then selecting a download by mediaType query param or by Accept has nothing to match against for that format — how should a client target it, and how does the "at most once" uniqueness rule even apply to an absent value?

Signed-off-by: Pavel Shukhman <pavel@reliza.io>
@oej

oej commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

One more question: artifact-format.mediaType — mentions a media type MUST appear at most once across a revision's formats, which is good, but mediaType itself isn't marked required on the schema.

I think mediaType should be required.

taleodor pushed a commit to relizaio/transparency-exchange-api that referenced this pull request Sep 4, 2026
…e policy

`latest/download` and `latest/signature/download` shared the versioned
endpoints' response components and so inherited
`Cache-Control: public, max-age=31536000, immutable`. That is right for a
specific revision, which never changes, but wrong for latest, whose target
changes when a new revision is published: a cache could serve a year-old
copy without ever revalidating (review comment by @Mehrn0ush on CycloneDX#262).

- New responses `artifact-content-latest` and
  `artifact-signature-content-latest`, used by the two latest operations.
  Same headers as the versioned responses except `Cache-Control`, whose
  example is `no-cache`: caches may store the response but shall
  revalidate before reuse. The `ETag` is that of the resolved revision,
  so revalidation answers `304 Not Modified` until a new revision is
  published, at which point the tag changes.
- `Content-Location` on the latest responses names the versioned URL the
  request resolved to (RFC 9110 section 8.7), so a client gets a stable,
  reproducible reference in the same round trip instead of having to
  resolve the revision first.
- Shared headers moved to `components/headers` and referenced from all
  four responses, so the immutable and latest variants cannot drift.
- Versioned signature `ETag`: the caveat "unless the publisher re-signs
  the content" contradicted `immutable`. A signature is fixed with its
  revision; re-signed content is published as a new revision.

Validated with openapi-generator v7.12.0 (`validate`, and the Go batch
generation CI runs); the only warning, unused model
`compliance-document-type`, is pre-existing.

Signed-off-by: Claude Code (ReARM Agent) <rearm-agent-claude@reliza.io>
Co-authored-by: Claude Code (ReARM Agent) <rearm-agent-claude@reliza.io>

Signed-off-by: Pavel Shukhman <pavel@reliza.io>
taleodor pushed a commit to relizaio/transparency-exchange-api that referenced this pull request Sep 4, 2026
…external and optional

Follow-up to review comments on CycloneDX#262 by @Mehrn0ush (mediaType not
required, yet selection by mediaType and the at-most-once rule depend on
it) and @oej (agreed it should be required).

- `artifact-format.mediaType` is now required. The at-most-once rule
  therefore applies to every format, and a format can always be selected
  by media type for content and signature download. The
  `application/octet-stream` fallback for formats without a media type
  is removed from the content response, since the case no longer exists.
- `url` and `signatureUrl` are defined as always external locations,
  outside the TEA API, and optional. Present: clients retrieve from
  there. Absent: the TEA server hosts the bytes itself and clients
  retrieve them from the versioned download endpoints introduced by
  CycloneDX#262, selecting the format by mediaType; the signature endpoint
  answers 404 when no signature is published. This replaces the earlier
  guidance that a self-hosting server publishes its own endpoint's
  absolute URL as `url`, which required servers to know their external
  base URL and made the endpoints mere targets of self-generated links.
  The access-token rule is unchanged: tokens go only to the TEA server's
  own API base URL.
- Endpoint descriptions updated to match; tea-collection.md field list
  and notes updated, including that the mutable `latest` endpoints are
  never used as a format's `url` or `signatureUrl`.

Validated with openapi-generator v7.12.0 (`validate`; Go batch
generation as CI runs it). All examples already carry a mediaType.

Signed-off-by: Claude Code (ReARM Agent) <rearm-agent-claude@reliza.io>
Co-authored-by: Claude Code (ReARM Agent) <rearm-agent-claude@reliza.io>

Signed-off-by: Pavel Shukhman <pavel@reliza.io>
Signed-off-by: Pavel Shukhman <pavel@reliza.io>
@taleodor
taleodor force-pushed the 2026-08-artifact-direct-download branch from 3569272 to 54a3ea8 Compare September 4, 2026 16:42
@taleodor

taleodor commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

@Mehrn0ush @oej I believe those points above are addressed now, pls check.

@Mehrn0ush

Copy link
Copy Markdown
Contributor

Thanks @taleodor
Looks good. latest vs versioned cache split and required mediaType address the earlier comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants