For the complete documentation index, see llms.txt. This page is also available as Markdown.

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:

1

Workflow declaration (most specific)

If the workflow or job declares a permissions: block, that declaration is the starting point. Anything not listed defaults to no access.

2

Repository and organization defaults

If the workflow does not declare permissions:, Copia uses the configured default mode (Permissive or Restricted) from the repository's Actions settings — or, if the repository does not override its owner, from the organization's Actions settings.

3

Maximum-permission ceiling

Whichever starting point applies, the result is then clamped by the maximum permissions configured at the repository (when override is on) or at the organization. A workflow can never grant itself more than the ceiling allows.

The two default modes

Both repositories and organizations have a single "default token permission mode" setting with two choices:

Mode
What the token gets by default

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.

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.

Unit
Workflow YAML key
Controls

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 both code and releases. If you specify code: or releases: 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:

Value
Meaning

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.

My workflow has `packages:` or `projects:` lines copied from GitHub Actions. Do I need to remove them?

No. Copia does not have packages or projects features, so those scopes are parsed and ignored. Workflows ported from GitHub Actions do not need to have them stripped out.

Last updated

Was this helpful?