From b62b117cce7589ea8cde0cca705bc76424339536 Mon Sep 17 00:00:00 2001 From: nickvines Date: Sat, 3 Jan 2026 22:18:38 -0800 Subject: [PATCH 1/7] Enable FIPS for OpenSSL builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add enable-fips flag to OpenSSL 3.5 configure (non-musl only) - Preserve fips.so when removing shared libraries - Copy FIPS modules and config to Python installation - Skip fips.so/fips.dylib in distribution validation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- cpython-unix/build-cpython.sh | 11 ++++++++++- cpython-unix/build-openssl-3.5.sh | 20 +++++++++++++++++--- src/validation.rs | 6 ++++++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/cpython-unix/build-cpython.sh b/cpython-unix/build-cpython.sh index 01abca1..8ae077b 100755 --- a/cpython-unix/build-cpython.sh +++ b/cpython-unix/build-cpython.sh @@ -44,7 +44,9 @@ sed "${sed_args[@]}" "s|/tools/host|${TOOLS_PATH}/host|g" ${TOOLS_PATH}/host/sha # We force linking of external static libraries by removing the shared # libraries. This is hacky. But we're building in a temporary container # and it gets the job done. -find ${TOOLS_PATH}/deps -name '*.so*' -a \! \( -name 'libtcl*.so*' -or -name 'libtk*.so*' \) -exec rm {} \; +# `fips.so` is an exception as it needs to be available to enable FIPS via +# openssl configuration. +find ${TOOLS_PATH}/deps -name '*.so*' ! -name 'fips.so' ! -name 'libtcl*.so*' ! -name 'libtk*.so*' -exec rm {} \; tar -xf Python-${PYTHON_VERSION}.tar.xz @@ -1290,6 +1292,13 @@ if [ -d "${TOOLS_PATH}/deps/usr/share/terminfo" ]; then cp -av ${TOOLS_PATH}/deps/usr/share/terminfo ${ROOT}/out/python/install/share/ fi +# Copy files required to enable FIPS if enabled. +if [ -f ${TOOLS_PATH}/deps/fipsmodule.cnf ]; then + mkdir -p ${ROOT}/out/python/install/share/ssl + cp -rv ${TOOLS_PATH}/deps/lib/ossl-modules ${ROOT}/out/python/install/share/ssl + cp -av ${TOOLS_PATH}/deps/fipsmodule.cnf ${ROOT}/out/python/install/share/ssl +fi + # config.c defines _PyImport_Inittab and extern references to modules, which # downstream consumers may want to strip. We bundle config.c and config.c.in so # a custom one can be produced downstream. diff --git a/cpython-unix/build-openssl-3.5.sh b/cpython-unix/build-openssl-3.5.sh index 952098c..025403f 100755 --- a/cpython-unix/build-openssl-3.5.sh +++ b/cpython-unix/build-openssl-3.5.sh @@ -16,18 +16,23 @@ pushd openssl-${OPENSSL_3_5_VERSION} # Otherwise it gets set to /tools/deps/ssl by default. case "${TARGET_TRIPLE}" in *apple*) - EXTRA_FLAGS="--openssldir=/private/etc/ssl" + OPENSSL_DIR=/private/etc/ssl ;; *) - EXTRA_FLAGS="--openssldir=/etc/ssl" + OPENSSL_DIR=/etc/ssl ;; esac +EXTRA_FLAGS="--openssldir=${OPENSSL_DIR}" +EXTRA_INSTALL_FLAGS="" # musl is missing support for various primitives. # TODO disable secure memory is a bit scary. We should look into a proper # workaround. if [ "${CC}" = "musl-clang" ]; then EXTRA_FLAGS="${EXTRA_FLAGS} no-async -DOPENSSL_NO_ASYNC -D__STDC_NO_ATOMICS__=1 no-engine -DOPENSSL_NO_SECURE_MEMORY" +else + EXTRA_INSTALL_FLAGS="install_fips" + EXTRA_FLAGS="${EXTRA_FLAGS} enable-fips" fi # The -arch cflags confuse Configure. And OpenSSL adds them anyway. @@ -35,6 +40,10 @@ fi EXTRA_TARGET_CFLAGS=${EXTRA_TARGET_CFLAGS/\-arch arm64/} EXTRA_TARGET_CFLAGS=${EXTRA_TARGET_CFLAGS/\-arch x86_64/} +# With -fvisibility=hidden, OSSL_provider_init symbol is not exported in fips module preventing it from loaded +# OSSL_provider_init is supposed to be `extern` so it should not happen but I can't find a more targeted solution +# at the moment. +EXTRA_TARGET_CFLAGS=${EXTRA_TARGET_CFLAGS//-fvisibility=hidden/} EXTRA_FLAGS="${EXTRA_FLAGS} ${EXTRA_TARGET_CFLAGS}" /usr/bin/perl ./Configure \ @@ -47,4 +56,9 @@ EXTRA_FLAGS="${EXTRA_FLAGS} ${EXTRA_TARGET_CFLAGS}" ${EXTRA_FLAGS} make -j ${NUM_CPUS} -make -j ${NUM_CPUS} install_sw install_ssldirs DESTDIR=${ROOT}/out +make -j ${NUM_CPUS} install_sw install_ssldirs ${EXTRA_INSTALL_FLAGS} DESTDIR=${ROOT}/out + +if [ -f ${ROOT}/out${OPENSSL_DIR}/fipsmodule.cnf ]; then + # install_fips does not use DESTDIR. we need to copy it so it gets added to the archive. + cp ${ROOT}/out${OPENSSL_DIR}/fipsmodule.cnf ${ROOT}/out/tools/deps/fipsmodule.cnf +fi diff --git a/src/validation.rs b/src/validation.rs index 5886f1e..a94e07b 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -1839,6 +1839,12 @@ fn validate_distribution( let mut entry = entry.map_err(|e| anyhow!("failed to iterate over archive: {}", e))?; let path = entry.path()?.to_path_buf(); + if let Some(file_name) = path.file_name() { + if file_name == "fips.dylib" || file_name == "fips.so" { + continue + } + } + seen_paths.insert(path.clone()); if let Some(link_name) = entry.link_name()? { From 73332ece38aebf7a619ab3f3f31536829837f4af Mon Sep 17 00:00:00 2001 From: nickvines Date: Sat, 3 Jan 2026 22:22:01 -0800 Subject: [PATCH 2/7] Add Verkada CI workflows for 3 target builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add vlinux.yml: Build aarch64 + x86_64 Linux targets on ubuntu-latest - Add vmacos.yml: Build aarch64 macOS target on macos-latest - Add vrelease.yml: Manual release workflow - Disable upstream linux/macos/windows workflow triggers (use workflow_dispatch only) - Reduce release.rs to only 3 targets: aarch64-apple-darwin, aarch64-unknown-linux-gnu, x86_64-unknown-linux-gnu Targets only build pgo+lto and freethreaded+pgo+lto (3.13+) variants. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .github/workflows/linux.yml | 8 +- .github/workflows/macos.yml | 8 +- .github/workflows/vlinux.yml | 251 ++++++++++++++++++++++++++++++++ .github/workflows/vmacos.yml | 126 ++++++++++++++++ .github/workflows/vrelease.yml | 97 +++++++++++++ .github/workflows/windows.yml | 8 +- src/release.rs | 256 ++------------------------------- 7 files changed, 502 insertions(+), 252 deletions(-) create mode 100644 .github/workflows/vlinux.yml create mode 100644 .github/workflows/vmacos.yml create mode 100644 .github/workflows/vrelease.yml diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 3c57cbb..4d76866 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -1,9 +1,11 @@ name: linux on: - push: - branches: [main] - pull_request: + # Disabled - use vlinux.yml instead + # push: + # branches: [main] + # pull_request: + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }} diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 2e98e70..a2ffe90 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -1,9 +1,11 @@ name: macos on: - push: - branches: [main] - pull_request: + # Disabled - use vmacos.yml instead + # push: + # branches: [main] + # pull_request: + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }} diff --git a/.github/workflows/vlinux.yml b/.github/workflows/vlinux.yml new file mode 100644 index 0000000..aaa64a8 --- /dev/null +++ b/.github/workflows/vlinux.yml @@ -0,0 +1,251 @@ +name: vlinux + +on: + push: + branches: [main] + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +env: + FORCE_COLOR: 1 + +permissions: {} + +jobs: + crate-build: + runs-on: ubuntu-latest + steps: + - name: Install System Dependencies + run: | + sudo apt update + sudo apt install -y --no-install-recommends libssl-dev pkg-config + + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + - name: Emit rustc version + run: | + rustc --version > .rustc-version + + - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-pythonbuild-${{ hashFiles('Cargo.lock', '.rustc-version') }} + + - name: Build + run: | + cargo build --release + + - name: Upload pythonbuild Executable + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: crate-linux-x86_64 + path: target/release/pythonbuild + + image: + strategy: + fail-fast: false + matrix: + include: + - name: build + arch: x86_64 + - name: build.cross + arch: x86_64 + - name: gcc + arch: x86_64 + name: image / ${{ matrix.name }} + runs-on: ubuntu-latest + permissions: + packages: write + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + - name: Set up uv + uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4 + with: + enable-cache: false + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 + + - name: Login to GitHub Container Registry + uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Generate Dockerfiles + run: | + ./build.py --make-target empty + repo_name=$(echo "${GITHUB_REPOSITORY,,}" | sed 's|\.|_|g') + git_ref_name=$(echo "${GITHUB_REF_NAME,,}" | sed 's|[^a-z0-9_-]|_|g') + echo "REPO_NAME=${repo_name}" >> "${GITHUB_ENV}" + echo "GIT_REF_NAME=${git_ref_name}" >> "${GITHUB_ENV}" + + - name: Build Image + id: build-image + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 + env: + SOURCE_DATE_EPOCH: 0 + DOCKER_BUILD_SUMMARY: false + DOCKER_BUILD_RECORD_UPLOAD: false + with: + context: . + file: build/${{ matrix.name }}.Dockerfile + labels: org.opencontainers.image.source=https://github.com/${{ env.REPO_NAME }} + cache-from: | + type=registry,ref=ghcr.io/${{ env.REPO_NAME }}:${{ matrix.name }}-linux_${{ matrix.arch }}-${{ env.GIT_REF_NAME }} + type=registry,ref=ghcr.io/${{ env.REPO_NAME }}:${{ matrix.name }}-linux_${{ matrix.arch }}-main + type=registry,ref=ghcr.io/astral-sh/python-build-standalone:${{ matrix.name }}-linux_${{ matrix.arch }}-main + cache-to: | + type=registry,ref=ghcr.io/${{ env.REPO_NAME }}:${{ matrix.name }}-linux_${{ matrix.arch }}-${{ env.GIT_REF_NAME }},ignore-error=true + outputs: | + type=docker,dest=build/image-${{ matrix.name }}.linux_${{ matrix.arch }}.tar + + - name: Compress Image + run: | + echo ${STEPS_BUILD_IMAGE_OUTPUTS_IMAGEID} > build/image-${MATRIX_NAME}.linux_${MATRIX_ARCH} + zstd -v -T0 -6 --rm build/image-*.tar + touch -t 197001010000 build/image-* + env: + STEPS_BUILD_IMAGE_OUTPUTS_IMAGEID: ${{ steps.build-image.outputs.imageid }} + MATRIX_NAME: ${{ matrix.name }} + MATRIX_ARCH: ${{ matrix.arch }} + + - name: Upload Docker Image + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: image-${{ matrix.name }}-linux_${{ matrix.arch }} + path: build/image-* + compression-level: '0' + + build: + needs: + - crate-build + - image + permissions: + id-token: write + attestations: write + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + target_triple: + - aarch64-unknown-linux-gnu + - x86_64-unknown-linux-gnu + python: + - "3.10" + - "3.11" + - "3.12" + - "3.13" + - "3.14" + build_options: + - pgo+lto + include: + # Freethreaded builds for Python 3.13+ + - target_triple: aarch64-unknown-linux-gnu + python: "3.13" + build_options: freethreaded+pgo+lto + - target_triple: aarch64-unknown-linux-gnu + python: "3.14" + build_options: freethreaded+pgo+lto + - target_triple: x86_64-unknown-linux-gnu + python: "3.13" + build_options: freethreaded+pgo+lto + - target_triple: x86_64-unknown-linux-gnu + python: "3.14" + build_options: freethreaded+pgo+lto + name: ${{ matrix.target_triple }} / ${{ matrix.python }} / ${{ matrix.build_options }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Set up uv + uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4 + with: + enable-cache: false + + - name: Download pythonbuild + uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + with: + name: crate-linux-x86_64 + path: build + + - name: Download images + uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + with: + pattern: image-* + path: build + merge-multiple: true + + - name: Cache downloads + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + with: + path: build/downloads + key: ${{ matrix.target_triple }}-${{ hashFiles('pythonbuild/downloads.py')}} + restore-keys: | + ${{ matrix.target_triple }}-${{ hashFiles('pythonbuild/downloads.py')}} + ${{ matrix.target_triple }}- + + - name: Load Docker Images + run: | + for f in build/image-*.tar.zst; do + echo "decompressing $f" + zstd -d --rm ${f} + done + + for f in build/image-*.tar; do + echo "loading $f" + docker load --input $f + done + + - name: Build + run: | + # Do empty target so all generated files are touched. + ./build.py --make-target empty + + # Touch mtimes of all images so they are newer than autogenerated files above. + touch build/image-* + + ./build.py --target-triple ${MATRIX_TARGET_TRIPLE} --python cpython-${MATRIX_PYTHON} --options ${MATRIX_BUILD_OPTIONS} + env: + MATRIX_TARGET_TRIPLE: ${{ matrix.target_triple }} + MATRIX_PYTHON: ${{ matrix.python }} + MATRIX_BUILD_OPTIONS: ${{ matrix.build_options }} + + - name: Generate attestations + uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 + if: ${{ github.ref == 'refs/heads/main' }} + with: + subject-path: dist/* + + - name: Upload Distribution + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: cpython-${{ matrix.python }}-${{ matrix.target_triple }}-${{ matrix.build_options }} + path: dist/* + + - name: Validate Distribution + run: | + chmod +x build/pythonbuild + + # Only run validation with --run for x86_64 (native architecture) + if [ "${MATRIX_TARGET_TRIPLE}" == "x86_64-unknown-linux-gnu" ]; then + EXTRA_ARGS="--run" + fi + + build/pythonbuild validate-distribution ${EXTRA_ARGS} dist/*.tar.zst + env: + MATRIX_TARGET_TRIPLE: ${{ matrix.target_triple }} diff --git a/.github/workflows/vmacos.yml b/.github/workflows/vmacos.yml new file mode 100644 index 0000000..b225c58 --- /dev/null +++ b/.github/workflows/vmacos.yml @@ -0,0 +1,126 @@ +name: vmacos + +on: + push: + branches: [main] + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +env: + FORCE_COLOR: 1 + +permissions: {} + +jobs: + crate-build: + runs-on: macos-latest + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + - name: Emit rustc version + run: | + rustc --version > .rustc-version + + - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-pythonbuild-${{ hashFiles('Cargo.lock', '.rustc-version') }} + + - name: Build + run: | + cargo build --release + + - name: Upload pythonbuild Executable + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: crate-darwin-aarch64 + path: target/release/pythonbuild + + build: + needs: + - crate-build + permissions: + id-token: write + attestations: write + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + target_triple: + - aarch64-apple-darwin + python: + - "3.10" + - "3.11" + - "3.12" + - "3.13" + - "3.14" + build_options: + - pgo+lto + include: + # Freethreaded builds for Python 3.13+ + - target_triple: aarch64-apple-darwin + python: "3.13" + build_options: freethreaded+pgo+lto + - target_triple: aarch64-apple-darwin + python: "3.14" + build_options: freethreaded+pgo+lto + name: ${{ matrix.target_triple }} / ${{ matrix.python }} / ${{ matrix.build_options }} + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Set up uv + uses: astral-sh/setup-uv@1e862dfacbd1d6d858c55d9b792c756523627244 # v7.1.4 + with: + enable-cache: false + + - name: Download pythonbuild + uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 + with: + name: crate-darwin-aarch64 + path: build + + - name: Build + run: | + ./build.py --target-triple ${MATRIX_TARGET_TRIPLE} --python cpython-${MATRIX_PYTHON} --options ${MATRIX_BUILD_OPTIONS} + env: + MATRIX_TARGET_TRIPLE: ${{ matrix.target_triple }} + MATRIX_PYTHON: ${{ matrix.python }} + MATRIX_BUILD_OPTIONS: ${{ matrix.build_options }} + + - name: Generate attestations + uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 + if: ${{ github.ref == 'refs/heads/main' }} + with: + subject-path: dist/* + + - name: Upload Distributions + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: cpython-${{ matrix.python }}-${{ matrix.target_triple }}-${{ matrix.build_options }} + path: dist/* + + - name: Checkout macOS SDKs for validation + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + repository: phracker/MacOSX-SDKs + ref: master + path: macosx-sdks + persist-credentials: false + + - name: Validate Distribution + run: | + chmod +x build/pythonbuild + + # macos-latest is aarch64, so we can run validation + build/pythonbuild validate-distribution --macos-sdks-path macosx-sdks --run dist/*.tar.zst diff --git a/.github/workflows/vrelease.yml b/.github/workflows/vrelease.yml new file mode 100644 index 0000000..637fc52 --- /dev/null +++ b/.github/workflows/vrelease.yml @@ -0,0 +1,97 @@ +name: vRelease + +on: + workflow_dispatch: + inputs: + tag: + description: "The version to release (e.g., '20250612')." + type: string + sha: + description: "The full SHA of the commit to be released (e.g., 'd09ff921d92d6da8d8a608eaa850dc8c0f638194')." + type: string + dry-run: + description: "Dry run? Tests the release process without publishing." + default: false + required: false + type: boolean + +env: + FORCE_COLOR: 1 + +permissions: {} + +jobs: + release: + name: Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + runs-on: ubuntu-latest + + permissions: + contents: write + packages: write + id-token: write + attestations: write + + steps: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + submodules: recursive + persist-credentials: true + + - uses: extractions/setup-crate@4993624604c307fbca528d28a3c8b60fa5ecc859 # v1.4.0 + with: + repo: casey/just + version: 1.42.4 + + # Perform a release in dry-run mode. + - run: just release-dry-run ${GH_TOKEN} ${GITHUB_EVENT_INPUTS_SHA} ${GITHUB_EVENT_INPUTS_TAG} + if: ${{ github.event.inputs.dry-run == 'true' }} + env: + GITHUB_EVENT_INPUTS_SHA: ${{ github.event.inputs.sha }} + GITHUB_EVENT_INPUTS_TAG: ${{ github.event.inputs.tag }} + + - name: Configure Git identity + if: ${{ github.event.inputs.dry-run == 'false' }} + run: | + git config --global user.name "$GITHUB_ACTOR" + git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com" + + - name: Fetch commit + if: ${{ github.event.inputs.dry-run == 'false' }} + run: git fetch origin ${GITHUB_EVENT_INPUTS_SHA} + env: + GITHUB_EVENT_INPUTS_SHA: ${{ github.event.inputs.sha }} + + - name: Create tag + if: ${{ github.event.inputs.dry-run == 'false' }} + run: git tag ${GITHUB_EVENT_INPUTS_TAG} ${GITHUB_EVENT_INPUTS_SHA} + env: + GITHUB_EVENT_INPUTS_TAG: ${{ github.event.inputs.tag }} + GITHUB_EVENT_INPUTS_SHA: ${{ github.event.inputs.sha }} + + - name: Push tag + if: ${{ github.event.inputs.dry-run == 'false' }} + run: git push origin ${GITHUB_EVENT_INPUTS_TAG} + env: + GITHUB_EVENT_INPUTS_TAG: ${{ github.event.inputs.tag }} + + - name: Create GitHub Release + if: ${{ github.event.inputs.dry-run == 'false' }} + run: just release-create ${GITHUB_EVENT_INPUTS_TAG} + env: + GITHUB_EVENT_INPUTS_TAG: ${{ github.event.inputs.tag }} + + - run: just release-run ${GH_TOKEN} ${GITHUB_EVENT_INPUTS_SHA} ${GITHUB_EVENT_INPUTS_TAG} + if: ${{ github.event.inputs.dry-run == 'false' }} + env: + GITHUB_EVENT_INPUTS_SHA: ${{ github.event.inputs.sha }} + GITHUB_EVENT_INPUTS_TAG: ${{ github.event.inputs.tag }} + + - name: Generate attestations + uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 + if: ${{ github.event.inputs.dry-run == 'false' }} + with: + subject-path: | + dist/*.tar.gz + dist/*.tar.zst diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index ee1b2d0..8ff211c 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -1,9 +1,11 @@ name: windows on: - push: - branches: [main] - pull_request: + # Disabled - not building Windows targets + # push: + # branches: [main] + # pull_request: + workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref_name }}-${{ github.event.pull_request.number || github.sha }} diff --git a/src/release.rs b/src/release.rs index ebdb6fd..a09248a 100644 --- a/src/release.rs +++ b/src/release.rs @@ -76,278 +76,48 @@ impl TripleRelease { pub static RELEASE_TRIPLES: Lazy> = Lazy::new(|| { let mut h = BTreeMap::new(); - // macOS. - let macos_suffixes = vec!["debug", "pgo+lto"]; - let macos_suffixes_313 = vec!["freethreaded+debug", "freethreaded+pgo+lto"]; + // Verkada targets only: aarch64-apple-darwin, aarch64-unknown-linux-gnu, x86_64-unknown-linux-gnu + let pgo_suffixes = vec!["pgo+lto"]; + let pgo_freethreaded_suffixes = vec!["freethreaded+pgo+lto"]; + + // macOS ARM64 h.insert( "aarch64-apple-darwin", TripleRelease { - suffixes: macos_suffixes.clone(), - install_only_suffix: "pgo+lto", - python_version_requirement: None, - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13.0rc0").unwrap(), - suffixes: macos_suffixes_313.clone(), - }], - }, - ); - h.insert( - "x86_64-apple-darwin", - TripleRelease { - suffixes: macos_suffixes, + suffixes: pgo_suffixes.clone(), install_only_suffix: "pgo+lto", python_version_requirement: None, conditional_suffixes: vec![ConditionalSuffixes { python_version_requirement: VersionSpecifier::from_str(">=3.13.0rc0").unwrap(), - suffixes: macos_suffixes_313.clone(), + suffixes: pgo_freethreaded_suffixes.clone(), }], }, ); - // Windows. - h.insert( - "i686-pc-windows-msvc", - TripleRelease { - suffixes: vec!["pgo"], - install_only_suffix: "pgo", - python_version_requirement: None, - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: vec!["freethreaded+pgo"], - }], - }, - ); - h.insert( - "x86_64-pc-windows-msvc", - TripleRelease { - suffixes: vec!["pgo"], - install_only_suffix: "pgo", - python_version_requirement: None, - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: vec!["freethreaded+pgo"], - }], - }, - ); - h.insert( - "aarch64-pc-windows-msvc", - TripleRelease { - suffixes: vec!["pgo"], - install_only_suffix: "pgo", - python_version_requirement: Some(VersionSpecifier::from_str(">=3.11").unwrap()), - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: vec!["freethreaded+pgo"], - }], - }, - ); - - // Linux. - let linux_suffixes_pgo = vec!["debug", "pgo+lto"]; - let linux_suffixes_nopgo = vec!["debug", "lto", "noopt"]; - let linux_suffixes_musl = vec![ - "debug", - "lto", - "noopt", - "debug+static", - "lto+static", - "noopt+static", - ]; - let linux_suffixes_musl_freethreaded = vec![ - "freethreaded+debug", - "freethreaded+lto", - "freethreaded+noopt", - ]; - let linux_suffixes_pgo_freethreaded = vec!["freethreaded+debug", "freethreaded+pgo+lto"]; - let linux_suffixes_nopgo_freethreaded = vec![ - "freethreaded+debug", - "freethreaded+lto", - "freethreaded+noopt", - ]; - + // Linux ARM64 h.insert( "aarch64-unknown-linux-gnu", TripleRelease { - suffixes: linux_suffixes_pgo.clone(), + suffixes: pgo_suffixes.clone(), install_only_suffix: "pgo+lto", python_version_requirement: None, conditional_suffixes: vec![ConditionalSuffixes { python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_pgo_freethreaded.clone(), - }], - }, - ); - - h.insert( - "ppc64le-unknown-linux-gnu", - TripleRelease { - suffixes: linux_suffixes_nopgo.clone(), - install_only_suffix: "lto", - python_version_requirement: Some(VersionSpecifier::from_str(">=3.10").unwrap()), - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_nopgo_freethreaded.clone(), - }], - }, - ); - - h.insert( - "riscv64-unknown-linux-gnu", - TripleRelease { - suffixes: linux_suffixes_nopgo.clone(), - install_only_suffix: "lto", - python_version_requirement: Some(VersionSpecifier::from_str(">=3.10").unwrap()), - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_nopgo_freethreaded.clone(), - }], - }, - ); - - h.insert( - "s390x-unknown-linux-gnu", - TripleRelease { - suffixes: linux_suffixes_nopgo.clone(), - install_only_suffix: "lto", - python_version_requirement: Some(VersionSpecifier::from_str(">=3.10").unwrap()), - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_nopgo_freethreaded.clone(), - }], - }, - ); - - h.insert( - "armv7-unknown-linux-gnueabi", - TripleRelease { - suffixes: linux_suffixes_nopgo.clone(), - install_only_suffix: "lto", - python_version_requirement: Some(VersionSpecifier::from_str(">=3.10").unwrap()), - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_nopgo_freethreaded.clone(), - }], - }, - ); - - h.insert( - "armv7-unknown-linux-gnueabihf", - TripleRelease { - suffixes: linux_suffixes_nopgo.clone(), - install_only_suffix: "lto", - python_version_requirement: Some(VersionSpecifier::from_str(">=3.10").unwrap()), - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_nopgo_freethreaded.clone(), + suffixes: pgo_freethreaded_suffixes.clone(), }], }, ); + // Linux x86_64 h.insert( "x86_64-unknown-linux-gnu", TripleRelease { - suffixes: linux_suffixes_pgo.clone(), - install_only_suffix: "pgo+lto", - python_version_requirement: None, - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_pgo_freethreaded.clone(), - }], - }, - ); - h.insert( - "x86_64_v2-unknown-linux-gnu", - TripleRelease { - suffixes: linux_suffixes_pgo.clone(), + suffixes: pgo_suffixes.clone(), install_only_suffix: "pgo+lto", - python_version_requirement: Some(VersionSpecifier::from_str(">=3.10").unwrap()), - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_pgo_freethreaded.clone(), - }], - }, - ); - h.insert( - "x86_64_v3-unknown-linux-gnu", - TripleRelease { - suffixes: linux_suffixes_pgo.clone(), - install_only_suffix: "pgo+lto", - python_version_requirement: Some(VersionSpecifier::from_str(">=3.10").unwrap()), - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_pgo_freethreaded.clone(), - }], - }, - ); - h.insert( - "x86_64_v4-unknown-linux-gnu", - TripleRelease { - suffixes: linux_suffixes_pgo.clone(), - install_only_suffix: "pgo+lto", - python_version_requirement: Some(VersionSpecifier::from_str(">=3.10").unwrap()), - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_pgo_freethreaded.clone(), - }], - }, - ); - h.insert( - "x86_64-unknown-linux-musl", - TripleRelease { - suffixes: linux_suffixes_musl.clone(), - install_only_suffix: "lto", - python_version_requirement: None, - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_musl_freethreaded.clone(), - }], - }, - ); - h.insert( - "x86_64_v2-unknown-linux-musl", - TripleRelease { - suffixes: linux_suffixes_musl.clone(), - install_only_suffix: "lto", - python_version_requirement: None, - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_musl_freethreaded.clone(), - }], - }, - ); - h.insert( - "x86_64_v3-unknown-linux-musl", - TripleRelease { - suffixes: linux_suffixes_musl.clone(), - install_only_suffix: "lto", - python_version_requirement: None, - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_musl_freethreaded.clone(), - }], - }, - ); - h.insert( - "x86_64_v4-unknown-linux-musl", - TripleRelease { - suffixes: linux_suffixes_musl.clone(), - install_only_suffix: "lto", - python_version_requirement: None, - conditional_suffixes: vec![ConditionalSuffixes { - python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_musl_freethreaded.clone(), - }], - }, - ); - h.insert( - "aarch64-unknown-linux-musl", - TripleRelease { - suffixes: vec!["debug", "lto", "noopt"], - install_only_suffix: "lto", python_version_requirement: None, conditional_suffixes: vec![ConditionalSuffixes { python_version_requirement: VersionSpecifier::from_str(">=3.13").unwrap(), - suffixes: linux_suffixes_musl_freethreaded.clone(), + suffixes: pgo_freethreaded_suffixes.clone(), }], }, ); From 447c1d3efeb746dac80b11dbe3e809dc5a2cd428 Mon Sep 17 00:00:00 2001 From: nickvines Date: Mon, 5 Jan 2026 10:22:49 -0800 Subject: [PATCH 3/7] Use namespace-profile-linux-arm for aarch64 builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update build job to use namespace-profile-linux-arm for aarch64-unknown-linux-gnu - Add crate-build matrix to build pythonbuild on both x86_64 and aarch64 runners - Add aarch64 Docker images (build.debian9, gcc.debian9) on namespace runner - Download correct pythonbuild artifact based on target architecture This fixes the 'No space left on device' errors by using native aarch64 builds instead of cross-compilation on x86_64 runners. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) --- .github/workflows/vlinux.yml | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/.github/workflows/vlinux.yml b/.github/workflows/vlinux.yml index aaa64a8..09cc074 100644 --- a/.github/workflows/vlinux.yml +++ b/.github/workflows/vlinux.yml @@ -16,7 +16,18 @@ permissions: {} jobs: crate-build: - runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - runner: ubuntu-latest + arch: x86_64 + artifact_name: crate-linux-x86_64 + - runner: namespace-profile-linux-arm + arch: aarch64 + artifact_name: crate-linux-aarch64 + runs-on: ${{ matrix.runner }} + name: crate / ${{ matrix.arch }} steps: - name: Install System Dependencies run: | @@ -37,7 +48,7 @@ jobs: ~/.cargo/registry ~/.cargo/git target - key: ${{ runner.os }}-pythonbuild-${{ hashFiles('Cargo.lock', '.rustc-version') }} + key: ${{ runner.os }}-${{ matrix.arch }}-pythonbuild-${{ hashFiles('Cargo.lock', '.rustc-version') }} - name: Build run: | @@ -46,7 +57,7 @@ jobs: - name: Upload pythonbuild Executable uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: - name: crate-linux-x86_64 + name: ${{ matrix.artifact_name }} path: target/release/pythonbuild image: @@ -56,12 +67,21 @@ jobs: include: - name: build arch: x86_64 + runner: ubuntu-latest - name: build.cross arch: x86_64 + runner: ubuntu-latest - name: gcc arch: x86_64 - name: image / ${{ matrix.name }} - runs-on: ubuntu-latest + runner: ubuntu-latest + - name: build.debian9 + arch: aarch64 + runner: namespace-profile-linux-arm + - name: gcc.debian9 + arch: aarch64 + runner: namespace-profile-linux-arm + name: image / ${{ matrix.arch }} / ${{ matrix.name }} + runs-on: ${{ matrix.runner }} permissions: packages: write steps: @@ -136,7 +156,7 @@ jobs: permissions: id-token: write attestations: write - runs-on: ubuntu-latest + runs-on: ${{ matrix.target_triple == 'aarch64-unknown-linux-gnu' && 'namespace-profile-linux-arm' || 'ubuntu-latest' }} strategy: fail-fast: false matrix: @@ -180,7 +200,7 @@ jobs: - name: Download pythonbuild uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: - name: crate-linux-x86_64 + name: ${{ matrix.target_triple == 'aarch64-unknown-linux-gnu' && 'crate-linux-aarch64' || 'crate-linux-x86_64' }} path: build - name: Download images From 150f8374a8235901dded3e72d0f3b79005357df2 Mon Sep 17 00:00:00 2001 From: nickvines Date: Mon, 5 Jan 2026 10:32:30 -0800 Subject: [PATCH 4/7] Switch to large caching namespace runners MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use namespace-profile-ubuntu-22-04-amd64-x86-64-large-caching for x86_64 - Use namespace-profile-ubuntu-22-04-amd64-arm-large-caching for aarch64 These larger runners with caching should provide better performance. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) --- .github/workflows/vlinux.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/vlinux.yml b/.github/workflows/vlinux.yml index 09cc074..fd67769 100644 --- a/.github/workflows/vlinux.yml +++ b/.github/workflows/vlinux.yml @@ -20,10 +20,10 @@ jobs: fail-fast: false matrix: include: - - runner: ubuntu-latest + - runner: namespace-profile-ubuntu-22-04-amd64-x86-64-large-caching arch: x86_64 artifact_name: crate-linux-x86_64 - - runner: namespace-profile-linux-arm + - runner: namespace-profile-ubuntu-22-04-amd64-arm-large-caching arch: aarch64 artifact_name: crate-linux-aarch64 runs-on: ${{ matrix.runner }} @@ -67,19 +67,19 @@ jobs: include: - name: build arch: x86_64 - runner: ubuntu-latest + runner: namespace-profile-ubuntu-22-04-amd64-x86-64-large-caching - name: build.cross arch: x86_64 - runner: ubuntu-latest + runner: namespace-profile-ubuntu-22-04-amd64-x86-64-large-caching - name: gcc arch: x86_64 - runner: ubuntu-latest + runner: namespace-profile-ubuntu-22-04-amd64-x86-64-large-caching - name: build.debian9 arch: aarch64 - runner: namespace-profile-linux-arm + runner: namespace-profile-ubuntu-22-04-amd64-arm-large-caching - name: gcc.debian9 arch: aarch64 - runner: namespace-profile-linux-arm + runner: namespace-profile-ubuntu-22-04-amd64-arm-large-caching name: image / ${{ matrix.arch }} / ${{ matrix.name }} runs-on: ${{ matrix.runner }} permissions: @@ -156,7 +156,7 @@ jobs: permissions: id-token: write attestations: write - runs-on: ${{ matrix.target_triple == 'aarch64-unknown-linux-gnu' && 'namespace-profile-linux-arm' || 'ubuntu-latest' }} + runs-on: ${{ matrix.target_triple == 'aarch64-unknown-linux-gnu' && 'namespace-profile-ubuntu-22-04-amd64-arm-large-caching' || 'namespace-profile-ubuntu-22-04-amd64-x86-64-large-caching' }} strategy: fail-fast: false matrix: From e2b35a0f051688fccc17a78b0dfd7bd0dd88c3f7 Mon Sep 17 00:00:00 2001 From: nickvines Date: Mon, 5 Jan 2026 10:45:09 -0800 Subject: [PATCH 5/7] Add debug output for Docker image loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Show files in build directory - Add file existence checks before decompressing/loading - Show loaded Docker images after loading This will help diagnose why Docker images aren't being found. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) --- .github/workflows/vlinux.yml | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/.github/workflows/vlinux.yml b/.github/workflows/vlinux.yml index fd67769..65c1ba0 100644 --- a/.github/workflows/vlinux.yml +++ b/.github/workflows/vlinux.yml @@ -221,16 +221,33 @@ jobs: - name: Load Docker Images run: | + echo "Files in build directory:" + ls -lah build/ + + echo "Looking for image archives..." + ls -lah build/image-* || echo "No image files found" + for f in build/image-*.tar.zst; do - echo "decompressing $f" - zstd -d --rm ${f} + if [ -f "$f" ]; then + echo "decompressing $f" + zstd -d --rm ${f} + else + echo "Warning: $f not found or is not a file" + fi done for f in build/image-*.tar; do - echo "loading $f" - docker load --input $f + if [ -f "$f" ]; then + echo "loading $f" + docker load --input $f + else + echo "Warning: $f not found or is not a file" + fi done + echo "Loaded Docker images:" + docker images + - name: Build run: | # Do empty target so all generated files are touched. From d21033f4ecee0db111d398862ae7a27be457b3da Mon Sep 17 00:00:00 2001 From: nickvines Date: Mon, 5 Jan 2026 10:57:04 -0800 Subject: [PATCH 6/7] Fix Docker image ID mismatch with containerd snapshotter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docker Buildx with containerd snapshotter returns a different image ID (config digest) than what docker load actually assigns (manifest digest). Solution: Capture the actual loaded image ID from docker load output and update the ID files so pythonbuild/docker.py can find the images. This fixes the ImageNotFound error that was causing builds to fail. Root cause identified by Opus agent analysis. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) --- .github/workflows/vlinux.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/vlinux.yml b/.github/workflows/vlinux.yml index 65c1ba0..f20f180 100644 --- a/.github/workflows/vlinux.yml +++ b/.github/workflows/vlinux.yml @@ -231,17 +231,22 @@ jobs: if [ -f "$f" ]; then echo "decompressing $f" zstd -d --rm ${f} - else - echo "Warning: $f not found or is not a file" fi done for f in build/image-*.tar; do if [ -f "$f" ]; then echo "loading $f" - docker load --input $f - else - echo "Warning: $f not found or is not a file" + # Capture the loaded image ID from docker load output + LOADED_ID=$(docker load --input $f 2>&1 | grep "Loaded image ID:" | awk '{print $4}') + echo "Loaded image ID: $LOADED_ID" + + # Update the ID file with the actual loaded ID + ID_FILE="${f%.tar}" + if [ -n "$LOADED_ID" ]; then + echo "$LOADED_ID" > "$ID_FILE" + echo "Updated $ID_FILE with $LOADED_ID" + fi fi done From 2a10d68d06d723613358d2bc2eab6256b68c8c98 Mon Sep 17 00:00:00 2001 From: nickvines Date: Mon, 5 Jan 2026 13:28:11 -0800 Subject: [PATCH 7/7] Use namespace macOS runner for vmacos workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch to namespace-profile-mac-small-tahoe for macOS builds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 (1M context) --- .github/workflows/vmacos.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/vmacos.yml b/.github/workflows/vmacos.yml index b225c58..1e51c9a 100644 --- a/.github/workflows/vmacos.yml +++ b/.github/workflows/vmacos.yml @@ -16,7 +16,7 @@ permissions: {} jobs: crate-build: - runs-on: macos-latest + runs-on: namespace-profile-mac-small-tahoe steps: - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: @@ -50,7 +50,7 @@ jobs: permissions: id-token: write attestations: write - runs-on: macos-latest + runs-on: namespace-profile-mac-small-tahoe strategy: fail-fast: false matrix: