Build & Deploy workflow (northsh/detection.studio)
The Build & Deploy workflow from northsh/detection.studio, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get run de-duplication, job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Build & Deploy workflow from the northsh/detection.studio repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Build & Deploy
on:
push:
branches:
- main
pull_request:
branches:
- main
permissions:
contents: read
jobs:
rsigma-wasm:
name: rsigma-wasm (Rust + JS integration)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Bun
uses: oven-sh/setup-bun@v2
- name: Set up Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry & build artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: rsigma-wasm
- name: Install dependencies
run: bun install
- name: Run rsigma-wasm Rust unit tests
run: bun run test:wasm
- name: Install wasm-pack
uses: jetli/wasm-pack-action@v0.4.0
with:
version: "v0.14.0"
# The pkg/ output is a build artifact (not committed) because the
# optimized .wasm produced by wasm-opt/LTO is not byte-reproducible
# across host platforms. Build it fresh from source here so the
# tests below run against bindings generated from the current source.
- name: Build WASM
run: bun run build:wasm
- name: Run Vitest unit tests against the real WASM
run: bun run test:unit
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
browser: [chromium]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Bun
uses: oven-sh/setup-bun@v2
- name: Set up Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry & build artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: rsigma-wasm
- name: Install wasm-pack
uses: jetli/wasm-pack-action@v0.4.0
with:
version: "v0.14.0"
- name: Get installed Playwright version
id: playwright-version
run: echo "PLAYWRIGHT_VERSION=$(bun pm ls 2>/dev/null | grep '@playwright/test' | sed 's/.*@//')" >> $GITHUB_ENV
- name: Cache playwright binaries
uses: actions/cache@v4
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}-${{ matrix.browser }}-${{ hashFiles('**/bun.lock') }}
- name: Install dependencies
run: bun install
- name: Install Playwright dependencies
run: npx playwright install-deps ${{ matrix.browser }}
if: steps.playwright-cache.outputs.cache-hit != 'true' || matrix.browser == 'webkit'
- name: Install Playwright browsers
run: bunx playwright install ${{ matrix.browser }}
if: steps.playwright-cache.outputs.cache-hit != 'true'
- name: Clone SigmaHQ rules (shallow)
run: git clone --depth 1 --single-branch --branch master https://github.com/SigmaHQ/sigma.git .sigma-repo
- name: Generate Sigma rules index
run: bun run scripts/generate-sigma-index.ts
- name: Build WASM
run: bun run build:wasm
# @northsh/pysigma-node is a workspace package whose dist/ is a
# gitignored build artifact. Build it so Vite can resolve the
# import from the app's source.
- name: Build pysigma-node
run: bun run build:lib
- name: Run Playwright tests for ${{ matrix.browser }}
run: bun run test --project=${{ matrix.browser }}
build-and-deploy:
runs-on: ubuntu-latest
needs: [test, rsigma-wasm]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Bun
uses: oven-sh/setup-bun@v2
- name: Set up Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry & build artifacts
uses: Swatinem/rust-cache@v2
with:
workspaces: rsigma-wasm
- name: Install wasm-pack
uses: jetli/wasm-pack-action@v0.4.0
with:
version: "v0.14.0"
- name: Install dependencies
run: bun install
- name: Build WASM
run: bun run build:wasm
- name: Build pysigma-node
run: bun run build:lib
- name: Build project
run: bun -b run build
- name: Deploy to BunnyCDN
uses: ayeressian/bunnycdn-storage-deploy@v2.2.5
with:
source: "dist"
destination: "/"
storageZoneName: "${{ secrets.STORAGE_NAME }}"
storagePassword: "${{ secrets.STORAGE_PASSWORD }}"
accessKey: "${{ secrets.STORAGE_KEY }}"
pullZoneId: "${{ secrets.ZONE_ID }}"
upload: "true"
remove: "true"
purgePullZone: "true"
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Build & Deploy on: push: branches: - main pull_request: branches: - main permissions: contents: read concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: rsigma-wasm: timeout-minutes: 30 name: rsigma-wasm (Rust + JS integration) runs-on: latchkey-small steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up Bun uses: oven-sh/setup-bun@v2 - name: Set up Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Cache cargo registry & build artifacts uses: Swatinem/rust-cache@v2 with: workspaces: rsigma-wasm - name: Install dependencies run: bun install - name: Run rsigma-wasm Rust unit tests run: bun run test:wasm - name: Install wasm-pack uses: jetli/wasm-pack-action@v0.4.0 with: version: "v0.14.0" # The pkg/ output is a build artifact (not committed) because the # optimized .wasm produced by wasm-opt/LTO is not byte-reproducible # across host platforms. Build it fresh from source here so the # tests below run against bindings generated from the current source. - name: Build WASM run: bun run build:wasm - name: Run Vitest unit tests against the real WASM run: bun run test:unit test: timeout-minutes: 30 runs-on: latchkey-small strategy: fail-fast: false matrix: browser: [chromium] steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up Bun uses: oven-sh/setup-bun@v2 - name: Set up Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Cache cargo registry & build artifacts uses: Swatinem/rust-cache@v2 with: workspaces: rsigma-wasm - name: Install wasm-pack uses: jetli/wasm-pack-action@v0.4.0 with: version: "v0.14.0" - name: Get installed Playwright version id: playwright-version run: echo "PLAYWRIGHT_VERSION=$(bun pm ls 2>/dev/null | grep '@playwright/test' | sed 's/.*@//')" >> $GITHUB_ENV - name: Cache playwright binaries uses: actions/cache@v4 id: playwright-cache with: path: | ~/.cache/ms-playwright key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}-${{ matrix.browser }}-${{ hashFiles('**/bun.lock') }} - name: Install dependencies run: bun install - name: Install Playwright dependencies run: npx playwright install-deps ${{ matrix.browser }} if: steps.playwright-cache.outputs.cache-hit != 'true' || matrix.browser == 'webkit' - name: Install Playwright browsers run: bunx playwright install ${{ matrix.browser }} if: steps.playwright-cache.outputs.cache-hit != 'true' - name: Clone SigmaHQ rules (shallow) run: git clone --depth 1 --single-branch --branch master https://github.com/SigmaHQ/sigma.git .sigma-repo - name: Generate Sigma rules index run: bun run scripts/generate-sigma-index.ts - name: Build WASM run: bun run build:wasm # @northsh/pysigma-node is a workspace package whose dist/ is a # gitignored build artifact. Build it so Vite can resolve the # import from the app's source. - name: Build pysigma-node run: bun run build:lib - name: Run Playwright tests for ${{ matrix.browser }} run: bun run test --project=${{ matrix.browser }} build-and-deploy: timeout-minutes: 30 runs-on: latchkey-small needs: [test, rsigma-wasm] if: github.event_name == 'push' && github.ref == 'refs/heads/main' permissions: contents: write steps: - name: Checkout repository uses: actions/checkout@v4 - name: Set up Bun uses: oven-sh/setup-bun@v2 - name: Set up Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Cache cargo registry & build artifacts uses: Swatinem/rust-cache@v2 with: workspaces: rsigma-wasm - name: Install wasm-pack uses: jetli/wasm-pack-action@v0.4.0 with: version: "v0.14.0" - name: Install dependencies run: bun install - name: Build WASM run: bun run build:wasm - name: Build pysigma-node run: bun run build:lib - name: Build project run: bun -b run build - name: Deploy to BunnyCDN uses: ayeressian/bunnycdn-storage-deploy@v2.2.5 with: source: "dist" destination: "/" storageZoneName: "${{ secrets.STORAGE_NAME }}" storagePassword: "${{ secrets.STORAGE_PASSWORD }}" accessKey: "${{ secrets.STORAGE_KEY }}" pullZoneId: "${{ secrets.ZONE_ID }}" upload: "true" remove: "true" purgePullZone: "true"
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cancel superseded runs when a branch or PR gets a newer push.
- Add a job timeout so a hung step cannot burn hours of runner time.
5 third-party actions are referenced by a movable tag. Pin them to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- End-to-end and browser tests
This workflow runs 3 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.