Skip to content

Patch dependency advisories, consolidate the test suite into go test - #3

Merged
ptinsley merged 5 commits into
mainfrom
deps-and-test-consolidation
Aug 5, 2026
Merged

ptinsley merged 5 commits into
mainfrom
deps-and-test-consolidation

Conversation

@ptinsley

@ptinsley ptinsley commented Aug 5, 2026 •

Copy link
Copy Markdown
Owner

Why

A push to main tripped Dependabot alerts. Fixing them surfaced an adjacent problem: the project carried two go.mod files, so the Pub/Sub test suite kept its own copy of the same transitive dependency tree and every advisory arrived twice. Merging the two test suites into one removes the duplicate module along with it.

Security

Three advisories, all indirect, all cleared:

Package Before After Severity
google.golang.org/grpc 1.79.1 1.83.0 high — xDS RBAC + HTTP/2
golang.org/x/crypto 0.48.0 0.54.0 critical — SSH auth bypass, unenforced agent/key constraints, several DoS paths
golang.org/x/net 0.50.0 0.57.0 medium — HTML parser DoS

otel, x/oauth2, x/sync, x/sys, x/text and genproto came along transitively.

govulncheck separately flagged 11 stdlib advisories reachable from main.go, including a crypto/tls ECH privacy leak and an HTTP/2 infinite loop. Those are toolchain, not dependency — fixed by moving the local Go from 1.26.2 to 1.26.5. The go directive in go.mod is untouched at 1.25.0, since raising it forces a minimum toolchain on everyone building this. Worth deciding separately.

govulncheck now reports 0 reachable vulnerabilities. One module-level advisory remains in x/crypto@v0.54.0 with no published fix; it is not called from this code.

One test pipeline

test/run_test.sh and the test/verify module are replaced by integration_test.go. go test ./... is now the whole pipeline: 33 unit tests plus 10 emulator scenarios, ~12s.

The emulator is not optional and never skips. Pub/Sub is the point of the tool, so a green run that silently tested nothing would be a liability. A missing gcloud, emulator component or JRE fails the test naming the command that fixes it. There is also an explicit check that java actually runs — macOS ships a /usr/bin/java shim that resolves fine with no JDK installed, so LookPath alone reports success and you then fail deep inside emulator startup.

test/verify bought nothing. It was split out to depend on the pubsub client directly, but the root module already does. It added zero dependencies and one extra copy of the transitive tree — which is why every advisory above arrived twice. One go.mod again.

Every wait is bounded, and each bound is an assertion. This replaces ~23s of fixed sleep. Message collection returns the moment each scenario has its full complement, then drains 2s more so a source publishing too many still trips its exact-count check. On expiry the failure names the scenario, got vs want per generator, and fling's captured output. Readiness comes from signals the process actually emits: "Adding tail for file" per path, and fling's own Pub/Sub init message for the publish path.

The before/after-startup split is preserved deliberately. All fixtures are written before fling.Start(); every append happens after. That is what the read_from_beginning and tail-mode scenarios exist to test — scenario 1's ForbiddenLines is what proves a tail-mode source really skipped pre-existing content. It is now stated in the code rather than implied by shell ordering.

One fixed wait survives, documented at its use: "Adding tail for file" is logged when the worker goroutine spawns, but a tail-mode source does not seek to end until inside that goroutine, so the log is a lower bound rather than proof. Removing it properly needs fling to signal post-seek readiness.

Same 10 scenarios, same 27 messages across 11 generators, ~12s instead of ~45s.

Test for the unknown-output guard

6c9a6d4 added a guard so a file naming an undefined output logs an error instead of crashing. This pins it.

The case that matters puts the bad name first in the output list: a guard that returned instead of continuing would silently cost that file its working outputs too, and no single-output test would catch it. Also covers delivery to a valid output, a key holding something that is not a channel, and an empty list.

Verified by reverting the guard, where the suite panics with the original interface conversion: interface {} is nil, not chan main.FlingEvent.

Tracked binary removed

