Repository navigation
✅ CI: Verify — PR #68 #265
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "✅ CI: Verify" | |
| run-name: >- | |
| ${{ | |
| github.event_name == 'schedule' && '✅ CI: Verify — Weekly schedule' || | |
| github.event_name == 'pull_request' && format('✅ CI: Verify — PR #{0}', github.event.pull_request.number) || | |
| format('✅ CI: Verify — {0}', github.ref_name) | |
| }} | |
| on: | |
| push: | |
| branches: [main, 'release/*'] | |
| pull_request: | |
| branches: [main] | |
| merge_group: | |
| schedule: | |
| - cron: '30 6 * * 1' # Weekly on Monday at 06:30 UTC | |
| concurrency: | |
| group: ci-verify-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| env: | |
| GORELEASER_VERSION: v2.15.3 | |
| jobs: | |
| zizmor: | |
| name: "🔒 Workflow Security" | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: read | |
| actions: read # required by zizmor-action telemetry | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Run zizmor | |
| uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 | |
| with: | |
| token: ${{ github.token }} | |
| # impostor-commit audit requires API access that harden-runner blocks | |
| # in the zizmor container. Skip online audits to keep the scan offline. | |
| online-audits: false | |
| # SARIF upload to code scanning requires GHAS, not available on free | |
| # private repos. Re-enable when sockguard goes public. | |
| advanced-security: false | |
| codeql: | |
| name: "🔍 CodeQL Analysis" | |
| # CodeQL SARIF upload requires GitHub Advanced Security (GHAS), which is not | |
| # available on free private repos. Skip unless the repo is public. | |
| if: github.event.repository.visibility == 'public' && (github.event_name == 'pull_request' || github.event_name == 'schedule' || (github.event_name == 'push' && github.ref == 'refs/heads/main')) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| permissions: | |
| actions: read | |
| contents: read | |
| security-events: write | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Initialize CodeQL | |
| uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 | |
| with: | |
| languages: go, javascript-typescript | |
| queries: security-and-quality | |
| - name: Setup Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version-file: app/go.mod | |
| cache-dependency-path: app/go.sum | |
| - name: Build Go | |
| run: go build ./... | |
| working-directory: app | |
| - name: Perform CodeQL Analysis | |
| uses: github/codeql-action/analyze@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 | |
| dependency-review: | |
| name: "📦 Dependency Review" | |
| # Dependency Review requires GitHub Advanced Security on private repos. | |
| # Gated on public visibility so it auto-activates when the repo goes public. | |
| # Disabled until the repository Dependency Graph setting is enabled. | |
| if: ${{ false && github.event.repository.visibility == 'public' && github.event_name == 'pull_request' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Dependency Review | |
| uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 | |
| commit-message: | |
| name: "💬 Commit Message" | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| continue-on-error: true # advisory — does not block merge | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 0 | |
| - name: Validate commit messages | |
| run: | | |
| set -euo pipefail | |
| pattern='^[\xF0-\xF4].*|^[\xE2-\xEF].*' | |
| failed=0 | |
| while IFS= read -r msg; do | |
| first_line="$(echo "${msg}" | head -n1)" | |
| if ! echo "${first_line}" | grep -qP '^(\p{So}|\p{Emoji_Presentation})+\s+\w+(\(\w[\w-]*\))?!?:\s.+$'; then | |
| echo "::warning::Non-conventional commit: ${first_line}" | |
| failed=1 | |
| fi | |
| done < <(git log --format=%s origin/main..HEAD) | |
| if [ "${failed}" -eq 1 ]; then | |
| echo "::warning::Some commits don't follow emoji conventional format. Expected: <emoji> <type>(scope): description" | |
| fi | |
| goreleaser-check: | |
| name: "📦 GoReleaser Config" | |
| if: github.event_name != 'schedule' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version-file: app/go.mod | |
| cache-dependency-path: app/go.sum | |
| - name: Run GoReleaser check | |
| uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2 | |
| with: | |
| distribution: goreleaser | |
| version: ${{ env.GORELEASER_VERSION }} | |
| args: check | |
| workdir: app | |
| go-lint: | |
| name: "🧹 Go Lint" | |
| if: github.event_name != 'schedule' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version-file: app/go.mod | |
| cache-dependency-path: app/go.sum | |
| - name: Check gofmt | |
| working-directory: app | |
| run: | | |
| unformatted="$(gofmt -l .)" | |
| if [ -n "${unformatted}" ]; then | |
| echo "::error::gofmt found unformatted files — run 'gofmt -w .' in app/ and commit:" | |
| echo "${unformatted}" | |
| exit 1 | |
| fi | |
| - name: Run golangci-lint | |
| uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 | |
| with: | |
| working-directory: app | |
| go-test: | |
| name: "🧪 Go Test" | |
| if: github.event_name != 'schedule' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version-file: app/go.mod | |
| cache-dependency-path: app/go.sum | |
| - name: Run tests | |
| run: | | |
| go list ./... | grep -v '/internal/testcert$' | xargs go test -race -coverprofile=coverage.txt -covermode=atomic | |
| working-directory: app | |
| - name: Upload coverage | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: go-coverage | |
| path: app/coverage.txt | |
| retention-days: 14 | |
| go-fuzz: | |
| # Tier 1 — per-PR smoke-level fuzzing. Each fuzzer gets a fixed 60 s | |
| # coverage budget in its own matrix job so the whole matrix runs in | |
| # parallel and the critical path stays at ~1–2 min wall time regardless | |
| # of how many fuzzers we ship. The deep-coverage tier lives in | |
| # .github/workflows/quality-fuzz-nightly.yml where each fuzzer gets 15 | |
| # minutes by default (configurable via workflow_dispatch input). | |
| # | |
| # `fail-fast: false` lets every fuzzer complete even if a sibling finds | |
| # a crash, so one failure surfaces alongside the other fuzzers' state | |
| # instead of aborting the run early. The Go test timeout stays above | |
| # the fuzz budget so a hung input produces a stack dump instead of | |
| # tying up the runner until the job-level ceiling fires. | |
| name: "🔀 Go Fuzz (${{ matrix.fuzzer.name }})" | |
| if: github.event_name == 'pull_request' || github.event_name == 'schedule' || (github.event_name == 'push' && github.ref == 'refs/heads/main') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| fuzzer: | |
| - { name: FuzzPathMatch, pkg: ./internal/filter/ } | |
| - { name: FuzzGlobToRegex, pkg: ./internal/filter/ } | |
| - { name: FuzzGlobToRegexString, pkg: ./internal/filter/ } | |
| - { name: FuzzNormalizePath, pkg: ./internal/filter/ } | |
| - { name: FuzzCompileRule, pkg: ./internal/filter/ } | |
| - { name: FuzzBuild, pkg: ./internal/filter/ } | |
| - { name: FuzzContainerCreate, pkg: ./internal/filter/ } | |
| - { name: FuzzExec, pkg: ./internal/filter/ } | |
| - { name: FuzzImagePull, pkg: ./internal/filter/ } | |
| - { name: FuzzVolume, pkg: ./internal/filter/ } | |
| - { name: FuzzSecret, pkg: ./internal/filter/ } | |
| - { name: FuzzConfigWrite, pkg: ./internal/filter/ } | |
| - { name: FuzzService, pkg: ./internal/filter/ } | |
| - { name: FuzzSwarm, pkg: ./internal/filter/ } | |
| - { name: FuzzPlugin, pkg: ./internal/filter/ } | |
| - { name: FuzzNetwork, pkg: ./internal/filter/ } | |
| - { name: FuzzProxyHeadersAndBody, pkg: ./internal/proxy/ } | |
| - { name: FuzzHijackHeadersAndBody, pkg: ./internal/proxy/ } | |
| - { name: FuzzPathRoutingDifferential, pkg: ./differential/ } | |
| - { name: FuzzVisibilityFilter, pkg: ./internal/visibility/ } | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Go | |
| uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 | |
| with: | |
| go-version-file: app/go.mod | |
| cache-dependency-path: app/go.sum | |
| - name: Fuzz ${{ matrix.fuzzer.name }} | |
| working-directory: app | |
| env: | |
| FUZZTIME: 60s | |
| TEST_TIMEOUT: 5m | |
| run: | | |
| go test -run=^$ \ | |
| -fuzz=^${{ matrix.fuzzer.name }}$ \ | |
| -fuzztime="${FUZZTIME}" \ | |
| -timeout="${TEST_TIMEOUT}" \ | |
| ${{ matrix.fuzzer.pkg }} | |
| - name: Upload fuzz corpus on failure | |
| if: failure() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: fuzz-corpus-${{ matrix.fuzzer.name }}-${{ github.run_id }} | |
| path: app/**/testdata/fuzz/${{ matrix.fuzzer.name }}/ | |
| retention-days: 30 | |
| if-no-files-found: ignore | |
| ts-lint: | |
| name: "🎨 Biome Lint" | |
| if: github.event_name != 'schedule' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Node | |
| uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run Biome | |
| run: npx biome check . | |
| ts-test: | |
| name: "🧪 TS Test" | |
| if: github.event_name != 'schedule' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Node | |
| uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run tests | |
| run: npm test | |
| ts-build: | |
| name: "🏗️ Build Workspaces" | |
| if: github.event_name != 'schedule' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Setup Node | |
| uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build all workspaces | |
| run: npx turbo build | |
| docker: | |
| name: "🐳 Docker Build" | |
| if: github.event_name != 'schedule' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@ab7a9404c0f3da075243ca237b5fac12c98deaa5 # v2.19.3 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 | |
| # Single-arch build to verify Dockerfile builds correctly. | |
| # Multi-arch (amd64 + arm64) is handled by the release workflow. | |
| - name: Build (single-arch) | |
| uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 | |
| with: | |
| context: . | |
| push: false | |
| load: true | |
| tags: sockguard:ci | |
| build-args: VERSION=ci | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max |