chore(test): cover real backends, patch dependencies, document security - #18
Merged
Merged
Conversation
ekalinin
force-pushed
the
chore/deps-and-docs
branch
from
August 17, 2026 19:26
0924278 to
e30b7c6
Compare
ekalinin
force-pushed
the
chore/deploy-hardening
branch
from
August 17, 2026 19:26
36712d3 to
ef48efb
Compare
ekalinin
force-pushed
the
chore/deps-and-docs
branch
from
August 17, 2026 19:35
e30b7c6 to
772c3f3
Compare
Every test ran on the in-memory MetaStore, the local filesystem and fake drivers, so the paths that only exist for the real backends had no coverage at all: Lua scripts and WATCH transactions in Redis, lease key expiry, pgx and MySQL type mapping, the S3 multipart uploader and the Close-waits-for-upload contract behind I4. test/integration runs those against Redis, PostgreSQL, MySQL and MinIO under testcontainers, behind the `integration` build tag and a separate CI job so a Docker problem is never mistaken for a code failure. It covers a full round trip per backend, multi-node idempotency, a subscription and a stop crossing instances, owner-loss reaping, the GC lock, and a heartbeat storm that must not clobber a terminal write. govulncheck reported two reachable advisories: GO-2026-6061 in grpc and GO-2026-5970 in x/text. Both are patched, and the check now runs in `make ci` and in the CI workflow. That check also raises the floor on the toolchain, because most of what it finds is in the standard library rather than in a dependency: go.mod asks for 1.26.6, which is the first release without any of the advisories reachable from this code. CI installs exactly what go.mod declares, so leaving it at 1.26.0 meant shipping a binary built against a stdlib with two dozen known issues in net/http, crypto/tls, crypto/x509 and html/template. spec.md gains the security section it never had - authentication, authorization and subject binding, the statement policy, TLS and trusted proxies, request and concurrency limits, listener isolation and error sanitization - which was a gap in the specification rather than a divergence from it. It also states what a reload cannot apply, and records that leases live outside the query record and that query events travel the control channel.
ekalinin
force-pushed
the
chore/deploy-hardening
branch
from
August 18, 2026 09:47
ef48efb to
359f8a9
Compare
ekalinin
force-pushed
the
chore/deps-and-docs
branch
from
August 18, 2026 09:47
772c3f3 to
55d41b2
Compare
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Integration tests
The whole suite ran on the in-memory MetaStore, the local filesystem and fake drivers, so the paths that exist only for the real backends were exercised nowhere outside miniredis and unit-level fakes: Lua scripts and
WATCHtransactions in Redis, lease key expiry, pgx and MySQL type mapping, the S3 multipart uploader, and the Close-waits-for-upload contract that I4 rests on.internal/state/redis_test.gocovers the Redis semantics against miniredis; the gap this closes is a run against the real thing.test/integrationbrings up Redis, PostgreSQL, MySQL and MinIO through testcontainers. It sits behind theintegrationbuild tag, somake testandmake cido not touch it, and runs as its own CI job so a Docker or image-pull problem is never mistaken for a code failure.make vetstill compiles and vets it with the tag set, because a package whose files are all cut out by a tag is skipped by./...without a word.Covered: a full round trip per backend (PostgreSQL, MySQL, S3), multi-node idempotency, reading a result from the instance that did not run it, watch and stop crossing instances, reaping by expired lease, the cluster lock behind GC, a heartbeat running concurrently with a terminal write, and the statement guard against a real database (after a rejected
DELETEthe rows are still there).Three of these tests did not check what their names said, and were rewritten:
TestRedis_HeartbeatKeepsTerminalWriteswas three sequential steps, so the interleaving the lost-update bug needs could not occur; it passed on the buggy implementation. It now runs the heartbeat in its own goroutine across the terminal write, 50 rounds, under-race, and fails on the pre-fixHeartbeatat round 2.TestS3_ResultRoundTripuploaded ~60 bytes, and the AWS uploader sends a non-seekable body below its 5 MiB part size as a plainPutObject, so multipart never ran. It now also materializes ~8 MB and checks the object against what was written.TestRedis_GCRunsOncenever ran GC - it calledTryLocktwice on one store. Renamed toTestRedis_TryLockIsExclusive, extended with a second store and with lock expiry, and the comment no longer claims otherwise.Dependencies
govulncheckreported two reachable advisories: GO-2026-6061 ingrpc(fixed in v1.82.1, symbols reachable through OTLP) and GO-2026-5970 inx/text. Onlygrpcis bumped here -x/text v0.40.0already arrived in the base branch - andgo.sumloses the orphaned lines. The check is wired intomake ciand the CI workflow, pinned to a version rather than@latest, so a release of the tool cannot fail CI on its own.That check also raises the floor on the toolchain, because most of what it finds lives in the standard library rather than in a dependency. CI installs exactly what
go.moddeclares, andgo 1.26.0carries two dozen advisories reachable from this code innet/http,crypto/tls,crypto/x509,html/template,net/urlandencoding/xml.go.modnow asks for 1.26.6, the first release clear of all of them. Expect this step to fail again when a new stdlib advisory lands - that is what it is for, and the fix is another patch bump.Specification
spec.mdsaid nothing about authentication, authorization, TLS, request limits or result ownership - that was a gap in the specification itself rather than a divergence from it. It gains a Security section: authentication and scopes, subject binding, the statement policy, TLS and trusted proxies, request and concurrency limits, listener isolation and error sanitization.Credentials are documented as configured rather than mandatory, which is what the code does: with no
authsection the API is open and says so at startup. It also records what a reload cannot apply (includingauth, so revoking a token takes a restart), that leases live outside the query record, and that query events travel the control channel.Verification
make ciin full (fmt, vet, test, race, lint, buf lint, govulncheck) - green.make test-containersagainst Docker - all 8 tests green under-race. The rewritten heartbeat test was also run against the pre-fixHeartbeatimplementation and fails there, which is the point of it.