Files
zeekay 65979bf7a0 feat(internal): cosigners + secrets resolver — layered cosigner SDK Go port
Brings the SDK-v1.0.3 layered cosigner pattern from app/server/src/domain/cosigners.ts
across to Go. Adds:

  internal/secrets/        URI-scheme secret resolver (literal:/env:/file:/kms:)
                           with pluggable KMS providers (init-time Register).
                           Single source of truth for mpcd bearer tokens,
                           cosigner PEMs, and any future secret material.

  internal/cosigners/      Layered cosigner SDK — per-swap external custodian
                           attestation on TOP of the native MPC threshold sig.
                           Wire shape mirrors the TS reference exactly (snake-
                           case, `kind` discriminator). Families:
                             - fireblocks.go      Real REST integration; RAW
                                                  transaction approval flow,
                                                  per-tenant JWT (RSA), polls
                                                  /v1/transactions/{id} to
                                                  terminal status.
                             - utila.go           Connect-RPC scaffold; mirrors
                                                  FireblocksRESTFamily shape so
                                                  the future port is one
                                                  contained method swap.
                             - stub_family.go     Catch-all for unknown kinds.

Security invariant baked in: SECRET MATERIAL NEVER CROSSES THE WIRE. The
SDK sends only public identifiers (org_id, client_id, api_key, vault ids).
ValidateIntents rejects SECRET_FIELD_NAMES (api_secret, private_key, jwt,
token, …) as a defensive layer. Secrets are fetched at dispatch time via
secrets.Resolver, which is also where KMS plugs in.

Tests: cosigners (2.0s) + secrets (0.3s) all green. Self-contained — no
out-of-tree imports beyond stdlib and within-repo packages.

Extracted from origin/whispers/bridgev2 as the first of a series of focused
slices integrating that branch onto main without dragging in the noise
(export.txt transcript dump, bridge binary diff). Per "x.x.x+1" rule the
next bridge release tag is v1.2.0 — this is the first additive feature
that warrants the minor bump (new internal packages, no consumer break).
2026-05-28 20:14:51 -07:00

42 lines
1.8 KiB
Go

package cosigners
import (
"context"
"fmt"
)
// StubFamilyDispatcher fails every cosign step with a clear "not
// implemented in Go bridge" reason. Used as the default during Phase 1.4
// so that institutional users hitting cmd/bridge see a LOUD failure
// pointing them at app/server, instead of the current silent-drop
// regression where the swap completes without cosigning at all.
//
// Drop-in replacements:
// - For Fireblocks: a real RESTful Fireblocks client (Task #39).
// - For Utila: pending implementation of the @luxfi/utila Connect-RPC
// transaction-approval flow (TS module currently also a stub).
//
// Tests should swap in MockFamilyDispatcher instead of using this — the
// stub's whole purpose is to produce a known failure shape, not to be
// mockable.
type StubFamilyDispatcher struct{}
// RunUtila returns StatusFailed with a clear "not implemented" reason.
func (StubFamilyDispatcher) RunUtila(_ context.Context, intent *UtilaIntent, _ string, opts DispatchOptions) Result {
return Result{
Intent: Intent{Kind: KindUtila, Utila: intent},
Status: StatusFailed,
Reason: fmt.Sprintf("utila cosign not yet implemented in cmd/bridge (Go); use app/server (Express) for swap=%s, or wait for §3.5 e2e soak", opts.SwapID),
}
}
// RunFireblocks returns StatusFailed with a clear "not implemented" reason
// that points at Task #39 (the real REST client work).
func (StubFamilyDispatcher) RunFireblocks(_ context.Context, intent *FireblocksIntent, _ string, opts DispatchOptions) Result {
return Result{
Intent: Intent{Kind: KindFireblocks, Fireblocks: intent},
Status: StatusFailed,
Reason: fmt.Sprintf("fireblocks cosign not yet implemented in cmd/bridge (Go); REST client + JWT signing pending — see Task #39 for swap=%s", opts.SwapID),
}
}