forked from 1b-agent/fieldcraft-upstream
ci: release secrets from the main-only release environment
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
1 parent
1dc4c27dc1
commit
7a9cb2cb22
5 files changed
+65
-7
No files matched your search
@@ -1,2 +1,13 @@
|
|||||||
# Every change to FieldCraft needs the maintainer's review before it merges.
|
# Every change to FieldCraft needs the maintainer's review before it merges.
|
||||||
* @jyviko
|
* @jyviko
|
||||||
|
|
||||||
|
# Release and supply-chain paths, named explicitly so they stay owner-reviewed if the rule above
|
||||||
|
# is ever relaxed: workflows and secrets use, packaging and signing, the updater, dependencies,
|
||||||
|
# licences.
|
||||||
|
/.github/ @jyviko
|
||||||
|
/packaging/ @jyviko
|
||||||
|
/crates/update/ @jyviko
|
||||||
|
/Cargo.toml @jyviko
|
||||||
|
/Cargo.lock @jyviko
|
||||||
|
/ATTRIBUTION.md @jyviko
|
||||||
|
/deny.toml @jyviko
|
||||||
@@ -33,6 +33,10 @@ env:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
# POSTHOG_KEY lives in the `release` environment (main only, docs/releasing.md). The deploy job
|
||||||
|
# already uses github-pages and a job has one environment, so the build job reads the key: on
|
||||||
|
# main it runs in `release`, elsewhere in no environment and with an empty key.
|
||||||
|
environment: ${{ github.ref == 'refs/heads/main' && 'release' || '' }}
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
timeout-minutes: 60
|
timeout-minutes: 60
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ jobs:
|
|||||||
macos:
|
macos:
|
||||||
name: macOS universal
|
name: macOS universal
|
||||||
needs: version
|
needs: version
|
||||||
|
# Signing, notarization and analytics secrets live in the `release` environment, which only
|
||||||
|
# `main` may use; a dry run on another branch asks for no environment and builds unsigned.
|
||||||
|
environment: ${{ github.ref == 'refs/heads/main' && 'release' || '' }}
|
||||||
runs-on: macos-14
|
runs-on: macos-14
|
||||||
timeout-minutes: 120
|
timeout-minutes: 120
|
||||||
outputs:
|
outputs:
|
||||||
@@ -118,6 +121,9 @@ jobs:
|
|||||||
name: Linux x86_64
|
name: Linux x86_64
|
||||||
needs: version
|
needs: version
|
||||||
# The oldest GitHub-hosted image, so the binaries need only glibc >= 2.35.
|
# The oldest GitHub-hosted image, so the binaries need only glibc >= 2.35.
|
||||||
|
# Signing, notarization and analytics secrets live in the `release` environment, which only
|
||||||
|
# `main` may use; a dry run on another branch asks for no environment and builds unsigned.
|
||||||
|
environment: ${{ github.ref == 'refs/heads/main' && 'release' || '' }}
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
timeout-minutes: 90
|
timeout-minutes: 90
|
||||||
env:
|
env:
|
||||||
@@ -201,6 +207,9 @@ jobs:
|
|||||||
windows:
|
windows:
|
||||||
name: Windows x64
|
name: Windows x64
|
||||||
needs: version
|
needs: version
|
||||||
|
# Signing, notarization and analytics secrets live in the `release` environment, which only
|
||||||
|
# `main` may use; a dry run on another branch asks for no environment and builds unsigned.
|
||||||
|
environment: ${{ github.ref == 'refs/heads/main' && 'release' || '' }}
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
timeout-minutes: 90
|
timeout-minutes: 90
|
||||||
env:
|
env:
|
||||||
@@ -230,6 +239,9 @@ jobs:
|
|||||||
release:
|
release:
|
||||||
name: Draft release (or dry-run artifacts)
|
name: Draft release (or dry-run artifacts)
|
||||||
needs: [version, macos, linux, windows]
|
needs: [version, macos, linux, windows]
|
||||||
|
# Signing, notarization and analytics secrets live in the `release` environment, which only
|
||||||
|
# `main` may use; a dry run on another branch asks for no environment and builds unsigned.
|
||||||
|
environment: ${{ github.ref == 'refs/heads/main' && 'release' || '' }}
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|||||||
+1
-1
@@ -86,5 +86,5 @@ A `command_run` as sent:
|
|||||||
The events and the policy are `fieldcraft_engine::usage`; the consent question and the settings
|
The events and the policy are `fieldcraft_engine::usage`; the consent question and the settings
|
||||||
are `crates/ui-egui/src/privacy.rs`; the desktop sender is `apps/fieldcraft/src/usage.rs`, the
|
are `crates/ui-egui/src/privacy.rs`; the desktop sender is `apps/fieldcraft/src/usage.rs`, the
|
||||||
web one `apps/fieldcraft-web/src/usage.rs`. The PostHog project key is the build-time variable
|
web one `apps/fieldcraft-web/src/usage.rs`. The PostHog project key is the build-time variable
|
||||||
`FIELDCRAFT_POSTHOG_KEY`, which the release workflow and the Pages build of `main` set from the repository secret
|
`FIELDCRAFT_POSTHOG_KEY`, which the release workflow and the Pages build of `main` set from the `release` environment secret
|
||||||
`POSTHOG_KEY`; it is an ingest-only key. A new event or property is added here first.
|
`POSTHOG_KEY`; it is an ingest-only key. A new event or property is added here first.
|
||||||
+37
-6
@@ -51,7 +51,8 @@ about it, and the release notes say which of the two the draft contains.
|
|||||||
| `APPLE_PASSWORD` | An app-specific password for that Apple ID (appleid.apple.com › Sign-In and Security) |
|
| `APPLE_PASSWORD` | An app-specific password for that Apple ID (appleid.apple.com › Sign-In and Security) |
|
||||||
| `APPLE_TEAM_ID` | The 10-character team id of the Developer ID |
|
| `APPLE_TEAM_ID` | The 10-character team id of the Developer ID |
|
||||||
|
|
||||||
Add them with `gh secret set <NAME> -R jyviko/fieldcraft`. With the certificate but without the
|
Add them to the `release` environment ([Where the secrets live](#where-the-secrets-live)) with
|
||||||
|
`gh secret set <NAME> --env release -R jyviko/fieldcraft`. With the certificate but without the
|
||||||
three notarization secrets the app is signed and not notarized. A dmg made locally with
|
three notarization secrets the app is signed and not notarized. A dmg made locally with
|
||||||
`packaging/macos/package.sh` is ad-hoc signed unless `MACOS_SIGN_IDENTITY` names an identity
|
`packaging/macos/package.sh` is ad-hoc signed unless `MACOS_SIGN_IDENTITY` names an identity
|
||||||
in the keychain.
|
in the keychain.
|
||||||
@@ -66,7 +67,7 @@ untrusted comment: minisign public key: FEF410EFEF5BAB21
|
|||||||
RWQhq1vv7xD0/uAOt8fqERP1hP+1UCM9U9QHTDYTYytWKiuedTkT7Lgr
|
RWQhq1vv7xD0/uAOt8fqERP1hP+1UCM9U9QHTDYTYytWKiuedTkT7Lgr
|
||||||
```
|
```
|
||||||
|
|
||||||
The secret half is the repository secret `FIELDCRAFT_SIGNING_KEY`: the whole secret key file
|
The secret half is the `release` environment secret `FIELDCRAFT_SIGNING_KEY`: the whole secret key file
|
||||||
(two lines), made without a password. With it, the release job signs `SHA256SUMS.txt` with
|
(two lines), made without a password. With it, the release job signs `SHA256SUMS.txt` with
|
||||||
[rsign2](https://github.com/jedisct1/rsign2) (pinned in `release.yml`), checks the signature
|
[rsign2](https://github.com/jedisct1/rsign2) (pinned in `release.yml`), checks the signature
|
||||||
against the public key in the source, and uploads `SHA256SUMS.txt.minisig`. Without it the
|
against the public key in the source, and uploads `SHA256SUMS.txt.minisig`. Without it the
|
||||||
@@ -79,7 +80,7 @@ Setting it up, once:
|
|||||||
```sh
|
```sh
|
||||||
cargo install --locked rsign2 --version 0.6.7
|
cargo install --locked rsign2 --version 0.6.7
|
||||||
rsign generate -W -p fieldcraft-release.pub -s fieldcraft-release.key # -W: no password
|
rsign generate -W -p fieldcraft-release.pub -s fieldcraft-release.key # -W: no password
|
||||||
gh secret set FIELDCRAFT_SIGNING_KEY -R jyviko/fieldcraft < fieldcraft-release.key
|
gh secret set FIELDCRAFT_SIGNING_KEY --env release -R jyviko/fieldcraft < fieldcraft-release.key
|
||||||
```
|
```
|
||||||
|
|
||||||
Keep an offline copy of the secret key file (a password manager, an encrypted backup) and
|
Keep an offline copy of the secret key file (a password manager, an encrypted backup) and
|
||||||
@@ -101,9 +102,39 @@ certificate is added.
|
|||||||
## Usage analytics key
|
## Usage analytics key
|
||||||
|
|
||||||
The release builds (macOS, Linux and Windows jobs) build in the PostHog project key from the
|
The release builds (macOS, Linux and Windows jobs) build in the PostHog project key from the
|
||||||
repository secret `POSTHOG_KEY` as `FIELDCRAFT_POSTHOG_KEY` ([privacy.md](privacy.md)). Without the
|
`release` environment secret `POSTHOG_KEY` as `FIELDCRAFT_POSTHOG_KEY` ([privacy.md](privacy.md)).
|
||||||
secret the builds ask nothing and send nothing, as local and fork builds do. The web build on
|
Without the secret the builds ask nothing and send nothing, as local, fork and dry-run builds do.
|
||||||
Pages has no key.
|
The web build on Pages gets the key only when it runs from `main`: its build job then runs in the
|
||||||
|
`release` environment (the deploy job already uses `github-pages`, and a job has one environment).
|
||||||
|
|
||||||
|
## Where the secrets live
|
||||||
|
|
||||||
|
Every release secret (the `APPLE_*` secrets, `KEYCHAIN_PASSWORD`, `FIELDCRAFT_SIGNING_KEY`,
|
||||||
|
`POSTHOG_KEY`) is a secret of the GitHub Environment `release`, whose deployment branches allow
|
||||||
|
`main` only. Repository secrets are readable by any workflow a writer can run on any branch;
|
||||||
|
environment secrets reach only jobs that name the environment and run from an allowed branch, so a
|
||||||
|
contributor with write access cannot read the signing keys from a branch of their own. The jobs
|
||||||
|
that read them (`release.yml`'s macos, linux, windows and release jobs, `pages.yml`'s build job)
|
||||||
|
ask for `release` only on `main`
|
||||||
|
(`environment: ${{ github.ref == 'refs/heads/main' && 'release' || '' }}`); elsewhere the name is
|
||||||
|
empty, the job runs in no environment, sees no secrets and builds unsigned. `.github/CODEOWNERS`
|
||||||
|
keeps the workflows, packaging and updater under the owner's review.
|
||||||
|
|
||||||
|
Moving them from repository secrets, once (the owner; each value comes from its own source file,
|
||||||
|
never the shell history):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
for n in APPLE_CERTIFICATE APPLE_CERTIFICATE_PASSWORD KEYCHAIN_PASSWORD APPLE_ID APPLE_PASSWORD \
|
||||||
|
APPLE_TEAM_ID FIELDCRAFT_SIGNING_KEY POSTHOG_KEY; do
|
||||||
|
gh secret set "$n" --env release -R jyviko/fieldcraft < "$n.txt"
|
||||||
|
done
|
||||||
|
gh secret list --env release -R jyviko/fieldcraft # all eight listed
|
||||||
|
# After a release run on main has signed with them:
|
||||||
|
for n in APPLE_CERTIFICATE APPLE_CERTIFICATE_PASSWORD KEYCHAIN_PASSWORD APPLE_ID APPLE_PASSWORD \
|
||||||
|
APPLE_TEAM_ID FIELDCRAFT_SIGNING_KEY POSTHOG_KEY; do
|
||||||
|
gh secret delete "$n" -R jyviko/fieldcraft
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
## Choose and prepare the version
|
## Choose and prepare the version
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user