Permissions
Mate uses an IAM-style permission model. Every agent declares a set of authorities it is allowed to use. At dispatch time, Mate computes the effective authority set by applying any deny rules from the trigger and from the tenant-wide configuration. The effective set determines both what the agent can do and the access level of the short-lived GitLab token minted for the job.
Authority resolution
Section titled “Authority resolution”The effective authority set for a job is computed as:
effective = agent.permissions − trigger.deny − tenant.denyExplicit deny at any layer always wins. If an authority is listed in trigger.deny or in the top-level tenant.deny, it is removed from the effective set regardless of what agent.permissions says. An empty effective set causes the job to be refused — an agent with no granted authorities cannot do anything meaningful.
Deny layers
Section titled “Deny layers”| Layer | Where it is set | Scope |
|---|---|---|
agent.permissions | Agent definition in tenant config or .mate.yml | Defines the maximum possible set for this agent. |
trigger.deny | Individual trigger entry | Subtracts authorities for this trigger only. The agent’s full permissions are still used when the agent is invoked from other triggers. |
tenant.deny | Top-level deny: list in tenant config | Subtracts authorities from every agent, for every trigger, across the entire tenant. Cannot be overridden by .mate.yml. |
Example
Section titled “Example”# tenant configdeny: - merge # no agent may merge, tenant-wide
agents: contributor: permissions: [read, comment, push_branch, open_mr, merge]
triggers: - on: issue_assigned agent: contributor deny: [push_branch] # this trigger: comment only, no push
- on: mr_opened agent: contributor # no trigger deny; effective = {read, comment, push_branch, open_mr} # (merge was removed by tenant.deny)For the issue_assigned trigger:
{read, comment, push_branch, open_mr, merge} − {push_branch} # trigger.deny − {merge} # tenant.deny= {read, comment, open_mr}The nine authorities
Section titled “The nine authorities”| Authority | Status | What it allows |
|---|---|---|
read | Available now | Read repository content, file trees, issues, MRs, pipelines, and all other project data. |
comment | Available now | Post comments on issues and MRs. |
push_branch | Reserved — tools not yet enabled | Push commits to any branch (new or existing). |
push_mr_branch | Reserved — tools not yet enabled | Push commits to a branch. (A narrowing to the current MR’s source branch is intended but not yet enforced.) |
open_mr | Reserved — tools not yet enabled | Open a new merge request, or update an existing MR’s title, description, or labels. |
merge | Reserved — tools not yet enabled | Merge an open MR. Requires the MR to pass all required approvals — Mate cannot bypass them. |
close_issue | Reserved — tools not yet enabled | Close an issue. |
update_issue | Reserved — tools not yet enabled | Update issue fields: title, description, labels, and state. |
touch_ci | Reserved — tools not yet enabled | Retry or cancel pipeline jobs. |
Any unknown authority string in permissions: or deny: is a validation error and causes the entire config to be rejected.
approve_mr does not exist
Section titled “approve_mr does not exist”There is no approve_mr authority and it is not grantable. This is by design: an agent can never approve a merge request. Approvals require a human reviewer in GitLab. This is a separation-of-duties constraint — an agent that opens an MR and then also approves it would eliminate the human checkpoint that approvals are designed to enforce.
GitLab token access level
Section titled “GitLab token access level”When Mate dispatches a job, it mints a short-lived GitLab project access token scoped to the minimum permissions required by the effective authority set. The access level and token scopes are derived automatically from the effective authorities:
| Effective authorities include | Token scopes | GitLab access level |
|---|---|---|
Only read | read_api, read_repository | Reporter |
comment, close_issue, or update_issue | api, read_repository | Reporter |
push_branch, push_mr_branch, or open_mr | api, read_repository, write_repository | Developer |
merge or touch_ci | api, read_repository, write_repository | Maintainer |
The highest applicable tier wins. If the effective set includes both comment and push_branch, the token is minted at Developer level.
The per-job token is the only GitLab credential the agent ever holds. It is scoped to a single project and expires when the job ends. The master GitLab token (configured in the tenant) never enters the agent container.
Narrowing permissions in .mate.yml
Section titled “Narrowing permissions in .mate.yml”A per-repository .mate.yml can narrow an agent’s permissions but never expand them. The effective permissions of any repo-defined agent must be a subset of the base (tenant) agent’s permissions. Attempting to add an authority the base agent does not have is a merge-time error.
agents: reviewer: permissions: [read, comment] # OK: subset of tenant reviewer's [read, comment, push_branch, open_mr]# .mate.yml — this will failagents: reviewer: permissions: [read, comment, merge] # Error: merge is not in the base agent's permissionsSetting up permissions in practice
Section titled “Setting up permissions in practice”Start with the minimum authority set your agent needs and expand only when required.
For a read-only reviewer that posts comments:
permissions: [read, comment]For an agent that implements issues by pushing a branch and opening an MR:
permissions: [read, comment, push_branch, open_mr]For an agent that fixes CI failures on the current MR branch:
permissions: [read, comment, push_mr_branch, touch_ci]For an agent that manages issues (comments, updates labels, closes when done):
permissions: [read, comment, close_issue, update_issue]