Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ self-hosted-runner:
- blacksmith-8vcpu-ubuntu-2404-arm
- blacksmith-8vcpu-windows-2025
- blacksmith-6vcpu-macos-26
- blacksmith-8vcpu-ubuntu-2404
4 changes: 2 additions & 2 deletions .github/workflows/agent-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
# Run unprivileged validation for stacked PRs as well as master targets.
workflow_dispatch:

# PR code, including forks, executes only on fresh hosted runners with a
# PR code, including forks, executes only on fresh managed runners with a
# read-only token. No signing, release publication, environment, or deployment
# credentials belong in this workflow.
permissions:
Expand Down Expand Up @@ -83,7 +83,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-26, windows-latest]
os: [blacksmith-8vcpu-ubuntu-2404, macos-26, windows-latest]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/agent-desktop-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ jobs:
name: Linux AppImage (${{ matrix.variant }})
needs: changes
if: ${{ always() && !cancelled() && ((github.event_name == 'pull_request' && (needs.changes.result != 'success' || needs.changes.outputs.agent != 'false')) || (github.repository == 'MaplePrivacyLabs/Maple' && github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch'))) }}
runs-on: ubuntu-latest
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 120
strategy:
fail-fast: false
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/android-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
environment: android-signing
needs: changes
if: ${{ always() && !cancelled() && (needs.changes.result != 'success' || needs.changes.outputs.frontend != 'false' || needs.changes.outputs.android != 'false') }}
runs-on: ubuntu-latest-8-cores
runs-on: blacksmith-8vcpu-ubuntu-2404
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # was v4
with:
Expand Down Expand Up @@ -102,7 +102,7 @@ jobs:

verify-android-artifacts:
needs: build-android
runs-on: ubuntu-latest-8-cores
runs-on: ubuntu-latest
permissions:
contents: read
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/android-pr-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
build-android:
needs: changes
if: ${{ always() && !cancelled() && (needs.changes.result != 'success' || needs.changes.outputs.android != 'false') }}
runs-on: ubuntu-latest
runs-on: blacksmith-8vcpu-ubuntu-2404
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # was v4
with:
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/desktop-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ jobs:
environment: desktop-signing
needs: changes
if: ${{ always() && !cancelled() && (needs.changes.result != 'success' || needs.changes.outputs.frontend != 'false' || needs.changes.outputs.linux != 'false') }}
runs-on: ubuntu-latest-8-cores
runs-on: blacksmith-8vcpu-ubuntu-2404
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # was v4
with:
Expand Down Expand Up @@ -167,7 +167,7 @@ jobs:
verify-linux-desktop-artifacts:
needs:
- build-linux
runs-on: ubuntu-latest-8-cores
runs-on: ubuntu-latest
permissions:
contents: read
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/desktop-pr-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ jobs:
build-linux:
needs: changes
if: ${{ always() && !cancelled() && (needs.changes.result != 'success' || needs.changes.outputs.linux != 'false') }}
runs-on: ubuntu-latest
runs-on: blacksmith-8vcpu-ubuntu-2404
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # was v4
with:
Expand Down
28 changes: 14 additions & 14 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ jobs:
- platform: macos-26-xlarge
nix_shell: ci
artifact_prefix: macos
- platform: ubuntu-latest-8-cores
- platform: blacksmith-8vcpu-ubuntu-2404
nix_shell: desktop-linux
artifact_prefix: linux

Expand All @@ -163,7 +163,7 @@ jobs:
- name: Cache sccache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # was v4
with:
path: ${{ startsWith(matrix.platform, 'macos') && '~/Library/Caches/Mozilla.sccache' || '~/.cache/sccache' }}
path: ${{ runner.os == 'macOS' && '~/Library/Caches/Mozilla.sccache' || '~/.cache/sccache' }}
key: ${{ runner.os }}-sccache-release-${{ hashFiles('apps/maple-research/frontend/src-tauri/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-sccache-release-
Expand All @@ -172,7 +172,7 @@ jobs:
# Ubuntu 24.04 restricts unprivileged user namespaces by default; linuxdeploy/AppImage
# packaging uses bubblewrap and otherwise fails with "bwrap: setting up uid map: Permission denied".
- name: Allow bubblewrap user namespaces
if: matrix.platform == 'ubuntu-latest-8-cores'
if: runner.os == 'Linux'
run: |
set -euo pipefail
if [ -e /proc/sys/kernel/apparmor_restrict_unprivileged_userns ]; then
Expand All @@ -185,15 +185,15 @@ jobs:
- name: Build Tauri desktop app
run: nix develop --no-update-lock-file .#${{ matrix.nix_shell }} -c ./scripts/ci/desktop-release.sh
env:
APPIMAGE_EXTRACT_AND_RUN: ${{ matrix.platform == 'ubuntu-latest-8-cores' && '1' || '' }}
NO_STRIP: ${{ matrix.platform == 'ubuntu-latest-8-cores' && 'true' || '' }}
APPIMAGE_EXTRACT_AND_RUN: ${{ runner.os == 'Linux' && '1' || '' }}
NO_STRIP: ${{ runner.os == 'Linux' && 'true' || '' }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_CERTIFICATE: ${{ runner.os == 'macOS' && secrets.APPLE_CERTIFICATE || '' }}
APPLE_CERTIFICATE_PASSWORD: ${{ runner.os == 'macOS' && secrets.APPLE_CERTIFICATE_PASSWORD || '' }}
APPLE_ID: ${{ runner.os == 'macOS' && secrets.APPLE_ID || '' }}
APPLE_PASSWORD: ${{ runner.os == 'macOS' && secrets.APPLE_ID_PASSWORD || '' }}
APPLE_TEAM_ID: ${{ runner.os == 'macOS' && secrets.APPLE_TEAM_ID || '' }}

- name: Show sccache stats
if: always()
Expand Down Expand Up @@ -382,7 +382,7 @@ jobs:
build-android:
environment: android-signing
needs: classify-app-release
runs-on: ubuntu-latest-8-cores
runs-on: blacksmith-8vcpu-ubuntu-2404
permissions:
contents: write
id-token: write
Expand Down Expand Up @@ -570,7 +570,7 @@ jobs:

build-web:
needs: classify-app-release
runs-on: ubuntu-latest-8-cores
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
Expand Down Expand Up @@ -764,7 +764,7 @@ jobs:
needs:
- classify-app-release
- build-android
runs-on: ubuntu-latest-8-cores
runs-on: ubuntu-latest
permissions:
contents: read
steps:
Expand Down Expand Up @@ -795,7 +795,7 @@ jobs:
needs:
- classify-app-release
- build-tauri
runs-on: ubuntu-latest-8-cores
runs-on: ubuntu-latest
permissions:
contents: read
steps:
Expand Down
12 changes: 12 additions & 0 deletions docs/repository-workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ artifacts to TestFlight. Creating a GitHub Release starts release builds and
downstream publication. Use `$release-maple` only for explicitly requested
release work, and report the tag and commit before publishing.

## Linux runners

Research desktop/Android compilation and Agent Linux CI/AppImage builds use
`blacksmith-8vcpu-ubuntu-2404`. Lightweight selectors, web builds, artifact
verification and the separate Agent attestation job remain on GitHub's standard
runners. Signing jobs retain their protected environments. The desktop release
build command only receives Apple environment variables on macOS, but that
condition does not restrict the runner's job secret context: approving a signing
job trusts its runner with the selected environment's secrets. PR builds have
no signing credentials and retain their existing branch-scoped caches. No
persistent vendor disks or Docker builders are configured by these workflows.

## macOS runners and Apple toolchain

Unsigned Research desktop/iOS PR builds and Agent release-binary jobs use
Expand Down
13 changes: 13 additions & 0 deletions scripts/ci/test_signing_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,19 @@ def test_windows_oidc_keeps_its_federated_environment_identity(self):
self.assertEqual(job["environment"], "windows-signing")
self.assertEqual(job.get("permissions", workflows()[name]["permissions"])["id-token"], "write")

def test_desktop_release_linux_build_subprocess_has_no_apple_environment(self):
# Step env is evaluated on the runner. This checks subprocess hygiene,
# not isolation from the job's protected-environment secret context.
job = workflows()["release.yml"]["jobs"]["build-tauri"]
build = next(step for step in job["steps"]
if step.get("name") == "Build Tauri desktop app")
for name in ("APPLE_CERTIFICATE", "APPLE_CERTIFICATE_PASSWORD", "APPLE_ID",
"APPLE_PASSWORD", "APPLE_TEAM_ID"):
self.assertTrue(build["env"][name].startswith("${{ runner.os == 'macOS' && secrets."))
self.assertTrue(build["env"][name].endswith(" || '' }}"))
for name in ("TAURI_SIGNING_PRIVATE_KEY", "TAURI_SIGNING_PRIVATE_KEY_PASSWORD"):
self.assertEqual(build["env"][name], "${{ secrets." + name + " }}")

def test_dev_testflight_runs_for_every_master_push_and_only_trusted_manual_runs(self):
config = workflows()["ios-dev-testflight.yml"]
self.assertEqual(config["on"], {"push": {"branches": ["master"]}, "workflow_dispatch": None})
Expand Down
Loading