Skip to content

Agent: distinguish sidebar task activity states #160

Agent: distinguish sidebar task activity states

Agent: distinguish sidebar task activity states #160

Workflow file for this run

# CI: the single required check (ci-ok) for every pull request, on any base.
# Lane selection lives in scripts/ci/lanes.py and scripts/ci/plan.py. Generic
# lanes run in the `nix` and `windows` matrices; a special job exists only where
# a step list cannot be expressed generically (services, OIDC, artifacts, or a
# cache that another workflow writes).
# Never add `paths:` here: ci-ok must always report.
name: CI
on:
pull_request:
merge_group:
types: [checks_requested]
push:
branches: [master]
schedule:
# The nightly lanes on the master tip: refreshes caches and catches misroutes.
- cron: "17 4 * * *"
workflow_dispatch:
inputs:
lanes:
description: "Lane ids (comma-separated) or 'all'"
type: string
default: all
permissions:
contents: read
concurrency:
# PRs replace superseded runs. Master, queue and dispatch runs are grouped per
# SHA and never cancelled, so every master commit gets a full verdict.
group: ci-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.merge_group.head_sha || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: "0"
CARGO_PROFILE_DEV_DEBUG: "0"
CARGO_NET_GIT_FETCH_WITH_CLI: "true"
jobs:
plan:
name: plan
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
issues: read # live PR labels: add a label, then re-run
pull-requests: read
outputs:
lanes: ${{ steps.plan.outputs.lanes }}
quarantine: ${{ steps.plan.outputs.quarantine }}
nix: ${{ steps.plan.outputs.nix }}
windows: ${{ steps.plan.outputs.windows }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0
filter: blob:none
persist-credentials: false
- name: Select lanes
id: plan
env:
GH_TOKEN: ${{ github.token }}
LANES_INPUT: ${{ inputs.lanes }}
CI_LINUX_RUNNER: ${{ vars.CI_LINUX_RUNNER }}
CI_LINUX_HEAVY_RUNNER: ${{ vars.CI_LINUX_HEAVY_RUNNER }}
CI_MACOS_RUNNER: ${{ vars.CI_MACOS_RUNNER }}
CI_WINDOWS_RUNNER: ${{ vars.CI_WINDOWS_RUNNER }}
CI_QUARANTINE: ${{ vars.CI_QUARANTINE }}
run: python3 scripts/ci/plan.py github
nix:
name: ${{ matrix.id }}
needs: plan
if: needs.plan.outputs.nix != '[]'
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(needs.plan.outputs.nix) }}
runs-on: ${{ matrix.runner }}
timeout-minutes: ${{ matrix.timeout }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
# OpenSecret's flake reads its submodule, which Nix fetches only with full history.
# Blobless history has every commit and tree but only the checked-out files'
# contents, so Nix reads the same source from a ninth of the download.
submodules: ${{ matrix.submodules }}
fetch-depth: ${{ matrix.fetch_depth }}
filter: ${{ matrix.filter }}
- uses: ./.github/actions/setup-nix
- name: Select pinned Xcode
if: runner.os == 'macOS'
run: python3 scripts/ci/select-xcode.py
- name: Restore master's Research Rust cache (read-only)
if: matrix.restore == 'research-rust'
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
# Exactly rust-tests.yml's key and paths; it is the only writer. Its Cargo git
# database spares the PDFOxide fetch Cargo makes for every target.
key: ci-v2-research-rust-${{ hashFiles('apps/maple-research/frontend/src-tauri/Cargo.lock', 'flake.lock') }}
restore-keys: ci-v2-research-rust-
path: |
~/.cache/sccache
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
- name: Rust cache (restore everywhere, save only on master and in the lane's home store)
id: rust-cache
if: matrix.cache != ''
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
prefix-key: ci-v2
# Restore key: the prefix, the shared key (the lane and its toolchain pins,
# plan.py cache_key) and the runner's rustc versions and CARGO*/RUST* variables.
# The cache key adds third-party Cargo.lock entries and versionless manifests:
# a version bump hits exactly, any other lockfile change restores by prefix.
shared-key: ${{ matrix.cache }}-${{ matrix.cache_key }}
workspaces: ${{ matrix.workspaces }}
cache-targets: ${{ matrix.cache_targets }}
add-rust-environment-hash-key: "true"
# The action runs cargo from the workspace directory: use an absolute flake path.
cmd-format: nix develop --no-update-lock-file ${{ github.workspace }}/${{ matrix.flake }} -c {0}
# cache_save (plan.py): a failover runner never saves into another vendor's store.
save-if: ${{ github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'schedule') && matrix.cache_save }}
- name: Build master's lane cache from one dependency graph
# rust-cache's save keeps every build of a crate still in the graph, so saving after
# a prefix restore would carry the old graph's builds forward: master starts clean.
if: matrix.cache != '' && matrix.cache_targets && steps.rust-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'schedule') && matrix.cache_save
env:
WORKSPACES: ${{ matrix.workspaces }}
run: |
root=${WORKSPACES%% ->*} target=${WORKSPACES##*-> }
rm -rf "${root:?}/${target:?}"
- name: Run lane
env:
LANE: ${{ matrix.id }}
run: python3 scripts/ci/plan.py run "$LANE"
windows:
name: ${{ matrix.id }}
needs: plan
if: needs.plan.outputs.windows != '[]'
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(needs.plan.outputs.windows) }}
runs-on: ${{ matrix.runner }}
timeout-minutes: ${{ matrix.timeout }}
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- uses: ./.github/actions/setup-agent-windows
- name: Rust cache (restore everywhere, save only on master and in the lane's home store)
id: rust-cache
if: matrix.cache != ''
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
# Keys as in the nix job: a lockfile change restores by prefix.
prefix-key: ci-v2
shared-key: ${{ matrix.cache }}-${{ matrix.cache_key }}
workspaces: ${{ matrix.workspaces }}
cache-targets: ${{ matrix.cache_targets }}
add-rust-environment-hash-key: "true"
# cache_save (plan.py): a failover runner never saves into another vendor's store.
save-if: ${{ github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'schedule') && matrix.cache_save }}
- name: Build master's lane cache from one dependency graph
# rust-cache's save keeps every build of a crate still in the graph, so saving after
# a prefix restore would carry the old graph's builds forward: master starts clean.
if: matrix.cache != '' && matrix.cache_targets && steps.rust-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/master' && (github.event_name == 'push' || github.event_name == 'schedule') && matrix.cache_save
env:
WORKSPACES: ${{ matrix.workspaces }}
run: |
root=${WORKSPACES%% ->*} target=${WORKSPACES##*-> }
rm -rf "${root:?}/${target:?}"
- name: Run lane
env:
LANE: ${{ matrix.id }}
run: python3 scripts/ci/plan.py run "$LANE"
# Unsigned Dev packages built like agent-desktop-build.yml's master builds, from
# their own thin-LTO cache, which only the nightly run saves. Run by ci:package,
# ci:full and the nightly run.
agent-package-linux:
name: agent-package-linux
needs: plan
if: fromJSON(needs.plan.outputs.lanes)['agent-package-linux']
runs-on: ${{ vars.CI_LINUX_RUNNER || 'blacksmith-8vcpu-ubuntu-2404' }}
timeout-minutes: 60
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- uses: ./.github/actions/setup-nix
- name: Restore the packaging rehearsal cache
id: package-cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
# Thin-LTO release artifacts; master's fat-LTO cache cannot serve them.
key: ci-v1-agent-package-${{ runner.os }}-${{ hashFiles('apps/maple-agent/flake.lock', 'apps/maple-agent/Cargo.lock') }}
restore-keys: ci-v1-agent-package-${{ runner.os }}-
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
apps/maple-agent/target
- name: Build, package, verify and smoke-test an unsigned Dev bundle
run: python3 scripts/ci/plan.py run agent-package-linux
- name: Save the packaging rehearsal cache (nightly, Blacksmith only)
if: ${{ github.ref == 'refs/heads/master' && github.event_name == 'schedule' && startsWith(runner.name, 'blacksmith') && steps.package-cache.outputs.cache-hit != 'true' }}
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
key: ${{ steps.package-cache.outputs.cache-primary-key }}
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
apps/maple-agent/target
- name: Upload the unsigned package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: maple-agent-dev-linux-x86_64-unsigned-${{ github.run_id }}
path: apps/maple-agent/dist/dev/
if-no-files-found: error
retention-days: 7
agent-package-macos:
name: agent-package-macos
needs: plan
if: fromJSON(needs.plan.outputs.lanes)['agent-package-macos']
runs-on: ${{ vars.CI_MACOS_RUNNER || 'blacksmith-6vcpu-macos-26' }}
timeout-minutes: 60
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- uses: ./.github/actions/setup-nix
- name: Select pinned Xcode
run: python3 scripts/ci/select-xcode.py
- name: Restore the packaging rehearsal cache
id: package-cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
# Thin-LTO release artifacts; master's fat-LTO cache cannot serve them.
key: ci-v1-agent-package-${{ runner.os }}-${{ hashFiles('apps/maple-agent/flake.lock', 'apps/maple-agent/Cargo.lock') }}
restore-keys: ci-v1-agent-package-${{ runner.os }}-
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
apps/maple-agent/target
- name: Build, package and verify an unsigned Dev app
run: python3 scripts/ci/plan.py run agent-package-macos
- name: Save the packaging rehearsal cache (nightly, Blacksmith only)
if: ${{ github.ref == 'refs/heads/master' && github.event_name == 'schedule' && startsWith(runner.name, 'blacksmith') && steps.package-cache.outputs.cache-hit != 'true' }}
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
key: ${{ steps.package-cache.outputs.cache-primary-key }}
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
apps/maple-agent/target
- name: Upload the unsigned package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: maple-agent-dev-macos-aarch64-unsigned-${{ github.run_id }}
path: apps/maple-agent/dist/dev/
if-no-files-found: error
retention-days: 7
agent-package-windows:
name: agent-package-windows
needs: plan
if: fromJSON(needs.plan.outputs.lanes)['agent-package-windows']
# GitHub's image, where master's install smoke runs (scripts/ci/lanes.py GITHUB_WINDOWS).
runs-on: ${{ vars.CI_WINDOWS_GITHUB_RUNNER || 'maple-windows-2025-16core' }}
timeout-minutes: 90
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- uses: ./.github/actions/setup-agent-windows
with:
release: "true"
- name: Restore the packaging rehearsal cache
id: package-cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
# Thin-LTO release artifacts; master's fat-LTO cache cannot serve them.
key: ci-v1-agent-package-${{ runner.os }}-${{ hashFiles('apps/maple-agent/flake.lock', 'apps/maple-agent/Cargo.lock') }}
restore-keys: ci-v1-agent-package-${{ runner.os }}-
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
apps/maple-agent/target
- name: Build, package and verify an unsigned Dev installer
run: python3 scripts/ci/plan.py run agent-package-windows
- name: Save the packaging rehearsal cache (nightly, GitHub's runners only)
if: ${{ github.ref == 'refs/heads/master' && github.event_name == 'schedule' && !startsWith(runner.name, 'blacksmith') && steps.package-cache.outputs.cache-hit != 'true' }}
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
key: ${{ steps.package-cache.outputs.cache-primary-key }}
path: |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
apps/maple-agent/target
- name: Upload the unsigned package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: maple-agent-dev-windows-x86_64-unsigned-${{ github.run_id }}
path: apps/maple-agent/dist/dev/
if-no-files-found: error
retention-days: 7
# Research Rust on PRs, warm from rust-tests.yml's master cache (read-only).
research-rust:
name: research-rust
needs: plan
if: fromJSON(needs.plan.outputs.lanes)['research-rust']
runs-on: ${{ vars.CI_LINUX_RUNNER || 'blacksmith-8vcpu-ubuntu-2404' }}
timeout-minutes: 45
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- uses: ./.github/actions/setup-nix
- name: Restore master's Research Rust cache (read-only)
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
# Exactly rust-tests.yml's key and paths; it is the only writer.
key: ci-v2-research-rust-${{ hashFiles('apps/maple-research/frontend/src-tauri/Cargo.lock', 'flake.lock') }}
restore-keys: ci-v2-research-rust-
path: |
~/.cache/sccache
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
- name: Check formatting and local dependencies, then test
run: python3 scripts/ci/plan.py run research-rust
# Unsigned Research platform builds. They restore what the master signed
# builds save and never save anything.
research-ios:
name: research-ios
needs: plan
if: fromJSON(needs.plan.outputs.lanes)['research-ios']
runs-on: ${{ vars.CI_MACOS_RUNNER || 'blacksmith-6vcpu-macos-26' }}
timeout-minutes: 120 # a missed ONNX Runtime cache builds it from source
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- name: Select pinned Xcode
id: select_xcode
run: python3 scripts/ci/select-xcode.py
- uses: ./.github/actions/setup-nix
- name: Restore master's ONNX Runtime iOS artifact (read-only)
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: |
apps/maple-research/frontend/src-tauri/onnxruntime-ios
key: release-onnxruntime-ios-artifact-1.23.2-xcode${{ steps.select_xcode.outputs.version }}-${{ steps.select_xcode.outputs.build }}-${{ hashFiles('flake.lock', 'flake.nix', 'scripts/ci/apple-toolchain.json', 'scripts/ci/select-xcode.py', 'scripts/ci/_common.sh', 'scripts/ci/ios-onnxruntime.sh', 'apps/maple-research/frontend/src-tauri/scripts/build-ios-onnxruntime-all.sh', 'apps/maple-research/frontend/src-tauri/scripts/canonicalize-static-archive.py', 'apps/maple-research/frontend/src-tauri/scripts/onnxruntime-pins.sh') }}
restore-keys: |
release-onnxruntime-ios-artifact-1.23.2-xcode${{ steps.select_xcode.outputs.version }}-${{ steps.select_xcode.outputs.build }}-
- name: Build the iOS simulator app
run: python3 scripts/ci/plan.py run research-ios
- name: Upload the simulator app
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: maple-ios-simulator-pr
path: |
apps/maple-research/frontend/src-tauri/gen/apple/build/**/*.app
apps/maple-research/frontend/src-tauri/target/reproducibility/ios-*.sha256
retention-days: 5
research-desktop-macos:
name: research-desktop-macos
needs: plan
if: fromJSON(needs.plan.outputs.lanes)['research-desktop-macos']
runs-on: ${{ vars.CI_MACOS_RUNNER || 'blacksmith-6vcpu-macos-26' }}
timeout-minutes: 45
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- name: Select pinned Xcode
run: python3 scripts/ci/select-xcode.py
- uses: ./.github/actions/setup-nix
- name: Restore master's macOS sccache (read-only)
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/Library/Caches/Mozilla.sccache
key: ${{ runner.os }}-sccache-macos-release-${{ hashFiles('apps/maple-research/frontend/src-tauri/Cargo.lock') }}
restore-keys: ${{ runner.os }}-sccache-macos-release-
- name: Build the unsigned universal app and DMG
run: python3 scripts/ci/plan.py run research-desktop-macos
- name: Upload the unsigned app
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: maple-macos-universal-pr
path: |
apps/maple-research/frontend/src-tauri/target/universal-apple-darwin/release/bundle/dmg/*.dmg
apps/maple-research/frontend/src-tauri/target/universal-apple-darwin/release/bundle/macos/*.app
apps/maple-research/frontend/src-tauri/target/reproducibility/maple-macos-app.tar.gz
apps/maple-research/frontend/src-tauri/target/reproducibility/desktop-pr-macos-*.sha256
retention-days: 5
research-desktop-linux:
name: research-desktop-linux
needs: plan
if: fromJSON(needs.plan.outputs.lanes)['research-desktop-linux']
runs-on: ${{ vars.CI_LINUX_RUNNER || 'blacksmith-8vcpu-ubuntu-2404' }}
timeout-minutes: 45
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- uses: ./.github/actions/setup-nix
- name: Restore master's Linux sccache (read-only)
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.cache/sccache
key: ${{ runner.os }}-sccache-linux-release-${{ hashFiles('apps/maple-research/frontend/src-tauri/Cargo.lock') }}
restore-keys: ${{ runner.os }}-sccache-linux-release-
- name: Allow bubblewrap user namespaces
# Ubuntu 24.04 restricts them; AppImage packaging fails without them.
run: |
if [ -e /proc/sys/kernel/apparmor_restrict_unprivileged_userns ]; then
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
fi
if [ -e /proc/sys/kernel/unprivileged_userns_clone ]; then
sudo sysctl -w kernel.unprivileged_userns_clone=1
fi
- name: Build unsigned packages with fake updater signatures
run: python3 scripts/ci/plan.py run research-desktop-linux
- name: Upload the packages
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: maple-linux-pr
path: |
apps/maple-research/frontend/src-tauri/target/release/bundle/appimage/*.AppImage
apps/maple-research/frontend/src-tauri/target/release/bundle/appimage/*.AppImage.sig
apps/maple-research/frontend/src-tauri/target/release/bundle/deb/*.deb
apps/maple-research/frontend/src-tauri/target/release/bundle/deb/*.deb.sig
apps/maple-research/frontend/src-tauri/target/release/bundle/rpm/*.rpm
apps/maple-research/frontend/src-tauri/target/release/bundle/rpm/*.rpm.sig
apps/maple-research/frontend/src-tauri/target/reproducibility/desktop-pr-linux-fake-updater.pub
apps/maple-research/frontend/src-tauri/target/reproducibility/desktop-pr-linux-*.sha256
retention-days: 5
# Builds the unsigned installer, then verifies its proofs, as desktop-build.yml's
# Linux verifier does for the signed one.
research-desktop-windows:
name: research-desktop-windows
needs: plan
if: fromJSON(needs.plan.outputs.lanes)['research-desktop-windows']
runs-on: ${{ vars.CI_WINDOWS_GITHUB_RUNNER || 'maple-windows-2025-16core' }}
timeout-minutes: 60
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- uses: oven-sh/setup-bun@f4d14e03ff726c06358e5557344e1da148b56cf7 # v1
with:
bun-version: 1.3.5
no-cache: true # its post step would save the binary from a pull request
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable action, exact toolchain below
with:
toolchain: 1.94.1 # desktop-build.yml's Windows toolchain
- name: Build the unsigned installer and verify its proofs
run: python3 scripts/ci/plan.py run research-desktop-windows
- name: Upload the installer and its proofs
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: maple-windows-x64-pr
path: |
apps/maple-research/frontend/src-tauri/target/release/bundle/nsis/*.exe
apps/maple-research/frontend/src-tauri/target/release/maple.exe
apps/maple-research/frontend/src-tauri/resources/windows/*.dll
apps/maple-research/frontend/src-tauri/target/reproducibility/desktop-pr-windows-*.sha256
retention-days: 5
research-dev-macos:
name: research-dev-macos
needs: plan
if: fromJSON(needs.plan.outputs.lanes)['research-dev-macos']
runs-on: ${{ vars.CI_MACOS_RUNNER || 'blacksmith-6vcpu-macos-26' }}
timeout-minutes: 45
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
# The package's evidence names the exact PR head, not the merge commit.
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- name: Select pinned Xcode
run: python3 scripts/ci/select-xcode.py
- uses: ./.github/actions/setup-nix
- name: Build the unsigned Research Dev app
run: python3 scripts/ci/plan.py run research-dev-macos
- name: Upload the Dev package and its identity proof
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: maple-research-dev-macos-pr
path: |
apps/maple-research/frontend/src-tauri/target/research-dev/maple-research-dev-macos.tar.gz
apps/maple-research/frontend/src-tauri/target/research-dev/build-profile.json
if-no-files-found: error
retention-days: 5
# Both SDKs against the in-tree OpenSecret backend and a disposable PostgreSQL.
os-sdk-e2e:
name: os-sdk-e2e
needs: plan
if: fromJSON(needs.plan.outputs.lanes)['os-sdk-e2e']
runs-on: ${{ vars.CI_LINUX_RUNNER || 'blacksmith-8vcpu-ubuntu-2404' }}
timeout-minutes: 45
services:
postgres:
image: postgres:17
env:
POSTGRES_DB: opensecret
POSTGRES_PASSWORD: password
POSTGRES_USER: opensecret_user
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U opensecret_user -d opensecret"
--health-interval 5s
--health-timeout 5s
--health-retries 12
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
submodules: recursive
# Nix requires revCount for recursively fetched Git inputs; blobless
# history keeps every commit, so Nix reads the same source.
fetch-depth: 0
filter: blob:none
- uses: ./.github/actions/setup-nix
- name: Migrate, start OpenSecret and run both SDKs' integration suites
run: python3 scripts/ci/plan.py run os-sdk-e2e
# OpenSecret's parent-side helper images (they run beside the enclave, not in
# the EIF): built for ARM64 and tested offline, never published, then scanned.
os-helpers:
name: os-helpers (${{ matrix.helper }})
needs: plan
if: fromJSON(needs.plan.outputs.lanes)['os-helpers']
runs-on: ubuntu-24.04-arm
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
helper: [credential-requester, enclave-logging]
env:
HELPER: ${{ matrix.helper }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- name: Build the Linux ARM64 image and run its tests offline
run: python3 scripts/ci/plan.py run os-helpers
- name: Scan finished image for fixable high and critical vulnerabilities
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
version: v0.75.0
image-ref: ${{ matrix.helper }}:ci
format: table
exit-code: '1'
ignore-unfixed: true
severity: HIGH,CRITICAL
scanners: vuln
cache: "false" # pull requests save no caches
# The PR EIF candidate: dev and prod EIFs built on the release builder's runner
# class, never signed or published. The planner selects it only for
# same-repository PRs to master whose diff has EIF inputs (or the ci:eif label)
# and edits no PCR approval (opensecret-eif.yml compares approval edits);
# because it mints an OIDC token for the FlakeHub cache, the event, base branch
# and head repository are checked here too.
os-eif:
name: os-eif (${{ matrix.mode }})
needs: plan
if: >-
${{
fromJSON(needs.plan.outputs.lanes)['os-eif'] &&
github.event_name == 'pull_request' &&
github.event.pull_request.base.ref == 'master' &&
github.event.pull_request.head.repo.full_name == github.repository
}}
permissions:
contents: read
id-token: write
runs-on: blacksmith-16vcpu-ubuntu-2404-arm
timeout-minutes: 180
strategy:
fail-fast: false
matrix:
mode: [dev, prod]
env:
EIF_MODE: ${{ matrix.mode }}
OPENSECRET_DEV_POSTGRES: "0"
OPENSECRET_DEV_ENV: "0"
OPENSECRET_DEV_CONTAINERS: "0"
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
submodules: recursive
# Blobless full history: the same source, narHash and EIF derivation as a full clone.
fetch-depth: 0
filter: blob:none
- name: Install pinned Determinate Nix for FlakeHub authentication
uses: DeterminateSystems/determinate-nix-action@96c5ee93a9dddf2830d31e1da6ec719077336c28 # v3.23.3
with:
source-tag: v3.23.3
github-token: ""
- name: Verify pinned Nix runtime
run: bash scripts/ci/verify-nix-runtime.sh
- name: Reuse FlakeHub with an Actions cache fallback
uses: DeterminateSystems/flakehub-cache-action@1f9a51a2959d3e26c7838c6f3bf9f48acae525ea # v3
with:
diff-store: true
# No Actions artifact, attestation, signing, or release is produced here.
# The Nix cache is only a build cache, not an approved deployment handoff.
- name: Build PR candidate without signing or publication
shell: bash
run: |
echo 'PR diagnostic only: source_sha is the PR merge ref, not a release source commit. No approved artifact is uploaded.' >> "$GITHUB_STEP_SUMMARY"
bash scripts/ci/build_opensecret_eif.sh "$EIF_MODE" "$RUNNER_TEMP/eif-candidate-$EIF_MODE"
- name: Inspect exact PR candidate user ramdisk CA bundle
shell: bash
run: python3 scripts/ci/verify_opensecret_eif_rootfs.py "$EIF_MODE" "$RUNNER_TEMP/eif-candidate-$EIF_MODE" "$GITHUB_SHA"
ci-ok:
name: ci-ok
if: always()
needs: [plan, nix, windows, agent-package-linux, agent-package-macos, agent-package-windows, research-rust,
research-ios, research-desktop-macos, research-desktop-linux, research-desktop-windows,
research-dev-macos, os-sdk-e2e, os-helpers, os-eif]
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
actions: read # the run's job results, read only to attribute a quarantined lane's failure
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
sparse-checkout: scripts/ci
- name: Every selected lane succeeded
env:
GH_TOKEN: ${{ github.token }}
NEEDS: ${{ toJSON(needs) }}
run: python3 scripts/ci/plan.py verdict