Skip to content

test(handler): add FuzzHandle for the empty-payload invariant#30

Merged
jmgilman merged 1 commit intomasterfrom
test/fuzz-handle
Apr 24, 2026
Merged

test(handler): add FuzzHandle for the empty-payload invariant#30
jmgilman merged 1 commit intomasterfrom
test/fuzz-handle

Conversation

@jmgilman
Copy link
Copy Markdown
Contributor

Summary

Adds a native Go fuzz target (FuzzHandle) against the Lambda handler's sole caller-controlled entry point. The handler's documented contract — "accepts empty or null payloads only; anything else is rejected so callers cannot influence token scope" — is a security invariant. This fuzz target asserts that contract across adversarial byte sequences the unit tests don't cover.

The oracle is derived directly from the documented rule: accept iff bytes.TrimSpace(payload) is empty or literally \"null\". Mismatches between oracle and implementation, panics on weird bytes, or future refactors that break control flow would all surface as a fuzz failure.

Changes

  • internal/handler/handler_fuzz_test.go (new, 61 lines).
    • 15 hand-picked seeds: six from TestHandleAcceptsOnlyEmptyPayloads + boundary cases (case variations of null, short/long near-misses, trailing NUL byte, surrounding whitespace, UTF-8 BOM, plausible JSON object).
    • Reuses the existing fakeBroker fixture from handler_test.go — no new helpers.
    • Logger drains to io.Discard so fuzz iterations stay quiet.

No CI changes. Moon's existing test task (moon.yml:36-41) runs go test ./cmd/... ./internal/..., which replays the seed corpus as regular subtests. That's enough for OpenSSF Scorecard's Fuzzing detector (alert #6) to pass on the next scan.

Verification

  • moon run :test — green across all packages; FuzzHandle's 15 seeds all pass as subtests.
  • go test -run=^$ -fuzz=FuzzHandle -fuzztime=30s ./internal/handler/ — 13,773,192 executions across 16 workers in 30s, 0 failures, no testdata/fuzz/ corpus written.
  • gofmt -l internal/handler/handler_fuzz_test.go — clean.

Out of scope

  • Scheduled fuzzing workflow. A follow-up PR could add a weekly fuzztime=5m job with crash-corpus artifact upload. Deferred intentionally — the seed-replay integration is enough for the Scorecard check and for catching regressions on known-adversarial inputs.
  • Fuzzing validateEmptyPayload directly. The private validator is an implementation detail; fuzzing the public Handle boundary catches control-flow regressions too.

Test plan

🤖 Generated with Claude Code

The handler's only caller-controlled input is the Lambda payload, and
its documented contract is "accepts empty or null only — anything else
is rejected so callers cannot influence token scope." Adds a native
Go fuzz target that asserts this contract across adversarial bytes.

Seeds include the six cases from TestHandleAcceptsOnlyEmptyPayloads
plus boundary inputs (case variations, length edges, trailing NUL,
surrounding whitespace, UTF-8 BOM). The oracle is derived directly
from the contract: accept iff the trimmed payload is empty or
literally "null".

Runs as part of `moon :test` (seed corpus replays as regular
subtests). A 30s live fuzz run locally produced 0 findings over
13.7M executions / 16 workers. No CI changes.

Clears OpenSSF Scorecard code-scanning alert #6 (FuzzingID, 0/10)
on the next Scorecard scan — the check passes when a `Fuzz*`
function exists in a Go `_test.go` file.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
github-token-broker 48b6c14 Commit Preview URL

Branch Preview URL
Apr 24 2026, 01:33 AM

@jmgilman jmgilman merged commit fdad7f4 into master Apr 24, 2026
7 checks passed
@jmgilman jmgilman deleted the test/fuzz-handle branch April 24, 2026 01:38
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.

1 participant