Skip to content

docs(trust): add GitLab CI keyless signing integration#728

Draft
erran wants to merge 1 commit into
nolabs-ai:mainfrom
erran:worktree-document-gitlab
Draft

docs(trust): add GitLab CI keyless signing integration#728
erran wants to merge 1 commit into
nolabs-ai:mainfrom
erran:worktree-document-gitlab

Conversation

@erran

@erran erran commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Documents GitLab CI as a supported keyless signing provider alongside GitHub Actions. Adds the build_signer_uri publisher field (GitLab CI only), updates issuer and repository field descriptions to cover both providers, and includes verified branch/tag trust policy examples with a warning about over-broad wildcard allowlisting.

⚠️ opening a draft docs update geneested from my personal notes by Claude so I can cross-reference with what I add to the GitLab documentation itself.

Documents GitLab CI as a supported keyless signing provider alongside
GitHub Actions. Adds the `build_signer_uri` publisher field (GitLab CI
only), updates `issuer` and `repository` field descriptions to cover
both providers, and includes verified branch/tag trust policy examples
with a warning about over-broad wildcard allowlisting.

Signed-off-by: Erran Carey <ecarey@gitlab.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Apr 22, 2026
| `ref_pattern` | The git ref that triggered the workflow (e.g., `refs/heads/main`, `refs/tags/v1.0`). Use wildcards to trust a range of refs | Yes (`refs/tags/v*`) |
| `issuer` | The OIDC provider URL. GitHub Actions: `https://token.actions.githubusercontent.com`. GitLab: `https://gitlab.com` | No |
| `repository` | GitHub: the `owner/repo` string (maps to the `repository` OIDC claim). GitLab: the full project URL (e.g. `https://gitlab.com/org/repo`). Use wildcards to trust a range of repos | Yes (`org/*`, `https://gitlab.com/org/*`) |
| `workflow` | Path to the CI config file that performed the signing, relative to the repo root (e.g. `.github/workflows/sign.yml`) | Yes (`*`) |

@erran erran Apr 22, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Supports CI_CONFIG_REF_URI after #706 which could be better than signer URL in some cases such as pipeline policies from security projects.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the documentation to include comprehensive instructions and examples for GitLab CI integration with keyless signing. It introduces the build_signer_uri field and provides example trust policies for both branch and tag references. The review feedback focuses on aligning the documentation with the underlying implementation: specifically, the repository field should use the project path (e.g., org/repo) rather than a full URL, and the build_signer_uri and workflow fields should not include the https:// scheme to ensure successful verification.

| `workflow` | Path to the workflow file that performed the signing, relative to the repo root | Yes (`*`) |
| `ref_pattern` | The git ref that triggered the workflow (e.g., `refs/heads/main`, `refs/tags/v1.0`). Use wildcards to trust a range of refs | Yes (`refs/tags/v*`) |
| `issuer` | The OIDC provider URL. GitHub Actions: `https://token.actions.githubusercontent.com`. GitLab: `https://gitlab.com` | No |
| `repository` | GitHub: the `owner/repo` string (maps to the `repository` OIDC claim). GitLab: the full project URL (e.g. `https://gitlab.com/org/repo`). Use wildcards to trust a range of repos | Yes (`org/*`, `https://gitlab.com/org/*`) |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The description for GitLab's repository field states it should be the "full project URL", but the implementation in gitlab_keyless_predicate (line 616 of trust_cmd.rs) uses CI_PROJECT_PATH, which is the namespace/project string. Using the full URL in the trust policy will cause verification to fail as it won't match the identity claim extracted from the OIDC token.

| `repository` | GitHub: the `owner/repo` string (maps to the `repository` OIDC claim). GitLab: the project path (e.g. `org/repo`). Use wildcards to trust a range of repos | Yes (`org/*`) |

| `ref_pattern` | The git ref that triggered the workflow (e.g., `refs/heads/main`, `refs/tags/v1.0`). Use wildcards to trust a range of refs | Yes (`refs/tags/v*`) |
| `issuer` | The OIDC provider URL. GitHub Actions: `https://token.actions.githubusercontent.com`. GitLab: `https://gitlab.com` | No |
| `repository` | GitHub: the `owner/repo` string (maps to the `repository` OIDC claim). GitLab: the full project URL (e.g. `https://gitlab.com/org/repo`). Use wildcards to trust a range of repos | Yes (`org/*`, `https://gitlab.com/org/*`) |
| `workflow` | Path to the CI config file that performed the signing, relative to the repo root (e.g. `.github/workflows/sign.yml`) | Yes (`*`) |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For GitLab, the workflow field in the identity is set to the full URI (without scheme), not just the path relative to the repo root. The description should be updated to reflect this difference from GitHub's behavior.

| `workflow` | Path to the CI config file that performed the signing. GitHub: relative to repo root. GitLab: full URI (e.g. `gitlab.com/org/repo//.gitlab-ci.yml@refs/heads/main`) | Yes (`*`) |

| `issuer` | The OIDC provider URL. GitHub Actions: `https://token.actions.githubusercontent.com`. GitLab: `https://gitlab.com` | No |
| `repository` | GitHub: the `owner/repo` string (maps to the `repository` OIDC claim). GitLab: the full project URL (e.g. `https://gitlab.com/org/repo`). Use wildcards to trust a range of repos | Yes (`org/*`, `https://gitlab.com/org/*`) |
| `workflow` | Path to the CI config file that performed the signing, relative to the repo root (e.g. `.github/workflows/sign.yml`) | Yes (`*`) |
| `build_signer_uri` | GitLab CI only. Full URI of the CI configuration file and ref that performed the signing (e.g. `https://gitlab.com/org/repo//.gitlab-ci.yml@refs/heads/main`) | Yes (`*`) |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The example for build_signer_uri includes the https:// scheme, but the code in trust_cmd.rs (line 604) and GitLab's CI_CONFIG_REF_URI variable do not include it. Including the scheme in the policy will cause a mismatch during verification.

| `build_signer_uri` | GitLab CI only. Full URI of the CI configuration file and ref that performed the signing (e.g. `gitlab.com/org/repo//.gitlab-ci.yml@refs/heads/main`) | Yes (`*`) |


### Trust Policy for CI-Signed Files

GitLab uses `build_signer_uri` instead of `workflow` to identify the signing pipeline. The `repository` field takes the full project URL, and `issuer` is `https://gitlab.com`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The repository field should be the project path (e.g., org/repo), not the full project URL, to match the CI_PROJECT_PATH used in the implementation.

GitLab uses `build_signer_uri` instead of `workflow` to identify the signing pipeline. The `repository` field takes the project path (e.g. `org/repo`), and `issuer` is `https://gitlab.com`.

Comment on lines +408 to +409
"build_signer_uri": "https://gitlab.com/erran/skills//.gitlab-ci.yml@refs/heads/main",
"repository": "https://gitlab.com/erran/skills",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update the build_signer_uri and repository values to match the implementation (no https:// scheme for the URI, and project path for the repository).

      "build_signer_uri": "gitlab.com/erran/skills//.gitlab-ci.yml@refs/heads/main",
      "repository": "erran/skills",

Comment on lines +428 to +429
"build_signer_uri": "https://gitlab.com/erran/skills//.gitlab-ci.yml@refs/tags/0.0.9",
"repository": "https://gitlab.com/erran/skills",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update the build_signer_uri and repository values to match the implementation.

      "build_signer_uri": "gitlab.com/erran/skills//.gitlab-ci.yml@refs/tags/0.0.9",
      "repository": "erran/skills",

Note the double slash in the `build_signer_uri` path separator (`org/repo//.gitlab-ci.yml`). This is the format Fulcio embeds in the certificate — copy it exactly from `nono trust verify` output if you are unsure.

<Warning>
Wildcards in `build_signer_uri` and `repository` make it easy to over-trust. An entry with `issuer: https://gitlab.com` and `repository: https://gitlab.com/*` trusts any project on GitLab.com — including forks and unrelated projects. Scope `repository` to the specific project URL, and use `ref_pattern` to restrict to protected branches or release tags.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The warning example should use the project path format for consistency with the implementation.

  Wildcards in `build_signer_uri` and `repository` make it easy to over-trust. An entry with `issuer: https://gitlab.com` and `repository: *` trusts any project on GitLab.com — including forks and unrelated projects. Scope `repository` to the specific project path, and use `ref_pattern` to restrict to protected branches or release tags.

```yaml
nono-cli-sign:
image:
name: ghcr.io/always-further/nono:0.36.0

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outdated already 😬 In the GitLab docs we could refer to CI/CD component equivalent of the GitHub action for attestation.

We can point this entire GitLab signing section to GitLab docs if that makes sense. 👍🏽

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally I’m playing around with having a Flow which can be enabled in GitLab.com projects which has nono and glab installed to download bundle from the latest pipeline from a default branch or tag.

example output

Click to expand Image Image Image

@lukehinds

Copy link
Copy Markdown
Contributor

Just let me know with a tag when you want eyes on this @erran

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

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants