CI trust rules
The repositories whose GitHub Actions or GitLab CI jobs may post annotations with their OIDC token, without a stored secret.
A trust rule lets a repository's CI jobs post annotations with the OIDC token that their provider gives each job, in place of an ingest key. To set one up end to end, follow Post from CI without a secret.
Anyone in the organization may list the rules. Owners and admins create and delete them, with a personal access token, or with an OAuth sign-in that has organization:manage.
Rules work with github.com and gitlab.com. GitHub Enterprise Server and self-managed GitLab aren't supported yet.
The trust rule object
public_idstringserverctr_…
providerenumrequiredOne of github, gitlab
repositorystringrequiredowner/repo on GitHub, or the project's path on GitLab, such as acme/platform/checkout.
repository_idstring, nullableoptionalThe provider's id for the repository. Left out, the first job that the rule lets in sets it. From then on the rule matches the id, not the name, so a renamed or recreated repository doesn't inherit the trust.
Rules: digits only.
refstring, nullableoptionalOnly jobs on this ref, such as refs/heads/main or refs/tags/v1.42.0. Null for any ref.
Rules: a full ref, starting refs/heads/ or refs/tags/.
environmentstring, nullableoptionalOnly jobs in this deployment environment, such as production. Null for any environment, or none.
Rules: not blank.
created_byobject, nullableserverThe person who created it.
created_attimestampserverWhen it was created.
Which jobs a rule lets in
A job's token gets in when it is valid and a rule matches it:
- The token's signature checks out against the provider's published keys.
- It was issued by the provider, it is addressed to
telemetrymachine.com, and it hasn't expired. Otherwise the call gets 401. - A rule of the organization in the URL names the job's repository, by id once the rule has one, and the job's ref and environment, where the rule names them. Otherwise the call gets 403.
A job must match everything that a rule names. To let in the jobs on main and also the jobs in production, create two rules. A GitLab branch such as main is matched as refs/heads/main.
A job that gets in may create annotations and retry its own keys. It can't update or delete annotations.
Create a trust rule
/api/organizations/{org}/ci-trust-rulesTakes the fields of the trust rule object that are marked required or optional.
curl -X POST https://telemetrymachine.com/api/organizations/<your-org>/ci-trust-rules \
-H "Authorization: Bearer $TM_TOKEN" -H 'Content-Type: application/json' \
-d '{ "provider": "github", "repository": "acme/checkout", "ref": "refs/heads/main" }'POST /api/organizations/<your-org>/ci-trust-rules
Authorization: Bearer TOKEN
Content-Type: application/json
{ "provider": "github", "repository": "acme/checkout", "ref": "refs/heads/main" }{
"status": 200,
"data": {
"public_id": "ctr_01m5z3h7q2w8e4r6t1y9u0i5op",
"provider": "github",
"repository": "acme/checkout",
"repository_id": null,
"ref": "refs/heads/main",
"environment": null,
"created_by": { "display_name": "Maya", "email": "[email protected]" },
"created_at": "2026-10-26T16:20:00.000Z"
}
}List trust rules
/api/organizations/{org}/ci-trust-rulesDelete a trust rule
/api/organizations/{org}/ci-trust-rules/{public_id}Jobs that no other rule lets in can't post from then on. The annotations that they posted stay.
Errors
| Status | When | What to do |
|---|---|---|
| 400 | A field breaks its rules, such as a ref that isn't a full ref | Fix the field that the error names. |
| 403 | You aren't an owner or admin, or an OAuth sign-in lacks organization:manage | Ask an owner or admin, or sign in with the scope. |
| 404 | The organization has no rule with this public_id | Check the id with List. |