Skip to content

🧪 test(ci): three-tier fuzz + soak + benchmarks (sockguard parity) and doc cleanup#19

Merged
scttbnsn merged 6 commits into
mainfrom
quality/test-posture-parity
Jun 16, 2026
Merged

🧪 test(ci): three-tier fuzz + soak + benchmarks (sockguard parity) and doc cleanup#19
scttbnsn merged 6 commits into
mainfrom
quality/test-posture-parity

Conversation

@scttbnsn

Copy link
Copy Markdown
Contributor

What

Brings Portwing's CI test posture to parity with sockguard's, and clears the version drift that accumulated across the docs after the v0.3.0 rename.

The testing arc is now three tiers of fuzz + soak + benchmarks, matching sockguard:

  • Tier-3 monthly deep fuzz (quality-fuzz-monthly.yml) — completes the smoke (per-PR) → nightly → monthly tiering. Each of the five fuzz targets gets a 1h budget on the first of the month, dispatchable to longer budgets before a release. Retries the known -fuzztime boundary flake once; crash corpora retain 180 days.
  • Weekly soak (quality-soak-weekly.yml + harness) — stands up loadgen → portwing (generic adapter) → mockdocker and drives a sustained mix (cached-inventory/version/proxy reads plus SSE subscriber connect/hold/disconnect churn, the leak-prone path), then fails if RSS grows past a budget (64 MiB default) over a multi-hour soak. New benchmarks/cmd/{mockdocker,loadgen} driven by scripts/soak.sh (has --dry-run).
  • Monthly benchmarks (quality-bench-monthly.yml + 12 benchmark funcs) — covers the per-request hot paths (auth middleware, Argon2id verify cold-vs-warm-cache, client-IP extraction, rate limiter) and the parse paths (PHC, image-ref, Drydock labels, trusted-proxy CIDRs, MCP dispatch). Reruns with -benchmem -count=5, keeps a 90-day artifact so a ns/op or allocs/op regression is visible month over month.

Plus doc cleanup: v0.2.x → v0.3.x references, dropped the dead 0.2.0 edge-mode mentions and the Snyk placeholder badge, and bumped the CONTRIBUTING dev-branch example.

Verification

  • gofmt clean, go vet clean, go build ./... + full go test ./... pass (no regressions).
  • All 12 benchmarks run and report sane numbers — Argon2 cold ~18ms vs warm-cache ~270ns is exactly the signal intended; ParseLabels and agentToken are 0-alloc.
  • Soak ran end-to-end twice locally (15s + 25s): portwing booted against the mock, 0 errors across 1.3M+ requests, SSE churned 100 connect/disconnect cycles, RSS grew ~6 MB — well under the 64 MB budget → PASS.
  • actionlint + zizmor clean on all three new workflows.

Notes

Schedules are slotted to avoid collisions: mutation 06:30, bench 07:45, deep fuzz 08:30 (UTC, day 1). The 24h soak target lands once a self-hosted runner is wired up; github-hosted runs soak 4h under the 6h job ceiling.

scttbnsn added 5 commits June 16, 2026 13:17
- 📝 docs: bump v0.2.x → v0.3.x references and current-release line
- 🗑️ remove: dead 0.2.0 edge-mode references and Snyk placeholder badge
- 🔧 config: CONTRIBUTING dev-branch example dev/0.2.0 → dev/0.4.0
Completes the smoke → nightly → monthly fuzz tiering. Gives each of the
five fuzz targets a 1h budget on the first of the month (dispatchable to
longer budgets before a release), retries the known -fuzztime boundary
flake once, and retains crash corpora for 180 days. Mirrors sockguard's
monthly tier.
Stands up loadgen → portwing (generic adapter) → mockdocker and drives a
sustained mixed load — cached-inventory/version/proxy reads plus SSE
subscriber connect/hold/disconnect churn (the leak-prone path) — then
fails if the agent's resident set grows past a budget (64 MiB default)
over a multi-hour soak. Catches the long-lived-agent leak profile the
unit/integration/fuzz tiers don't.

- ✨ feat(bench): mockdocker fake Docker daemon over a unix socket
- ✨ feat(bench): loadgen HTTP generator with bearer auth + SSE-churn mode
- 🧪 test: scripts/soak.sh orchestrator (build, warmup, RSS baseline, assert)
- 🧪 test(ci): quality-soak-weekly.yml (Sundays + dispatch, 4h / 64 MiB)
Go benchmarks on the per-request hot paths (auth middleware, Argon2id
verify — cold derivation vs. warm SHA-256 cache, client-IP extraction,
rate limiter) and the parse paths (PHC, image-ref, Drydock labels,
trusted-proxy CIDRs, MCP dispatch). quality-bench-monthly.yml reruns them
with -benchmem -count=5 on the first of each month and keeps a 90-day
artifact, so a ns/op or allocs/op regression shows up month over month.
Completes the test-posture parity with sockguard.
- 📝 docs(changelog): [Unreleased] entries for tier-3 fuzz, weekly soak,
  and monthly benchmark tracking
- 📝 docs(roadmap): mark three-tier fuzzing, soak, and benchmark tracking
  shipped under the sockguard test-posture parity item
CI lint gate flagged the soak mock:
- 🔧 config(gosec): tighten socket perms 0o666 → 0o600 (G302); same-user soak
- 🐛 fix(errcheck): check the fmt.Fprint error on the event stream
- 🔧 config(gosec): justified #nosec G706 on the opt-in %q-quoted debug log

@biggest-littlest biggest-littlest left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI's green across the board — build, integration against real dockerd, all five fuzz smokes, govulncheck, CodeQL, lint. The three new workflows validate clean and the soak ran end-to-end with zero leak. Benchmarks are a sensible baseline. Good to merge.

@ALARGECOMPANY ALARGECOMPANY left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second pass — agree with the above. All required checks pass, workflows lint clean (actionlint + zizmor), and the changes are test/CI-only plus docs, no runtime code touched. LGTM.

@scttbnsn scttbnsn merged commit 542b32f into main Jun 16, 2026
16 checks passed
@scttbnsn scttbnsn deleted the quality/test-posture-parity branch June 16, 2026 17:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants