Workflows push as a dedicated ci-bot account rather than a human one, so its PAT can be scoped, rotated and revoked on its own. Adding a repo to `ciBotRepos` and redeploying is all it takes to grant access. Collaborator access and branch-protection push-whitelisting exist only on gitea's HTTP API — no CLI, no config-file surface — so this one part stays imperative: a oneshot that PUT/PATCHes the API into the desired state. It runs on deploys where the script changed, which means it won't self-heal a revert done through the web UI unless the unit is restarted too. Two secrets, deliberately distinct: - gitea_provisioning_token is darman's own token (write:repository + write:user). Only an owner-scoped token clears reqOwnerCheck on the collaborator and branch-protection endpoints, and write:user is what lets it write the Actions secret below. ci-bot cannot grant itself access. - gitea_ci_bot_token is ci-bot's push token, generated once by hand (the command is in the comment) and pushed into gitea as a user-level Actions secret CI_BOT_TOKEN. Gitea has no instance-wide secret scope, and every repo here is owned by darman directly rather than an org, so a user-level secret is the closest thing — repo-level lookups fall back to it. Branch protection is applied to the default branch plus `develop`, since version-bump.yml pushes there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
52 lines
2.4 KiB
Nix
52 lines
2.4 KiB
Nix
{ config, ... }:
|
|
|
|
# sops-nix secret wiring (real host only; not imported by vm.nix).
|
|
# Encrypted values live in ../../secrets/jupiter.yaml, decrypted at activation to
|
|
# /run/secrets/<name>.
|
|
#
|
|
# The host decrypts with its OWN SSH host key (age identity derived via
|
|
# ssh-to-age, recipient listed in ../../.sops.yaml). The key is pre-generated on
|
|
# the laptop and shipped once at install as /etc/ssh/ssh_host_ed25519_key
|
|
# (nixos-anywhere --extra-files) — so decryption works on boot #1 and there is
|
|
# no separate sops-only key to manage.
|
|
{
|
|
sops.defaultSopsFile = ../../secrets/jupiter.yaml;
|
|
sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
|
|
|
|
# Decrypts to /run/secrets/samba_password (root-only by default).
|
|
sops.secrets.samba_password = { };
|
|
|
|
# darman's login password (a sha-512 hash, not plaintext — generate with
|
|
# `mkpasswd -m sha-512`, edit via ./edit_secrets). neededForUsers makes it
|
|
# available before user setup, at /run/secrets-for-users/darman_password.
|
|
sops.secrets.darman_password.neededForUsers = true;
|
|
users.users.darman.hashedPasswordFile =
|
|
config.sops.secrets.darman_password.path;
|
|
|
|
# Headscale pre-auth key for tailscale auto-registration (see configuration.nix).
|
|
sops.secrets.tailscale_authkey = { };
|
|
|
|
# Immich's OIDC client secret, from its Authentik application (a SEPARATE
|
|
# app from headscale's and headplane's — see hosts/neptun/secrets.nix).
|
|
# Referenced as settings.oauth.clientSecret._secret in
|
|
# services/media/immich.nix; the module resolves it through systemd
|
|
# LoadCredential, which reads as root before dropping privileges, so the
|
|
# sops default of root:root 0400 is correct — do NOT set `owner`.
|
|
sops.secrets.immich_oauth_client_secret = { };
|
|
|
|
# Gitea Actions runner registration token (services/dev/gitea.nix). Gitea
|
|
# generates this itself once Actions is enabled — it is not a password
|
|
# chosen up front. Rendered into a `TOKEN=...` env file because
|
|
# gitea-actions-runner takes an EnvironmentFile, not a raw secret path.
|
|
sops.secrets.gitea_runner_token = { };
|
|
sops.templates."gitea-runner.env".content =
|
|
"TOKEN=${config.sops.placeholder.gitea_runner_token}";
|
|
|
|
# provisioning access token for gitea used to setup ci-bot account + repo access
|
|
sops.secrets.gitea_provisioning_token.owner = "gitea";
|
|
|
|
# ci-bot access token to allow the ci-bot user to push to repos
|
|
sops.secrets.gitea_ci_bot_token.owner = "gitea";
|
|
|
|
}
|