Files
zeekay f3fbb687d2 purge: rip remaining Infisical residue — docs, env examples, repo boilerplate
Following the earlier AdminShell+CollectionCRUD rewrite (PR #14) which
already deleted backend/, backend-go/, cloudformation/, helm-charts/,
nginx/, sink/, wasm/, upgrade-impact/, e2e/, migration/, package.json
and switched the frontend to a 184K Hanzo-first build, complete the
cleanup by deleting the remaining Infisical-era residue:

  - docs/                                   (1.0G Infisical mintlify docs)
  - .env.example, .env.dev.example,
    .env.migration.example, .env.test.example
                                            (legacy Postgres/Redis envs;
                                             no Go code references them)
  - .eslintignore, .husky/                  (TS toolchain leftovers)
  - CODE_OF_CONDUCT.md, CONTRIBUTING.md,
    SECURITY.md                             (Infisical repo boilerplate)

Working tree drops from ~1.0G to <600K of content (1.5G total is .git/
which `git gc --aggressive --prune=now` shrinks locally; the remote
keeps its history shape — anyone pulling gets the lean checkout).

Build + test verification:
  go build ./...                            (4 cmd binaries: green)
  go test ./... -count=1 -short             (all packages: ok)

Kept: cmd/, pkg/, sdk/, frontend/ (AdminShell), schema/, examples/,
root Go (audit.go, auth.go, consensus.go, embed.go, jwks.go, mount.go,
versioning.go + tests), Dockerfile, Dockerfile.kms-fetch, Makefile,
LLM.md, CLAUDE.md, DEPRECATED.md, SOVEREIGN-KMS-ARCHITECTURE.md,
TFHE-KMS-ARCHITECTURE.md, LICENSE, README.md, VERSION, .github/
(8 Hanzo workflows: build, build-kms-fetch, check-fe-ts-and-lint,
ci, pr-preview, release, validate-pr-title, workflow-sanity).
2026-06-07 14:23:12 -07:00

112 lines
2.6 KiB
Go

// Copyright (C) 2020-2026, Hanzo AI Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package kms
import (
"bufio"
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
)
// SecretEvent represents a change event from the CRDT sync stream.
type SecretEvent struct {
// Type is the event type: "set", "delete", or "rotate".
Type string `json:"type"`
// SecretID is the (encrypted) identifier of the affected secret.
SecretID string `json:"secret_id"`
// Timestamp is the server-observed event time (epoch milliseconds).
Timestamp int64 `json:"timestamp"`
}
// Sync triggers CRDT sync across all MPC nodes for this org.
// This is normally automatic; use this to force immediate convergence.
func (c *Client) Sync() error {
path := fmt.Sprintf("/v1/orgs/%s/zk/sync", url.PathEscape(c.orgSlug))
return c.broadcastPost(path, []byte(`{}`))
}
// Watch subscribes to secret change events via server-sent events (SSE).
// Events are encrypted CRDT operations — the client observes which secrets
// changed without seeing plaintext values.
//
// The returned channel is closed when the context is cancelled or the
// connection drops. Errors during streaming are silently dropped; reconnect
// by calling Watch again.
func (c *Client) Watch(ctx context.Context) (<-chan SecretEvent, error) {
if len(c.nodes) == 0 {
return nil, fmt.Errorf("kms: no nodes configured")
}
// Connect to the first available node for SSE.
var (
resp *http.Response
err error
)
path := fmt.Sprintf("/v1/orgs/%s/zk/watch", url.PathEscape(c.orgSlug))
for _, node := range c.nodes {
req, reqErr := http.NewRequestWithContext(ctx, http.MethodGet, node+path, nil)
if reqErr != nil {
err = reqErr
continue
}
req.Header.Set("Accept", "text/event-stream")
resp, err = c.http.Do(req)
if err == nil && resp.StatusCode == http.StatusOK {
break
}
if resp != nil {
resp.Body.Close()
}
}
if err != nil {
return nil, fmt.Errorf("kms: watch: connect: %w", err)
}
if resp == nil || resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("kms: watch: no node available")
}
ch := make(chan SecretEvent, 64)
go func() {
defer resp.Body.Close()
defer close(ch)
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
select {
case <-ctx.Done():
return
default:
}
line := scanner.Text()
if len(line) == 0 {
continue
}
var event SecretEvent
if err := json.Unmarshal([]byte(line), &event); err != nil {
continue
}
select {
case ch <- event:
case <-ctx.Done():
return
}
}
}()
return ch, nil
}