Build-Info Provenance
Every artifact in OrbitalReg can carry a build-info envelope that links it back to the CI pipeline that produced it. Once a build-info record is attached, the artifact-detail page renders a Provenance card with three sections — Source, Build, and Signing — so an operator answering a compliance audit (or a curious developer) can trace a JAR / wheel / image / chart back to the commit + CI run + signing identity in one click.
The card lives at /artifacts/<id> (visible to anyone who can read the artifact's project).
What the card shows
The card stacks one expandable panel per CI build that declared the artifact's SHA-256. The most-recent build is open by default. Multiple builds for the same SHA is normal — a re-run of a release candidate produces byte-identical artifacts and that's usually what you want.
Source
Where the bytes came from in version control.
| Field | Source |
|---|---|
| Commit | body.vcsRevision |
| Branch | body.vcs.branch or body.vcsBranch |
| Repository | body.vcsUrl |
| Author | body.principal |
| Started | body.started (ISO-8601) |
Empty cells render as — rather than disappearing, so a partially- populated envelope still makes it obvious which CI emitter is missing a field.
Build
Which CI run produced the bytes.
| Field | Source |
|---|---|
| CI system | inferred from body.agent.name + body.buildUrl (GitHub Actions, GitLab CI, Jenkins, CircleCI, Buildkite, TeamCity, Drone, Azure Pipelines, Bamboo) |
| Agent | body.agent.name + body.agent.version |
| Run URL | body.buildUrl or body.url |
| Step | module.id → artifact.name |
| Build | deep-link into /projects/<id>/builds/<name>/<number> |
Signing
Sigstore subject / issuer / Rekor inclusion.
The current schema doesn't persist a per-artifact verification record yet, so this section renders an explicit Not recorded state with a pointer at /admin/trust#sigstore for configuring an upload-time policy. When a future migration lands the column set, the card will populate the values without page-level changes.
Populating the card from CI
The card only renders for artifacts whose SHA-256 matches a row in build_info_artifacts. The denormalised view is refreshed atomically on every PUT /api/build submission, so the only thing a CI lane needs to do is publish a standard Build-Info envelope.
GitHub Actions
- name: Publish JAR
run: mvn -B deploy
- name: Publish Build-Info to OrbitalReg
env:
ORBITALREG_TOKEN: ${{ secrets.ORBITALREG_TOKEN }}
run: |
cat > build-info.json <<JSON
{
"name": "${{ github.workflow }}",
"number": "${{ github.run_id }}",
"started": "$(date -Iseconds)",
"buildUrl": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"vcsUrl": "${{ github.server_url }}/${{ github.repository }}",
"vcsRevision": "${{ github.sha }}",
"vcsBranch": "${{ github.ref_name }}",
"principal": "${{ github.actor }}",
"agent": { "name": "github-actions", "version": "${{ runner.os }}" },
"modules": [{
"id": "com.acme:my-app:${{ github.run_id }}",
"artifacts": [{
"name": "my-app-${{ github.run_id }}.jar",
"type": "jar",
"sha256": "$(sha256sum target/my-app.jar | awk '{print $1}')"
}]
}]
}
JSON
curl -fsS -X PUT \
-H "Authorization: Bearer $ORBITALREG_TOKEN" \
-H "Content-Type: application/json" \
"https://orbitalreg.example.com/api/build?project=acme.platform" \
--data-binary @build-info.jsonGitLab CI
publish-build-info:
stage: post-publish
image: curlimages/curl:latest
script:
- |
cat > build-info.json <<JSON
{
"name": "$CI_PROJECT_NAME",
"number": "$CI_PIPELINE_ID",
"started": "$(date -Iseconds)",
"buildUrl": "$CI_PIPELINE_URL",
"vcsUrl": "$CI_REPOSITORY_URL",
"vcsRevision": "$CI_COMMIT_SHA",
"vcsBranch": "$CI_COMMIT_REF_NAME",
"principal": "$GITLAB_USER_LOGIN",
"agent": { "name": "gitlab-ci", "version": "$CI_RUNNER_VERSION" },
"modules": [ ... ]
}
JSON
- |
curl -fsS -X PUT \
-H "Authorization: Bearer $ORBITALREG_TOKEN" \
-H "Content-Type: application/json" \
"$ORBITALREG_URL/api/build?project=$ORBITALREG_PROJECT" \
--data-binary @build-info.jsonThe name and number together form the build's unique key per project; re-publishing the same (name, number) pair upserts the envelope, so a re-run of the same pipeline doesn't duplicate the row.
What ends up in the card vs. what gets stored
OrbitalReg stores the entire submitted envelope as a JSONB body, so custom fields the standard Build-Info schema doesn't define round-trip on GET /api/build/<name>/<number> without loss. The artifact-detail card pulls the canonical subset documented above; everything else is visible on the project-scoped Build-Detail page at /projects/<id>/builds/<name>/<number>.
Out of scope
- Editing provenance — the card is read-only. Provenance is written at upload time, not in the UI.
- SBOM render — handled separately on the project-scoped Build- Detail page (CycloneDX 1.5 download via the Export SBOM action).
- Cross-project provenance — for a SHA shared across multiple projects, the card only renders builds the caller has read access to. The visibility filter sits on the same
VisibleProjectIDshelper every other v1 read endpoint uses, so a shared library uploaded into a sibling project never leaks into the card.