Commit Graph
30 Commits
Author SHA1 Message Date
343872f5da feat: native /v1/sdk enveloped secrets + threshold-sign plane (red-approved) (#9)
* test(zapserver): fix e2e seed/assert mismatch (secret-value vs sk_live_real)

TestConsensusE2E_ValidatorReadsSecret seeded "secret-value" but asserted
"sk_live_real" — the E2E read path was correct, the assertion constant
disagreed with the seed. Align the seed to the asserted live-secret value
so the green test actually guards the consensus read path.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>

* feat(zapserver): expose enveloped secret+sign plane over HTTP /v1/sdk

Decomplect the verify->authorize->dispatch core so the ZAP wire and a new
HTTP /v1/sdk transport share ONE implementation (Server.dispatch). Add:

- POST /v1/sdk/secrets: single RPC endpoint. The op is read from the
  SIGNED env.Op field, never the URL, so no framing can escalate a read
  identity into a write. Maps status byte -> HTTP code; replay masked as
  generic 403 'forbidden' (nonce ledger unprobeable); 4 MiB body cap.
- OpSign (0x0050, write/operator) + OpVerify (0x0051, read/validator):
  deliberate, documented widening of the authorizer. Dispatch to a narrow
  SignBackend that delegates to luxfi/mpc t-of-n; KMS holds no key
  material. nil backend -> clear 'signing not configured'.

18 new httptest end-to-end tests: validator read / operator write splits,
replay/stale/tamper/oversize/malformed/unknown-op rejection, and sign
delegation gated BEFORE the backend (forbidden sign never reaches MPC).
All prior authz tests stay green.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>

* feat(sdksign): keys.Manager -> zapserver.SignBackend adapter

Sign delegates to the MPC t-of-n cluster (KMS holds no full key). Verify
is a local public-key check: ed25519 (corona) via stdlib crypto/ed25519
(real, tested with a live keypair); secp256k1 (bls) returns a precise
ErrVerifyBLSDelegated — a documented capability boundary (secp256k1
verification is owned by the chain/precompile layer), not a fake.

Tests (CGO=0, no MPC daemon needed): sign routes to the correct wallet
per scheme, result propagates; ed25519 valid verifies + tampered
sig/message do NOT; bls verify hits the delegated boundary; unknown
validator errors.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>

* fix(gomod): realign age@v1.5.0 + keys@v1.1.0 go.sum to re-tagged hashes

Both tags were force-moved (vendor/docs sync lineage, per LLM.md); go.sum
held the pre-re-tag zip hashes, so any GOWORK=off / clean-cache build
(CI) failed 'checksum mismatch' before compiling. Updated the two h1
lines to the authoritative direct-fetch hashes; the GOWORK=off build
re-verifies the downloaded bits against these, which is the proof they
are correct. Never bypassed the check.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>

* feat(kms): mount /v1/sdk enveloped secrets+sign surface in kmsd

Construct the zapserver.Server once from the loaded REK and back BOTH
transports with ONE consensus authorizer + ONE nonce ledger: the HTTP
/v1/sdk surface (SDK-facing) and the in-cluster ZAP wire. The authorizer
and ledger are built whenever the REK is present (fail-closed: refuse to
boot without them), independent of ZAP_PORT — so /v1/sdk is available
even when the ZAP wire is disabled. Wire the MPC-backed sign/verify via
sdksign.New(mgr) when a vault is configured; nil otherwise.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>

* docs(llm): document /v1/sdk enveloped secrets+sign surface

Co-authored-by: Hanzo Dev <dev@hanzo.ai>

---------

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-03 10:37:07 -07:00
f9d4832cdf docs(LLM): finished web UI reality + canonical image (#7)
* docs(LLM): state finished web UI reality + canonical image

* feat(oidc): derive KMS SSO client id+secret from brand (zero env, matches IAM)

loadOIDCConfig now DERIVES the confidential SSO client from KMS_IAM_OWNER:
client_id=<owner>-kms, client_secret=HMAC-SHA256("hanzo-kms-oidc/v1",<owner>-kms),
state_secret=HMAC("hanzo-kms-state/v1",<owner>-kms). Same derivation hanzoai/iam
init_apps.go uses, so IAM provisions and KMS consumes the identical secret with
ZERO coordination — no KMS_OIDC_CLIENT_SECRET/KMS_STATE_SECRET env, no stored
secret, no manual copy. Env still overrides each (escape hatch). Only the
non-secret IAM_ENDPOINT remains required. Closes the deterministic KMS-admin
loop: reboot IAM+KMS -> SSO works -> admins mint scoped identities.

Note: full repo build is blocked by the pre-existing luxfi/* go.sum re-publish
mismatch (luxfi/age, luxfi/keys); oidc.go itself is gofmt-clean and the
derivation is parity-verified against the IAM side.

---------

Co-authored-by: hanzo-dev <dev@hanzo.ai>
2026-07-01 10:35:21 -07:00
zeekayandHanzo Dev 3b9334e26f feat(mnemonic): canonical BIP-39 bootstrap-mnemonic loader over native ZAP
One canonical path for every Lux-derived service (luxd, netrunner, cli,
descending L1 bootstrap) to resolve the bootstrap mnemonic: MNEMONIC env
wins for local/CI; KMS over native ZAP is the production fallback. Lives
in luxfi/kms (not luxfi/keys) to keep the keys->kms edge from closing an
import cycle. Real guard test covers env-precedence (no KMS dial when env
set), BIP-39 validation reject, KMS-fake valid/empty paths, and the
SplitSecretPath addressing convention.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
v1.12.1
2026-06-30 16:00:59 -07:00
zeekayandHanzo Dev 95cdad9ee5 feat(mnemonic): add pkg/mnemonic.Load — cycle-free KMS bootstrap mnemonic loader
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
v1.12.0
2026-06-30 15:56:29 -07:00
z 888d5f5a78 docs(brand): add hero banner 2026-06-28 20:36:07 -07:00
z 91a16411a9 chore(brand): dynamic hero banner 2026-06-28 20:36:06 -07:00
hanzo-dev a20bc707f1 build: drop GOPRIVATE from Dockerfiles — use immutable public proxy+sumdb
The Docker builds set GOPRIVATE=luxfi/*,hanzoai/* which routes module fetches
'direct' (git) and bypasses sum.golang.org. After luxfi/keys@v1.1.0 was
force-republished, the git tag content diverged from the immutable proxy/sumdb
hash — so 'go mod download' fetched bits that no longer matched the (correct,
sumdb-canonical) go.sum, failing every image build with SECURITY ERROR checksum
mismatch. These modules are public; resolving them through the default public
proxy + sumdb yields the canonical immutable hash that matches go.sum and a
re-publish can no longer break. GITHUB_TOKEN insteadOf stays for the direct
fallback.
v1.11.8
2026-06-28 14:15:10 -07:00
hanzo-dev 5ac2347a04 fix(deps): sync go.sum to canonical public sumdb hashes (no GOPRIVATE/sum hacks)
The committed go.sum carried stale hashes for re-published luxfi modules,
because the dev go env used GOPROXY=direct + GONOSUMDB/GOPRIVATE for these
PUBLIC repos — bypassing the immutable proxy + checksum db, so a force-moved tag
silently poisoned the cache. luxfi/age, luxfi/keys et al are public; routing
them through the standard public proxy (proxy.golang.org) + sumdb gives
canonical immutable hashes that a re-publish can no longer break. go.sum now
matches sum.golang.org; 'go mod verify' = all modules verified; go.mod
unchanged.
2026-06-28 14:09:17 -07:00
1cffefaa57 build: fix keys@v1.1.0 go.sum to authoritative direct hash (unblocks KMS build) (#8)
luxfi/keys v1.1.0 was re-published; go.sum still pinned the original D3s754…
zip hash → 'go mod download SECURITY ERROR' in CI/clean builds. Updated to the
authoritative direct-from-GitHub hash /3mQfl… (same fix applied to hanzoai/iam
this cycle). age@v1.5.0 already correct. Builds clean (CGO sqlcipher).

Co-authored-by: hanzo-dev <dev@hanzo.ai>
2026-06-28 13:48:55 -07:00
hanzo-dev 00c5b6b6c6 feat(oidc): derive KMS SSO client id+secret from brand (zero env, matches IAM)
loadOIDCConfig now DERIVES the confidential SSO client from KMS_IAM_OWNER:
client_id=<owner>-kms, client_secret=HMAC-SHA256("hanzo-kms-oidc/v1",<owner>-kms),
state_secret=HMAC("hanzo-kms-state/v1",<owner>-kms). Same derivation hanzoai/iam
init_apps.go uses, so IAM provisions and KMS consumes the identical secret with
ZERO coordination — no KMS_OIDC_CLIENT_SECRET/KMS_STATE_SECRET env, no stored
secret, no manual copy. Env still overrides each (escape hatch). Only the
non-secret IAM_ENDPOINT remains required. Closes the deterministic KMS-admin
loop: reboot IAM+KMS -> SSO works -> admins mint scoped identities.

Note: full repo build is blocked by the pre-existing luxfi/* go.sum re-publish
mismatch (luxfi/age, luxfi/keys); oidc.go itself is gofmt-clean and the
derivation is parity-verified against the IAM side.
2026-06-28 13:45:06 -07:00
zeekay 50ad9fbd51 remove Stripe from CSP + de-brand test fixtures (Stripe account disabled)
frontend CSP no longer needs to allow *.stripe.com (Infisical-era billing
UI we don't use). Drop all stripe.com sources + the stripe-only child-src.
Rename the Stripe-flavored example secret in zapserver/envelope tests to a
neutral api-key/secret-value fixture. No Go code paths change.
v1.11.7
2026-06-24 12:36:52 -07:00
Hanzo 6dd26decd0 rebrand: neutralize legacy upstream brand across UI, backend, docs; add NOTICE
Replace all inline references to the legacy upstream project with Lux KMS
branding (prose/labels), neutral identifiers (code), and neutral string
literals (frontend-internal cache keys, sentinels, masks), with every
reference renamed consistently so behavior is unchanged. Dead networking
UI (relay/gateway/pam) CLI examples now reference the Lux CLI.

Add a NOTICE file carrying the required upstream MIT attribution and full
permission notice — the only place the upstream name remains, as required
by that license.

No functional changes. Frontend (vite build) and Go backend
(go build -tags sqlite_fts5 sqlcipher) both build green.
2026-06-24 11:19:41 -07:00
zeekay 944e8a3462 docs(kms): record go.sum re-tag fix + keys↔kms phantom-cycle analysis in LLM.md 2026-06-24 10:32:58 -07:00
zeekay 2e949dfbf3 fix(kms): re-tag go.sum for luxfi/age@v1.5.0 (second re-tagged dep)
After the keys@v1.1.0 go.sum fix (1889442), the Build KMS run for
v1.9.14 surfaced a SECOND re-tagged module at 'go mod download':
luxfi/age@v1.5.0 was force-moved the same way (the 'fa86744 vendor:
sync luxfi/keys + luxfi/age docs' lineage), so CI's direct-from-GitHub
fetch computed h1:zC/Fw/… while go.sum pinned the stale
h1:G69HbSV4… → checksum mismatch.

Updated the one age h1 line to the authoritative current hash
(verified from a pristine GOMODCACHE; the /go.mod hash was unchanged).
A full pristine 'go mod download' of the entire module graph (CI
fidelity: isolated cache, GOPROXY=direct, GOWORK=off) is now CLEAN —
no remaining checksum mismatches. age is not compiled into the
cmd/kms server binary (transitive verify-only dep).
v1.9.15
2026-06-24 10:31:23 -07:00
zeekay 1889442402 fix(kms): re-tag go.sum for keys@v1.1.0 + org sub-scope auth (lux→lux-infra)
Build (Build KMS / Dockerfile, -mod=mod) failed 17 days at 'go mod
download': luxfi/keys@v1.1.0 was re-tagged (force-moved to a different
commit) after kms's go.sum was written, so CI's direct-from-GitHub
fetch (GOPRIVATE) computed h1:D3s754vT… while go.sum pinned the stale
h1:a4UkVVg6… → 'SECURITY ERROR: checksum mismatch'. Regenerated the one
go.sum line to the authoritative current hash (no security bypass).

The keys↔kms 'cycle' (keys@v1.1.0 → kms@v1.9.12, a tag that does not
exist) does NOT block this build: the package graph is acyclic
(go list -deps ./pkg/zapclient has zero luxfi/keys; pkg/envelope is
interface-decoupled, keys appears only in its _test files), and MVS
resolves the kms self-module from the local tree, never fetching the
phantom v1.9.12. The production server binary (cmd/kms) and operator
(cmd/kms-operator) compile ZERO external luxfi/keys (cmd/kms uses the
in-repo pkg/keys; only the cmd/smoke-replay dev tool pulls external
keys) — so no keys content enters the shipped images.

org sub-scope auth: the lux-operator queries KMS with org=lux-infra
(its Infisical projectSlug) but the lux-kms token's org claim is 'lux'
→ strict equality returned 403. orgAuthorizes() now admits a requested
org that equals the token org OR is a hyphen-delimited sub-scope of it
(lux authorizes lux-infra/lux-mainnet/…; the '-' boundary keeps lux
from leaking into luxx-infra). One function, one call site.

Tests: cmd/kms ok (14 TestRequireOrgJWT incl. 2 new sub-scope cases),
pkg/{envelope,zapclient,zapserver} ok.
v1.9.14
2026-06-24 10:14:53 -07:00
z 7b37424326 ci(kms): build-lux-kms runs-on lux-build (ARC scale-set label)
runs-on [self-hosted,linux,amd64] never matches the lux-build ARC
AutoscalingRunnerSet (its runner label is the scale-set name 'lux-build'),
so Build KMS jobs queued forever with 'assigned job=0'. Same fix already
applied to build-operator.yml.
v1.9.10
2026-06-24 09:40:47 -07:00
zandzeekay 61770f655f fix(kms): post client_credentials/auth_code to /v1/iam/oauth/token
The hanzoai/iam OAuth API moved under the /v1/iam prefix. The legacy
root /login/oauth/access_token is now a frontend redirect, not the
token API, so the KMS auth-login proxy and OIDC SSO code-exchange both
got HTML back -> empty access_token -> 401 'invalid credentials' to the
kms-operator (breaking every KMSSecret sync, incl. luxd-staking on
devnet/testnet/mainnet).

Route both call sites to the canonical token endpoint via a single
env-overridable knob IAM_TOKEN_PATH (default /v1/iam/oauth/token), so a
future path move needs no rebuild. cmd/kms tests updated + green.
2026-06-24 09:35:41 -07:00
Hanzo AI fa86744f90 vendor: sync luxfi/keys + luxfi/age docs with upstream wording 2026-06-24 08:21:46 -07:00
zeekay d912da333c fix(operator): COPY in-module deps (pkg/envelope, pkg/zap) into build context
zapclient imports github.com/luxfi/kms/pkg/{envelope,zap}, which are the
module's own packages. -mod=vendor only vendors external deps, so these
must be present in the Docker build context as source. The selective COPY
missed them, so the build failed:

  pkg/zapclient/client.go:34:2: cannot find module providing package
    github.com/luxfi/kms/pkg/envelope: import lookup disabled by -mod=vendor

COPY both packages; also add them to the workflow paths filter so the
operator image rebuilds when they change.
2026-06-22 08:13:46 -07:00
zeekay bf7f5f97f6 ci(kms-operator): runs-on lux-build (ARC) — classic self-hosted amd64 label is offline for luxfi/kms 2026-06-22 05:12:03 -07:00
zeekay bd804cb17c ci(kms-operator): build + push the ZAP-transport KMSSecret reconciler
The deployed kms-operator (ghcr.io/luxfi/kms-operator:0d446b0) is the legacy
Infisical-flavor HTTP operator: it POSTs /api/v1/auth/universal-auth/login,
which the Go KMS server does NOT expose, so every KMSSecret sync fails with
CallUniversalAuthLogin 404 (e.g. lux-devnet/luxd-staking-kms-sync). The fix —
cmd/kms-operator, which reconciles over the native luxfi/zap binary transport
on port 9999 (no HTTP auth round-trip) — already exists in source but had no
CI to ship it. Add a self-contained build for Dockerfile.operator (same
pattern as build-lux-kms.yml), publishing ghcr.io/luxfi/kms-operator.
2026-06-22 03:43:31 -07:00
Antje WorringandHanzo Dev a92ebad1aa docs: tidy LLM.md indexes; CLAUDE.md -> LLM.md symlink convention
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-06-17 09:53:43 -07:00
zeekay e8d23a25fa deps: update to latest real-semver, drop local replaces, fix breaks 2026-06-11 09:48:18 -07:00
zeekay e7f9501df5 deps: update to latest real-semver, drop local replaces, fix breaks 2026-06-11 09:05:44 -07:00
zeekay 53bfc1e9dc scrub branding + corona→corona (OSS brand hygiene) 2026-06-10 23:36:10 -07:00
zeekay b0a12cf63f kms: drop deployment leak + genericize secret-path examples
cloudbuild.kms.yaml built and pushed lux/kms to 's GAR
(us-docker.pkg.dev/-devnet) — a downstream deployment artifact
that doesn't belong in lux OSS (lux builds to ghcr.io/luxfi via arcd).
Remove it; genericize the / strings in zapclient +
secrets doc comments.
2026-06-10 21:47:06 -07:00
zeekay 21b6198c7b ci: route to canonical native arcd labels [self-hosted, linux, <arch>]
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.
2026-06-10 20:22:33 -07:00
zeekay 9f3174372a auth: neutral example org identifiers 2026-06-10 19:27:35 -07:00
Antje WorringandHanzo Dev add99ec004 ci: target native arcd runners (evo/spark)
Replace retired self-hosted labels with native host arcd daemons:
evo (linux/amd64), spark (linux/arm64).

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-06-07 15:58:50 -07:00
Hanzo AI da574aa1db lux/kms: orphan history at f2e793bf8 (was: kms: wire luxfi/mpc as REK backend)
Squashes all pre-rewrite history into a single root commit. Previous tree:
- 14506 commits including upstream Infisical fork history
- Multiple merge chains carrying pre-purge content

Force-rewrite per disk-space reclamation discipline. GHCR images
(1.9.9, 1.9.11) remain immutable; their git lineage is no longer
materialized.
2026-06-07 14:28:09 -07:00