diff --git a/.forgejo/workflows/apple-distribute-testers.yml b/.forgejo/workflows/apple-distribute-testers.yml index d3ca415..aed30e0 100644 --- a/.forgejo/workflows/apple-distribute-testers.yml +++ b/.forgejo/workflows/apple-distribute-testers.yml @@ -84,7 +84,7 @@ env: jobs: prepare: name: Prepare Apple Distribution - runs-on: namespace-profile-linux-medium + runs-on: namespace-profile-linux-medium-apple outputs: build_number: ${{ steps.plan.outputs.build_number }} sparkle_channel: ${{ steps.plan.outputs.sparkle_channel }} @@ -123,7 +123,7 @@ jobs: build-ios: name: Build Apple iOS needs: prepare - runs-on: namespace-profile-macos-large + runs-on: namespace-profile-macos-large-apple steps: - name: Checkout uses: https://code.forgejo.org/actions/checkout@v4 @@ -219,7 +219,7 @@ jobs: build-macos: name: Build Apple macOS needs: prepare - runs-on: namespace-profile-macos-large + runs-on: namespace-profile-macos-large-apple steps: - name: Checkout uses: https://code.forgejo.org/actions/checkout@v4 @@ -319,7 +319,7 @@ jobs: - prepare - build-ios - build-macos - runs-on: namespace-profile-linux-medium + runs-on: namespace-profile-linux-medium-apple steps: - name: Checkout uses: https://code.forgejo.org/actions/checkout@v4 @@ -398,7 +398,7 @@ jobs: - prepare - sign-apple if: ${{ github.event.inputs.upload_app_store == 'true' }} - runs-on: namespace-profile-macos-large + runs-on: namespace-profile-macos-large-apple steps: - name: Checkout uses: https://code.forgejo.org/actions/checkout@v4 @@ -501,7 +501,7 @@ jobs: - prepare - sign-apple if: ${{ github.event.inputs.upload_sparkle == 'true' }} - runs-on: namespace-profile-linux-medium + runs-on: namespace-profile-linux-medium-apple steps: - name: Checkout uses: https://code.forgejo.org/actions/checkout@v4 diff --git a/Scripts/_burrow-flake.sh b/Scripts/_burrow-flake.sh index ba4e372..25fb6e1 100755 --- a/Scripts/_burrow-flake.sh +++ b/Scripts/_burrow-flake.sh @@ -27,7 +27,7 @@ burrow_prepare_flake_ref() { local resolved resolved="$(cd "${input}" && pwd)" - local cache_root="${HOME}/.cache/burrow" + local cache_root="${BURROW_FLAKE_CACHE_ROOT:-${HOME}/.cache/burrow}" mkdir -p "${cache_root}" local copy_root @@ -37,6 +37,8 @@ burrow_prepare_flake_ref() { rsync -a \ --delete \ --exclude '.git' \ + --exclude '.cache' \ + --exclude '.derived-data' \ --exclude '.direnv' \ --exclude 'result' \ --exclude 'burrow.sock' \ diff --git a/Scripts/ci/ensure-nsc.sh b/Scripts/ci/ensure-nsc.sh index a4d3496..87cd9d9 100755 --- a/Scripts/ci/ensure-nsc.sh +++ b/Scripts/ci/ensure-nsc.sh @@ -31,7 +31,7 @@ if [[ "$os" != "linux" ]]; then exit 1 fi -version="${NSC_VERSION:-0.0.506}" +version="${NSC_VERSION:-0.0.520}" expected_sha256="" case "${version}/${arch}" in 0.0.506/amd64) expected_sha256="4a093e0269878a9514e7c00d99b88a924f307ad15fb9d1595ee5f6582f99a0f0" ;; diff --git a/Scripts/provision-forgejo-nsc.sh b/Scripts/provision-forgejo-nsc.sh index 890d9a2..b82757c 100755 --- a/Scripts/provision-forgejo-nsc.sh +++ b/Scripts/provision-forgejo-nsc.sh @@ -136,7 +136,20 @@ autoscaler_src="${REPO_ROOT}/services/forgejo-nsc/deploy/autoscaler.yaml" if [[ "${REFRESH_TOKEN}" -eq 1 || ! -s "${token_file}" ]]; then "${NSC_BIN}" auth check-login --duration 20m >/dev/null - "${NSC_BIN}" auth generate-dev-token --output_to "${token_file}" >/dev/null + token_name="${TOKEN_NAME_PREFIX}-namespace-$(date -u +%Y%m%dT%H%M%SZ)" + "${NSC_BIN}" token create \ + --name "${token_name}" \ + --description "Burrow Forgejo Namespace runner dispatcher" \ + --expires_in "${NSC_TOKEN_EXPIRES_IN:-30d}" \ + --grant '{"resource_type":"instance","resource_id":"*","actions":["create","destroy","dial_host","exec","get","list","refresh","ssh","wait"]}' \ + --grant '{"resource_type":"instance/ingress","resource_id":"*","actions":["list","register"]}' \ + --grant '{"resource_type":"instance/notification","resource_id":"*","actions":["list"]}' \ + --grant '{"resource_type":"instance/o11y/logs","resource_id":"*","actions":["get"]}' \ + --grant '{"resource_type":"cache/httpcache","resource_id":"*","actions":["ensure","read","write"]}' \ + --grant '{"resource_type":"bazel/cache","resource_id":"*","actions":["ensure"]}' \ + --grant '{"resource_type":"artifact","resource_id":"*","actions":["create","resolve","list"]}' \ + --token_file "${token_file}" \ + --output json >/dev/null chmod 600 "${token_file}" fi @@ -155,6 +168,7 @@ forgejo_pat="$( -o StrictHostKeyChecking=accept-new \ "${HOST}" \ "set -euo pipefail; forgejo_bin=\$(systemctl show -p ExecStart forgejo.service --value | sed -E 's/^\\{ path=([^ ;]+).*/\\1/'); sudo -u forgejo \"\${forgejo_bin}\" --config /var/lib/forgejo/custom/conf/app.ini --custom-path /var/lib/forgejo/custom --work-path /var/lib/forgejo admin user generate-access-token --username '${CONTACT_USER}' --scopes all --raw --token-name '${token_name}'" \ + | awk 'NF { line = $0 } END { print line }' \ | tr -d '\r\n' )" diff --git a/evolution/proposals/BEP-0009-release-infrastructure-and-store-upload-pipeline.md b/evolution/proposals/BEP-0009-release-infrastructure-and-store-upload-pipeline.md index e3e8ad9..a4aab36 100644 --- a/evolution/proposals/BEP-0009-release-infrastructure-and-store-upload-pipeline.md +++ b/evolution/proposals/BEP-0009-release-infrastructure-and-store-upload-pipeline.md @@ -103,6 +103,17 @@ The same change also makes the forge itself the release authority: release tags - `namespace-profile-linux-medium` - `namespace-profile-macos-large` - `namespace-profile-windows-large` +- Use dedicated Apple distribution labels for the focused tester-distribution + workflow so stale generic Namespace jobs cannot consume Apple release runners: + - `namespace-profile-linux-medium-apple` + - `namespace-profile-macos-large-apple` +- Run forge Namespace services with the repo-owned `nsc` package and keep it + current with the token format expected by Namespace. `nsc 0.0.520` is the + first required baseline for revokable token-file auth. +- Render the sealed Namespace runner token with `nsc token create --token_file` + instead of `nsc auth generate-dev-token`. The dev-token output is for direct + API/registry access, while the dispatcher needs the JSON token-file format + consumed by `nsc run`. - Add a Rust `burrow-windows-stub` binary so the Windows lane can validate packaging and upload mechanics before native Windows networking support is implemented. - Treat Sparkle as a macOS public-channel upload lane: - Generate staged appcast content from the signed macOS artifact when present. diff --git a/flake.nix b/flake.nix index dd81a6a..8727747 100644 --- a/flake.nix +++ b/flake.nix @@ -178,7 +178,7 @@ EOF nscPkg = if pkgs.stdenv.isLinux || pkgs.stdenv.isDarwin then let - version = "0.0.452"; + version = "0.0.520"; osName = if pkgs.stdenv.isLinux then "linux" @@ -192,18 +192,18 @@ EOF arch = "amd64"; hash = if pkgs.stdenv.isLinux then - "sha256-FBqOJ0UQWTv2r4HWMHrR/aqFzDa0ej/mS8dSoaCe6fY=" + "sha256-Fqy6baIGQOGwbMCYHECOy5GcJg23xSs8XaZRfia5aHE=" else - "sha256-3fRKWO0SCCa5PEym5yCB7dtyEx3xSxXSHfJYz8B+/4M="; + "sha256-dCOr3mjAAhaByXX4yUr0dXZan8Mx8nbfggUemK7psbM="; } else if pkgs.stdenv.hostPlatform.isAarch64 then { arch = "arm64"; hash = if pkgs.stdenv.isLinux then - "sha256-A6twO8Ievbu7Gi5Hqon4ug5rCGOm/uHhlCya3px6+io=" + "sha256-Vv+UUd0BpcxwEg2dCsGJ/7lFOcXrl9yNwHDoHrgivKY=" else - "sha256-n363xLaGhy+a6lw2F+WicQYGXnGYnqRW8aTQCSppwcw="; + "sha256-ASVXJhNwuWQ6T5nGTclZkv+5pPDPD/Q4i4nyAjVw2Gw="; } else throw "nsc: unsupported host platform ${pkgs.stdenv.hostPlatform.system}"; diff --git a/nixos/hosts/burrow-forge/default.nix b/nixos/hosts/burrow-forge/default.nix index 8de0d85..744dd43 100644 --- a/nixos/hosts/burrow-forge/default.nix +++ b/nixos/hosts/burrow-forge/default.nix @@ -50,6 +50,29 @@ let forgeAuthorizedKeys = map (username: builtins.readFile identities.${username}.sshPublicKeyPath) (builtins.attrNames (lib.filterAttrs (_: identity: identity.forgeAuthorized or false) identities)); + forgejoNscMaterializeTokenCache = '' + install -d -m 700 -o forgejo-nsc -g forgejo-nsc /var/lib/forgejo-nsc/.config/ns + ${pkgs.python3}/bin/python3 - <<'PY' +import json +from pathlib import Path + +raw = Path("/var/lib/forgejo-nsc/nsc.token").read_text(encoding="utf-8").strip() +if not raw: + raise SystemExit("empty Namespace token") +if raw.startswith("{"): + data = json.loads(raw) + if "bearer_token" not in data and "session_token" not in data: + raise SystemExit("Namespace token JSON must contain bearer_token or session_token") +else: + data = {"session_token": raw} +Path("/var/lib/forgejo-nsc/.config/ns/token.json").write_text( + json.dumps(data) + "\n", + encoding="utf-8", +) +PY + chown forgejo-nsc:forgejo-nsc /var/lib/forgejo-nsc/.config/ns/token.json + chmod 600 /var/lib/forgejo-nsc/.config/ns/token.json + ''; in { @@ -250,6 +273,7 @@ in services.forgejo-nsc = { enable = true; + nscPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.nsc; nscTokenFile = config.age.secrets.burrowForgejoNscToken.path; dispatcher = { configFile = config.age.secrets.burrowForgejoNscDispatcherConfig.path; @@ -260,6 +284,9 @@ in }; }; + systemd.services.forgejo-nsc-dispatcher.preStart = lib.mkAfter forgejoNscMaterializeTokenCache; + systemd.services.forgejo-nsc-autoscaler.preStart = lib.mkAfter forgejoNscMaterializeTokenCache; + services.burrow.authentik = { enable = true; envFile = config.age.secrets.burrowAuthentikEnv.path; diff --git a/secrets/infra/forgejo-nsc-autoscaler-config.age b/secrets/infra/forgejo-nsc-autoscaler-config.age index 0194fbc..3a37c7b 100644 Binary files a/secrets/infra/forgejo-nsc-autoscaler-config.age and b/secrets/infra/forgejo-nsc-autoscaler-config.age differ diff --git a/secrets/infra/forgejo-nsc-dispatcher-config.age b/secrets/infra/forgejo-nsc-dispatcher-config.age index ea48dbd..ce726c3 100644 Binary files a/secrets/infra/forgejo-nsc-dispatcher-config.age and b/secrets/infra/forgejo-nsc-dispatcher-config.age differ diff --git a/secrets/infra/forgejo-nsc-token.age b/secrets/infra/forgejo-nsc-token.age index ebbedd8..87ebd26 100644 Binary files a/secrets/infra/forgejo-nsc-token.age and b/secrets/infra/forgejo-nsc-token.age differ diff --git a/services/forgejo-nsc/deploy/autoscaler.yaml b/services/forgejo-nsc/deploy/autoscaler.yaml index 96b76b7..bafb81a 100644 --- a/services/forgejo-nsc/deploy/autoscaler.yaml +++ b/services/forgejo-nsc/deploy/autoscaler.yaml @@ -25,10 +25,18 @@ instances: min_idle: 0 ttl: "20m" machine_type: "8x16" + - labels: ["namespace-profile-linux-medium-apple"] + min_idle: 0 + ttl: "30m" + machine_type: "8x16" - labels: ["namespace-profile-macos-large"] min_idle: 0 ttl: "60m" machine_type: "macos/arm64:8x16" + - labels: ["namespace-profile-macos-large-apple"] + min_idle: 0 + ttl: "90m" + machine_type: "macos/arm64:8x16" - labels: ["namespace-profile-windows-large"] min_idle: 0 ttl: "45m" diff --git a/services/forgejo-nsc/deploy/dispatcher.yaml b/services/forgejo-nsc/deploy/dispatcher.yaml index 8fea57c..28f55ac 100644 --- a/services/forgejo-nsc/deploy/dispatcher.yaml +++ b/services/forgejo-nsc/deploy/dispatcher.yaml @@ -15,7 +15,7 @@ forgejo: namespace: nsc_binary: "/run/current-system/sw/bin/nsc" compute_base_url: "https://ord4.compute.namespaceapis.com" - image: "code.forgejo.org/forgejo/runner:3" + image: "code.forgejo.org/forgejo/runner:11" machine_type: "8x16" macos_base_image_id: "tahoe" macos_machine_arch: "arm64"