Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 112 additions & 52 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ jobs:
with:
add-rust-environment-hash-key: false
save-if: ${{ github.ref == 'refs/heads/main' }}
# One cache per leg: they build different things, and a shared key
# let the quicker 5.10 leg save first, so the runner leg's debug
# build for the live tests was never cached.
key: ${{ matrix.kernel }}
- name: Download eBPF artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
Expand Down Expand Up @@ -390,26 +394,11 @@ jobs:
test_binary="$(cargo test --locked --lib --no-run --message-format=json | jq -r 'select(.reason == "compiler-artifact" and .target.kind == ["lib"] and .executable != null) | .executable')"
sudo "$test_binary" integration_group_ --ignored --test-threads=1

atomic:
name: ${{ matrix.shard == '1/1' && format('Atomic ({0})', matrix.platform) || format('Atomic ({0} shard {1})', matrix.platform, matrix.shard) }}
atomic-linux:
name: Atomic (linux)
if: ${{ !inputs.skip_atomics }}
runs-on: ${{ matrix.os }}
runs-on: ubuntu-latest
needs: ebpf-build
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
platform: linux
shard: 1/1
# Windows runs its ~75 atomics sequentially and is the long pole, so
# it is split across two runners.
- os: windows-latest
platform: windows
shard: 1/2
- os: windows-latest
platform: windows
shard: 2/2
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
Expand All @@ -426,23 +415,14 @@ jobs:
save-if: ${{ github.ref == 'refs/heads/main' }}

- name: Download eBPF artifact
if: matrix.platform == 'linux'
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: rustinel-ebpf-object
path: ebpf/

# Each shard builds its own binary. With a warm cache this is quicker
# than a shared build job plus an artifact hop, and the Linux leg does
# not wait on the Windows build.
- name: Build PR binary
run: cargo build --locked --release

- name: Run native capture contract (Windows)
if: matrix.platform == 'windows' && matrix.shard == '1/2'
run: python tests\native_capture_contract.py --binary "$env:GITHUB_WORKSPACE\target\release\rustinel.exe"
shell: pwsh

- name: Read shared atomic rules pin
id: rules-pin
shell: bash
Expand Down Expand Up @@ -479,13 +459,7 @@ jobs:
working-directory: rustinel-rules
run: python tests/atomic/run_atomics.py --check-coverage --strict-essential

- name: Exclude workspace from Defender (Windows, for EICAR)
if: matrix.platform == 'windows'
run: Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE" -ErrorAction SilentlyContinue
shell: pwsh

- name: Run atomic tests (Linux)
if: matrix.platform == 'linux'
working-directory: rustinel-rules
run: |
# The hosted runner leaves /opt writable by other accounts.
Expand All @@ -497,12 +471,113 @@ jobs:
--engine-bin "$GITHUB_WORKSPACE/scripts/atomic_managed_service.sh" \
--engine-dir /opt/rustinel \
--rules-dir "$GITHUB_WORKSPACE/rustinel-rules" \
--pack auto \
--shard "${{ matrix.shard }}"
--pack auto
shell: bash

- name: Prepare atomic logs for upload (Unix)
if: always()
run: |
if [ -d /opt/rustinel/logs ]; then
sudo cp -a /opt/rustinel/logs rustinel-rules/tests/atomic/managed-logs
sudo chown -R "$(id -u):$(id -g)" rustinel-rules/tests/atomic/managed-logs
fi
if [ -f /opt/rustinel/engine.stdout.log ]; then
sudo cp /opt/rustinel/engine.stdout.log rustinel-rules/tests/atomic/engine.stdout.log
sudo chown "$(id -u):$(id -g)" rustinel-rules/tests/atomic/engine.stdout.log
fi
shell: bash

- name: Upload atomic report and logs
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: atomic-linux
path: |
rustinel-rules/tests/atomic/report-*.json
rustinel-rules/tests/atomic/.engine/engine.stdout.log
rustinel-rules/tests/atomic/.engine/logs/
rustinel-rules/tests/atomic/engine.stdout.log
rustinel-rules/tests/atomic/managed-logs/
include-hidden-files: true
if-no-files-found: warn

