One name per thing, per the HQ glossary: the module/container/image/binary/repo becomes mesh-controller, the seat the-controller, and the store+broker pair the foundation (embedded base bundles, default template and example lock renamed with their go:embed directives). No behaviour change — a pure vocabulary rename. Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
80 lines
3.2 KiB
Go
80 lines
3.2 KiB
Go
package secrets
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"os"
|
|
"testing"
|
|
|
|
"golang.org/x/crypto/nacl/box"
|
|
)
|
|
|
|
// The manager module's TypeScript seal and this package's Go seal are the SAME anonymous sealed box,
|
|
// byte for byte — the property the refreshable-grant carve-out rests on (novox/hq ADR 0050).
|
|
//
|
|
// **Why it must hold.** The refresh token is sealed to the manager node — at adoption and after each
|
|
// rotation — by the manager MODULE, in TypeScript (mesh-catalog anthropic-manager/sealedbox.ts). The
|
|
// HOST then unseals it with Go's box.OpenAnonymous (mesh-host identity.SealingKey.Unseal) to mount the
|
|
// cleartext, and mesh-controller seals every other credential with box.SealAnonymous (secrets.Seal). If
|
|
// the TS seal and the Go box disagreed by a byte, the host would refuse the refresh token as a value
|
|
// it cannot open — silently, as a manager that never gets its credential. So this is load-bearing, and
|
|
// it is pinned here rather than trusted.
|
|
//
|
|
// The fixture is produced by the module's own compiled seal() over a fresh node key pair; this test
|
|
// opens it with box.OpenAnonymous — exactly what the host runs — and with secrets.Open, and recovers
|
|
// the plaintext. Regenerate it with the module's seal() if the construction ever changes; a drift
|
|
// shows up here as a fixture Go cannot open, which is the whole point.
|
|
func TestModuleSealedBoxOpensInGo(t *testing.T) {
|
|
raw, err := os.ReadFile("testdata/module-sealedbox-fixture.json")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var f struct {
|
|
ManagerPublicKey string `json:"managerPublicKey"`
|
|
ManagerPrivateKey string `json:"managerPrivateKey"`
|
|
Plaintext string `json:"plaintext"`
|
|
Sealed string `json:"sealed"`
|
|
}
|
|
if err := json.Unmarshal(raw, &f); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
pub, err := base64.StdEncoding.DecodeString(f.ManagerPublicKey)
|
|
if err != nil || len(pub) != 32 {
|
|
t.Fatalf("the fixture public key is not a 32-byte X25519 key")
|
|
}
|
|
priv, err := base64.StdEncoding.DecodeString(f.ManagerPrivateKey)
|
|
if err != nil || len(priv) != 32 {
|
|
t.Fatalf("the fixture private key is not 32 bytes")
|
|
}
|
|
blob, err := base64.StdEncoding.DecodeString(f.Sealed)
|
|
if err != nil {
|
|
t.Fatalf("the sealed value is not base64: %v", err)
|
|
}
|
|
|
|
// The host's path: box.OpenAnonymous with the node's key pair.
|
|
var pubA, privA [32]byte
|
|
copy(pubA[:], pub)
|
|
copy(privA[:], priv)
|
|
out, ok := box.OpenAnonymous(nil, blob, &pubA, &privA)
|
|
if !ok {
|
|
t.Fatal("box.OpenAnonymous (the host's Unseal) FAILED to open the module's TS seal — " +
|
|
"the TypeScript crypto_box_seal has drifted from Go's box")
|
|
}
|
|
if string(out) != f.Plaintext {
|
|
t.Fatalf("opened to %q, expected %q", out, f.Plaintext)
|
|
}
|
|
|
|
// And it is exactly what secrets.Seal produces: a value this package can round-trip is one the TS
|
|
// module could equally have produced, so the two are interchangeable at the seam.
|
|
roundTrip, err := Seal(f.ManagerPublicKey, []byte(f.Plaintext))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
rtBlob, _ := base64.StdEncoding.DecodeString(roundTrip)
|
|
back, ok := box.OpenAnonymous(nil, rtBlob, &pubA, &privA)
|
|
if !ok || string(back) != f.Plaintext {
|
|
t.Fatal("secrets.Seal did not round-trip under box.OpenAnonymous")
|
|
}
|
|
}
|