Workflow · DevOps & platform engineers

Bowire as a pipeline step

You're wiring the CI/CD pipeline. Bowire ships as a single binary + Docker image that drops into any runner.

Four subcommands carry the load: bowire mock as an integration-test fixture, bowire test as the regression gate, bowire scan as a SAST gate, bowire fuzz as a security-regression step. Real exit codes, no daemons, native SARIF output.

What you can do in the pipeline

Four Bowire steps cover the heavy lifting between “tests pass” and “safe to ship”. Each runs as a one-liner and exits with a real code.

bowire mock — integration-test fixture

Replay a recorded session as a live endpoint on the runner. Same protocol-shape as the real service (REST, gRPC, WebSocket, MQTT, …), hot-reload on file edits, capture-on-miss for new calls. Fixtures live in your repo as .bwr files — reviewable in PRs.

Service-mocking lane: develop without the real backend →

bash
# Background the mock for the rest of the job
$ bowire mock --recording fixtures/api.bwr \
              --port 5099 &

bowire test — regression gate

Run a recording or a flow file headless — the format is auto-detected. Inline assertions, snapshots, and data-driven rows all execute; a non-zero exit code fails the job. Emits JUnit for the test-report tab, SARIF for Code Scanning, and an HTML --report; --annotations writes GitHub check annotations and --fail-on sets the severity gate. Pair it with bowire contract verify to hold the provider to a published Pact-style contract.

Contract-testing lane: from a session to a regression →

bash
# Replay the recording as a regression gate
$ bowire test fixtures/api.bwr --base-url http://localhost:5099 \
              --junit test-results.xml --sarif test.sarif \
              --annotations --fail-on error

# Hold the provider to the published contract
$ bowire contract verify fixtures/api.bwr \
              --base-url http://localhost:5099

bowire scan — SAST gate with native SARIF

Built-in passive checks plus the 8000+ Nuclei community templates via --nuclei, fed through the same engine. Findings emit as SARIF 2.1.0 — GitHub Code Scanning, GitLab Security Dashboard, or Azure DevOps ingest it natively. Gating happens via Code-Scanning branch-protection rules.

Security solution overview →

bash
# Built-in + Nuclei templates, one SARIF report
$ bowire scan --target http://localhost:5099 \
              --nuclei ~/nuclei-templates \
              --out findings.sarif --severity medium

bowire fuzz — security-regression step

Schema-aware field-level mutation. Knows not to throw SQL-injection at a latitude (lat) field; image.bytes gets magic-byte mutation, not XSS strings. Baseline-diff oracle flags responses that look materially different from clean runs. Same SARIF surface as scan.

bash
# Targeted mutation, baseline-diff oracle, SARIF out
$ bowire fuzz --target http://localhost:5099 \
              --template fixtures/api.bwr \
              --payloads sqli,xss --out fuzz.sarif

How you integrate it

All four Bowire steps in one job. Same shape on GitLab CI and Azure DevOps — dotnet tool install + invoke the binary.

flowchart LR
    Install(["Install bowire"])
    BWR[("fixtures/api.bwr")]
    Mock(["bowire mock"])
    Tests(["Integration tests"])
    Btest(["bowire test"])
    Scan(["bowire scan"])
    Fuzz(["bowire fuzz"])
    SARIF[("SARIF reports")]
    CS(["GitHub Code Scanning"])

    Install --> Mock
    BWR -->|"--recording"| Mock
    Mock -->|"localhost:5099"| Tests
    Mock -->|"--base-url"| Btest
    Mock -->|"--target"| Scan
    Mock -->|"--target"| Fuzz
    Btest -->|"--sarif test.sarif"| SARIF
    Scan -->|"--out findings.sarif"| SARIF
    Fuzz -->|"--out fuzz.sarif"| SARIF
    SARIF -->|"upload-sarif"| CS
        
One bowire mock instance becomes the shared fixture for integration tests, bowire test, bowire scan, and bowire fuzz in the same job. SARIF outputs flow straight into Code Scanning — alerts land in the calling repo’s Security tab without an intermediate format conversion.
yaml .github/workflows/api-check.yml
name: API check
on: [push, pull_request]

jobs:
  api-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Bowire
        run: dotnet tool install -g Kuestenlogik.Bowire.Tool

      # 1. Mock server for integration tests
      - name: Start mock server
        run: bowire mock --recording fixtures/api.bwr --port 5099 &

      - name: Run integration tests
        run: dotnet test --filter Category=Integration

      # 2. Regression gate + contract verify against the mock
      - name: Regression test
        run: |
          bowire test fixtures/api.bwr --base-url http://localhost:5099 \
                      --junit test-results.xml --sarif test.sarif \
                      --annotations --fail-on error
          bowire contract verify fixtures/api.bwr \
                      --base-url http://localhost:5099

      # 3. Security scan against the mock
      - name: Security scan
        run: |
          bowire scan --target http://localhost:5099 \
                      --nuclei ~/nuclei-templates \
                      --out findings.sarif --severity medium

      # 4. Field-level fuzz for regression
      - name: Field-level fuzz
        run: |
          bowire fuzz --target http://localhost:5099 \
                      --template fixtures/api.bwr \
                      --payloads sqli,xss --out fuzz.sarif

      # 5. SARIF goes to GitHub Code Scanning
      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: findings.sarif

A reusable GitHub Action wraps the scan + SARIF-upload pair behind one uses: line for downstream repos — same pattern, less boilerplate.

scan-template.yml on GitHub →

Wire it in

Pull the binary, drop the three steps into your workflow, let SARIF light up your Security tab.