Permissions
Every Copia Actions job is given a short-lived token (${{ secrets.COPIA_TOKEN }}) that the job uses to talk back to Copia — for example to clone the repository, push commits, and comment on pull requests. The token permissions system controls what that token is allowed to do.
This page describes how to configure those defaults at the organization and repository level, how to narrow them further from inside a workflow, and what behavior to expect when something is denied.
Default posture: out of the box, the Actions token can read code and releases on the job's own repository, and nothing else. Any workflow that needs to write to the repo (push commits, open PRs, upload releases) or read non-code units (issues, wiki) must either be granted broader permissions by an admin, or declare an explicit permissions: block in the workflow YAML.
How permissions are resolved
When a job is dispatched to a runner, Copia computes the effective permission set for that job's token. Three inputs combine to produce the final answer:
The two default modes
Both repositories and organizations have a single "default token permission mode" setting with two choices:
Restricted
Read access to Code and Releases on the job's repository. No access to Issues, Pull Requests, or Wiki.
Permissive
Read and write access to all units on the job's repository (Code, Issues, Pull Requests, Wiki, Releases).
These defaults only apply when a workflow does not declare its own permissions: block. A workflow can always narrow further — it just can't go higher than the ceiling configured for the repository or organization.
Restricted is the out-of-the-box default, and it is stricter than the implicit "read everything" behavior most CI systems use. Workflows that read issues, pull requests, or the wiki via COPIA_TOKEN will receive 403 Forbidden or 404 Not Found responses unless their workflow declares the matching permissions: block, or an admin switches the repository (or its organization) to Permissive.
Permission scopes
Permissions are granted per unit, where each unit corresponds to a feature of the repository. Each unit can be set to No access, Read, or Write.
Code
code or contents
Cloning, pushing commits, reading file contents
Issues
issues
Reading and creating issues and issue comments
Pull Requests
pull-requests
Reading and creating PRs, leaving review comments, merging
Wiki
wiki
Reading and updating the repository wiki
Releases
releases or contents
Reading and creating releases and release assets
A few notes:
contents:is a shorthand that applies to bothcodeandreleases. If you specifycode:orreleases:individually, the individual value wins.GitHub-only and unused scopes (
packages,projects,id-token,checks,pages,deployments,attestations,security-events,statuses,discussions, etc.) are accepted for compatibility but have no effect in Copia. Workflows ported from GitHub Actions do not need to be edited to remove them.
Configuration
Organization-level (owner) settings
Organization owners can set the default mode and the maximum-permission ceiling for every repository owned by the organization that does not opt out.
Go to your organization on Copia, then Settings → Actions → General.

The page has two sections:
Default Token Permissions — pick Permissive or Restricted. This is the mode every repository in the organization inherits unless it overrides.
Maximum Token Permissions — optional ceiling. Enable Customize maximum permissions to expose the unit-by-unit table. Any permission requested by a workflow above the ceiling is clamped down.
When Customize maximum permissions is unchecked, the ceiling is effectively "write on everything" — i.e., the only thing limiting a workflow is the default mode and the workflow's own permissions: declaration.
You must be an organization Owner to view or modify these settings.
Repository-level settings
Repository admins can configure the same knobs per-repository, and choose whether the repository follows the organization or overrides it.
Go to your repository on Copia, then Settings → Actions → General.

The page has three parts:
Override owner-level configuration — when off (the default), the repository inherits everything from the organization, and the mode/maximum controls below are disabled. When on, the repository's own configuration is used and the organization's settings are ignored for this repository.
Default Token Permissions — same Permissive/Restricted choice as the organization page, applied only when override is on.
Maximum Token Permissions — same per-unit ceiling table as the organization page, applied only when override is on.
You must be a repository Admin to view or modify these settings.
Toggling override off does not delete the repository's saved configuration — it just stops applying it. If you turn override off and back on later, the previously saved mode and maximum table are still there.
Declaring permissions in a workflow
The recommended pattern is to leave the org/repo default at Restricted and have each workflow opt into exactly the permissions it needs. This makes the workflow self-documenting and survives changes to the org default.
permissions: can be declared at the workflow level (applies to every job) or at the job level (applies only to that job). A job-level block fully replaces the workflow-level block for that job — they do not merge.
Workflow-level
Job-level
Shorthand values
Instead of a per-scope mapping, you can use a single keyword:
read-all
Read access on every supported unit
write-all
Read and write access on every supported unit
{} (empty mapping)
No access on any unit
Any other scalar value (e.g., permissions: foo) parses to "no access on any unit" — i.e., the safer interpretation.
Per-scope values
Each scope accepts read, write, or none:
Scopes you do not list default to no access when you declare a permissions: block. This is intentional — declaring permissions: means "I am taking responsibility for the full permission set of this workflow."
Re-runs and configuration changes
The permissions a job declared in its workflow YAML are stored on the job row at dispatch time, but the clamp against the org/repo configuration is re-applied every time the token is used. Concretely:
If you tighten the org maximum after a job is already running, the running job's in-flight requests immediately start hitting the new, tighter ceiling.
If you re-run a previous job, the workflow's declared permissions are reused as-is, but the org/repo ceiling that exists at the time of the re-run is what gets applied. You do not have to re-trigger the workflow from a push to pick up new ceiling values.
Troubleshooting
My workflow used to work and now I'm getting 403s on issue/PR comments.
The fork's default mode is Restricted, which grants read on Code and Releases only. Either declare the permissions your workflow needs in its YAML:
…or ask an admin to switch the organization (or just this repository) to Permissive.
A workflow on a feature branch declares `permissions: write-all`, but the token still can't push.
Check the organization's Maximum Token Permissions. A workflow can never request more than the ceiling allows — if the org's max for Code is set to Read, then write-all in the workflow is clamped down to read. Either raise the org maximum or, if appropriate, enable override on the repository and raise the repository's maximum instead.
Last updated
Was this helpful?
