v1.4.0
The operational round: the tools an operator reaches for, and the evidence that what they are
running is what was built.
Added
-
outbox stats,outbox failedandoutbox requeue— the admin API's operations as
subcommands, over the database connection instead of over HTTP. The HTTP route needs a reachable
pod, a token and a JSON body; what is to hand during an incident is a shell in the container the
binary already lives in. Both paths run the same store calls, so neither can drift into being the
one that does it correctly.Authorisation differs on purpose. The endpoints are guarded by
OUTBOX_HTTP_ADMIN_TOKENbecause
anything that can route to the pod can call them; the commands are guarded by holding the database
credentials, which is a stronger thing to have.outbox failed -stream local,outbox requeue <id>...,outbox requeue -before <RFC3339>, and
-jsonon any of them for a pipe intojq. -
govulncheckon every CI run, andmake vulnso it is the same command locally. It reports
only the vulnerabilities the code actually reaches, so a finding is something to act on rather
than a line in an advisory feed. It runs as its own job: a vulnerable dependency is a fact about
the module, not a failing test, and should not be discovered by whoever happens to be reading a
red test run. -
A CycloneDX SBOM per platform, attached to every release. Generated from the compiled binaries
rather than from the source tree, so each one lists what was actually linked into the artefact it
describes.make dist SBOM=1writes them beside the archives, andmake sbomwrites one for a
local build; the default stays off so a developer'smake distneeds no extra tool. -
Keyless cosign signatures on the release and the image.
SHA256SUMS.cosign.bundlecovers
every archive and every SBOM through the checksum file, and the image is signed by digest — a tag
is a name that can be moved, so a signature against one says nothing about what anybody pulls.
There is no key to distribute or to lose: cosign gets a short-lived certificate against the
workflow's OIDC identity, and what a verifier establishes is that this repository, on this
workflow, produced the artefact. Verification commands are in
docs/UseCases.md.Tool versions are pinned, and cosign's own download is checked against a recorded hash. Fetching a
signing tool over the network without checking what came back would be an odd way to start
signing things. -
A Grafana dashboard,
dashboards/outbox.json. Alert rules shipped
without one, so every adopter built the same panels from the same metric reference. Thirteen
panels in four rows, with astreamvariable for narrowing to one broker when only one of them is
the problem.It is checked against the code rather than against a screenshot: a test walks every query in the
file and fails if it names a metric the dispatcher does not register, or filters on a label that
metric does not carry. Both render an empty panel, which reads as "nothing is happening" and is
indistinguishable from good news until somebody needs it. -
?stream=onGET /api/v1/messages/failed, so working through one broker's backlog does not
mean paging through everybody else's. The CLI needed the filter first; adding it to the endpoint
too is what keeps parity a fact rather than a claim.
Changed
- Administrative commands check only the configuration they use.
migrate,stats,failed
andrequeueneed a database and nothing else, and previously refused to run on a broken routing
table. The moment an operator most needs to see what stopped is often the moment the routing table
is what is wrong, and a tool that answers "your broker is misconfigured" to the question "what
failed?" is useless precisely then. The dispatcher itself is unchanged: it still refuses to start
without a routing table, because it cannot deliver without one.