A 24MB arm64 executable was checked in at the repo root. It went stale on every change and showed up dirty after any local build. Untracked in one commit, ignored in the next.

Note the blob remains in history — every clone still pays for it. Purging needs git filter-repo and a force-push that rewrites every hash, so it is left alone here.

Running it locally

The emulator needs a JRE. Homebrew's openjdk is keg-only, so installing it is not enough — it has to be on PATH:

brew install openjdk@21
export PATH="/opt/homebrew/opt/openjdk@21/bin:$PATH"
gcloud components install pubsub-emulator

Not addressed

  • main.go is not gofmt-clean, and already was not before this branch — an unsorted import plus the //Comment → // Comment rule, which would rewrite most of its doc comments. Deserves its own commit.
  • cloud.google.com/go/pubsub v1.50.1 is deprecated upstream in favour of pubsub/v2, already present as an indirect dep at v2.0.0. That is an API migration, not a security fix.

🤖 Generated with Claude Code

ptinsley and others added 5 commits August 5, 2026 13:13
Clears the Dependabot alerts raised on push:

  google.golang.org/grpc  1.79.1 -> 1.83.0  (high, needs >=1.82.1)
    xDS RBAC and HTTP/2 vulnerabilities
  golang.org/x/crypto     0.48.0 -> 0.54.0  (critical, needs >=0.52.0)
    SSH auth bypass, unenforced agent/key constraints, several DoS paths
  golang.org/x/net        0.50.0 -> 0.57.0  (medium, needs >=0.55.0)
    HTML parser denial of service

otel, x/oauth2, x/sync, x/sys, x/text and genproto came along
transitively. govulncheck reports no reachable vulnerabilities.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replaces test/run_test.sh and the test/verify module with
integration_test.go, so `go test ./...` is the whole pipeline. The
emulator scenarios are not optional and never skip: Pub/Sub is the point
of the tool, so a missing gcloud, emulator component or JRE fails the
test naming the command that fixes it.

test/verify existed to depend on the pubsub client directly, but the
root module already does, so it added no dependencies -- only a second
copy of the transitive tree, which is why every advisory arrived twice.
One go.mod again.

Every wait is bounded and each bound is an assertion, replacing ~23s of
fixed sleeps. Message collection returns as soon as each scenario has its
full complement, then drains 2s more so a source publishing too many
still trips its exact-count check. On expiry the failure names the
scenario, got vs want, and fling's captured output.

Fixture setup stays before startup and appends stay after: that split is
what the read_from_beginning and tail-mode scenarios exist to test, so it
is now stated in the code rather than implied by shell ordering.

One fixed wait remains. "Adding tail for file" is logged when the worker
goroutine spawns, but a tail-mode source does not seek to end until
inside it, so the log is a lower bound rather than proof.

Same 10 scenarios, 27 messages, ~12s instead of ~45s.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A 24MB arm64 executable was checked in at the repo root. It goes stale the
moment anything changes, shows up dirty after any local build, and is
useless to anyone on a different platform. Build it with `go build .`.

Left untracked rather than ignored so the removal lands on its own.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A file naming an output that no output block defines - a config typo is
enough - used to take the process down on its first event, because the
map value was asserted straight to a channel. 6c9a6d4 added the guard;
this pins the behaviour.

Covers delivery to a valid output, an undefined output being dropped with
the offending name reported, a key holding something that is not a
channel, and an empty output list. The case that matters most puts the
bad name FIRST in the list: a guard that returned instead of continuing
would silently cost that file its working outputs too, which no
single-output test would catch.

Verified by reverting the guard, where the suite panics with the original
"interface conversion: interface {} is nil, not chan main.FlingEvent".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Follow-up to 5205d7f, which untracked it. Anchored to the repo root so it
only covers the build output, not a directory or source file named fling
elsewhere in the tree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ptinsley
ptinsley merged commit f9319e9 into main Aug 5, 2026
@ptinsley
ptinsley deleted the deps-and-test-consolidation branch August 5, 2026 18:44
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

⌂ 换网址