Private repositories
Patchwire scans private repos via per-project HTTPS access tokens. Tokens are encrypted with AES-256-GCM before persistence and are never returned in any API response.
How it works
When you save a token on a project, the API:
- Reads
PATCHWIRE_DATA_KEYfrom environment (32-byte symmetric key, mounted from a sealed Kubernetes Secret). - Generates a fresh 12-byte nonce.
- Encrypts the plaintext PAT with AES-256-GCM.
- Stores the wire format
nonce ‖ ciphertext ‖ taginprojects.access_token_enc(BYTEA).
When a scan starts:
- The scan task fetches the row including the encrypted blob.
- Decrypts in-memory, no longer than the duration of the clone.
- Builds the URL
https://USER:TOKEN@host/path, passes togit clone. - The URL string lives in the cloning task's stack frame and is dropped at end of scope.
The wire-format response from the API only ever shows has_access_token: true — never the blob, never the plaintext.
Per-provider token setup
GitHub
Use a fine-grained personal access token scoped to one repository.
- https://github.com/settings/personal-access-tokens/new
- Resource owner: your account or org.
- Repository access: Only select repositories → pick the one repo.
- Repository permissions: Contents: Read-only.
- Generate.
- In Patchwire: project edit form → Access token → paste.
- Token username: leave default (
x-access-token).
Fine-grained tokens have a maximum 1-year lifetime. Rotate by editing the project and pasting a fresh token; the old encrypted blob is overwritten.
GitLab
Use a project access token.
- Project → Settings → Access Tokens.
- Token name:
patchwire. - Role: Reporter (the lowest role that can clone).
- Scopes:
read_repository. - Click Create.
- Copy the token value (you won't see it again).
- In Patchwire: project edit form → Access token → paste.
- Token username:
oauth2.
Bitbucket Cloud
Use an app password scoped to repository read.
- https://bitbucket.org/account/settings/app-passwords/
- Label:
patchwire. - Permissions: Repositories: Read.
- Create.
- Copy the password value.
- In Patchwire: project edit form → Access token → paste the app password.
- Token username: your Bitbucket username (the one that owns or has access to the repo).
Forgejo
You don't need to set anything. Patchwire's installation has its own cluster-wide Forgejo PAT (FORGEJO_CLONE_TOKEN) that authenticates clones from git.ahmedanbar.dev automatically. Per-project tokens for Forgejo are simply ignored.
Updating or removing a token
In the project edit form (/projects/<slug>):
| Action | What to do |
|---|---|
| Replace the token | Type the new token in the field. Submit. |
| Keep the existing token | Leave the field blank. Submit. |
| Remove the token | Click Clear token, then submit. The badge reverts to "no token configured". |
The API enforces this tri-state on the PATCH body:
access_tokenfield absent → leave unchangedaccess_token: ""→ clear (NULL the column)access_token: "<value>"→ re-encrypt and replace
Security notes
- Encryption-at-rest only. The plaintext is in memory inside the API pod for as long as a scan takes to clone — typically 10 seconds. We do not yet redact the URL from in-process logs (a known follow-up; logs go to stdout and are read by
kubectl logs). - One key, no rotation today. Rotating
PATCHWIRE_DATA_KEYwould invalidate every existing token. Akey_versioncolumn lands when rotation becomes a real ask. - Per-project scope. Compromising one tenant's data-key access (effectively, root on the API pod) yields tokens for every project in every org. The blast radius is the entire installation, not one tenant.
- The token is yours. Patchwire never makes outbound calls beyond
git clone. There is no telemetry, no third-party reporting.
Troubleshooting
Scan fails with Authentication failed — the token doesn't grant read on this repo, or the username field is wrong (try oauth2 for GitLab, your real username for Bitbucket).
Scan fails with repository not found — the URL is wrong, the token is for the wrong account, or the repo was deleted/archived.
Token field shows "(currently configured)" but you don't remember setting it — check the audit trail: git log -- crates/api/src/handlers/projects.rs will tell you when token storage was added.