> ## 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.

# Commit Signing

> Register OpenPGP or SSH public keys. Use a ref policy to require signed commits on selected refs.

Git creates each commit signature. Code Storage checks the signature when a `verify-sig` ref policy
applies to an update.

The **Signing Keys** page stores public keys for your organization. A registered key does not enable
a check by itself.

## How the parts work together

| Part                    | Purpose                                                               |
| ----------------------- | --------------------------------------------------------------------- |
| Git                     | Create an OpenPGP or SSH signature in the commit object.              |
| **Signing Keys**        | Store the public keys that Code Storage trusts for your organization. |
| `verify-sig` ref policy | Require a valid signature when a token updates a matched ref.         |
| `getCommit()`           | Return the signature and its exact payload for a client check.        |

## Require signed commits

### 1. Create a signed commit

Configure Git for OpenPGP or SSH signatures. Then use `-S` to sign a commit.

```bash theme={"theme":{"light":"github-light","dark":"min-dark"}}
git commit -S -m "Add the release manifest"
git log --show-signature -1
```

### 2. Register the public key

Open **Signing Keys** in the dashboard. Select **New signing key**, then paste an OpenPGP or SSH
public key.

Signing keys belong to the organization. Code Storage reads the current key list for each ref
update.

### 3. Add `verify-sig` to a ref policy

This policy requires a registered signature on each commit that enters `main`.

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  const url = await repo.getRemoteURL({
    permissions: ['git:read', 'git:write'],
    refPolicies: [{ pattern: 'main', ops: ['verify-sig'] }],
  });
  ```

  ```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  url = await repo.get_remote_url(
      permissions=["git:read", "git:write"],
      ref_policies=[{"pattern": "main", "ops": ["verify-sig"]}],
  )
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  url, err := repo.RemoteURL(ctx, storage.RemoteURLOptions{
      Permissions: []storage.Permission{storage.PermissionGitRead, storage.PermissionGitWrite},
      RefPolicies: storage.RefPolicyList{
          {Pattern: "main", Ops: storage.Ops{storage.OpVerifySig}},
      },
  })
  ```
</CodeGroup>

Use `ops: ['verify-sig', 'no-force-push']` to require signatures and reject a history rewrite.

See [Ref Policies](/docs/guides/ref-policies) for rule order, patterns, and ephemeral refs.

### 4. Push the signed commit

Use the URL with this policy as a Git remote. Code Storage rejects the complete update if one
introduced commit fails the check.

## What Code Storage checks

Code Storage checks commits that the update introduces to the matched ref.

* For a new ref, Code Storage checks every commit that the new tip can reach.
* For a ref that already exists, Code Storage checks commits that its new tip can reach but its
  prior tip cannot reach.
* Code Storage checks a commit again when it first enters another protected ref.

Code Storage rejects the update in these cases:

* A commit has no signature.
* No registered key matches the signature.
* The signature data is invalid or uses an unsupported format.
* The organization has no registered signing keys.

A ref deletion introduces no commits. The `verify-sig` operation does not reject that deletion.

## Server-created commits

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

Use a signed Git push when a ref requires a signature. Code Storage does not create a signature for
a server-created commit.

## Read signature data

You can read signature data without a ref policy. `getCommit()` returns an armored `signature` and
the exact `payload` for a signed commit.

<CodeGroup>
  ```typescript TypeScript theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  const { commit } = await repo.getCommit({ sha: 'abc123def456' });

  if (commit.signature && commit.payload) {
    checkSignature(commit.payload, commit.signature);
  }
  ```

  ```python Python theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  result = await repo.get_commit(sha="abc123def456")
  commit = result["commit"]

  if commit.get("signature") and commit.get("payload"):
      check_signature(commit["payload"], commit["signature"])
  ```

  ```go Go theme={null} theme={"theme":{"light":"github-light","dark":"min-dark"}}
  result, err := repo.GetCommit(ctx, storage.GetCommitOptions{
  	SHA: "abc123def456",
  })

  if result.Commit.Signature != "" && result.Commit.Payload != "" {
  	checkSignature(result.Commit.Payload, result.Commit.Signature)
  }
  ```
</CodeGroup>

This method does not return a trust result. Check the pair with an OpenPGP or SSH library.

See the [`getCommit()` reference](/docs/reference/sdk/get-commit) for the complete response.

## Remove a key

Delete a key. Code Storage rejects a signature from that key on the next ref update.

The deletion does not change stored commits or their signatures.
