> ## Documentation Index
> Fetch the complete documentation index at: https://code.storage/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Ref Policies

> Use JWT ref policies for branch protection. Limit the refs that a token can update and the update types it permits.

Code Storage uses ref policies for branch protection. Each ref policy limits writes from one JWT.

A ref policy is not a repository setting. It applies only to a request that uses its JWT. Give each
client or task a JWT with the limits it needs.

<Note>
  A `git:write` scope grants write access. A ref policy can limit that access, but it cannot grant
  access.
</Note>

The SDK accepts `refPolicies` on `getRemoteURL()`, `getEphemeralRemoteURL()`, and
`getImportRemoteURL()`. The write methods in this guide also accept this option.

## Policy operations

| Operation       | Constant                                                      | Effect                                                                                                                  |
| --------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `no-force-push` | `OP_NO_FORCE_PUSH` (TypeScript/Python) / `OpNoForcePush` (Go) | Reject a non-fast-forward move when the ref already exists. Permit ref creation, ref deletion, and a fast-forward move. |
| `no-push`       | `OP_NO_PUSH` (TypeScript/Python) / `OpNoPush` (Go)            | Reject all updates to the matched ref. This includes ref creation and deletion.                                         |
| `verify-sig`    | `OP_VERIFY_SIG` (TypeScript/Python) / `OpVerifySig` (Go)      | Reject an update when an introduced commit lacks a valid signature from a registered key.                               |

## Add a ref policy

The `refPolicies` option is an ordered list of rules. Each rule has a `pattern` and an optional
`ops` list.

