Commit Graph
4 Commits
Author SHA1 Message Date
jklein b19da4e580 fix(garage): a comment in the ConfigMap tripped Trivy's KSV-0109
Validate Helm Charts / Detect changed charts (pull_request) Successful in 2s
Validate Helm Charts / Resource quantities (pull_request) Successful in 11s
Validate Helm Charts / Build garage (pull_request) Successful in 5s
Install-test / Install-test garage (pull_request) Successful in 1m20s
Validate Helm Charts / Install-test (pull_request) Successful in 1m20s
Validate Helm Charts / Trivy config garage (pull_request) Successful in 16s
Publish Helm Chart with patched Application Version / publish-helm-chart (push) Successful in 10s
Publish Garage Helm Chart / Publish Garage Helm Chart (push) Successful in 10s
SonarQube Analysis / SonarQube Analysis (push) Successful in 36s
Run 446 reported one HIGH finding, and it was prose, not data: the line
"metrics_require_token = true plus a token to close it" sits inside the
ConfigMap's data block, and KSV-0109 reads a <key> = <value> assignment with a
credential-ish key name as a stored secret - comments included. The ConfigMap
holds no credential at all; the RPC secret arrives as an environment variable
precisely so that it cannot.

Reworded rather than excepted: an entry in ci/trivy/trivyignore.yaml would
carry a permanent exception for one sentence, and the next reader of the report
would have to re-establish that the ConfigMap really is secret-free. The
replacement names the mechanism at the line, so the shape does not come back.
2026-10-03 20:45:56 +00:00
jklein 01336af953 docs(garage): state the admin surface precisely, including open /metrics
Validate Helm Charts / Detect changed charts (pull_request) Successful in 5s
Validate Helm Charts / Trivy config garage (pull_request) Successful in 15s
Install-test / Install-test garage (pull_request) Successful in 1m22s
Validate Helm Charts / Install-test (pull_request) Successful in 1m23s
Validate Helm Charts / Resource quantities (pull_request) Successful in 11s
Validate Helm Charts / Build garage (pull_request) Successful in 7s
"No admin_token is set" read like "nothing is open", and two parts of that
were wrong. /metrics needs no authentication either, because
metrics_require_token defaults to false - internal metrics on a ClusterIP port.
And a config token is not the only way to reach the authenticated API: Garage
2.x keeps admin tokens in the cluster as well ("garage admin-token create"),
which work without any entry in garage.toml. Both now stated at the ConfigMap
and the Service, plus the way to close /metrics.
2026-10-03 20:42:20 +00:00
jklein 5d10b02458 fix(garage): compressionLevel disables with "none", never with 0
Validate Helm Charts / Detect changed charts (pull_request) Successful in 3s
Validate Helm Charts / Trivy config garage (pull_request) Successful in 16s
Install-test / Install-test garage (pull_request) Successful in 1m17s
Validate Helm Charts / Install-test (pull_request) Successful in 1m17s
Validate Helm Charts / Resource quantities (pull_request) Successful in 12s
Validate Helm Charts / Build garage (pull_request) Successful in 7s
My own values comment claimed 0 switches compression off. It does not:
Garage's deserializer takes an integer OR the literal string "none"
(src/util/config.rs, deserialize_compression), and 0 is a valid integer that
zstd reads as its default level - 3, i.e. MORE compression than the chart's 1,
not none. A comment that invites an operator to write 0 for "off" is the
values-that-must-not-lie shape with the lie in the documentation instead of in
the template.

The schema now accepts an integer (negative included, those are zstd's fast
modes) or exactly "none", and the ConfigMap quotes the string form so the
rendered TOML stays valid. Verified: 1, 7, -3 render unquoted, "none" renders
quoted and the result still parses as TOML, and any other string is rejected by
the schema.

No version bump: the chart is not published yet.
2026-10-03 20:40:47 +00:00
jklein 79b7e44fdc feat(garage): new chart for the Garage object store
Validate Helm Charts / Detect changed charts (pull_request) Successful in 3s
Validate Helm Charts / Resource quantities (pull_request) Successful in 11s
Validate Helm Charts / Build garage (pull_request) Successful in 6s
Validate Helm Charts / Trivy config garage (pull_request) Successful in 16s
Install-test / Install-test garage (pull_request) Successful in 1m15s
Validate Helm Charts / Install-test (pull_request) Successful in 1m15s
One Garage node with replication_factor = 1, built from template-chart to the
style guide rather than copied from upstream's in-tree chart (Gitea #81). The
single-node trade is deliberate and its price is named at the value: the factor
applies to the metadata as well, where upstream calls a corrupted database
"generally not recoverable" and a replicated volume replicates the corruption
faithfully. The three countermeasures that work at factor 1 are therefore
mandatory, not optional - metadata_fsync = true (off in Garage's defaults), the
automatic metadata snapshots, and those snapshots on a second PVC.

Storage: PVC 1 carries metadata_dir AND data_dir as two subdirectories, because
volume snapshots are atomic per volume and that is what keeps index and blocks
consistent with each other; PVC 2 carries metadata_snapshots_dir, because a
recovery point must not die with the volume whose corruption it should repair.
Garage creates all three directories itself, which matters because the image is
FROM scratch and has no mkdir.

Two corrections to the approved plan, both verified against the source at tag
v2.4.1 and decided on the issue before implementation:

- The RPC secret arrives as GARAGE_RPC_SECRET via secretKeyRef, not through
  rpc_secret_file. The file form cannot work in a non-root pod:
  read_secret_file rejects any mode with a group or other bit set
  (src/garage/secrets.rs:144, mask 0o077) while the kubelet OR-s the group-read
  bit onto every file of a secret volume once fsGroup is set
  (pkg/volume/volume_linux.go), and Kubernetes can set the group of such a file
  but never its owner. The mechanism is documented at the value so the next
  round does not "fix" it back.
- The first start is done by the server, not by hand: garage server
  --single-node creates the layout in-process before any listener opens, is
  idempotent on the layout version and has no --version argument that could be
  reused, and --default-access-key/--default-bucket import key and bucket FROM
  the vault item. Both premises of the original "manual first start" decision
  fell with that.

Probes follow from the same source reading: readiness is GET /health on the
admin port, which answers 503 while no layout exists; liveness and startup are
a TCP connect, because a probe that can only fail would restart a node waiting
for its layout forever (same lesson as zipline, README 12.3). The S3 listener
binds independently of the layout, so a TCP probe on 3900 would have been the
lie the plan warned about.

CI: fixtures under ci/garage/ rather than an exclusion - with --single-node the
pod reaches Ready on its own, which makes the install-test an assertion about
the layout, the one-PVC subdirectory layout and readOnlyRootFilesystem instead
of a formality. The Renovate block carries a regex versioning anchored to
^v<major>.<minor>.<patch>$, because the registry receives 40-character
commit-SHA tags almost daily (measured 2026-10-03: the newest 22 tags are all
of that kind) and the four v1.99.x-internal builds sort above the v1.3.x line.

Part of #81
2026-10-03 20:29:38 +00:00