From 5f6ba5fd60b64b51ef98b9fd5d0997a5104f1773 Mon Sep 17 00:00:00 2001 From: patrick kenneally Date: Fri, 31 Oct 2025 12:28:23 -0600 Subject: [PATCH 1/6] Make nuget source read-only to PRs from forks --- .github/workflows/pull-request.yml | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index c93c4a3f8..a68e51a46 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -12,9 +12,8 @@ defaults: shell: bash --noprofile --norc -euo pipefail {0} env: - USERNAME: ${{ github.repository_owner }} FEED_URL: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json - VCPKG_BINARY_SOURCES: "clear;nuget,https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json,readwrite" + VCPKG_BINARY_SOURCES: "clear;nuget,https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json,read" VCPKG_FEATURE_FLAGS: "manifests,registries,binarycaching" CMAKE_BUILD_PARALLEL_LEVEL: 4 CTEST_PARALLEL_LEVEL: 4 @@ -67,7 +66,7 @@ jobs: python-version: ["3.9", "3.10", "3.11"] permissions: contents: read - packages: write + packages: read actions: read security-events: write steps: @@ -132,18 +131,18 @@ jobs: ${{ runner.workspace }}/b/vcpkg/buildtrees key: vcpkg-${{ runner.os }}-${{ hashFiles('src/vcpkg.json', 'src/vcpkg-configuration.json') }} - - name: Add NuGet sources for vcpkg binary cache (portable) + - name: Add NuGet sources for vcpkg binary cache (read-only) env: VCPKG_EXE: ${{ runner.workspace }}/b/vcpkg/vcpkg + NUGET_USER: ${{ github.repository_owner }} + NUGET_TOKEN: ${{ github.token }} run: | set -euo pipefail NUGET="$(${VCPKG_EXE} fetch nuget | tail -n 1)" - # Build the command invocation safely (handles paths with spaces) if [[ "$NUGET" == *.exe ]]; then NUGET_CMD=(mono "$NUGET") else - # e.g., "nuget" shim from Mono on macOS, or a native path NUGET_CMD=("$NUGET") fi @@ -151,12 +150,12 @@ jobs: "${NUGET_CMD[@]}" sources add \ -Source "${FEED_URL}" \ - -StorePasswordInClearText \ -Name GitHubPackages \ - -UserName "${USERNAME}" \ - -Password "${{ secrets.GH_VCPKG_PACKAGES_TOKEN }}" + -UserName "${NUGET_USER}" \ + -Password "${NUGET_TOKEN}" \ + -StorePasswordInClearText - "${NUGET_CMD[@]}" setapikey "${{ secrets.GH_VCPKG_PACKAGES_TOKEN }}" \ + "${NUGET_CMD[@]}" setapikey "${NUGET_TOKEN}" \ -Source "${FEED_URL}" - name: Create virtual environment From e0034ed83706e57befd9ea201ab067d2c6576e85 Mon Sep 17 00:00:00 2001 From: patrick kenneally Date: Fri, 31 Oct 2025 12:28:55 -0600 Subject: [PATCH 2/6] Add workflow to update nuget cache after approval --- .github/workflows/pr-nuget-packaging.yml | 149 +++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 .github/workflows/pr-nuget-packaging.yml diff --git a/.github/workflows/pr-nuget-packaging.yml b/.github/workflows/pr-nuget-packaging.yml new file mode 100644 index 000000000..528b11387 --- /dev/null +++ b/.github/workflows/pr-nuget-packaging.yml @@ -0,0 +1,149 @@ +name: "Pull Request NuGet Packaging" + +on: + workflow_run: + workflows: + - Pull Request Test + types: + - completed + +concurrency: + group: ${{ github.workflow }}-${{ github.event.workflow_run.id }} + cancel-in-progress: false + +defaults: + run: + shell: bash --noprofile --norc -euo pipefail {0} + +env: + USERNAME: ${{ github.repository_owner }} + FEED_URL: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json + VCPKG_BINARY_SOURCES: "clear;nuget,https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json,readwrite" + VCPKG_FEATURE_FLAGS: "manifests,registries,binarycaching" + CMAKE_BUILD_PARALLEL_LEVEL: 4 + CTEST_PARALLEL_LEVEL: 4 + CTEST_OUTPUT_ON_FAILURE: 1 + +jobs: + publish-nuget: + name: Publish NuGet packages (ubuntu-24.04) + if: > + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.pull_requests[0].number != null + runs-on: ubuntu-24.04 + environment: + name: nuget-publish + permissions: + contents: read + packages: write + actions: read + steps: + - name: Checkout pull request merge commit + uses: actions/checkout@v4 + with: + repository: ${{ github.event.workflow_run.repository.full_name }} + ref: ${{ format('refs/pull/{0}/merge', github.event.workflow_run.pull_requests[0].number) }} + fetch-depth: 0 + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: 'pip' + cache-dependency-path: | + requirements.txt + **/pyproject.toml + **/requirements*.txt + + - name: Install system dependencies (Linux) + run: | + sudo apt-get update + sudo apt-get install -y \ + ninja-build build-essential \ + pkg-config autoconf automake libtool \ + zip unzip \ + bison swig \ + libdrm-dev \ + libx11-dev libxkbcommon-x11-dev libx11-xcb-dev \ + libxft-dev libxext-dev libgles2-mesa-dev \ + libxi-dev libxtst-dev libxrandr-dev libltdl-dev \ + libgtk2.0-dev \ + python3-setuptools python3-jinja2 python3-tk \ + mono-complete + + - name: Setup CMake 3.28.3 + uses: jwlawson/actions-setup-cmake@v2 + with: + cmake-version: '3.28.3' + + - name: Install vcpkg + uses: lukka/run-vcpkg@v11 + with: + vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg' + vcpkgJsonGlob: "src/vcpkg.json" + vcpkgConfigurationJsonGlob: "src/vcpkg-configuration.json" + + - name: Cache vcpkg build artifacts + uses: actions/cache@v4 + with: + path: | + ${{ runner.workspace }}/b/vcpkg/installed + ${{ runner.workspace }}/b/vcpkg/packages + ${{ runner.workspace }}/b/vcpkg/buildtrees + key: vcpkg-${{ runner.os }}-${{ hashFiles('src/vcpkg.json', 'src/vcpkg-configuration.json') }} + + - name: Add NuGet sources for vcpkg binary cache (portable) + env: + VCPKG_EXE: ${{ runner.workspace }}/b/vcpkg/vcpkg + run: | + set -euo pipefail + NUGET="$(${VCPKG_EXE} fetch nuget | tail -n 1)" + + if [[ "$NUGET" == *.exe ]]; then + NUGET_CMD=(mono "$NUGET") + else + NUGET_CMD=("$NUGET") + fi + + echo "Using NuGet CLI: ${NUGET_CMD[*]}" + + "${NUGET_CMD[@]}" sources add \ + -Source "${FEED_URL}" \ + -StorePasswordInClearText \ + -Name GitHubPackages \ + -UserName "${USERNAME}" \ + -Password "${{ secrets.GH_VCPKG_PACKAGES_TOKEN }}" + + "${NUGET_CMD[@]}" setapikey "${{ secrets.GH_VCPKG_PACKAGES_TOKEN }}" \ + -Source "${FEED_URL}" + + - name: Create virtual environment + run: | + python -m venv .venv + source .venv/bin/activate + python -V + pip -V + + - name: Install required Python dependencies + run: | + source .venv/bin/activate + python -m pip install -r requirements.txt + + - name: Configure (CMake preset) + working-directory: src + run: cmake --preset ci-test + + - name: Build + working-directory: src + run: cmake --build ../build --parallel + + - name: Install Basilisk (editable) + run: | + source .venv/bin/activate + cmake --install build --prefix $(pwd)/dist + python -m pip install -e . + + - name: Run C/C++ tests + working-directory: ./build + run: ctest --output-on-failure From b0305bc461ab62589b1940901a9e6440fa00ccce Mon Sep 17 00:00:00 2001 From: patrick kenneally Date: Tue, 2 Dec 2025 09:13:08 -0700 Subject: [PATCH 3/6] edit --- .github/workflows/pr-nuget-packaging.yml | 3 +- .github/workflows/pull-request-target.yml | 180 ++++++++++++++++++++++ .github/workflows/pull-request.yml | 4 +- 3 files changed, 184 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/pull-request-target.yml diff --git a/.github/workflows/pr-nuget-packaging.yml b/.github/workflows/pr-nuget-packaging.yml index 528b11387..29f1bac31 100644 --- a/.github/workflows/pr-nuget-packaging.yml +++ b/.github/workflows/pr-nuget-packaging.yml @@ -30,7 +30,8 @@ jobs: if: > github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' && - github.event.workflow_run.pull_requests[0].number != null + github.event.workflow_run.pull_requests[0].number != null && + github.event.workflow_run.head_repository.full_name == github.repository runs-on: ubuntu-24.04 environment: name: nuget-publish diff --git a/.github/workflows/pull-request-target.yml b/.github/workflows/pull-request-target.yml new file mode 100644 index 000000000..c1773e0f4 --- /dev/null +++ b/.github/workflows/pull-request-target.yml @@ -0,0 +1,180 @@ +name: "Pull Request (Forks, NuGet cache read-only)" + +on: + pull_request_target: + +permissions: + contents: read + packages: read + actions: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash --noprofile --norc -euo pipefail {0} + +env: + FEED_URL: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json + VCPKG_BINARY_SOURCES: "clear;nuget,${{ env.FEED_URL }},read" + VCPKG_FEATURE_FLAGS: "manifests,registries,binarycaching" + CMAKE_BUILD_PARALLEL_LEVEL: 4 + CTEST_PARALLEL_LEVEL: 4 + CTEST_OUTPUT_ON_FAILURE: 1 + +jobs: + pre-commit: + runs-on: ubuntu-24.04 + if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} + permissions: + contents: read + steps: + - name: Checkout PR head (no credentials) + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + persist-credentials: false + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + cache: 'pip' + cache-dependency-path: | + requirements.txt + **/pyproject.toml + **/requirements*.txt + + - uses: actions/cache@v4 + with: + path: ~/.cache/pre-commit + key: pre-commit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }} + + - name: Install clang-format (Linux static binary) + run: | + sudo wget -qO /usr/local/bin/clang-format https://github.com/cpp-linter/clang-tools-static-binaries/releases/latest/download/clang-format-20_linux-amd64 + sudo chmod a+x /usr/local/bin/clang-format + clang-format --version + + - id: file_changes + uses: tj-actions/changed-files@v46 + + - name: Run pre-commit (changed files) + uses: pre-commit/action@v3.0.1 + with: + extra_args: --color always --files ${{ steps.file_changes.outputs.all_changed_files }} + + build-test: + name: Build & Test (forks, ubuntu-24.04 / py3.11) + runs-on: ubuntu-24.04 + if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} + steps: + - name: Checkout PR head (no credentials) + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + persist-credentials: false + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: 'pip' + cache-dependency-path: | + requirements.txt + **/pyproject.toml + **/requirements*.txt + + - name: Install system dependencies (Linux) + run: | + sudo apt-get update + sudo apt-get install -y \ + ninja-build build-essential \ + pkg-config autoconf automake libtool \ + zip unzip \ + bison swig \ + libdrm-dev \ + libx11-dev libxkbcommon-x11-dev libx11-xcb-dev \ + libxft-dev libxext-dev libgles2-mesa-dev \ + libxi-dev libxtst-dev libxrandr-dev libltdl-dev \ + libgtk2.0-dev \ + python3-setuptools python3-jinja2 python3-tk \ + mono-complete + + - name: Setup CMake 3.28.3 + uses: jwlawson/actions-setup-cmake@v2 + with: + cmake-version: '3.28.3' + + - name: Install vcpkg + uses: lukka/run-vcpkg@v11 + with: + vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg' + vcpkgJsonGlob: "src/vcpkg.json" + vcpkgConfigurationJsonGlob: "src/vcpkg-configuration.json" + + - name: Add NuGet sources for vcpkg binary cache (read-only) + env: + VCPKG_EXE: ${{ runner.workspace }}/b/vcpkg/vcpkg + NUGET_USER: ${{ github.repository_owner }} + NUGET_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + NUGET="$(${VCPKG_EXE} fetch nuget | tail -n 1)" + + if [[ "$NUGET" == *.exe ]]; then + NUGET_CMD=(mono "$NUGET") + else + NUGET_CMD=("$NUGET") + fi + + echo "Using NuGet CLI: ${NUGET_CMD[*]}" + + "${NUGET_CMD[@]}" sources add \ + -Source "${FEED_URL}" \ + -Name GitHubPackages \ + -UserName "${NUGET_USER}" \ + -Password "${NUGET_TOKEN}" \ + -StorePasswordInClearText + + "${NUGET_CMD[@]}" setapikey "${NUGET_TOKEN}" \ + -Source "${FEED_URL}" + + - name: Create virtual environment + run: | + python -m venv .venv + source .venv/bin/activate + python -V + pip -V + + - name: Install required Python dependencies + run: | + source .venv/bin/activate + python -m pip install -r requirements.txt + + - name: Configure (CMake preset) + working-directory: src + run: cmake --preset fuzz-smoke-test + + - name: Build + working-directory: src + run: cmake --build ../build --parallel + + - name: Install Xmera (editable) + run: | + source .venv/bin/activate + cmake --install build --prefix $(pwd)/dist + python -m pip install -e . + + - name: Run Python tests + run: | + source .venv/bin/activate + cd src + pytest -n auto -m "not scenarioTest" + + - name: Run C/C++ unit tests (include fuzz-smoke) + working-directory: ./build + env: + CTEST_PARALLEL_LEVEL: 1 + run: ctest --output-on-failure -LE fuzz diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index a68e51a46..b6192983b 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -24,6 +24,7 @@ jobs: runs-on: ubuntu-24.04 permissions: contents: read + if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} steps: - uses: actions/checkout@v4 @@ -59,6 +60,7 @@ jobs: name: Build & Test (${{ matrix.os }} / py${{ matrix.python-version }}) runs-on: ${{ matrix.os }} if: ${{ github.event.pull_request.draft == false }} + && github.event.pull_request.head.repo.full_name == github.repository strategy: fail-fast: false matrix: @@ -172,8 +174,6 @@ jobs: - name: Configure (CMake preset) working-directory: src - env: - VCPKG_BINARY_SOURCES: "clear;nuget,${{ env.FEED_URL }},readwrite" run: cmake --preset fuzz-smoke-test - name: Build From fa80c04a218450a5e0fd5b5a51c4d1d06b583afe Mon Sep 17 00:00:00 2001 From: patrick kenneally Date: Tue, 2 Dec 2025 09:37:17 -0700 Subject: [PATCH 4/6] squash --- .github/workflows/pull-request-target.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull-request-target.yml b/.github/workflows/pull-request-target.yml index c1773e0f4..0c9fe6aa8 100644 --- a/.github/workflows/pull-request-target.yml +++ b/.github/workflows/pull-request-target.yml @@ -18,7 +18,7 @@ defaults: env: FEED_URL: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json - VCPKG_BINARY_SOURCES: "clear;nuget,${{ env.FEED_URL }},read" + VCPKG_BINARY_SOURCES: "clear;nuget,https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json,read" VCPKG_FEATURE_FLAGS: "manifests,registries,binarycaching" CMAKE_BUILD_PARALLEL_LEVEL: 4 CTEST_PARALLEL_LEVEL: 4 From 627e8247b36577a16359f5999527172828816867 Mon Sep 17 00:00:00 2001 From: patrick kenneally Date: Tue, 2 Dec 2025 10:17:55 -0700 Subject: [PATCH 5/6] squash --- .github/workflows/pull-request.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index b6192983b..1d2971fd2 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -59,8 +59,7 @@ jobs: build-test: name: Build & Test (${{ matrix.os }} / py${{ matrix.python-version }}) runs-on: ${{ matrix.os }} - if: ${{ github.event.pull_request.draft == false }} - && github.event.pull_request.head.repo.full_name == github.repository + if: ${{ github.event.pull_request.draft == false && github.event.pull_request.head.repo.full_name == github.repository }} strategy: fail-fast: false matrix: From 8f248c99ebfda410b0380846819db57dc9d77479 Mon Sep 17 00:00:00 2001 From: patrick kenneally Date: Tue, 2 Dec 2025 10:23:18 -0700 Subject: [PATCH 6/6] squash --- .github/workflows/pull-request-target.yml | 29 +++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pull-request-target.yml b/.github/workflows/pull-request-target.yml index 0c9fe6aa8..ce145a89f 100644 --- a/.github/workflows/pull-request-target.yml +++ b/.github/workflows/pull-request-target.yml @@ -66,9 +66,19 @@ jobs: extra_args: --color always --files ${{ steps.file_changes.outputs.all_changed_files }} build-test: - name: Build & Test (forks, ubuntu-24.04 / py3.11) - runs-on: ubuntu-24.04 + name: Build & Test (forks, ${{ matrix.os }} / py${{ matrix.python-version }}) + runs-on: ${{ matrix.os }} if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-24.04, macos-14] + python-version: ["3.9", "3.10", "3.11"] + permissions: + contents: read + packages: read + actions: read + security-events: write steps: - name: Checkout PR head (no credentials) uses: actions/checkout@v4 @@ -76,10 +86,10 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false - - name: Set up Python 3.11 + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: - python-version: "3.11" + python-version: ${{ matrix.python-version }} cache: 'pip' cache-dependency-path: | requirements.txt @@ -87,6 +97,7 @@ jobs: **/requirements*.txt - name: Install system dependencies (Linux) + if: runner.os == 'Linux' run: | sudo apt-get update sudo apt-get install -y \ @@ -102,6 +113,16 @@ jobs: python3-setuptools python3-jinja2 python3-tk \ mono-complete + - name: Install system dependencies (macOS) + if: runner.os == 'macOS' + env: + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_ANALYTICS: 1 + run: | + brew install ninja swig pkg-config mono || true + swig -version + mono --version || true + - name: Setup CMake 3.28.3 uses: jwlawson/actions-setup-cmake@v2 with: