Skip to content

v1.0.0

Latest

Choose a tag to compare

@csatib02 csatib02 released this 07 Aug 18:46
v1.0.0
c023f6e

The first 1.0 release. The runner's internals are rewritten and the HTTP contract
changes. Read MIGRATION.md
before upgrading.

⚠️ Before upgrading

Anything already listening on 9533 collides with the runner. Metrics moved to
their own listener, defaulting to 9533. Containers in a pod share a network
namespace, so a second listener on that port fails to bind and crash-loops:

metrics server: listen tcp 0.0.0.0:9533: bind: address already in use

Give each runner an explicit -metrics-port, or -metrics-port 0 to disable.
It does not take two runners — any other process on 9533 is enough. In
logging-operator this affects the syslog-ng pod (two runners), the fluentd pod (a
runner alongside config-reloader, which also owns 9533), and the fluentbit pod
when configHotReload is enabled. Handled in
logging-operator#2311.

GET /exit is now 405. Anything shutting the runner down over HTTP needs
-X POST, including logging-operator's drain-watch.sh.

The new flags do not exist in older runners. -metrics-port, -address and
-metrics-address are new in v1.0, and Go's flag parsing rejects what it does not
know. If you embed the binary in your own image, move the image and any config
that passes these flags together, or the container exits immediately:

flag provided but not defined: -metrics-port

Breaking changes

Change What to do
Mutating verbs require POST (exec, kill, restart, exit); reads stay GET Add -X POST. A method mismatch returns 405
/metrics moved off the command port to its own listener, default 9533 Scrape :9533. Set -metrics-port per runner in shared pods
The command API binds 127.0.0.1 Set -address 0.0.0.0 only behind a NetworkPolicy
get, exec, kill, restart return a process object, not a one-element array Drop the [0] index. list still returns an array, now sorted by key
Process keys must match ^[A-Za-z0-9._-]{1,64}$ Rename any key outside that set. Others return 400
Config rejects unknown event names, unknown action verbs, multi-document files and multi-verb actions at load Fix typos; they used to be ignored silently
Images run as uid 65534 Check mounted volumes are readable by 65534
/config returns the typed config rather than the raw parsed map Empty sections are omitted

An empty or comment-only config file is now accepted rather than crash-looping
the sidecar.

Security

The command API executes arbitrary shell and previously bound 0.0.0.0 with no
way to change it, while the README documented binding to loopback as the
mitigation. In a default cluster a pod IP is reachable from every other pod, so
any workload could POST a command into the logging sidecar and reach its mounted
output credentials.

It now binds loopback by default, with -address to override. Metrics moved to a
separate listener so scraping never requires exposing it. Request bodies are
capped, HTTP timeouts are set, and process keys are validated — an unvalidated key
became a Prometheus label and let a caller mint unbounded series.

Fixed

  • Two data races, both reproducible under -race: exec shared an err
    between the caller and the goroutine running Wait(), and restart read the
    process map without holding the lock.
  • /list and /get returned unable to json marshal api response whenever a
    process was running.
  • SIGTERM orphaned children and dropped in-flight requests. Shutdown now
    drains the servers, runs onExit, kills the process group and reaps it.
  • onExit never fired. It was defined, documented and unreachable.
  • Killing a shell left its grandchildren running. Processes now run in their
    own process group.
  • A ConfigMap/Secret update never fired onFileWrite on the mounted
    filename.
    kubelet only swaps the ..data symlink, so watching
    /mount/conf stayed silent. Sibling paths now receive onFileWrite.
  • A deliberate restart was recorded as a crash, leaving
    last_reload_error stuck at 1 for the lifetime of a supervised daemon and
    making onError: [{restart: …}] an infinite loop.
  • A clean shutdown recorded every child as an error and dispatched onError
    actions mid-teardown.
  • A failing process incremented the success counter.
  • Event ordering was not guaranteed — each event was delivered by its own
    goroutine.
  • kill reported success on a process that had not started yet, and restart in
    that window blocked forever.

Added

  • GET /healthz and GET /readyz on the metrics listener. Readiness returns
    503 naming the path when a configured watch fails to register — the failure
    where the sidecar stays healthy while silently never reloading again.
  • An end-to-end suite (make e2e, bats) covering the HTTP API, config dispatch,
    lifecycle and the logging-operator integration contract.
  • -address, -metrics-address, -metrics-port flags.
  • Native multi-arch cross-compilation; arm64 previously built under QEMU.
  • A real README, and MIGRATION.md.

Notes

  • Layout moved to cmd/ + internal/. The binary still lives at /runner in
    every image, so COPY --from keeps working.
  • The scratch image has no shell. Since every command runs through sh -c, use
    it as a build stage and pick a shell variant (Dockerfile.alpine,
    .busybox) to run the runner directly.
  • github.com/mitchellh/mapstructure (archived upstream) is no longer a
    dependency.
  • Built with Go 1.26.5.

What's Changed

Features 🚀

  • feat!: repo overhaul and runner rewrite for v1.0 by @csatib02 in #165

Dependency Updates ⬆️

  • chore(deps): update all dependencies by @renovate[bot] in #146
  • fix: pin cosign installer version to 3.10.0 by @csatib02 in #147
  • chore(deps): update all dependencies by @renovate[bot] in #148
  • chore(deps): update module github.com/fsnotify/fsnotify to v1.10.1 by @renovate[bot] in #149
  • chore(deps): update all dependencies by @renovate[bot] in #150
  • chore(deps): update all dependencies by @renovate[bot] in #151
  • chore(deps): update docker/setup-qemu-action action to v4.1.0 by @renovate[bot] in #153
  • chore(deps): update module golang.org/x/sys to v0.44.0 [security] by @renovate[bot] in #152
  • chore(deps): update all dependencies by @renovate[bot] in #154
  • chore(deps): update all dependencies to v3.24.0 by @renovate[bot] in #155
  • chore(deps): update all dependencies to v3.24.1 by @renovate[bot] in #156
  • chore(deps): update all dependencies to v7 by @renovate[bot] in #157
  • chore(deps): update all dependencies by @renovate[bot] in #158
  • chore(deps): update all dependencies by @renovate[bot] in #159
  • chore(deps): update all dependencies by @renovate[bot] in #160
  • chore(deps): update all dependencies by @renovate[bot] in #161
  • chore(deps): update all dependencies by @renovate[bot] in #162
  • chore(deps): update all dependencies by @renovate[bot] in #163
  • chore(deps): update github/codeql-action action to v4.37.6 by @renovate[bot] in #164

Full Changelog: v0.16.0...v1.0.0