Add CI job project and commit to token-exchange payload
What does this MR do and why?
This adds CI job provenance to the token minted by POST /api/v4/token_exchange (API::Authn::TokenExchange, ee/lib/api/authn/token_exchange.rb), which issues a short-lived RS256 JWT for modular services such as Artifact Registry via Authn::TokenExchange::TokenIssuer (ee/lib/authn/token_exchange/token_issuer.rb).
TokenIssuer now accepts an optional job: keyword. When present, the nested gitlab claim gains a job object with project_id (the job's project id, as an integer) and git_commit_sha (the commit the job ran against, as a string). The endpoint passes current_authenticated_job, which is only set when the caller authenticated with a CI job token. For personal access tokens, OAuth tokens, and project/group access tokens, the job key is absent, since the payload hash is .compacted.
Artifact Registry's Version resource has project_id and git_commit_sha fields for build provenance, and they read null on every version today because the token carried nothing to populate them. Publisher identity already comes from gitlab.local_id; this MR only adds the two missing fields.
The change is additive: SCHEMA_VERSION stays 1, and the shared Go verifier gitlab.com/gitlab-org/auth/iam/pkg/userauth ignores unknown claims, so this can merge before the verifier learns the new fields.
Also fixed a stale comment in the endpoint that incorrectly said a job token authenticates as a per-build bot user; it actually authenticates as the job's user (the pipeline's triggering user). Updated the endpoint desc and regenerated doc/api/openapi/openapi_v3.yaml to match.
This is a token payload change and needs AppSec review before merge.
References
- Work item: #629690
- ADR-020 amendment: gitlab-com/content-sites/handbook!21210 (merged)
- Artifact Registry write-side work item: gitlab-org/ops/artifact-registry#1275
- Follow-up needed in the IAM Go verifier to read these fields (no MR yet)
Screenshots or screen recordings
Not applicable, this is an API-only change with no UI impact.
How to set up and validate locally
- Run a GDK with a CI runner and a project.
- From a CI job, request a token:
curl --request POST --form audience=gitlab-artifact-registry \
--header "JOB-TOKEN: $CI_JOB_TOKEN" \
"$CI_API_V4_URL/token_exchange"- Decode the returned JWT (for example with
jwt decode, or by base64-decoding the middle segment) and confirmgitlab.job.project_idequals$CI_PROJECT_IDandgitlab.job.git_commit_shaequals$CI_COMMIT_SHA. - Call the same endpoint with a PAT instead:
curl --request POST --form audience=gitlab-artifact-registry \
--header "PRIVATE-TOKEN: <pat>" \
"$CI_API_V4_URL/token_exchange"Confirm the decoded token has no gitlab.job key.
New examples cover this in ee/spec/lib/authn/token_exchange/token_issuer_spec.rb (job absent without a job, present with a job, ver stays 1) and ee/spec/requests/api/authn/token_exchange_spec.rb (job-token request carries project and sha, PAT request does not). All 53 examples pass.
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.