# Windows needs no eBPF object, so it starts at once instead of waiting on
# ebpf-build. Its ~75 atomics run sequentially and are the long pole, so
# they are split across three runners.
atomic:
name: Atomic (windows shard ${{ matrix.shard }})
if: ${{ !inputs.skip_atomics }}
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
shard: [1/3, 2/3, 3/3]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false

- uses: actions-rust-lang/setup-rust-toolchain@ecabd13d1c56bd1345c230e542e9144811ad706f # v2.0.0
with:
cache: false
rustflags: ""

- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
add-rust-environment-hash-key: false
save-if: ${{ github.ref == 'refs/heads/main' }}

# Each shard builds its own binary: with a warm cache that beats a
# shared build job plus an artifact hop.
- name: Build PR binary
run: cargo build --locked --release

- name: Run native capture contract (Windows)
if: matrix.shard == '1/3'
run: python tests\native_capture_contract.py --binary "$env:GITHUB_WORKSPACE\target\release\rustinel.exe"
shell: pwsh

- name: Read shared atomic rules pin
id: rules-pin
shell: bash
run: |
ref="$(cat .github/atomic-rules-ref)"
if [[ ! "$ref" =~ ^[0-9a-f]{40}$ ]]; then
echo "Expected a full commit SHA in .github/atomic-rules-ref" >&2
exit 1
fi
echo "ref=$ref" >> "$GITHUB_OUTPUT"

- name: Check out pinned rules
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: Karib0u/rustinel-rules
ref: ${{ steps.rules-pin.outputs.ref }}
path: rustinel-rules
persist-credentials: false

- name: Install uv
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
with:
enable-cache: false

- name: Build pinned rules pack
working-directory: rustinel-rules
run: |
uv sync --frozen
# Validate a rules commit, not the enclosing engine release tag.
uv run python -c "import os, subprocess, sys; os.environ.pop('GITHUB_REF_TYPE', None); sys.exit(subprocess.call([sys.executable, 'tools/validate.py']))"
uv run python tools/build_packs.py

- name: Check atomic coverage metadata
working-directory: rustinel-rules
run: python tests/atomic/run_atomics.py --check-coverage --strict-essential

- name: Exclude workspace from Defender (Windows, for EICAR)
run: Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE" -ErrorAction SilentlyContinue
shell: pwsh

- name: Run atomic tests (Windows)
if: matrix.platform == 'windows'
working-directory: rustinel-rules
run: |
# The runner's D:\a grants Users write, and the agent refuses inputs
Expand All @@ -527,30 +602,15 @@ jobs:
--shard "${{ matrix.shard }}"
shell: pwsh

- name: Prepare atomic logs for upload (Unix)
if: always() && matrix.platform != 'windows'
run: |
if [ -d /opt/rustinel/logs ]; then
sudo cp -a /opt/rustinel/logs rustinel-rules/tests/atomic/managed-logs
sudo chown -R "$(id -u):$(id -g)" rustinel-rules/tests/atomic/managed-logs
fi
if [ -f /opt/rustinel/engine.stdout.log ]; then
sudo cp /opt/rustinel/engine.stdout.log rustinel-rules/tests/atomic/engine.stdout.log
sudo chown "$(id -u):$(id -g)" rustinel-rules/tests/atomic/engine.stdout.log
fi
shell: bash

- name: Upload atomic report and logs
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: atomic-${{ matrix.platform }}-${{ strategy.job-index }}
name: atomic-windows-${{ strategy.job-index }}
path: |
rustinel-rules/tests/atomic/report-*.json
rustinel-rules/tests/atomic/.engine/engine.stdout.log
rustinel-rules/tests/atomic/.engine/logs/
rustinel-rules/tests/atomic/engine.stdout.log
rustinel-rules/tests/atomic/managed-logs/
include-hidden-files: true
if-no-files-found: warn

Expand Down
Loading