Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 78 additions & 4 deletions docs/cli/features/trust.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,11 @@ These fields are matched against claims in the Fulcio certificate that Sigstore
| Field | Description | Wildcards |
|-------|-------------|-----------|
| `name` | Human-readable label for this publisher (not matched against anything) | No |
| `issuer` | The OIDC provider URL. For GitHub Actions this is always `https://token.actions.githubusercontent.com` | No |
| `repository` | The `owner/repo` that ran the signing workflow (maps to the GitHub OIDC `repository` claim). Use `org/*` to trust all repos in an org | Yes (`org/*`) |
| `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/*`) |

| `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.

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 (`*`) |

| `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 (`*`) |

| `ref_pattern` | The git ref that triggered the job (e.g., `refs/heads/main`, `refs/tags/v1.0`). Use wildcards to trust a range of refs | Yes (`refs/tags/v*`) |

### blocklist

Expand Down Expand Up @@ -367,6 +368,79 @@ jobs:

This policy declares: only trust files signed by a GitHub Actions workflow in `my-org/my-repo`, from the `main` branch.

## GitLab CI Integration

Keyless signing also integrates with GitLab CI's OIDC tokens. The signing job must request an ID token with the `sigstore` audience so Fulcio can issue a certificate.

### Signing Job

```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

entrypoint: [""]
script:
- nono trust sign --all --keyless
id_tokens:
SIGSTORE_ID_TOKEN:
aud: sigstore
artifacts:
paths:
- "**/*.bundle"
```

The `id_tokens` block instructs GitLab to inject a short-lived OIDC token into `$SIGSTORE_ID_TOKEN`. Nono reads this variable automatically when `--keyless` is specified — no additional configuration is needed.

### 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`.


**Branch ref:**

```json
{
"version": 1,
"includes": ["SKILLS*", "CLAUDE*"],
"publishers": [
{
"name": "erran-skills@main",
"issuer": "https://gitlab.com",
"build_signer_uri": "https://gitlab.com/erran/skills//.gitlab-ci.yml@refs/heads/main",
"repository": "https://gitlab.com/erran/skills",
Comment on lines +408 to +409

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",

"ref_pattern": "refs/heads/main"
}
],
"blocklist": { "digests": [] },
"enforcement": "deny"
}
```

**Tag ref:**

```json
{
"version": 1,
"includes": ["SKILLS*", "CLAUDE*"],
"publishers": [
{
"name": "erran-skills@0.0.9",
"issuer": "https://gitlab.com",
"build_signer_uri": "https://gitlab.com/erran/skills//.gitlab-ci.yml@refs/tags/0.0.9",
"repository": "https://gitlab.com/erran/skills",
Comment on lines +428 to +429

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",

"ref_pattern": "refs/tags/0.0.9"
}
],
"blocklist": { "digests": [] },
"enforcement": "deny"
}
```

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.

</Warning>

## Signing Modes

There are two signing modes, with two key storage backends for keyed signing:
Expand Down