diff --git a/.forgejo/workflows/ci.yaml b/.forgejo/workflows/ci.yaml index d011ec3..4b51b76 100644 --- a/.forgejo/workflows/ci.yaml +++ b/.forgejo/workflows/ci.yaml @@ -7,9 +7,10 @@ name: Flatpak # tag X.Y.Z -> publish as `stable` and create release X.Y.Z # # The `flatpak` runner label is the privileged runner on the Hetzner box -# (bubblewrap needs it) with three volumes allowed: the Sdk install, the +# (bubblewrap needs it) with four volumes allowed: the Sdk install, the # flatpak-builder state (ccache and the LLVM module, so only crafter-build -# itself rebuilds on a normal run) and the published repo's web root. +# itself rebuilds on a normal run), the published repo's web root, and the +# repo signing key, which lives on the runner host and never in the forge. on: pull_request: branches: [master] @@ -35,6 +36,7 @@ jobs: -v crafter-flatpak-system:/var/lib/flatpak -v crafter-flatpak-builder:/root/.cache/flatpak-builder -v /var/www/flatpak:/srv/flatpak + -v /etc/crafter-flatpak:/run/crafter-flatpak:ro steps: - name: Install tools run: | @@ -118,13 +120,18 @@ jobs: - name: Publish to the Catcrafts repo if: github.event_name != 'pull_request' - env: - FLATPAK_GPG_PRIVATE_KEY: ${{ secrets.FLATPAK_GPG_PRIVATE_KEY }} - FLATPAK_GPG_KEY_ID: ${{ secrets.FLATPAK_GPG_KEY_ID }} run: | set -eu + # The signing key is generated once on the runner host + # (/etc/crafter-flatpak: signing-key.asc and key-id) and mounted + # read-only; it is imported into a throwaway keyring per run. + if [ ! -s /run/crafter-flatpak/signing-key.asc ] || [ ! -s /run/crafter-flatpak/key-id ]; then + echo "no signing key under /etc/crafter-flatpak on the runner host; generate it as described in AGENTS.md (CI and publishing)" >&2 + exit 1 + fi export GNUPGHOME=$(mktemp -d) - printf '%s' "$FLATPAK_GPG_PRIVATE_KEY" | gpg --batch --quiet --import + gpg --batch --quiet --import /run/crafter-flatpak/signing-key.asc + FLATPAK_GPG_KEY_ID=$(cat /run/crafter-flatpak/key-id) # The live repo is the canonical copy; builds are promoted into it, # never built into it. [ -d "$REPO_DIR" ] || ostree init --repo="$REPO_DIR" --mode=archive diff --git a/AGENTS.md b/AGENTS.md index 1ad41da..63ee7e3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -143,12 +143,22 @@ These were decided deliberately. Do not undo them without the maintainer's say-s - Unpinned dependencies `git pull` on every invocation, so builds and tests need network. A missing or private repo surfaces as a clone failure before anything is built. - `--runner=cmd:` executes the named wrapper around every test binary. Wrappers come from `--runner=` or `CRAFTER_BUILD_RUNNER_*`; do not hardcode hosts, wrappers or credentials in `project.cpp` or tests. - The linter loads `libclang` at runtime by name. `CRAFTER_BUILD_LIBCLANG` pins an exact path and must fail loudly when wrong, never fall back to another library. -- CI force-pushes the rolling `latest` tag and publishes a prerelease on every push to `master` with the workflow's own token, and signs the Flatpak repo with the key in the `FLATPAK_GPG_PRIVATE_KEY` secret. Do not add other secrets to the workflow or echo the environment in it. +- CI force-pushes the rolling `latest` tag and publishes a prerelease on every push to `master` with the workflow's own token, and signs the Flatpak repo with the key mounted from the runner host. Do not add secrets to the workflow or echo the environment in it. - Tests write only under `fs::temp_directory_path()` and the fixture's own `bin/` and `build/`. Keep it that way. ## CI and publishing -`.forgejo/workflows/ci.yaml` runs on the `flatpak` runner label: the privileged forgejo-runner on the Hetzner box (bubblewrap inside the job container needs it). Its `config.yml` allows three volumes, which the workflow mounts: `crafter-flatpak-system` (the Sdk install at `/var/lib/flatpak`), `crafter-flatpak-builder` (flatpak-builder state and ccache, so the LLVM and WASI modules are rebuilt only when their sources change) and `/var/www/flatpak`, the web root Caddy serves as `https://flatpak.catcrafts.net/`. Secrets: `FLATPAK_GPG_PRIVATE_KEY` (armored, no passphrase) and `FLATPAK_GPG_KEY_ID`. The live repo at `/var/www/flatpak/repo` is canonical; builds are promoted into it with `flatpak build-commit-from`, never built into it. +`.forgejo/workflows/ci.yaml` runs on the `flatpak` runner label: the privileged forgejo-runner on the Hetzner box (bubblewrap inside the job container needs it). Its `config.yml` allows three volumes, which the workflow mounts: `crafter-flatpak-system` (the Sdk install at `/var/lib/flatpak`), `crafter-flatpak-builder` (flatpak-builder state and ccache, so the LLVM and WASI modules are rebuilt only when their sources change) and `/var/www/flatpak`, the web root Caddy serves as `https://flatpak.catcrafts.net/`, and `/etc/crafter-flatpak`, which holds the repo signing key (`signing-key.asc`, no passphrase, and `key-id`), generated once on the host and mounted read-only into the job; nothing is stored in the forge. The live repo at `/var/www/flatpak/repo` is canonical; builds are promoted into it with `flatpak build-commit-from`, never built into it. + +The key is made once, as root on the runner host, and the step fails with a message pointing here when it is missing: + +```bash +install -d -m 700 /etc/crafter-flatpak/gnupg && export GNUPGHOME=/etc/crafter-flatpak/gnupg +gpg --batch --pinentry-mode loopback --passphrase '' --quick-generate-key 'Catcrafts Flatpak Repository ' ed25519 sign never +KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec/{print $5; exit}') +gpg --batch --pinentry-mode loopback --passphrase '' --export-secret-keys --armor "$KEYID" > /etc/crafter-flatpak/signing-key.asc +printf '%s\n' "$KEYID" > /etc/crafter-flatpak/key-id && chmod 600 /etc/crafter-flatpak/signing-key.asc /etc/crafter-flatpak/key-id +``` To release: add a `` to `packaging/flatpak/net.catcrafts.CrafterBuild.metainfo.xml` (its description becomes the release notes), merge, and push the tag `X.Y.Z`. CI refuses a tag that does not match the newest entry. Local builds: `flatpak-builder --user --force-clean --ccache --repo=repo build-dir packaging/flatpak/net.catcrafts.CrafterBuild.yaml`, then `flatpak-builder --run build-dir crafter-build --version`.