Skip to content
Latchkey

Build & Deploy workflow (northsh/detection.studio)

The Build & Deploy workflow from northsh/detection.studio, explained and optimized by Latchkey.

C

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.

Grade your own workflow free or run it on Latchkey →
Source: northsh/detection.studio.github/workflows/deploy.ymlLicense MITView source

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

workflow (.yml)
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

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:

This workflow runs 3 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow