Skip to content

✅ CI: Verify — PR #68 #265

✅ CI: Verify — PR #68

✅ CI: Verify — PR #68 #265

Workflow file for this run

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