This policy permits branches under `agents/` in the default namespace. It rejects all other refs.

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  const agentPolicies = [
    { pattern: 'agents/*' }, // Permit these branches.
    { pattern: '*', ops: ['no-push'] }, // Reject every other ref.
  ];

  const url = await repo.getRemoteURL({
    permissions: ['git:read', 'git:write'],
    refPolicies: agentPolicies,
  });
  ```

  ```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  agent_policies = [
      {"pattern": "agents/*"},  # Permit these branches.
      {"pattern": "*", "ops": ["no-push"]},  # Reject every other ref.
  ]

  url = await repo.get_remote_url(
      permissions=["git:read", "git:write"],
      ref_policies=agent_policies,
  )
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  agentPolicies := storage.RefPolicyList{
      {Pattern: "agents/*"}, // Permit these branches.
      {Pattern: "*", Ops: storage.Ops{storage.OpNoPush}}, // Reject every other ref.
  }

  url, err := repo.RemoteURL(ctx, storage.RemoteURLOptions{
      Permissions: []storage.Permission{storage.PermissionGitRead, storage.PermissionGitWrite},
      RefPolicies: agentPolicies,
  })
  ```
</CodeGroup>

A rule with no `ops` permits its matched ref. Code Storage also permits a write when no rule
matches.

Add a final `*` rule with `no-push` when you need an allowlist. This rule rejects each ref that no
earlier rule permits.

## Match refs

Use an exact ref or a prefix glob. A prefix glob has one final `*` after a slash. Use `*` to match
all refs.

Code Storage treats a pattern without `refs/` as a branch name in the default namespace.

| Pattern                                  | Pattern after normalization | Match                                             |
| ---------------------------------------- | --------------------------- | ------------------------------------------------- |
| `main`                                   | `refs/heads/main`           | The `main` branch in the default namespace        |
| `agents/*`                               | `refs/heads/agents/*`       | Branches under `agents/` in the default namespace |
| `refs/heads/*`                           | `refs/heads/*`              | All branches in the default namespace             |
| `refs/tags/*`                            | `refs/tags/*`               | All tags in the default namespace                 |
| `refs/namespaces/ephemeral/refs/heads/*` | unchanged                   | All ephemeral branches                            |
| `*`                                      | unchanged                   | All refs in all namespaces                        |

Code Storage uses the first rule whose pattern matches the ref. It does not check a later rule when
the first rule has no `ops`.

<Warning>
  Put a broad rule after each specific rule. An earlier `*` rule hides all later rules.
</Warning>

<div id="ephemeral-namespace-quirk" />

## Apply policies to ephemeral branches

Ref policies apply to ephemeral branches. Code Storage stores them in the `ephemeral` ref namespace.

The policy sees the complete stored ref. For example, the ephemeral branch `preview/pr-123` has this
ref:

```text theme={"theme":{"light":"github-light","dark":"min-dark"}}
refs/namespaces/ephemeral/refs/heads/preview/pr-123
```

A short `preview/*` pattern becomes `refs/heads/preview/*`. It matches branches in the default
namespace only.

| Target                                       | Pattern                                               |
| -------------------------------------------- | ----------------------------------------------------- |
| One ephemeral branch                         | `refs/namespaces/ephemeral/refs/heads/preview/pr-123` |
| Ephemeral branches under `preview/`          | `refs/namespaces/ephemeral/refs/heads/preview/*`      |
| All ephemeral branches                       | `refs/namespaces/ephemeral/refs/heads/*`              |
| Refs in the default and ephemeral namespaces | `*`                                                   |

This URL permits only ephemeral branches under `agents/`:

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  const url = await repo.getEphemeralRemoteURL({
    permissions: ['git:read', 'git:write'],
    refPolicies: [
      { pattern: 'refs/namespaces/ephemeral/refs/heads/agents/*' },
      { pattern: '*', ops: ['no-push'] },
    ],
  });
  ```

  ```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  url = await repo.get_ephemeral_remote_url(
      permissions=["git:read", "git:write"],
      ref_policies=[
          {"pattern": "refs/namespaces/ephemeral/refs/heads/agents/*"},
          {"pattern": "*", "ops": ["no-push"]},
      ],
  )
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  url, err := repo.EphemeralRemoteURL(ctx, storage.RemoteURLOptions{
  	Permissions: []storage.Permission{
  		storage.PermissionGitRead,
  		storage.PermissionGitWrite,
  	},
  	RefPolicies: storage.RefPolicyList{
  		{Pattern: "refs/namespaces/ephemeral/refs/heads/agents/*"},
  		{Pattern: "*", Ops: storage.Ops{storage.OpNoPush}},
  	},
  })
  ```
</CodeGroup>

See [Ephemeral Namespace](/docs/guides/ephemeral-branches) for remote URLs and branch promotion.

## Use a policy with an SDK call

Pass the same option to an SDK method that writes a ref. The SDK puts the rules in the JWT for that
call.

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  await repo.createBranch({
    baseRef: headSha,
    targetBranch: 'agents/research-bot',
    refPolicies: agentPolicies,
  });
  ```

  ```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  await repo.create_branch(
      base_ref=head_sha,
      target_branch="agents/research-bot",
      ref_policies=agent_policies,
  )
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  _, err := repo.CreateBranch(ctx, storage.CreateBranchOptions{
      BaseRef:      headSHA,
      TargetBranch: "agents/research-bot",
      RefPolicies:  agentPolicies,
  })
  ```
</CodeGroup>

These SDK write methods accept a ref policy:

* `createBranch()` and `deleteBranch()`
* `createTag()` and `deleteTag()`
* `createCommit()`, `createCommitFromDiff()`, and `restoreCommit()`
* `merge()` and `pullUpstream()`
* `createNote()`, `appendNote()`, and `deleteNote()`

The policy checks the target ref.

## Add a policy to a JWT

The SDK converts `refPolicies` to the `refs` JWT claim. Each claim entry is an ordered
`[pattern, ops]` pair.

```json theme={"theme":{"light":"github-light","dark":"min-dark"}}
{
  "refs": [
    ["refs/heads/main", ["no-force-push"]],
    ["*", ["no-push"]]
  ]
}
```

Keep the array order. JSON objects do not represent these rules.

See [Authentication & Security](/docs/getting-started/authentication) for the other JWT claims.

<div id="commit-signing-verifications" />

## Commit signature checks

The `verify-sig` operation checks each commit that an update introduces to the matched ref. Code
Storage checks each signature against the registered organization keys.

A registered key does not enable a check by itself. Add `verify-sig` to a ref policy rule.

See [Commit Signing](/docs/guides/commit-signing) for key setup, check behavior, and an example.

<Warning>
  Do not target a `verify-sig` ref with `createCommit`, `createCommitFromDiff`, or `merge`. These
  methods create unsigned commits.
</Warning>

## Where ref policies apply

Code Storage checks ref policies on these write paths:

* A Git push over HTTPS
* A supported SDK or HTTP API method that updates a ref

## Legacy `ops` option

Remote URL methods also accept a top-level `ops` list. This old option applies its operations to the
`*` rule.

Use `refPolicies` in new code. It shows the catch-all rule and supports specific refs.
