Skip to content

PD · Passphrase + Dispatch

One shared passphrase, held by you, sent sealed with each build you trigger.

One passphrase, shared by the team and held on your machine. No decryption material on GitHub. sgit push starts the build and sends the passphrase with it, sealed, for that one build.

The same trigger model as RD, with the simpler encryption mode. Right when you are one person, or a small team that already shares secrets and does not need per-person revocation.

1 · Create the token

Do this first. sgit init uploads the secrets your workflow reads, and without a token it sets up everything except the half that makes builds run.

GitHub → Settings → Developer settings → Fine-grained tokens → Generate new

Repository accessOnly select repositories → this one
ContentsRead and write — so you can push
ActionsRead and write — so sgit push can trigger builds
SecretsRead and write — so init can upload them

Metadata: read is added for you.

terminal
export GITHUB_PAT=github_pat_…

GH_TOKEN and GITHUB_TOKEN work too. If none is set and you are at a terminal, init offers to take it and stores it per project.

2 · Choose the passphrase, then seal

Passphrase mode does not invent your secret — you pick it:

terminal
export SGIT_KEY="$(openssl rand -base64 32)"
sgit init --mode passphrase --ci-mode portal-dispatch

On your disk:

$CODESEAL/<project>/
passphrase      # a copy of $SGIT_KEY, so it outlives the shell
dispatch.key    # unwraps the dispatch token; uploaded to GitHub

The copy matters. A passphrase that exists only as an exported variable is one reboot from gone and appears in no backup — and there is no recovering it. sgit encrypt and sgit decrypt read the environment first and fall back to this file, so a new terminal just works.

In the repository: the manifest (naming SGIT_KEY as the variable), the generated workflow, and a managed .gitignore block. No admin key, no recipients file — passphrase mode has neither.

3 · Check GitHub is ready

sgit init uploaded CODESEAL_DISPATCH_PRIVATE_KEY as it went — that is what the token in step 1 was for. Confirm it landed:

terminal
sgit ci verify
mylife-inc/demo is ready to build.

Note what is not uploaded: the passphrase itself never reaches GitHub's secret store. It travels inside each dispatch token, sealed, and is gone when the build ends.

4 · Protect something

terminal
sgit add-sensitive src/private
sgit encrypt

5 · The everyday loop

terminal
sgit add -s src/private/payment.rs
sgit commit -- -m "protect payments"
sgit push origin main

Identical to RD. The difference is only what rides inside the token — a passphrase rather than a runner key.

Adding and removing people

This is where the modes part company.

Adding someone means giving them the passphrase. There is no per-person key, no recipients file, nothing to rewrap.

Removing someone means changing it — new passphrase, re-encrypt everything, tell everyone who is left, re-provision. Their old copy still opens every blob in the history they already have.

terminal
export SGIT_KEY="$(openssl rand -base64 32)"
sgit encrypt --force
sgit ci provision

What you end up with

On GitHubciphertext, and one key that decrypts nothing by itself
On your machinethe passphrase and the dispatch key
Adding a teammatetell them the passphrase
Removing onerotate everything
To start a buildyou, from a terminal

See also

  • RD — same triggering, per-developer keys
  • PS — same passphrase, GitHub triggers and holds it