verifyJWT compared the token iss against the ENTIRE IAM_ISSUER string, so a
comma-list ('https://hanzo.id,https://iam.hanzo.ai,https://hanzo.ai') — the
production config — rejected every real token as wrong_iss. (The 2.x line
carried this split; it was lost in the 0.159.x re-baseline.) Mirror
checkAudience: split IAM_ISSUER on ',' into an allowlist, drop the single-value
jwt.WithIssuer, enforce via checkIssuer post-parse (trailing-slash normalized).
Single-issuer + wrong/attacker/missing-iss rejection unchanged.
Test: TestJWT_MultiIssuer_Accepted (3 listed issuers accepted, evil rejected);
existing F1 issuer-rejection + F4 multi-audience + TestList suites still green.
The image build-stage runs 'go mod download' WITHOUT GOPRIVATE in effect
(the env prefix binds to the preceding git-config, not the download), so
public luxfi modules resolve via proxy.golang.org (immutable version
content), while upstream has force-moved several luxfi tags so DIRECT git
now serves different bytes. Regenerate ALL luxfi sums via the same proxy
path the build uses (keys +AriQNM7, zap MiVRsRA8, ...). Gate: a
Dockerfile-identical 'go mod download' + CGO_ENABLED=0 build + TestList
suite verify against the regenerated go.sum.
The Dockerfile build stage runs 'go mod download' WITHOUT GOPRIVATE in effect
(shell: 'VAR=x git config ... && go mod download' applies VAR only to the
git-config, not the download), so luxfi/keys (public) resolves via
proxy.golang.org, whose v1.2.0 cache is immutable (+AriQNM7...). Upstream
later force-moved the v1.2.0 tag, so DIRECT git now serves different content
(3TAcr4tw...). The image build verifies against the proxy value; pin go.sum to
it. /go.mod hash already matches (build passed graph-load, failed only on zip).
go mod tidy and go mod download resolve the re-cut luxfi tags to different
commits; the image build uses 'go mod download', which stably resolves
luxfi/[email protected] to the +AriQNM7 content. Regenerate luxfi sums via the
build path so the Dockerfile 'go mod download' verifies. Proven in-job:
go mod verify + fresh readonly download + CGO_ENABLED=0 build of kmsd/kms
+ TestList endpoint suite all pass.
The recorded luxfi/* hashes were generated against an internal mirror
that still serves pre-force-move content; github.com (what CI and the
image build fetch) serves the re-cut tags. Regenerate luxfi sums via
'go mod tidy' against github.com so 'go mod download' verifies in the
build environment. go.mod versions unchanged; go mod verify + CGO_ENABLED=0
build of kmsd/kms + TestList endpoint suite all pass.
Add a bare list endpoint so an operator console can browse an org's secret
KEYS without ever exposing a value. Structurally incapable of leaking a value:
the scan iterates ZapDB KEYS ONLY (PrefetchValues=false) under
kms/secrets/<brand/org>/ and the row type has no value field — there is no
code path from this handler to a secret value blob.
Verified against the store: secret path/name/env are PLAINTEXT in the ZapDB
key kms/secrets/{path}/{env}/{name}; only the value blob is at-rest encrypted.
So names are honestly listable; values are never touched.
- Authz: identical authorize()+canActOnOrg() gate as get-one — never weaker.
Structurally confined to the org's brand/<org>/ namespace (stricter: cannot
enumerate another tenant's names). Optional ?prefix= (safePath + org
containment) and ?env= filters.
- Routing: bare GET coexists with the {rest...} wildcard (Go 1.22 ServeMux);
the bare path hits list, .../secrets/<path>/<name> still returns its value.
- updatedTime sourced from a new kms/mtimes/ sibling index (mirrors
versioning.go), written on put/patch, deleted on delete — never from the
value blob. Records predating this carry no mtime (updatedTime omitted),
never faked.
- TestRed3 traversal heuristic tightened: '/secrets/foo/..' path-cleans to
'/secrets' (the list), an authorized empty {secrets:[]} with no value; the
test now asserts on an actual value payload, not the substring 'secret'.
Tests: 9 new TestList_* (no-value-leak, authz fail-closed, routing
precedence, prefix injection-safety, env filter, empty org, mtime RFC3339).
VERSION 2.5.2 -> 0.159.4 (patch, v0.x server line; tag cut on merge, not now).
origin/main pins age v1.5.0 / keys v1.2.0 / zap v0.8.1 whose upstream tags
were re-cut (brand-scrub), so the recorded h1 content hashes no longer match
and `go build` fails closed with a checksum mismatch. Recompute the three
hashes from the actual module content (go, not a hand-copy) and drop pq's
stale zip hash (its code isn't compiled on this build graph — module-graph
pruning). kms stays v1.11.7 (origin/main's pin, untouched). `go mod verify`
=> all modules verified. Pre-existing drift, also fixed independently on
fix/kms-cli-build-luxfi-keys-gosum; values agree byte-for-byte.
Deliberate single-patch bump of the canonical backend to pull in the derived
<org>-kms OIDC client (KMS computes client_id/secret/state from KMS_IAM_OWNER —
no env coordination with IAM). hanzoai/kms is a thin wrapper; it pins luxfi/kms
intentionally rather than tracking latest.
Replace inline upstream-brand mentions in DEPRECATED.md, LLM.md, and a
frontend gap description with neutral 'legacy fork' wording. Add a NOTICE
file carrying the required upstream MIT attribution. The LICENSE retains
the upstream copyright notice as required by the MIT license; that is the
only place the upstream name remains.
No functional changes. Go backend and frontend build unchanged.
The current KMS is a pure Go binary. Per DEPRECATED.md the Node.js +
PostgreSQL + Redis Infisical fork was replaced — "no Node.js / Postgres /
Redis dependencies." The KMS Go runtime contains zero Redis references;
the `REDIS_URL` / `REDIS_HOST` knobs in these examples were leftover from
the deprecated stack and are never read.
Remove the orphaned Redis declarations from the three HSM compose examples
and the Zymbit k8s manifest:
- zymbit-hsm/compose.yml: redis service, REDIS_URL env, depends_on, volume
- zymbit-hsm/kubernetes-deployment.yaml: Redis Deployment/Service/PVC,
REDIS_HOST/PORT ConfigMap keys, redis egress NetworkPolicy rule
- aws-cloudhsm/compose.yml: redis service, REDIS_URL env, depends_on, volume
- google-cloud-hsm/compose.yml: redis service, REDIS_URL env, depends_on, volume
No consumer migration needed — nothing read Redis. Postgres left intact.
The root module zip exceeds Go's download limit, so importing
github.com/hanzoai/kms/pkg/kmsclient pulled an undownloadable module.
The light sdk/go module now owns the Go client surface; consumers
import github.com/hanzoai/kms/sdk/go/kmsclient.
Replaces non-canonical scale-set / org-prefixed labels with the
existing labels every arcd host registers with. Matches evo for
amd64 and spark for arm64. No new labels added.