Skip to content

Add Plugin surface alignment tests #15308

Add Plugin surface alignment tests

Add Plugin surface alignment tests #15308

Workflow file for this run

name: build
permissions: # Principle of least privilege
contents: read
actions: read
on:
push:
branches: [master, nightly, develop, test-ci, test-pre-commit]
pull_request:
branches-ignore: [master, nightly]
concurrency:
# yamllint disable-line rule:line-length
group: ${{ github.workflow }}-${{ github.event.pull_request.number || format('{0}-{1}', github.ref_name, github.sha) }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
# Fork PRs lack repo/org vars, so audit instead of block.
EGRESS_POLICY: >-
${{ github.event.pull_request.head.repo.fork && 'audit'
|| vars.STEP_SECURITY_EGRESS_POLICY
|| 'block' }}
jobs:
plan:
runs-on: ubuntu-latest
outputs:
run-tests: ${{ steps.plan.outputs.run_tests }}
run-rust-tests: ${{ steps.plan.outputs.run_rust_tests }}
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
- name: Plan
id: plan
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
BASE_REF: ${{ github.event.pull_request.base.ref }}
BEFORE_SHA: ${{ github.event.before }}
run: bash scripts/ci/plan.sh
pre-commit:
# Fork PRs stay GitHub-hosted.
runs-on: >-
${{ github.event.pull_request.head.repo.fork
&& 'ubuntu-22.04'
|| fromJson('["self-hosted", "Linux", "X64", "build"]') }}
env:
# Self-hosted keeps Rust artifacts outside the workspace.
CARGO_TARGET_DIR: >-
${{ github.event.pull_request.head.repo.fork
&& format('{0}/target', github.workspace)
|| '/home/runner/.cache/cargo-target/pre-commit' }}
CARGO_CI_PROFILE: >-
${{ github.event.pull_request.head.repo.fork && 'ci-pr' || 'nextest' }}
# Scopes incremental clippy/doc checks; empty for non-PR/push events.
CHANGED_BASE_SHA: >-
${{ github.event.pull_request.base.sha || github.event.before }}
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# Full history so changed-file scripts can resolve CHANGED_BASE_SHA.
fetch-depth: 0
# Temporary: fail fast on rare runner worktree corruption while we isolate the root cause
- name: Verify immutable CI inputs (post-checkout)
run: bash scripts/ci/verify-ci-inputs.sh post-checkout
- name: Common setup
uses: ./.github/actions/common-setup
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
python-version: "3.13"
free-disk-space: "true"
build-type: "pre-commit"
rust-cache-enabled: >-
${{ github.event.pull_request.head.repo.fork && 'true' || 'false' }}
- name: Limit Cargo build jobs on GitHub-hosted runners
if: github.event.pull_request.head.repo.fork
run: echo "CARGO_BUILD_JOBS=2" >> "$GITHUB_ENV"
- name: Run pre-commit
run: prek run --all-files
- name: Verify capnp schemas are up-to-date
run: make check-capnp-schemas
# Dependency license, advisory, and ban checks (master only - gates releases)
# https://embarkstudios.github.io/cargo-deny/
cargo-deny:
if: github.ref == 'refs/heads/master'
runs-on: ubuntu-22.04
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Install cargo-deny
uses: ./.github/actions/cargo-tool-install
with:
tool-name: cargo-deny
- name: Run cargo-deny (advisories, licenses, sources, bans)
run: cargo deny --all-features check advisories licenses sources bans
# Supply chain security auditing (master only - gates releases)
# https://mozilla.github.io/cargo-vet/configuring-ci.html
cargo-vet:
if: github.ref == 'refs/heads/master'
runs-on: ubuntu-22.04
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Install cargo-vet
uses: ./.github/actions/cargo-tool-install
with:
tool-name: cargo-vet
- name: Run cargo-vet
run: cargo vet --locked
build-linux-x86:
if: github.ref != 'refs/heads/test-pre-commit' && needs.plan.outputs.run-tests == 'true'
strategy:
fail-fast: false
matrix:
python-version:
- "3.12"
- "3.13"
- "3.14"
defaults:
run:
shell: bash
# Ubuntu 22.04 (glibc 2.35) keeps the wheel runtime range broad.
# Fork PRs stay GitHub-hosted.
name: build - python ${{ matrix.python-version }} (ubuntu-22.04)
runs-on: >-
${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork
&& 'ubuntu-22.04'
|| github.event_name == 'pull_request'
&& fromJson('["self-hosted", "Linux", "X64", "build"]')
|| github.event_name == 'push' && github.ref_name == 'develop'
&& fromJson('["self-hosted", "Linux", "X64", "build"]')
|| fromJson('["depot-ubuntu-22.04-8"]') }}
needs:
- plan
- pre-commit
env:
BUILD_MODE: >-
${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork
&& 'ci-pr' || 'release' }}
CARGO_CI_PROFILE: >-
${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork
&& 'ci-pr' || 'nextest' }}
PARALLEL_BUILD: >-
${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork
&& 'false' || 'true' }}
# Self-hosted develop pushes keep Rust artifacts outside the workspace so
# they survive actions/checkout's git clean -ffdx between runs.
CARGO_TARGET_DIR: >-
${{ github.event_name == 'push' && github.ref_name == 'develop'
&& format('/home/runner/.cache/cargo-target/build-linux-x86/py{0}', matrix.python-version)
|| format('{0}/target/build-linux-x86', github.workspace) }}
RUST_BACKTRACE: 1
# yamllint disable rule:line-length
services:
redis:
image: public.ecr.aws/docker/library/redis:7.4.5-alpine3.21@sha256:bb186d083732f669da90be8b0f975a37812b15e913465bb14d845db72a4e3e08
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
postgres:
image: public.ecr.aws/docker/library/postgres:16.4-alpine@sha256:5660c2cbfea50c7a9127d17dc4e48543eedd3d7a41a595a2dfa572471e37e64c
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: pass
POSTGRES_DB: nautilus
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d nautilus" --health-interval 10s --health-timeout 5s --health-retries
5
# yamllint enable rule:line-length
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# Temporary: fail fast on rare runner worktree corruption while we isolate the root cause
- name: Verify immutable CI inputs (post-checkout)
run: bash scripts/ci/verify-ci-inputs.sh post-checkout
- name: Common setup
uses: ./.github/actions/common-setup
with:
python-version: ${{ matrix.python-version }}
free-disk-space: "true"
# Persistent CARGO_TARGET_DIR on the self-hosted build pool replaces
# Swatinem/rust-cache for develop push builds.
rust-cache-enabled: ${{ github.event_name == 'push' && github.ref_name == 'develop' && 'false' || 'true' }}
rust-cache-key: build-linux-x86
rust-cache-workspaces: . -> target/build-linux-x86
rust-cache-save-if: ${{ github.event_name == 'push' }}
- name: Limit Cargo build jobs on GitHub-hosted runners
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork
run: echo "CARGO_BUILD_JOBS=2" >> "$GITHUB_ENV"
- name: Install Nautilus CLI
env:
NAUTILUS_CLI_FORCE_SOURCE: ${{ github.ref == 'refs/heads/nightly' && '1' || '0' }}
run: bash scripts/ci/install-nautilus-cli.sh
- name: Init postgres schema
run: nautilus database init --schema ${{ github.workspace }}/schema/sql
env:
POSTGRES_HOST: localhost
POSTGRES_PORT: 5432
POSTGRES_USERNAME: postgres
POSTGRES_PASSWORD: pass
POSTGRES_DATABASE: nautilus
- name: Cached test data
uses: ./.github/actions/common-test-data
- name: Run Rust tests (core)
if: needs.plan.outputs.run-rust-tests == 'true'
run: make cargo-test-core EXTRA_FEATURES="capnp,hypersync" NEXTEST_PROFILE=ci
- name: Run Rust tests (adapters)
if: needs.plan.outputs.run-rust-tests == 'true'
run: make cargo-test-adapters EXTRA_FEATURES="capnp,hypersync" NEXTEST_PROFILE=ci
- name: Clean Rust test artifacts
if: needs.plan.outputs.run-rust-tests == 'true'
run: |
rm -rf "${CARGO_TARGET_DIR}/nextest"
rm -rf "${CARGO_TARGET_DIR}/${CARGO_CI_PROFILE:-nextest}"
df -h .
# Temporary: fail fast on rare runner worktree corruption while we isolate the root cause
- name: Verify immutable CI inputs (pre-wheel build)
run: bash scripts/ci/verify-ci-inputs.sh pre-wheel-build
- name: Build and install wheel
uses: ./.github/actions/common-wheel-build
with:
python-version: ${{ matrix.python-version }}
github_ref: ${{ github.ref }}
- name: Run tests
run: |
uv run --no-sync pytest --ignore=tests/performance_tests \
-n logical --dist=loadgroup --reruns 2 --reruns-delay 1
- name: Upload wheel artifact
uses: ./.github/actions/upload-artifact-wheel
build-linux-arm:
strategy:
fail-fast: false
matrix:
python-version:
- "3.12"
- "3.13"
- "3.14"
defaults:
run:
shell: bash
name: build - python ${{ matrix.python-version }} (ubuntu-22.04-arm)
runs-on: depot-ubuntu-22.04-arm-8
# ARM stays off PRs, develop pushes, and pre-commit-only test runs.
# yamllint disable-line rule:line-length
if: >
needs.plan.outputs.run-tests == 'true' &&
!(
(github.event_name == 'push' &&
(github.ref_name == 'develop' ||
github.ref_name == 'test-pre-commit'))
|| github.event_name == 'pull_request'
)
needs:
- plan
- pre-commit
env:
BUILD_MODE: release
CARGO_TARGET_DIR: ${{ github.workspace }}/target/build-linux-arm
RUST_BACKTRACE: 1
# yamllint disable rule:line-length
services:
redis:
image: public.ecr.aws/docker/library/redis:7.4.5-alpine3.21@sha256:bb186d083732f669da90be8b0f975a37812b15e913465bb14d845db72a4e3e08
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
postgres:
image: public.ecr.aws/docker/library/postgres:16.4-alpine@sha256:5660c2cbfea50c7a9127d17dc4e48543eedd3d7a41a595a2dfa572471e37e64c
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: pass
POSTGRES_DB: nautilus
ports:
- 5432:5432
options: --health-cmd "pg_isready -U postgres -d nautilus" --health-interval 10s --health-timeout 5s --health-retries
5
# yamllint enable rule:line-length
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# Temporary: fail fast on rare runner worktree corruption while we isolate the root cause
- name: Verify immutable CI inputs (post-checkout)
run: bash scripts/ci/verify-ci-inputs.sh post-checkout
- name: Common setup
uses: ./.github/actions/common-setup
with:
python-version: ${{ matrix.python-version }}
free-disk-space: "true"
rust-cache-key: build-linux-arm
rust-cache-workspaces: . -> target/build-linux-arm
rust-cache-save-if: ${{ github.event_name == 'push' }}
- name: Install Nautilus CLI
env:
NAUTILUS_CLI_FORCE_SOURCE: ${{ github.ref == 'refs/heads/nightly' && '1' || '0' }}
run: bash scripts/ci/install-nautilus-cli.sh
- name: Init postgres schema
run: nautilus database init --schema ${{ github.workspace }}/schema/sql
env:
POSTGRES_HOST: localhost
POSTGRES_PORT: 5432
POSTGRES_USERNAME: postgres
POSTGRES_PASSWORD: pass
POSTGRES_DATABASE: nautilus
- name: Cached test data
uses: ./.github/actions/common-test-data
- name: Run Rust tests (core)
if: needs.plan.outputs.run-rust-tests == 'true'
run: make cargo-test-core EXTRA_FEATURES="capnp" NEXTEST_PROFILE=ci
- name: Run Rust tests (adapters)
if: needs.plan.outputs.run-rust-tests == 'true'
run: make cargo-test-adapters EXTRA_FEATURES="capnp" NEXTEST_PROFILE=ci
- name: Clean Rust test artifacts
if: needs.plan.outputs.run-rust-tests == 'true'
run: |
rm -rf "${CARGO_TARGET_DIR}/nextest"
df -h .
# Temporary: fail fast on rare runner worktree corruption while we isolate the root cause
- name: Verify immutable CI inputs (pre-wheel build)
run: bash scripts/ci/verify-ci-inputs.sh pre-wheel-build
- name: Build and install wheel
uses: ./.github/actions/common-wheel-build
with:
python-version: ${{ matrix.python-version }}
github_ref: ${{ github.ref }}
- name: Run tests
run: |
uv run --no-sync pytest --ignore=tests/performance_tests --reruns 2 --reruns-delay 1
- name: Upload wheel artifact
uses: ./.github/actions/upload-artifact-wheel
build-macos:
# macOS stays off develop pushes and pre-commit-only test runs.
if: >
needs.plan.outputs.run-tests == 'true' &&
github.event_name == 'push' &&
github.ref != 'refs/heads/develop' &&
github.ref != 'refs/heads/test-pre-commit'
strategy:
fail-fast: false
matrix:
python-version:
- "3.12"
- "3.13"
- "3.14"
defaults:
run:
shell: bash
name: build - python ${{ matrix.python-version }} (macos)
runs-on: macos-latest
needs:
- plan
- pre-commit
env:
BUILD_MODE: release
CARGO_TARGET_DIR: ${{ github.workspace }}/target/build-macos
RUST_BACKTRACE: 1
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# Temporary: fail fast on rare runner worktree corruption while we isolate the root cause
- name: Verify immutable CI inputs (post-checkout)
run: bash scripts/ci/verify-ci-inputs.sh post-checkout
- name: Log macOS runner version
run: |
echo "::group::macOS runner info"
sw_vers
uname -a
echo "::endgroup::"
- name: Common setup
uses: ./.github/actions/common-setup
with:
python-version: ${{ matrix.python-version }}
free-disk-space: "true"
rust-cache-key: build-macos
rust-cache-workspaces: . -> target/build-macos
rust-cache-on-failure: "false"
rust-cache-save-if: ${{ github.event_name == 'push' }}
- name: Cached test data
uses: ./.github/actions/common-test-data
- name: Set compile jobs from cache state
run: bash scripts/ci/set-cargo-build-jobs.sh
- name: Run Rust tests (core)
if: needs.plan.outputs.run-rust-tests == 'true'
run: make cargo-test-core EXTRA_FEATURES="capnp,hypersync" NEXTEST_PROFILE=ci
- name: Run Rust tests (adapters)
if: needs.plan.outputs.run-rust-tests == 'true'
run: make cargo-test-adapters EXTRA_FEATURES="capnp,hypersync" NEXTEST_PROFILE=ci
# Temporary: fail fast on rare runner worktree corruption while we isolate the root cause
- name: Verify immutable CI inputs (pre-wheel build)
run: bash scripts/ci/verify-ci-inputs.sh pre-wheel-build
- name: Build and install wheel
id: build-wheel
uses: ./.github/actions/common-wheel-build
env:
CARGO_TARGET_DIR: ${{ github.workspace }}/target/build-macos
PARALLEL_BUILD: false
with:
python-version: ${{ matrix.python-version }}
github_ref: ${{ github.ref }}
- name: Diagnose failed macOS wheel build
if: failure() && steps.build-wheel.outcome == 'failure'
env:
# yamllint disable-line rule:line-length
MACOS_WHEEL_TARGET_DIR: ${{ github.workspace }}/target/build-macos/release
run: |
set +e
echo "::group::macOS runner and toolchain"
uname -a
sw_vers
rustc -Vv || true
cargo -Vv || true
python --version || true
which python || true
env | rg '^(ARCHFLAGS|CARGO|DYLD_LIBRARY_PATH|LD_LIBRARY_PATH|LIBRARY_PATH|PYO3|RUST)=' || true
echo "::endgroup::"
if [ ! -d "$MACOS_WHEEL_TARGET_DIR" ]; then
echo "Wheel target dir not found: $MACOS_WHEEL_TARGET_DIR"
exit 0
fi
build_scripts="$(find "$MACOS_WHEEL_TARGET_DIR/build" -type f -name build-script-build | sort)"
echo "::group::macOS build-script artifacts"
if [ -z "$build_scripts" ]; then
echo "No build-script-build artifacts found"
else
while IFS= read -r build_script; do
[ -z "$build_script" ] && continue
echo "--- $build_script"
ls -l "$build_script"
shasum -a 256 "$build_script" || true
file "$build_script" || true
otool -hv "$build_script" || true
done <<< "$build_scripts"
fi
echo "::endgroup::"
echo "::group::macOS Rust archives"
for archive in \
"$MACOS_WHEEL_TARGET_DIR/libnautilus_backtest.a" \
"$MACOS_WHEEL_TARGET_DIR/libnautilus_common.a" \
"$MACOS_WHEEL_TARGET_DIR/libnautilus_core.a" \
"$MACOS_WHEEL_TARGET_DIR/libnautilus_model.a" \
"$MACOS_WHEEL_TARGET_DIR/libnautilus_persistence.a"; do
if [ ! -f "$archive" ]; then
echo "Missing archive: $archive"
continue
fi
echo "--- $archive"
ls -l "$archive"
shasum -a 256 "$archive" || true
file "$archive" || true
ar -t "$archive" | head -n 20 || true
done
echo "::endgroup::"
- name: Run tests
run: |
uv run --no-sync pytest --ignore=tests/performance_tests --reruns 2 --reruns-delay 1
- name: Upload wheel artifact
uses: ./.github/actions/upload-artifact-wheel
build-windows:
# Windows stays off PRs, develop pushes, and pre-commit-only test runs.
# yamllint disable-line rule:line-length
if: >
needs.plan.outputs.run-tests == 'true' &&
!(
(github.event_name == 'push' &&
(github.ref_name == 'develop' ||
github.ref_name == 'test-pre-commit'))
|| github.event_name == 'pull_request'
)
strategy:
fail-fast: false
matrix:
python-version:
- "3.12"
- "3.13"
- "3.14"
defaults:
run:
shell: bash
name: build - python ${{ matrix.python-version }} (windows)
runs-on: depot-windows-2022-8
needs:
- plan
- pre-commit
env:
BUILD_MODE: release
CARGO_TARGET_DIR: ${{ github.workspace }}/target/build-windows
HIGH_PRECISION: false
PARALLEL_BUILD: false
RUST_BACKTRACE: 1
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# Temporary: fail fast on rare runner worktree corruption while we isolate the root cause
- name: Verify immutable CI inputs (post-checkout)
run: bash scripts/ci/verify-ci-inputs.sh post-checkout
- name: Common setup
uses: ./.github/actions/common-setup
with:
python-version: ${{ matrix.python-version }}
free-disk-space: "true"
rust-cache-key: build-windows
rust-cache-workspaces: . -> target/build-windows
rust-cache-save-if: ${{ github.event_name == 'push' }}
# Temporary: fail fast on rare runner worktree corruption while we isolate the root cause
- name: Verify immutable CI inputs (pre-wheel build)
run: bash scripts/ci/verify-ci-inputs.sh pre-wheel-build
- name: Build and install wheel
uses: ./.github/actions/common-wheel-build
with:
python-version: ${{ matrix.python-version }}
github_ref: ${{ github.ref }}
- name: Cached test data
uses: ./.github/actions/common-test-data
- name: Run tests
run: |
uv run --no-sync python -m pytest --ignore=tests/performance_tests --reruns 2 --reruns-delay 1
- name: Upload wheel artifact
uses: ./.github/actions/upload-artifact-wheel
publish-wheels-develop:
name: publish-wheels-develop
runs-on: ubuntu-latest
environment: r2-develop
permissions:
actions: write # Required for deleting artifacts
contents: read
id-token: write # Required for attestations
attestations: write # Required for attestations
needs:
- build-linux-x86
# - build-windows # Windows builds moved to nightly only
# - build-linux-arm # Keep for nightly only (slow build)
# - build-macos # macOS builds moved to nightly only
if: >
github.event_name == 'push' && github.ref == 'refs/heads/develop'
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
CLOUDFLARE_R2_URL: ${{ secrets.CLOUDFLARE_R2_URL }}
CLOUDFLARE_R2_REGION: "auto"
CLOUDFLARE_R2_BUCKET_NAME: "packages"
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
# Sigstore TUF trust root (for gh attestation verify)
tuf-repo-cdn.sigstore.dev:443
${{ secrets.CLOUDFLARE_R2_ALLOWED_HOST }}:443
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Block develop publish after failed security audit
if: github.ref_name == 'develop'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bash scripts/ci/check-security-audit-result.sh
- name: Download built wheels
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: dist
pattern: "nautilus_trader-*.whl"
merge-multiple: true
# https://github.com/actions/attest-build-provenance
- name: Attest wheel provenance
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: "dist/nautilus_trader-*.whl"
- name: Verify wheel attestations
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
IDENTITY: ${{ github.server_url }}/${{ github.workflow_ref }}
ISSUER: https://token.actions.githubusercontent.com
run: |
set -e
for whl in dist/nautilus_trader-*.whl; do
gh attestation verify "$whl" \
--repo "$GITHUB_REPOSITORY" \
--cert-identity "$IDENTITY" \
--cert-oidc-issuer "$ISSUER"
done
- name: Publish wheels to Cloudflare R2
uses: ./.github/actions/publish-wheels
- name: Fetch and delete artifacts for current run
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
bash ./scripts/ci/publish-wheels-delete-artifacts.sh
security-gate-nightly:
name: security-gate-nightly
runs-on: ubuntu-latest
needs:
- build-linux-x86
- build-linux-arm
- build-macos
- build-windows
if: >
github.event_name == 'push' && github.ref == 'refs/heads/nightly'
steps:
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.SECURITY_AUDIT_ALLOWED_ENDPOINTS }}
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
# Requires admin access to modify; does not widen attack surface.
# See .github/OVERVIEW.md "Security gate override" for rationale.
- name: Check security gate override
id: gate
run: |
override="${{ vars.SECURITY_GATE_OVERRIDE }}"
if [ -n "$override" ] && [ "$(date -u +%s)" -lt "$(date -u -d "$override" +%s 2>/dev/null || echo 0)" ]; then
echo "::warning::Security gate override active until $override"
echo "override_active=true" >> "$GITHUB_OUTPUT"
else
echo "override_active=false" >> "$GITHUB_OUTPUT"
fi
- name: Install cargo-audit
if: steps.gate.outputs.override_active != 'true'
uses: ./.github/actions/cargo-tool-install
with:
tool-name: cargo-audit
- name: Run cargo-audit (fail on vulnerabilities)
if: steps.gate.outputs.override_active != 'true'
run: cargo audit --deny unsound
- name: Run osv-scanner
id: osv-scan
if: steps.gate.outputs.override_active != 'true'
continue-on-error: true
uses: google/osv-scanner-action/osv-scanner-action@c51854704019a247608d928f370c98740469d4b5 # v2.3.5
with:
scan-args: |
--config=osv-scanner.toml
--format json
--output=/github/workspace/osv-results.json
--lockfile=Cargo.lock
--lockfile=uv.lock
--lockfile=python/uv.lock
- name: Check OSV severity (fail on critical/high only)
if: steps.osv-scan.outcome == 'failure' && steps.gate.outputs.override_active != 'true'
run: bash scripts/ci/osv-severity-gate.sh osv-results.json
publish-wheels-nightly:
name: publish-wheels-nightly
runs-on: ubuntu-latest
environment: r2-nightly
permissions:
actions: write # Required for deleting artifacts
contents: read
id-token: write # Required for attestations
attestations: write # Required for attestations
needs:
- security-gate-nightly
if: >
github.event_name == 'push' && github.ref == 'refs/heads/nightly'
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
CLOUDFLARE_R2_URL: ${{ secrets.CLOUDFLARE_R2_URL }}
CLOUDFLARE_R2_REGION: "auto"
CLOUDFLARE_R2_BUCKET_NAME: "packages"
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
# Sigstore TUF trust root (for gh attestation verify)
tuf-repo-cdn.sigstore.dev:443
${{ secrets.CLOUDFLARE_R2_ALLOWED_HOST }}:443
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Download built wheels
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: dist
pattern: "nautilus_trader-*.whl"
merge-multiple: true
# https://github.com/actions/attest-build-provenance
- name: Attest wheel provenance
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: "dist/nautilus_trader-*.whl"
- name: Verify wheel attestations
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
IDENTITY: ${{ github.server_url }}/${{ github.workflow_ref }}
ISSUER: https://token.actions.githubusercontent.com
run: |
set -e
for whl in dist/nautilus_trader-*.whl; do
gh attestation verify "$whl" \
--repo "$GITHUB_REPOSITORY" \
--cert-identity "$IDENTITY" \
--cert-oidc-issuer "$ISSUER"
done
- name: Publish wheels to Cloudflare R2
uses: ./.github/actions/publish-wheels
- name: Fetch and delete artifacts for current run
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
bash ./scripts/ci/publish-wheels-delete-artifacts.sh
publish-cargo-crates:
runs-on: ubuntu-latest
environment: release
permissions:
contents: read
id-token: write # Required for crates.io Trusted Publishing
needs:
- publish-wheels-master
- tag-release
if: >
github.event_name == 'push' && github.ref == 'refs/heads/master'
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
crates.io:443
index.crates.io:443
static.crates.io:443
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Common setup
uses: ./.github/actions/common-setup
with:
python-version: "3.13"
build-type: "release"
uv-cache-enabled: "false"
prek-cache-enabled: "false"
capnp-cache-enabled: "false"
rust-cache-enabled: "false"
rust-cache-save-if: "false"
- name: Check Cargo crate publish plan
run: bash scripts/ci/publish-cargo-crates.sh --check
- name: Authenticate to crates.io
id: crates-io-auth
# https://github.com/rust-lang/crates-io-auth-action
uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe # v1.0.4
- name: Publish Cargo crates
env:
CARGO_REGISTRY_TOKEN: ${{ steps.crates-io-auth.outputs.token }}
CARGO_PUBLISH_ATTEMPTS: "5"
CARGO_PUBLISH_POLL_SECONDS: "5"
CARGO_PUBLISH_RETRY_DELAY_SECONDS: "15"
CARGO_PUBLISH_SUCCESS_DELAY_SECONDS: "0"
CARGO_PUBLISH_WAIT_TIMEOUT_SECONDS: "120"
CARGO_PUBLISH_USER_AGENT: >-
nautilus-trader-release
(${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
run: bash scripts/ci/publish-cargo-crates.sh
publish-wheels-master:
runs-on: ubuntu-latest
environment: release
permissions:
contents: write # Required for uploading release assets
actions: read # Required for downloading build artifacts
needs:
- build-linux-x86
- build-linux-arm
- build-macos
- build-windows
- tag-release
- upload-sdist-release
if: >
github.event_name == 'push' && github.ref == 'refs/heads/master'
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
CLOUDFLARE_R2_URL: ${{ secrets.CLOUDFLARE_R2_URL }}
CLOUDFLARE_R2_REGION: "auto"
CLOUDFLARE_R2_BUCKET_NAME: "packages"
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
${{ secrets.CLOUDFLARE_R2_ALLOWED_HOST }}:443
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Download built wheels for GitHub release
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: dist
pattern: "nautilus_trader-*.whl"
merge-multiple: true
- name: Upload wheels to GitHub release
# https://cli.github.com/manual/gh_release_upload
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ needs.tag-release.outputs.tag_name }}
run: bash ./scripts/ci/upload-github-release-assets.bash wheels dist/nautilus_trader-*.whl
- name: Publish wheels to Cloudflare R2
uses: ./.github/actions/publish-wheels
publish-wheels-pypi:
runs-on: ubuntu-latest
environment: release
permissions:
actions: read # Required for downloading build artifacts
contents: read
id-token: write # Required for PyPI Trusted Publishing and publish attestations
attestations: write # Required for GitHub artifact attestations
needs:
- publish-wheels-master
- tag-release
if: >
github.event_name == 'push' && github.ref == 'refs/heads/master'
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
# Sigstore TUF trust root (for gh attestation verify)
tuf-repo-cdn.sigstore.dev:443
pypi.org:443
files.pythonhosted.org:443
upload.pypi.org:443
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Get release Python tool versions
shell: bash
run: |
echo "UV_VERSION=$(bash scripts/uv-version.sh)" >> "$GITHUB_ENV"
echo "PYPI_ATTESTATIONS_VERSION=$(bash scripts/tool-version.sh pypi-attestations)" >> "$GITHUB_ENV"
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: false
- name: Download built wheel artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: dist
pattern: "nautilus_trader-*.whl"
merge-multiple: true
- name: Generate PyPI publish attestations
run: |
uv run --no-project --no-build --with "pypi-attestations==${PYPI_ATTESTATIONS_VERSION}" -- \
python -m pypi_attestations sign dist/nautilus_trader-*.whl
# https://github.com/actions/attest-build-provenance
- name: Attest wheel provenance
id: attest-wheels
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: "dist/nautilus_trader-*.whl"
- name: Verify wheel attestations
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
IDENTITY: ${{ github.server_url }}/${{ github.workflow_ref }}
ISSUER: https://token.actions.githubusercontent.com
run: |
set -e
for whl in dist/nautilus_trader-*.whl; do
gh attestation verify "$whl" \
--repo "$GITHUB_REPOSITORY" \
--cert-identity "$IDENTITY" \
--cert-oidc-issuer "$ISSUER"
done
- name: Publish wheels to PyPI
if: success()
run: bash ./scripts/ci/publish-pypi-trusted.bash wheels
- name: Prepare wheel attestation siblings
shell: bash
env:
BUNDLE_PATH: ${{ steps.attest-wheels.outputs.bundle-path }}
run: bash ./scripts/ci/prepare-release-attestation-siblings.bash dist/nautilus_trader-*.whl
- name: Upload wheel attestation siblings
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-wheel-attestation-siblings
path: |
dist/nautilus_trader-*.whl.sigstore
dist/nautilus_trader-*.whl.intoto.jsonl
if-no-files-found: error
retention-days: 1
tag-release:
needs:
- build-linux-x86
- build-linux-arm
- build-macos
- build-windows
- cargo-deny
- cargo-vet
permissions:
contents: write # Required for pushing tags and upload release assets
actions: write # Required for creating releases
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create-release.outputs.upload_url }}
tag_name: ${{ env.TAG_NAME }}
steps:
# Security hardening
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: true # Required for salsify action to push git tags
fetch-depth: 2
fetch-tags: true
- name: Set up Python environment
# https://github.com/actions/setup-python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.13"
- name: Create git tag
# https://github.com/salsify/action-detect-and-tag-new-version
uses: salsify/action-detect-and-tag-new-version@b1778166f13188a9d478e2d1198f993011ba9864 # v2.0.3
with:
version-command: ./scripts/package-version.sh
- name: Set output
id: vars
run: |
echo "TAG_NAME=v$(./scripts/package-version.sh)" >> "$GITHUB_ENV"
echo "RELEASE_NAME=NautilusTrader $(./scripts/package-version.sh) Beta" >> "$GITHUB_ENV"
sed -n '/^#/,$ {p;/^---/q}; w RELEASE.md' RELEASES.md
- name: Create draft GitHub release
id: create-release
# https://github.com/softprops/action-gh-release v3.0.0
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ env.TAG_NAME }}
name: ${{ env.RELEASE_NAME }}
draft: true
prerelease: false
body_path: RELEASE.md
build-sdist:
needs:
- tag-release
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
permissions:
contents: read
env:
COPY_TO_SOURCE: false # Do not copy built *.so files back into source tree
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
pypi.org:443
files.pythonhosted.org:443
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Common setup
uses: ./.github/actions/common-setup
with:
python-version: "3.13"
free-disk-space: "true"
uv-cache-enabled: "false"
prek-cache-enabled: "false"
capnp-cache-enabled: "false"
rust-cache-enabled: "false"
- name: Build sdist
run: bash ./scripts/ci/build-sdist-release-asset.bash
- name: Upload sdist artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-sdist
path: dist/nautilus_trader-*.tar.gz
if-no-files-found: error
retention-days: 1
upload-sdist-release:
needs:
- build-sdist
- tag-release
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
permissions:
actions: read # Required for downloading the sdist artifact
contents: write # Required for uploading release assets
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Download sdist artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-sdist
path: release-sdist
- name: Upload sdist to GitHub release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ needs.tag-release.outputs.tag_name }}
run: bash ./scripts/ci/upload-github-release-assets.bash sdist release-sdist/nautilus_trader-*.tar.gz
publish-sdist-pypi:
needs:
- publish-wheels-pypi
- tag-release
- upload-sdist-release
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
environment: release
permissions:
actions: read # Required for downloading the sdist artifact
contents: read
id-token: write # Required for PyPI Trusted Publishing and publish attestations
attestations: write # Required for GitHub artifact attestations
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
# Sigstore TUF trust root (for gh attestation verify)
tuf-repo-cdn.sigstore.dev:443
pypi.org:443
files.pythonhosted.org:443
upload.pypi.org:443
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Get release Python tool versions
shell: bash
run: |
echo "UV_VERSION=$(bash scripts/uv-version.sh)" >> "$GITHUB_ENV"
echo "PYPI_ATTESTATIONS_VERSION=$(bash scripts/tool-version.sh pypi-attestations)" >> "$GITHUB_ENV"
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: false
- name: Download sdist artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-sdist
path: dist
- name: Generate PyPI publish attestation
run: |
uv run --no-project --no-build --with "pypi-attestations==${PYPI_ATTESTATIONS_VERSION}" -- \
python -m pypi_attestations sign dist/nautilus_trader-*.tar.gz
# https://github.com/actions/attest-build-provenance
- name: Attest sdist provenance
id: attest-sdist
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: "dist/nautilus_trader-*.tar.gz"
- name: Verify sdist attestation
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
IDENTITY: ${{ github.server_url }}/${{ github.workflow_ref }}
ISSUER: https://token.actions.githubusercontent.com
run: |
gh attestation verify dist/nautilus_trader-*.tar.gz \
--repo "$GITHUB_REPOSITORY" \
--cert-identity "$IDENTITY" \
--cert-oidc-issuer "$ISSUER"
- name: Publish sdist to PyPI
if: success()
run: bash ./scripts/ci/publish-pypi-trusted.bash sdist
- name: Prepare sdist attestation sibling
shell: bash
env:
BUNDLE_PATH: ${{ steps.attest-sdist.outputs.bundle-path }}
run: bash ./scripts/ci/prepare-release-attestation-siblings.bash dist/nautilus_trader-*.tar.gz
- name: Upload sdist attestation sibling
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-sdist-attestation-sibling
path: |
dist/nautilus_trader-*.tar.gz.sigstore
dist/nautilus_trader-*.tar.gz.intoto.jsonl
if-no-files-found: error
retention-days: 1
publish-release-integrity:
needs:
- publish-cargo-crates
- publish-wheels-pypi
- publish-sdist-pypi
- tag-release
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
permissions:
actions: write # Required for downloading and deleting release artifacts
contents: write # Required for uploading release integrity assets
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
# Sigstore TUF trust root (for pypi-attestations verify)
tuf-repo-cdn.sigstore.dev:443
pypi.org:443
files.pythonhosted.org:443
crates.io:443
index.crates.io:443
static.crates.io:443
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Get uv version from pyproject.toml
shell: bash
run: |
echo "UV_VERSION=$(bash scripts/uv-version.sh)" >> "$GITHUB_ENV"
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: false
- name: Publish release checksums
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ needs.tag-release.outputs.tag_name }}
ATTESTATION_IDENTITY: ${{ github.server_url }}/${{ github.workflow_ref }}
ATTESTATION_ISSUER: https://token.actions.githubusercontent.com
run: bash ./scripts/ci/publish-release-checksums.sh
- name: Verify published registries
shell: bash
env:
TAG_NAME: ${{ needs.tag-release.outputs.tag_name }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PYPI_PUBLISHER_WORKFLOW: build.yml
PYPI_PUBLISHER_ENVIRONMENT: release
CARGO_PUBLISH_USER_AGENT: >-
nautilus-trader-release-verifier
(${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
run: bash ./scripts/ci/verify-published-registries.bash release-assets
- name: Upload crates manifest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ needs.tag-release.outputs.tag_name }}
run: >-
bash ./scripts/ci/upload-github-release-assets.bash
crates-manifest
release-assets/crates-manifest.json
- name: Download attestation sibling artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: release-attestations
pattern: "release-*-attestation-*"
merge-multiple: true
- name: Attach attestation siblings to GitHub release
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ needs.tag-release.outputs.tag_name }}
run: bash ./scripts/ci/upload-release-attestation-siblings.bash release-attestations
# success() so a failed publish-release-integrity leaves attestation
# workflow artifacts in place for re-runs.
- name: Delete artifacts for current run
if: success()
continue-on-error: true
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: bash ./scripts/ci/publish-wheels-delete-artifacts.sh
publish-github-release:
needs:
- publish-release-integrity
- tag-release
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
permissions:
attestations: read # Required for verifying the immutable release attestation
contents: write # Required for publishing the draft release
steps:
# https://github.com/step-security/harden-runner
- uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1
with:
egress-policy: ${{ env.EGRESS_POLICY }}
allowed-endpoints: >-
${{ vars.COMMON_ALLOWED_ENDPOINTS }}
${{ vars.CI_ALLOWED_ENDPOINTS }}
- name: Checkout repository
# https://github.com/actions/checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Publish GitHub release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ needs.tag-release.outputs.tag_name }}
run: bash ./scripts/ci/publish-github-release.bash
- name: Verify GitHub release attestation
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG_NAME: ${{ needs.tag-release.outputs.tag_name }}
run: bash ./scripts/ci/verify-github-release-attestation.bash