Resolve "Modify PublishProvenanceService to persist attestation"
What does this MR do and why?
This MR and the involved changes
This merge request persists Sigstore bundles into the database. This is the integration of "Modify PublishProvenanceService so that it calls cosign, performing attestation." and "Add file uploader for SLSA attestations". The next merge requests will deal with retrieving these bundles and providing a way for users to verify the integrity of their artifacts.
This will happen only where the FF is enabled, and attestation has been explicitly enabled. More info in testing section.
What are "Sigstore bundles"?
The grouppipeline security group is working towards providing users with SLSA Level 3 Provenance Attestations. Quoting from the SLSA documentation, it states that attestations are:
It’s the verifiable information about software artifacts describing where, when, and how something was produced. For higher SLSA levels and more resilient integrity guarantees, provenance requirements are stricter and need a deeper, more technical understanding of the predicate. Describe how an artifact or set of artifacts was produced so that:
- Consumers of the provenance can verify that the artifact was built according to expectations.
- Others can rebuild the artifact, if desired.
As a simplified TL;DR, in the context of GitLab, a provenance statement is a JSON document that correlates the SHA-256 sum of an artifact with the build information. A worker then performs a digital signature, called a provenance attestation, stored as a "Sigstore Bundle" blob. This is a highly sought-after feature, particularly for our GitLab Ultimate customers.
References
- ticket: Modify PublishProvenanceService to persist attestation
- Add file uploader for SLSA attestations
- Modify PublishProvenanceService so that it calls cosign, performing attestation.
- [FF]
slsa_provenance_statement-- Roll out feature flag to publish SLSA provenance statements - [Discussion] UX to enable SLSA provenance generation
Testing locally:
To test this end-to-end, we need an OIDC provider that Fulcio can reach and is allowlisted. In production, this is simple because gitlab.com is an authorised OIDC provider. Locally, there are some prerequisites.
- Install sigstore, as documented in Sigstore Local. This will install Fulcio, Rekor and TUF.
- You need to configure GDK to have runners enabled as documented in doc/howto/runner.md · main · GitLab.org / GitLab Development Kit · GitLab
- You need to configure your local
cosigncommand to use the local TUF by running regenerating TUF,cd tuf/repository, executingpython3 -m http.server, and thencosign initialize --mirror http://localhost:8000 --root ~/root.json - You need to configure a build that generates an artifact and uses our temporary environment variable GENERATE_PROVENANCE to trigger a build, and properly populates the
SIGSTORE_ID_TOKENvariable. The project associated with the build must be public. - The build must have an age of less than 60 minutes. This is because
SIGSTORE_ID_TOKENexpires after that time.
The following .gitlab.yml file complies with the requirements above.
build-job:
stage: build
variables:
GENERATE_PROVENANCE: true
id_tokens:
SIGSTORE_ID_TOKEN:
aud: sigstore
script:
- echo "Hello, $GITLAB_USER_LOGIN!"
- echo "Hello, $GITLAB_USER_LOGIN!" > test.txt
artifacts:
paths:
- test.txt
Once that is in place
% COSIGN_FULCIO_URL="http://sigstore.local:5555" COSIGN_REKOR_URL="http://sigstore.local:3090" bundle exec rails c
> build = Ci::Build.last; pps = Ci::Slsa::PublishProvenanceService.new(build);
[...]
> pps.execute
[...]
=> #<ServiceResponse:0x000000032b259580
@http_status=:ok,
@message="OK",
@payload=
{:attestations=>
[#<SupplyChain::Attestation:0x000000015d717d08
id: 17,
created_at: Mon, 29 Sep 2025 03:33:08.742091000 UTC +00:00,
updated_at: Mon, 29 Sep 2025 03:33:08.742091000 UTC +00:00,
project_id: 20,
build_id: 400,
status: "success",
expire_at: Wed, 29 Sep 2027 03:33:08.737975000 UTC +00:00,
predicate_kind: "provenance",
predicate_type: "https://slsa.dev/provenance/v1",
subject_digest: "3c5bba498d6f7a2cb4c195cf0873c8b68c9407f04dfa9acaad7fe4875e5e93f1",
file: "attestation-20250929-13540-q1gkmp.bundle",
file_store: 1>]},
@reason=nil,
@status=:success>
> a = SupplyChain::Attestation.last
> a.file.read
=> "{\"mediaType\":\"application/vnd.dev.sigstore.bundle.v0.3+json\",\"verificationMaterial\":{\"certificate\":{\"rawBytes\":\"MIIFyjCCBVGgAwIBAgIUUwF2f95As+4QTt4lsvnr5xQOWQswCgYI
KoZIzj0EAwMwaTEMMAoGA1UEBhMDVVNBMREwDwYDVQQIEwhBbnlQbGFjZTEQMA4GA1UEBxMHQW55dG93bjEUMBIGA1UECRMLMTIzIE1haW4gU3QxDzANBgNVBBETBkFCQ0RFRjENMAsGA1UEChMEYWNtZTAeFw0yNTA5MjkwMzMzMDhaFw0
yNTA5MjkwMzQzMDhaMAAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS51osueUBOvXOlSUW/Qn9qxlidvMskx6rOAw1OhmANEhkvY5XW9WD0+9S9ewRf5sU67lq2atflZZ1PgZUhnhyZo4IEPjCCBDowDgYDVR0PAQH/BAQDAgeAMBMGA1
UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBTsY64rSw7IdOL+1iQhdh9nXHW19zAfBgNVHSMEGDAWgBTkoCXkrI1TAK8OKo8/Tollcu4UPjBZBgNVHREBAf8ETzBNhktodHRwczovL2dkay50ZXN0OjMwMDAvcm9vdC90ZXN0LXNsc2Etd
29ya2VyLy8uZ2l0bGFiLWNpLnltbEByZWZzL2hlYWRzL21haW4wIgYKKwYBBAGDvzABAQQUaHR0cDovL2dkay50ZXN0OjMwMDAwJAYKKwYBBAGDvzABCAQWDBRodHRwOi8vZ2RrLnRlc3Q6MzAwMDBbBgorBgEEAYO/MAEJBE0MS2h0dHBz
Oi8vZ2RrLnRlc3Q6MzAwMC9yb290L3Rlc3Qtc2xzYS13b3JrZXIvLy5naXRsYWItY2kueW1sQHJlZnMvaGVhZHMvbWFpbjA4BgorBgEEAYO/MAEKBCoMKDU2YzdhY2RmMWY4OTFlZDZmYWVlZGM1ODkxZGNlMTdkOGNlMDgxYjAwGwYKKwY
BBAGDvzABCwQNDAtzZWxmLWhvc3RlZDA4BgorBgEEAYO/MAEMBCoMKGh0dHBzOi8vZ2l0bGFiLmNvbS9yb290L3Rlc3Qtc2xzYS13b3JrZXIwOAYKKwYBBAGDvzABDQQqDCg1NmM3YWNkZjFmODkxZWQ2ZmFlZWRjNTg5MWRjZTE3ZDhjZT
A4MWIwMB8GCisGAQQBg78wAQ4EEQwPcmVmcy9oZWFkcy9tYWluMBIGC[...]
Database Full query + Plan
Full query for destroy call, as required by Danger:
> existing_attestation.destroy
SupplyChain::Attestation Destroy (0.5ms) DELETE FROM "slsa_attestations" WHERE "slsa_attestations"."id" = 7 /*application:console,db_config_database:gitlabhq_development,db_config_name:main,console_hostname:sroque-worcel--20250519-QHYJX,console_username:samroque-worcel,line:(pry):3:in `__pry__'*/
Explain plan:
EXPLAIN ANALYZE DELETE FROM "slsa_attestations" WHERE "slsa_attestations"."id" = 7;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
Delete on slsa_attestations (cost=0.15..2.17 rows=0 width=0) (actual time=0.034..0.034 rows=0 loops=1)
-> Index Scan using slsa_attestations_pkey on slsa_attestations (cost=0.15..2.17 rows=1 width=6) (actual time=0.033..0.034 rows=0 loops=1)
Index Cond: (id = 7)
Planning Time: 0.756 ms
Execution Time: 0.160 ms
(5 rows)
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to #567885 (closed)