refactor(cloud): drop the svc suffix — bare package names + spelled-out test helpers

One name per thing, no compound-word cruft. The `svc` suffix was never a real
package (zero `package *svc`) — only import aliases and abbreviated test helpers.

- Import aliases → bare package names: plansvc→plan (commerceclient),
  captablesvc→captable + dataroomsvc→dataroom (company/adapters). No stutter, no
  alias where the bare name is unambiguous.
- Test helpers spelled out: fakeSvc→fakeService, testSvc→testService,
  newSvc→newService — across admin/agents/deploy/domain/functions/ingress/
  integrations/ml/platform/provisioning/storage/wallets tests, callers updated
  in-package.
- Stale `// Package …svc` doc-comment prose corrected to the real package name
  (exec/iam/plugin/pricing/product/provisioning/sync/tasks).

Naming only — no logic change. go build + test-compile green on all 21 packages.

Note: the clients/team package (filesSvc/fsvc rename) is excluded here — it has
concurrent in-progress work; its svc cleanup lands with that change.
This commit is contained in:
antje
2026-07-20 12:56:12 -07:00
parent f6b29f7050
commit db7a8f99fa
38 changed files with 162 additions and 162 deletions
+3 -3
View File
@@ -24,16 +24,16 @@ import (
// mount builds a zip app with admin mounted against the given upstream bases,
// and returns a `do` helper that issues test requests through the whole app.
func mount(t *testing.T, iamURL, commerceURL, healthURL string) func(method, path string, hdr map[string]string) (*http.Response, []byte) {
do, _, _ := mountSvc(t, iamURL, commerceURL, healthURL)
do, _, _ := mountService(t, iamURL, commerceURL, healthURL)
return do
}
// mountSvc is mount but also returns the underlying cloud.Service[state] (so finance tests can swap
// mountService is mount but also returns the underlying cloud.Service[state] (so finance tests can swap
// in a fake DigitalOcean client, and the cockpit tests can attach an audit store)
// AND the raw fiber app (so tests that need a request BODY can drive it directly —
// the returned `do` sends a nil body). The handlers read s.* live at request time,
// so an override before issuing a request takes effect.
func mountSvc(t *testing.T, iamURL, commerceURL, healthURL string) (func(method, path string, hdr map[string]string) (*http.Response, []byte), *cloud.Service[core.State], *fiber.App) {
func mountService(t *testing.T, iamURL, commerceURL, healthURL string) (func(method, path string, hdr map[string]string) (*http.Response, []byte), *cloud.Service[core.State], *fiber.App) {
t.Helper()
app := zip.New(zip.Config{Logger: luxlog.New("test")})
s := &cloud.Service[core.State]{State: core.State{
+1 -1
View File
@@ -203,7 +203,7 @@ func newCockpitFakes(t *testing.T) *cockpitFakes {
}
}))
_, s, fa := mountSvc(t, f.iam.URL, f.commerce.URL, "")
_, s, fa := mountService(t, f.iam.URL, f.commerce.URL, "")
f.service = s
f.do = func(method, path string, hdr map[string]string, body string) (*http.Response, []byte) {
t.Helper()
+4 -4
View File
@@ -15,7 +15,7 @@ import (
// The finance PURE-math derivation tests (ComputeFinance / AvgDailyBurnCents) live with
// the handler in clients/admin/finance. These are the INTEGRATION tests that drive GET
// /v1/admin/finance through the shared admin mount harness (mountSvc + fake IAM/commerce/DO).
// /v1/admin/finance through the shared admin mount harness (mountService + fake IAM/commerce/DO).
// newFakeDO serves the DO billing API with fixed decimal-dollar strings so the
// finance aggregation is deterministic. account_balance is NEGATIVE (credit held).
@@ -49,7 +49,7 @@ func TestFinance_RealAggregation(t *testing.T) {
do := newFakeDO()
defer do.Close()
doReq, s, _ := mountSvc(t, iam.server.URL, commerce.URL, "")
doReq, s, _ := mountService(t, iam.server.URL, commerce.URL, "")
s.State.DO = digitalocean.NewWithBase(do.URL, "test-do-token") // configured DO client
admin := map[string]string{
"X-User-IsAdmin": "true", "X-Org-Id": "admin",
@@ -151,7 +151,7 @@ func TestFinance_HonestUnconfiguredDO(t *testing.T) {
commerce := newFakeCommerceFinance()
defer commerce.Close()
doReq, _, _ := mountSvc(t, iam.server.URL, commerce.URL, "") // s.do already has empty token → unconfigured
doReq, _, _ := mountService(t, iam.server.URL, commerce.URL, "") // s.do already has empty token → unconfigured
admin := map[string]string{"X-User-IsAdmin": "true", "X-Org-Id": "admin"}
resp, body := doReq("GET", "/v1/admin/finance", admin)
@@ -212,7 +212,7 @@ func TestFinance_RevenueSourceDown_NoFabrication(t *testing.T) {
defer commerce.Close()
// IAM points nowhere reachable → listOrgs errors; commerce /v1/costs still 200s.
doReq, _, _ := mountSvc(t, "http://127.0.0.1:0", commerce.URL, "")
doReq, _, _ := mountService(t, "http://127.0.0.1:0", commerce.URL, "")
admin := map[string]string{"X-User-IsAdmin": "true", "X-Org-Id": "admin"}
resp, body := doReq("GET", "/v1/admin/finance", admin)
+9 -9
View File
@@ -48,9 +48,9 @@ func (c *countingAI) Embed(_ context.Context, _ *types.EmbedRequest) ([][]float3
return nil, nil
}
// schedSvc builds a Service + scheduler with NO billing (gate allows) and the given
// schedService builds a Service + scheduler with NO billing (gate allows) and the given
// AI, seeded with the supplied agents. Returns the scheduler for direct tick().
func schedSvc(t *testing.T, ai types.AIClient, seed ...Agent) *scheduler {
func schedService(t *testing.T, ai types.AIClient, seed ...Agent) *scheduler {
t.Helper()
s := &cloud.Service[state]{Base: cloud.Base{Log: luxlog.New("test")}, State: state{store: testStore(t), ai: ai}}
for _, a := range seed {
@@ -83,7 +83,7 @@ func waitFor(cond func() bool) bool {
// run; a tick at a non-matching minute launches none.
func TestSchedulerFiresDueAgent(t *testing.T) {
ai := &countingAI{}
sc := schedSvc(t, ai, longRunning("acme", "cron", "*/5 * * * *"))
sc := schedService(t, ai, longRunning("acme", "cron", "*/5 * * * *"))
ctx := context.Background()
sc.tick(ctx, at(t, "2026-07-01 12:36")) // 36 not multiple of 5 -> no fire
@@ -102,7 +102,7 @@ func TestSchedulerFiresDueAgent(t *testing.T) {
// like an HTTP run — the scheduler shares runAgent.
func TestSchedulerRecordsRun(t *testing.T) {
ai := &countingAI{}
sc := schedSvc(t, ai, longRunning("acme", "cron", "* * * * *"))
sc := schedService(t, ai, longRunning("acme", "cron", "* * * * *"))
ctx := context.Background()
sc.tick(ctx, at(t, "2026-07-01 12:00"))
if !waitFor(func() bool {
@@ -119,7 +119,7 @@ func TestSchedulerRecordsRun(t *testing.T) {
// tick fires; the immediately-following matching tick is skipped (backoff=1).
func TestSchedulerBackoffOnFailure(t *testing.T) {
ai := &countingAI{fail: true}
sc := schedSvc(t, ai, longRunning("acme", "cron", "* * * * *"))
sc := schedService(t, ai, longRunning("acme", "cron", "* * * * *"))
ctx := context.Background()
sc.tick(ctx, at(t, "2026-07-01 12:00"))
@@ -152,7 +152,7 @@ func TestSchedulerBackoffOnFailure(t *testing.T) {
// second matching tick while it is in flight does NOT start a second run.
func TestSchedulerConcurrencyCap(t *testing.T) {
ai := &countingAI{block: make(chan struct{})}
sc := schedSvc(t, ai, longRunning("acme", "cron", "* * * * *"))
sc := schedService(t, ai, longRunning("acme", "cron", "* * * * *"))
ctx := context.Background()
sc.tick(ctx, at(t, "2026-07-01 12:00")) // starts run #1, which blocks
@@ -257,7 +257,7 @@ func TestSchedulerGatesUnfundedRun(t *testing.T) {
// path that lets Shutdown close the store safely.
func TestSchedulerStopDrainsCleanly(t *testing.T) {
ai := &countingAI{}
sc := schedSvc(t, ai, longRunning("acme", "cron", "* * * * *"))
sc := schedService(t, ai, longRunning("acme", "cron", "* * * * *"))
sc.start()
// Fire one run via a direct tick, then stop — stop must return after drain.
sc.tick(context.Background(), at(t, "2026-07-01 12:00"))
@@ -286,7 +286,7 @@ func TestSchedulerStopDrainsCleanly(t *testing.T) {
// rather than waiting the full runTimeout.
func TestSchedulerStopHonorsDeadline(t *testing.T) {
ai := &countingAI{block: make(chan struct{})}
sc := schedSvc(t, ai, longRunning("acme", "cron", "* * * * *"))
sc := schedService(t, ai, longRunning("acme", "cron", "* * * * *"))
sc.start()
sc.tick(context.Background(), at(t, "2026-07-01 12:00"))
if !waitFor(func() bool { return ai.count() == 1 }) {
@@ -310,7 +310,7 @@ func TestSchedulerStopHonorsDeadline(t *testing.T) {
func TestSchedulerOnlyLongRunning(t *testing.T) {
ai := &countingAI{}
one := mk("acme", "one") // one-shot default, no schedule
sc := schedSvc(t, ai, one)
sc := schedService(t, ai, one)
sc.tick(context.Background(), at(t, "2026-07-01 12:00"))
time.Sleep(20 * time.Millisecond)
if ai.count() != 0 {
+2 -2
View File
@@ -24,7 +24,7 @@ import (
"sync/atomic"
"time"
plansvc "github.com/hanzoai/cloud/clients/plan"
"github.com/hanzoai/cloud/clients/plan"
"github.com/hanzoai/cloud/types"
commercemod "github.com/hanzoai/commerce"
"github.com/hanzoai/commerce/datastore"
@@ -134,7 +134,7 @@ func (c *inProcessClient) CheckEntitlement(ctx context.Context, orgID, productID
if slug == "" {
continue // no resolvable plan tier on this sub — cannot grant from it
}
_, features, found, ferr := plansvc.LicenseEntitlement(ctx, slug)
_, features, found, ferr := plan.LicenseEntitlement(ctx, slug)
if ferr != nil {
// MACHINERY failure (plans vocabulary unavailable): cannot resolve features
// ⇒ cannot verify ⇒ fail closed. Never deny-by-guess on an outage.
+3 -3
View File
@@ -10,7 +10,7 @@ import (
"github.com/hanzoai/cloud"
inproc "github.com/hanzoai/cloud/clients/commerceclient"
plansvc "github.com/hanzoai/cloud/clients/plan"
"github.com/hanzoai/cloud/clients/plan"
commercemod "github.com/hanzoai/commerce"
"github.com/hanzoai/commerce/billing/grant"
"github.com/hanzoai/commerce/datastore"
@@ -27,8 +27,8 @@ func mountPlansVocab(t *testing.T) {
t.Helper()
plansOnce.Do(func() {
app := zip.New(zip.Config{Logger: luxlog.New("test-plans")})
if err := plansvc.Mount(app, cloud.Deps{Logger: luxlog.New("test-plans"), Brand: "hanzo"}); err != nil {
t.Fatalf("plansvc.Mount: %v", err)
if err := plan.Mount(app, cloud.Deps{Logger: luxlog.New("test-plans"), Brand: "hanzo"}); err != nil {
t.Fatalf("plan.Mount: %v", err)
}
})
}
+15 -15
View File
@@ -4,8 +4,8 @@ import (
"context"
"fmt"
captablesvc "github.com/hanzoai/cloud/clients/captable"
dataroomsvc "github.com/hanzoai/cloud/clients/dataroom"
"github.com/hanzoai/cloud/clients/captable"
"github.com/hanzoai/cloud/clients/dataroom"
)
// adapters.go wires the company provider interfaces to the REAL sibling subsystems
@@ -28,7 +28,7 @@ const (
type dataroomSink struct{}
func (dataroomSink) Ingest(ctx context.Context, org, name, contentType string, data []byte) (string, error) {
return dataroomsvc.Ingest(ctx, org, name, contentType, data)
return dataroom.Ingest(ctx, org, name, contentType, data)
}
// ---- CapTable → captable ----
@@ -37,7 +37,7 @@ type captableAdapter struct{}
// SetIncorporation records the entity kind on the tenant's canonical company row.
func (captableAdapter) SetIncorporation(ctx context.Context, org, companyName, incType, country, state string) error {
return captablesvc.SetIncorporation(ctx, org, companyName, incType, country, state)
return captable.SetIncorporation(ctx, org, companyName, incType, country, state)
}
// SeedFounders writes the founding allocation into the cap table: it sets the
@@ -46,24 +46,24 @@ func (captableAdapter) SetIncorporation(ctx context.Context, org, companyName, i
// the 10M pool). Idempotent enough to re-run: stakeholders dedupe by email, the
// share class is ensured-by-name, and certificate ids are per-founder.
func (a captableAdapter) SeedFounders(ctx context.Context, org, companyName string, founders []Founder) error {
holders := make([]captablesvc.StakeholderInput, 0, len(founders))
holders := make([]captable.StakeholderInput, 0, len(founders))
for _, fo := range founders {
holders = append(holders, captablesvc.StakeholderInput{
holders = append(holders, captable.StakeholderInput{
Name: fo.Name, Email: fo.Email,
StakeholderType: "INDIVIDUAL", CurrentRelationship: "FOUNDER",
})
}
if _, err := captablesvc.AddStakeholders(ctx, org, holders); err != nil {
if _, err := captable.AddStakeholders(ctx, org, holders); err != nil {
return fmt.Errorf("seed founders: add stakeholders: %w", err)
}
classID, err := captablesvc.EnsureShareClass(ctx, org, captablesvc.ShareClassInput{
classID, err := captable.EnsureShareClass(ctx, org, captable.ShareClassInput{
Name: "Common", ClassType: "COMMON", InitialSharesAuthorized: foundingAuthorizedShares,
VotesPerShare: 1, ParValue: 0.0001, PricePerShare: 0.0001,
})
if err != nil || classID == "" {
return fmt.Errorf("seed founders: ensure common class: %w", err)
}
ids, err := captablesvc.StakeholderIDsByEmail(ctx, org)
ids, err := captable.StakeholderIDsByEmail(ctx, org)
if err != nil {
return fmt.Errorf("seed founders: resolve ids: %w", err)
}
@@ -76,7 +76,7 @@ func (a captableAdapter) SeedFounders(ctx context.Context, org, companyName stri
if err != nil {
return err
}
if err := captablesvc.IssueShares(ctx, org, captablesvc.ShareInput{
if err := captable.IssueShares(ctx, org, captable.ShareInput{
StakeholderID: sid, ShareClassID: classID, CertificateID: fmt.Sprintf("%s-%d", cert, i+1),
Quantity: int64(fo.EquityBps) * sharesPerBps, Status: "ACTIVE",
}); err != nil {
@@ -89,7 +89,7 @@ func (a captableAdapter) SeedFounders(ctx context.Context, org, companyName stri
// AddStakeholders maps company stakeholders (used by the cap-table import path) to
// the captable contract.
func (captableAdapter) AddStakeholders(ctx context.Context, org string, holders []Stakeholder) (int, error) {
in := make([]captablesvc.StakeholderInput, 0, len(holders))
in := make([]captable.StakeholderInput, 0, len(holders))
for _, h := range holders {
st := h.StakeholderType
if st == "" {
@@ -99,17 +99,17 @@ func (captableAdapter) AddStakeholders(ctx context.Context, org string, holders
if rel == "" {
rel = "INVESTOR"
}
in = append(in, captablesvc.StakeholderInput{
in = append(in, captable.StakeholderInput{
Name: h.Name, Email: h.Email, StakeholderType: st,
CurrentRelationship: rel, InstitutionName: h.InstitutionName,
})
}
return captablesvc.AddStakeholders(ctx, org, in)
return captable.AddStakeholders(ctx, org, in)
}
// RecordRound maps a company fundraising round to the captable contract.
func (captableAdapter) RecordRound(ctx context.Context, org string, r RoundInput) (string, error) {
return captablesvc.RecordRound(ctx, org, captablesvc.RoundInput{
return captable.RecordRound(ctx, org, captable.RoundInput{
Name: r.Name, RoundType: r.RoundType, TargetAmount: r.TargetAmount,
PreMoneyValuation: r.PreMoneyValuation, PricePerShare: r.PricePerShare,
ShareClassID: r.ShareClassID,
@@ -130,6 +130,6 @@ func (captableUpgrader) MarkCompany(ctx context.Context, f *Formation) error {
if name == "" {
name = f.Org
}
return captablesvc.SetIncorporation(ctx, f.Org, name,
return captable.SetIncorporation(ctx, f.Org, name,
f.Structure.incorporationType(), "US", string(f.Jurisdiction))
}
+7 -7
View File
@@ -52,7 +52,7 @@ func getJSON(t *testing.T, s *cloud.Service[state], path string) map[string]any
// column reads (items[].server/name/connectionState), with the fleet's app count,
// and NO cluster credential.
func TestDashClustersEndpoint(t *testing.T) {
s := fakeSvc(
s := fakeService(
appCR("App", "hanzo", "cloud", "u1", "ghcr.io/hanzoai/cloud", "v1", "Running", 1, 1),
appCR("App", "hanzo", "iam", "u2", "ghcr.io/hanzoai/iam", "v1", "Running", 1, 1),
)
@@ -86,7 +86,7 @@ func TestDashClustersEndpoint(t *testing.T) {
// TestDashProjectsEndpoint_Synthesizes: with no AppProject CRD served, /projects
// synthesizes the distinct App-CR project set (default always present).
func TestDashProjectsEndpoint_Synthesizes(t *testing.T) {
s := fakeSvc(appCR("App", "hanzo", "cloud", "u1", "ghcr.io/hanzoai/cloud", "v1", "Running", 1, 1))
s := fakeService(appCR("App", "hanzo", "cloud", "u1", "ghcr.io/hanzoai/cloud", "v1", "Running", 1, 1))
body := getJSON(t, s, "/v1/deploy/projects")
items, ok := body["items"].([]any)
@@ -107,7 +107,7 @@ func TestDashProjectsEndpoint_Synthesizes(t *testing.T) {
// TestDashProjectsEndpoint_PrefersRealCRs: when real AppProject CRs are served,
// /projects lists THOSE (not synthesized ones) and surfaces only intended fields.
func TestDashProjectsEndpoint_PrefersRealCRs(t *testing.T) {
s := fakeSvc(
s := fakeService(
appCR("App", "hanzo", "cloud", "u1", "ghcr.io/hanzoai/cloud", "v1", "Running", 1, 1),
appProjectCR("team-a", "https://git.hanzo.ai/team-a/*"),
)
@@ -136,7 +136,7 @@ func TestDashProjectsEndpoint_PrefersRealCRs(t *testing.T) {
// the SuperAdmin claim (fail-closed, no fleet/cluster data to an anonymous caller).
func TestNewRoutesRequireAdmin(t *testing.T) {
app := zip.New(zip.Config{Logger: luxlog.New("test")})
routes(app, fakeSvc())
routes(app, fakeService())
for _, path := range []string{"/v1/deploy/clusters", "/v1/deploy/projects", "/v1/deploy/stream/applications"} {
// EventSource sends Accept: text/event-stream + Sec-Fetch-Dest: empty, so a
// non-admin gets a 403 (not the browser-document redirect) — assert both.
@@ -202,7 +202,7 @@ func TestStreamFailsClosedWithoutCluster(t *testing.T) {
// the argo Application shape (status.health/sync), projected identically to
// dashAppList.
func TestStreamBurstEmitsAddedPerApp(t *testing.T) {
s := fakeSvc(
s := fakeService(
appCR("App", "hanzo", "cloud", "u1", "ghcr.io/hanzoai/cloud", "v1", "Running", 1, 1),
appCR("App", "hanzo", "iam", "u2", "ghcr.io/hanzoai/iam", "v1", "Running", 1, 1),
)
@@ -246,7 +246,7 @@ func TestStreamBurstEmitsAddedPerApp(t *testing.T) {
func TestStreamBurstZeroAppsNoPanic(t *testing.T) {
var buf bytes.Buffer
w := bufio.NewWriter(&buf)
if ok := streamAppBurst(fakeSvc(), superScope(), context.Background(), w); !ok {
if ok := streamAppBurst(fakeService(), superScope(), context.Background(), w); !ok {
t.Fatal("streamAppBurst on zero apps returned false, want true")
}
_ = w.Flush()
@@ -260,7 +260,7 @@ func TestStreamBurstZeroAppsNoPanic(t *testing.T) {
// return directly (the keep-alive interval is irrelevant), so this needs no global
// tuning and cannot race a concurrent stream.
func TestStreamHonorsContextCancel(t *testing.T) {
s := fakeSvc(appCR("App", "hanzo", "cloud", "u1", "ghcr.io/hanzoai/cloud", "v1", "Running", 1, 1))
s := fakeService(appCR("App", "hanzo", "cloud", "u1", "ghcr.io/hanzoai/cloud", "v1", "Running", 1, 1))
ctx, cancel := context.WithCancel(context.Background())
done := make(chan struct{})
go func() {
+2 -2
View File
@@ -17,7 +17,7 @@ import (
// /v1/deploy/ui route without wrapping it in guard() breaks this test.
func TestDeployRoutesRequireAdmin(t *testing.T) {
app := zip.New(zip.Config{Logger: luxlog.New("test")})
routes(app, fakeSvc()) // the COMPLETE surface: native + engine + dashboard
routes(app, fakeService()) // the COMPLETE surface: native + engine + dashboard
guarded := []struct{ method, path string }{
// engine
@@ -109,7 +109,7 @@ func TestDeployRoutesRequireAdmin(t *testing.T) {
// anonymous answer carries the sign-in URL and NOTHING that identifies anyone.
func TestUserInfoIsPublicBootstrap(t *testing.T) {
app := zip.New(zip.Config{Logger: luxlog.New("test")})
routes(app, fakeSvc())
routes(app, fakeService())
resp, err := app.Fiber().Test(httptest.NewRequest("GET", "/v1/deploy/session/userinfo", nil))
if err != nil {
+4 -4
View File
@@ -16,7 +16,7 @@ import (
// ── fixtures ────────────────────────────────────────────────────────────────
func fakeSvc(objs ...runtime.Object) *cloud.Service[state] {
func fakeService(objs ...runtime.Object) *cloud.Service[state] {
scheme := runtime.NewScheme()
dyn := dynamicfake.NewSimpleDynamicClientWithCustomListKinds(scheme, map[schema.GroupVersionResource]string{
appsCRGVR: "AppList",
@@ -235,7 +235,7 @@ func TestObserveApplication(t *testing.T) {
// ── CR resolution ────────────────────────────────────────────────────────────
func TestGetAppCR(t *testing.T) {
s := fakeSvc(appCR("App", "hanzo", "iam", "u-app", "ghcr.io/hanzoai/iam", "v2.0.0", "Running", 1, 1))
s := fakeService(appCR("App", "hanzo", "iam", "u-app", "ghcr.io/hanzoai/iam", "v2.0.0", "Running", 1, 1))
obj, gvr, err := getAppCR(s, context.Background(), "hanzo", "iam")
if err != nil {
t.Fatalf("getAppCR: %v", err)
@@ -253,7 +253,7 @@ func TestGetAppCR(t *testing.T) {
}
func TestListAppCRs(t *testing.T) {
s := fakeSvc(
s := fakeService(
appCR("App", "hanzo", "iam", "u1", "r", "v2.0.0", "Running", 1, 1),
appCR("App", "hanzo", "cloud", "u3", "r", "v1.799.0", "Running", 1, 1),
)
@@ -284,7 +284,7 @@ func TestBuildTreeOwnership(t *testing.T) {
dep := deployment("hanzo", "iam", "d1", "u1", "ghcr.io/hanzoai/iam:v1.0.0", 1, 1) // owned by CR uid u1
svc := coreService("hanzo", "iam", "u1") // owned by CR uid u1
p := pod("hanzo", "iam-abc", "ghcr.io/hanzoai/iam:v1.0.0", map[string]any{"app.kubernetes.io/instance": "iam"})
s := fakeSvc(cr, dep, svc, p)
s := fakeService(cr, dep, svc, p)
nodes := buildTree(s, context.Background(), "hanzo", "iam", cr)
kinds := map[string]bool{}
+3 -3
View File
@@ -98,7 +98,7 @@ func TestWantsDocument(t *testing.T) {
// navigation gets bounced to sign-in. Neither is ever served the data.
func TestGuardRefusesNonAdmin(t *testing.T) {
app := zip.New(zip.Config{Logger: luxlog.New("test")})
routes(app, fakeSvc())
routes(app, fakeService())
// API call (no Accept, the shape every API client and the existing e2e sends).
resp := do(t, app, httptest.NewRequest("GET", "/v1/deploy/applications", nil))
@@ -367,7 +367,7 @@ func TestSessionMaxAge(t *testing.T) {
// origin the OAuth hop refuses rather than deriving a redirect_uri from the
// caller-controlled Host / X-Forwarded-Proto headers.
func TestSignInFailsClosedWithoutPublicOrigin(t *testing.T) {
svc := fakeSvc()
svc := fakeService()
svc.State.oauth = oauth{
issuer: "https://iam.test", clientID: defaultClientID, adminOrg: "admin",
http: &http.Client{Timeout: time.Second},
@@ -611,7 +611,7 @@ func signinApp(t *testing.T, issuer string) (*zip.App, *fakeIAM) {
t.Cleanup(srv.Close)
issuer = srv.URL
}
svc := fakeSvc()
svc := fakeService()
svc.State.oauth = oauth{
issuer: issuer, clientID: defaultClientID, adminOrg: "admin",
publicURL: "https://cd.hanzo.ai", http: &http.Client{Timeout: 5 * time.Second},
+2 -2
View File
@@ -169,7 +169,7 @@ func TestResolveScope_Boundary(t *testing.T) {
// twoTenantFleet is a fleet with apps for two tenants (in their tenant-<org> namespaces)
// plus a system app in the platform "hanzo" namespace.
func twoTenantFleet() *cloud.Service[state] {
return fakeSvc(
return fakeService(
orgAppCR("tenant-acme", "acme-web", "acme", "storefront"),
orgAppCR("tenant-acme", "acme-api", "acme", "storefront"),
orgAppCR("tenant-bravo", "bravo-web", "bravo", "site"),
@@ -330,7 +330,7 @@ func TestProjectApp_UnlabeledFallsIntoDefault(t *testing.T) {
// NEVER surfaces the unscoped cluster-wide AppProject list (that path is SuperAdmin-only) —
// even when real AppProject CRs are served — and always contains 'default'.
func TestDashProjects_OrgNeverSeesCrossOrgAppProjects(t *testing.T) {
s := fakeSvc(
s := fakeService(
orgAppCR("tenant-acme", "acme-web", "acme", "storefront"),
appProjectCR("team-secret", "https://git.hanzo.ai/team-secret/*"), // a cross-org real AppProject CR
)
+11 -11
View File
@@ -100,7 +100,7 @@ func (z *mockZones) EnsureZone(_ context.Context, _, _ string) ([]string, error)
// --- helpers ---------------------------------------------------------------------
func newSvc(reg *mockReg, bill *mockBill, zones *mockZones) *Service {
func newService(reg *mockReg, bill *mockBill, zones *mockZones) *Service {
return NewService(reg, bill, zones, NewMemStore(), Config{
Markup: Markup{Multiplier: 1.15, MinMarginCents: 300},
Nameservers: []string{"ns1.hanzo.ai", "ns2.hanzo.ai"},
@@ -133,7 +133,7 @@ func TestAvailabilityPricesWithMarkup(t *testing.T) {
reg := &mockReg{configured: true, avail: map[string]namecom.SearchResult{
"acme.ai": {DomainName: "acme.ai", Purchasable: true, PurchasePrice: 55.99, RenewalPrice: 55.99, TLD: "ai"},
}}
svc := newSvc(reg, &mockBill{balance: -1}, &mockZones{ns: []string{"ns1.hanzo.ai"}})
svc := newService(reg, &mockBill{balance: -1}, &mockZones{ns: []string{"ns1.hanzo.ai"}})
qs, err := svc.Availability(context.Background(), "acme.ai")
if err != nil {
t.Fatal(err)
@@ -153,7 +153,7 @@ func TestRegisterHappyPath_BillsAndPointsNameservers(t *testing.T) {
}}
bill := &mockBill{balance: 100000} // $1000
zones := &mockZones{ns: []string{"ns1.hanzo.ai", "ns2.hanzo.ai"}}
svc := newSvc(reg, bill, zones)
svc := newService(reg, bill, zones)
res, err := svc.Register(context.Background(), "acme", "acme.ai", 1, nil)
if err != nil {
@@ -189,7 +189,7 @@ func TestRegisterRefusedWhenInsufficientBalance_NoRegistrarCall(t *testing.T) {
"acme.ai": {DomainName: "acme.ai", Purchasable: true, PurchasePrice: 55.99},
}}
bill := &mockBill{balance: 100} // $1.00 — nowhere near $64.39
svc := newSvc(reg, bill, &mockZones{})
svc := newService(reg, bill, &mockZones{})
_, err := svc.Register(context.Background(), "acme", "acme.ai", 1, nil)
if !errors.Is(err, ErrInsufficientFunds) {
@@ -208,7 +208,7 @@ func TestRegisterRegistrarFailure_NoCharge(t *testing.T) {
"acme.ai": {DomainName: "acme.ai", Purchasable: true, PurchasePrice: 55.99},
}}
bill := &mockBill{balance: 100000}
svc := newSvc(reg, bill, &mockZones{ns: []string{"ns1.hanzo.ai"}})
svc := newService(reg, bill, &mockZones{ns: []string{"ns1.hanzo.ai"}})
_, err := svc.Register(context.Background(), "acme", "acme.ai", 1, nil)
if err == nil {
@@ -224,7 +224,7 @@ func TestRegisterUnavailable(t *testing.T) {
reg := &mockReg{configured: true, avail: map[string]namecom.SearchResult{
"taken.ai": {DomainName: "taken.ai", Purchasable: false},
}}
svc := newSvc(reg, &mockBill{balance: -1}, &mockZones{})
svc := newService(reg, &mockBill{balance: -1}, &mockZones{})
_, err := svc.Register(context.Background(), "acme", "taken.ai", 1, nil)
if !errors.Is(err, ErrUnavailable) {
t.Fatalf("want ErrUnavailable, got %v", err)
@@ -236,7 +236,7 @@ func TestRegisterAlreadyOwned(t *testing.T) {
"acme.ai": {DomainName: "acme.ai", Purchasable: true, PurchasePrice: 55.99},
}}
bill := &mockBill{balance: 100000}
svc := newSvc(reg, bill, &mockZones{ns: []string{"ns1.hanzo.ai"}})
svc := newService(reg, bill, &mockZones{ns: []string{"ns1.hanzo.ai"}})
if _, err := svc.Register(context.Background(), "acme", "acme.ai", 1, nil); err != nil {
t.Fatal(err)
}
@@ -252,7 +252,7 @@ func TestRegisterFallsBackToConfigNameserversWhenZoneFails(t *testing.T) {
}}
bill := &mockBill{balance: 100000}
zones := &mockZones{err: errors.New("dns down")}
svc := newSvc(reg, bill, zones)
svc := newService(reg, bill, zones)
if _, err := svc.Register(context.Background(), "acme", "acme.ai", 1, nil); err != nil {
t.Fatal(err)
@@ -269,7 +269,7 @@ func TestRenewOwnedDomainBills(t *testing.T) {
"acme.ai": {DomainName: "acme.ai", Purchasable: true, PurchasePrice: 55.99, RenewalPrice: 55.99},
}}
bill := &mockBill{balance: 100000}
svc := newSvc(reg, bill, &mockZones{ns: []string{"ns1.hanzo.ai"}})
svc := newService(reg, bill, &mockZones{ns: []string{"ns1.hanzo.ai"}})
if _, err := svc.Register(context.Background(), "acme", "acme.ai", 1, nil); err != nil {
t.Fatal(err)
}
@@ -291,7 +291,7 @@ func TestRenewOwnedDomainBills(t *testing.T) {
func TestRenewNotOwned(t *testing.T) {
reg := &mockReg{configured: true}
svc := newSvc(reg, &mockBill{balance: -1}, &mockZones{})
svc := newService(reg, &mockBill{balance: -1}, &mockZones{})
_, err := svc.Renew(context.Background(), "acme", "nope.ai", 1)
if !errors.Is(err, ErrNotOwned) {
t.Fatalf("want ErrNotOwned, got %v", err)
@@ -300,7 +300,7 @@ func TestRenewNotOwned(t *testing.T) {
func TestNotConfigured(t *testing.T) {
reg := &mockReg{configured: false}
svc := newSvc(reg, &mockBill{balance: -1}, &mockZones{})
svc := newService(reg, &mockBill{balance: -1}, &mockZones{})
if _, err := svc.Availability(context.Background(), "acme.ai"); !errors.Is(err, ErrNotConfigured) {
t.Fatalf("want ErrNotConfigured, got %v", err)
}
+4 -4
View File
@@ -1,4 +1,4 @@
// Package execsvc exposes the Code Interpreter ("Run Code") surface on the
// Package exec exposes the Code Interpreter ("Run Code") surface on the
// unified cloud-api /v1 plane, per HIP-0106.
//
// hanzo.chat (LibreChat fork) drives its execute_code agent tool against a
@@ -76,7 +76,7 @@ func newProxy(rawURL string) (http.Handler, error) {
return nil, err
}
if target.Scheme == "" || target.Host == "" {
return nil, fmt.Errorf("execsvc: CODE_EXEC_UPSTREAM must be an absolute URL, got %q", rawURL)
return nil, fmt.Errorf("exec: CODE_EXEC_UPSTREAM must be an absolute URL, got %q", rawURL)
}
proxy := httputil.NewSingleHostReverseProxy(target)
base := proxy.Director
@@ -123,11 +123,11 @@ func writeErr(w http.ResponseWriter, status int, msg string) {
// node process with the shared service key, so we enforce that key here.
func Mount(app *zip.App, deps cloud.Deps) error {
if app == nil {
return fmt.Errorf("execsvc.Mount: nil zip.App")
return fmt.Errorf("exec.Mount: nil zip.App")
}
logger := deps.Logger
if logger == nil {
return fmt.Errorf("execsvc.Mount: nil deps.Logger")
return fmt.Errorf("exec.Mount: nil deps.Logger")
}
logger = logger.New("subsystem", "exec")
+7 -7
View File
@@ -85,10 +85,10 @@ func (s *sandbox) start(t *testing.T) string {
}
func (s *sandbox) ran() int32 { return atomic.LoadInt32(&s.calls) }
// newBilledSvc builds a functions service with a store, an exec client pointed at
// newBilledService builds a functions service with a store, an exec client pointed at
// execUpstream (empty ⇒ unconfigured), and a metering client pointed at
// commerceURL (default org "hanzo"; empty ⇒ !Enabled()).
func newBilledSvc(t *testing.T, commerceURL, execUpstream string) *cloud.Service[state] {
func newBilledService(t *testing.T, commerceURL, execUpstream string) *cloud.Service[state] {
t.Helper()
log := luxlog.New("module", "fnbilltest")
m, err := metering.New(metering.Config{BaseURL: commerceURL, Token: "svc-token", Org: "hanzo"})
@@ -141,7 +141,7 @@ func fireInvoke(t *testing.T, s *cloud.Service[state], org, name string) *http.R
func TestInvoke_RefusesUnfundedOrg(t *testing.T) {
sb := &sandbox{}
bs := &billServer{available: 0}
s := newBilledSvc(t, bs.start(t), sb.start(t))
s := newBilledService(t, bs.start(t), sb.start(t))
seedFn(t, s, "acme", "resize")
resp := fireInvoke(t, s, "acme", "resize")
@@ -162,7 +162,7 @@ func TestInvoke_RefusesUnfundedOrg(t *testing.T) {
func TestInvoke_AllowsAndDebitsCallerOrg(t *testing.T) {
sb := &sandbox{}
bs := &billServer{available: 100000}
s := newBilledSvc(t, bs.start(t), sb.start(t))
s := newBilledService(t, bs.start(t), sb.start(t))
seedFn(t, s, "acme", "resize")
resp := fireInvoke(t, s, "acme", "resize")
@@ -207,7 +207,7 @@ func TestInvoke_AllowsAndDebitsCallerOrg(t *testing.T) {
func TestInvoke_TransportFailureNotBilled(t *testing.T) {
bs := &billServer{available: 100000}
// execUpstream points at a dead address so run() returns a transport error.
s := newBilledSvc(t, bs.start(t), "http://127.0.0.1:1")
s := newBilledService(t, bs.start(t), "http://127.0.0.1:1")
seedFn(t, s, "acme", "resize")
resp := fireInvoke(t, s, "acme", "resize")
@@ -227,7 +227,7 @@ func TestInvoke_FreeFeeUngated(t *testing.T) {
t.Setenv("CLOUD_FUNCTION_FEE_CENTS", "0")
sb := &sandbox{}
bs := &billServer{available: 0}
s := newBilledSvc(t, bs.start(t), sb.start(t))
s := newBilledService(t, bs.start(t), sb.start(t))
seedFn(t, s, "acme", "resize")
resp := fireInvoke(t, s, "acme", "resize")
@@ -248,7 +248,7 @@ func TestInvoke_FreeFeeUngated(t *testing.T) {
// nothing is billed.
func TestInvoke_BillingUnconfiguredNoop(t *testing.T) {
sb := &sandbox{}
s := newBilledSvc(t, "", sb.start(t)) // empty commerce URL ⇒ !Enabled()
s := newBilledService(t, "", sb.start(t)) // empty commerce URL ⇒ !Enabled()
seedFn(t, s, "acme", "resize")
resp := fireInvoke(t, s, "acme", "resize")
+1 -1
View File
@@ -1,4 +1,4 @@
// Package iamsvc folds Hanzo IAM into the unified hanzoai/cloud binary as an
// Package iam folds Hanzo IAM into the unified hanzoai/cloud binary as an
// in-process subsystem (HIP-0106) — the LAST binary-consolidation piece:
// "one Go binary (hanzoai/cloud) embeds IAM + KMS + o11y".
//
+2 -2
View File
@@ -30,7 +30,7 @@ func testStore(t *testing.T) *Store {
return st
}
func testSvc(t *testing.T) *cloud.Service[state] {
func testService(t *testing.T) *cloud.Service[state] {
t.Helper()
return &cloud.Service[state]{
Base: cloud.NewBase(cloud.Deps{Logger: luxlog.NewNoOpLogger()}, "ingress"),
@@ -216,7 +216,7 @@ func TestTLSHostPolicy(t *testing.T) {
}
func TestReloadBuildsTLSHostSet(t *testing.T) {
s := testSvc(t)
s := testService(t)
ctx := context.Background()
// A TLS route + an org-level extraHost.
+13 -13
View File
@@ -9,9 +9,9 @@ import (
"github.com/hanzoai/cloud"
)
// testSvc builds a bare cloud.Service[state] with a fixed 32-byte signing key — enough to exercise
// testService builds a bare cloud.Service[state] with a fixed 32-byte signing key — enough to exercise
// sign/verify in isolation (no store/KMS/HTTP).
func testSvc() *cloud.Service[state] {
func testService() *cloud.Service[state] {
key := make([]byte, minStateKeyLen)
for i := range key {
key[i] = byte(i + 1)
@@ -20,7 +20,7 @@ func testSvc() *cloud.Service[state] {
}
func TestStateSignVerifyHappy(t *testing.T) {
s := testSvc()
s := testService()
tok, err := sign(s, "acme", "slack", "nonce-1")
if err != nil {
t.Fatalf("sign: %v", err)
@@ -35,7 +35,7 @@ func TestStateSignVerifyHappy(t *testing.T) {
}
func TestStateTamperFails(t *testing.T) {
s := testSvc()
s := testService()
tok, _ := sign(s, "acme", "slack", "n")
// Flip a byte in the payload half (before the dot). The MAC no longer matches.
dot := strings.IndexByte(tok, '.')
@@ -61,7 +61,7 @@ func TestStateTamperFails(t *testing.T) {
}
func TestStateExpiredFails(t *testing.T) {
s := testSvc()
s := testService()
old := stateTTL
stateTTL = -time.Minute // sign with an already-past exp
tok, _ := sign(s, "acme", "slack", "n")
@@ -72,7 +72,7 @@ func TestStateExpiredFails(t *testing.T) {
}
func TestStateWrongProviderFails(t *testing.T) {
s := testSvc()
s := testService()
tok, _ := sign(s, "acme", "slack", "n")
if _, err := verify(s, tok, "github"); err == nil {
t.Fatal("state signed for slack must fail verify for github")
@@ -80,10 +80,10 @@ func TestStateWrongProviderFails(t *testing.T) {
}
func TestStateWrongKeyFails(t *testing.T) {
signer := testSvc()
signer := testService()
tok, _ := sign(signer, "acme", "slack", "n")
other := testSvc()
other := testService()
other.State.stateKey = make([]byte, minStateKeyLen) // all-zero: a different key
if _, err := verify(other, tok, "slack"); err == nil {
t.Fatal("a token signed under a different key must fail verify")
@@ -91,7 +91,7 @@ func TestStateWrongKeyFails(t *testing.T) {
}
func TestStateMalformedFails(t *testing.T) {
s := testSvc()
s := testService()
for _, bad := range []string{"", ".", "abc", "abc.", ".abc", "onlyonepart"} {
if _, err := verify(s, bad, "slack"); err == nil {
t.Fatalf("malformed token %q must fail verify", bad)
@@ -104,7 +104,7 @@ func TestStateMalformedFails(t *testing.T) {
// an empty payload half all fail — the MAC is bound to the exact payload substring
// before the FIRST dot, and a base64url payload/MAC never itself contains a '.'.
func TestStateDotInjectionRejected(t *testing.T) {
s := testSvc()
s := testService()
tok, _ := sign(s, "acme", "slack", "n")
dot := strings.IndexByte(tok, '.')
payloadB64, macB64 := tok[:dot], tok[dot+1:]
@@ -128,7 +128,7 @@ func TestStateDotInjectionRejected(t *testing.T) {
// carrying an attacker-chosen MAC, is rejected at the constant-time MAC gate and
// never reaches (and never panics in) json.Unmarshal.
func TestStateMACCheckedBeforeParse(t *testing.T) {
s := testSvc()
s := testService()
garbage := base64.URLEncoding.EncodeToString([]byte("this-is-not-json-{{{"))
forgedMAC := base64.URLEncoding.EncodeToString(make([]byte, 32)) // all-zero MAC
if _, err := verify(s, garbage+"."+forgedMAC, "slack"); err == nil {
@@ -141,7 +141,7 @@ func TestStateMACCheckedBeforeParse(t *testing.T) {
// org would smuggle path structure — so a callback can never fold a hostile org
// into the KMS/store key, independent of the connect-boundary check.
func TestStateBadOrgRejected(t *testing.T) {
s := testSvc()
s := testService()
for _, org := range []string{"bad/org", "..", "a b", "org\x00", ""} {
tok, err := sign(s, org, "slack", "n")
if err != nil {
@@ -156,7 +156,7 @@ func TestStateBadOrgRejected(t *testing.T) {
// TestStateOverlongRejected proves an oversized token is rejected before any
// base64 work — capping the allocation a forged callback can force.
func TestStateOverlongRejected(t *testing.T) {
s := testSvc()
s := testService()
huge := strings.Repeat("A", maxStateLen+1) + "." + strings.Repeat("B", 64)
if _, err := verify(s, huge, "slack"); err == nil {
t.Fatal("token longer than maxStateLen must fail verify")
+3 -3
View File
@@ -60,7 +60,7 @@ func (b *billDouble) lastDebit() (string, []byte) {
return b.usageOrg, b.usageBody
}
func newBilledMLSvc(t *testing.T, commerceURL string) *cloud.Service[state] {
func newBilledMLService(t *testing.T, commerceURL string) *cloud.Service[state] {
t.Helper()
log := luxlog.New("module", "mlbilltest")
m, err := metering.New(metering.Config{BaseURL: commerceURL, Token: "svc-token", Org: "hanzo"})
@@ -101,7 +101,7 @@ func postTrainJob(t *testing.T, s *cloud.Service[state], org string) *http.Respo
// billed. This closes the free-GPU hole.
func TestComputeCreate_RefusesUnfundedOrg(t *testing.T) {
bd := &billDouble{available: 0}
s := newBilledMLSvc(t, bd.start(t))
s := newBilledMLService(t, bd.start(t))
resp := postTrainJob(t, s, "acme")
if resp.StatusCode != http.StatusPaymentRequired {
@@ -121,7 +121,7 @@ func TestComputeCreate_RefusesUnfundedOrg(t *testing.T) {
// hanzo) is debited the compute fee under provider "compute".
func TestComputeCreate_AllowsAndDebitsCallerOrg(t *testing.T) {
bd := &billDouble{available: 100000}
s := newBilledMLSvc(t, bd.start(t))
s := newBilledMLService(t, bd.start(t))
resp := postTrainJob(t, s, "acme")
if resp.StatusCode != http.StatusCreated {
+5 -5
View File
@@ -24,10 +24,10 @@ func seedGitApp(t *testing.T, s *cloud.Service[state], org, slug, repoURL, branc
return a
}
// pushSvc mounts a Service over a ready fake cluster (no HTTP routes needed —
// pushService mounts a Service over a ready fake cluster (no HTTP routes needed —
// buildFromPush is called directly) and trusts the embedded-git apex as a build
// source, exactly as platform.Mount does from deps.Domain.
func pushSvc(t *testing.T) *cloud.Service[state] {
func pushService(t *testing.T) *cloud.Service[state] {
t.Helper()
_, s := mountSvcK8s(t, fakeK8s())
prev := selfGitHost
@@ -40,7 +40,7 @@ func pushSvc(t *testing.T) *cloud.Service[state] {
// "building" and a "building" deployment for the pushed commit is recorded.
func TestBuildFromPush_LaunchesMatchingApp(t *testing.T) {
ctx := context.Background()
s := pushSvc(t)
s := pushService(t)
const clone = "https://git.hanzo.ai/v1/git/acme/site.git"
a := seedGitApp(t, s, "acme", "site", "https://git.hanzo.ai/v1/git/acme/site", "main")
@@ -69,7 +69,7 @@ func TestBuildFromPush_LaunchesMatchingApp(t *testing.T) {
// A push to a branch no app tracks is a no-op: no deployment, no error.
func TestBuildFromPush_NoMatchIsNoop(t *testing.T) {
ctx := context.Background()
s := pushSvc(t)
s := pushService(t)
a := seedGitApp(t, s, "acme", "site", "https://git.hanzo.ai/v1/git/acme/site", "main")
// Right repo, wrong branch.
@@ -92,7 +92,7 @@ func TestBuildFromPush_NoMatchIsNoop(t *testing.T) {
// An image-source app matching the repo URL is never built by a push (git only).
func TestBuildFromPush_IgnoresImageApp(t *testing.T) {
ctx := context.Background()
s := pushSvc(t)
s := pushService(t)
img := Application{
ID: "app_acme_api", Org: "acme", ProjectID: "default", Slug: "api", Name: "api",
Source: "image", RepoURL: "https://git.hanzo.ai/v1/git/acme/api", ImageRepo: "ghcr.io/hanzoai/api", ImageTag: "1",
+5 -5
View File
@@ -16,7 +16,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func testSvc() *cloud.Service[state] {
func testService() *cloud.Service[state] {
return &cloud.Service[state]{Base: cloud.Base{Log: luxlog.New("test")}}
}
@@ -205,7 +205,7 @@ func TestComputeReleaseVersion(t *testing.T) {
defer srv.Close()
defer swapAPIBase(srv.URL)()
got, err := computeReleaseVersion(testSvc(), context.Background(), releaseRepoSlug)
got, err := computeReleaseVersion(testService(), context.Background(), releaseRepoSlug)
if err != nil {
t.Fatalf("computeReleaseVersion: %v", err)
}
@@ -232,7 +232,7 @@ func TestTagRelease_RefPath(t *testing.T) {
defer swapAPIBase(srv.URL)()
sha := "deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"
if err := tagRelease(testSvc(), context.Background(), releaseRepoSlug, sha, "v1.786.44"); err != nil {
if err := tagRelease(testService(), context.Background(), releaseRepoSlug, sha, "v1.786.44"); err != nil {
t.Fatalf("tagRelease: %v", err)
}
if gotBody["ref"] != "refs/tags/v1.786.44" || gotBody["sha"] != sha {
@@ -260,7 +260,7 @@ func TestNotifyUniverse_Payload(t *testing.T) {
defer swapAPIBase(srv.URL)()
img := "ghcr.io/hanzoai/cloud:v1.786.44"
if err := notifyUniverse(testSvc(), context.Background(), img, "deadbeef"); err != nil {
if err := notifyUniverse(testService(), context.Background(), img, "deadbeef"); err != nil {
t.Fatalf("notifyUniverse: %v", err)
}
if got["event_type"] != "image-update" {
@@ -277,7 +277,7 @@ func TestNotifyUniverse_Payload(t *testing.T) {
func TestReleaseSeams_FailClosedWithoutTokens(t *testing.T) {
t.Setenv("GH_PAT", "")
t.Setenv("UNIVERSE_DISPATCH_TOKEN", "")
s := testSvc()
s := testService()
if err := tagRelease(s, context.Background(), releaseRepoSlug, "sha", "v1.0.0"); err == nil {
t.Fatal("tagRelease with no GH_PAT: want fail-closed error")
}
+3 -3
View File
@@ -1,4 +1,4 @@
// Package pluginsvc is the runtime plugin loader for the unified cloud binary.
// Package plugin is the runtime plugin loader for the unified cloud binary.
//
// cloud is a thin host: its native Go subsystems are compiled in, but
// everything else mounts at RUNTIME from a manifest — no cloud rebuild to add
@@ -13,7 +13,7 @@
// client when available; until then proxying uses plain HTTP. Either
// way cloud never recompiles to point at a service.
//
// The manifest path comes from CLOUD_PLUGINS (a JSON file); if unset, pluginsvc
// The manifest path comes from CLOUD_PLUGINS (a JSON file); if unset, plugin
// mounts nothing. Adding a service = edit the manifest + drop a .wasm or
// redeploy the standalone — cloud is unchanged unless its own core changes.
package plugin
@@ -62,7 +62,7 @@ type Manifest struct {
//
// The proxy kind dials its target through an http.RoundTripper chosen by
// Plugin.Via. "http" is built in; "zap" (and any future transport) is
// registered here by its client package, so pluginsvc has no hard dependency
// registered here by its client package, so plugin has no hard dependency
// on the ZAP wire code and works today over HTTP.
var (
+2 -2
View File
@@ -1,4 +1,4 @@
// Package pricingsvc mounts the @hanzo/pricing service into the unified cloud
// Package pricing mounts the @hanzo/pricing service into the unified cloud
// binary under /v1/pricing/* (+ the /v1/models, /v1/gpu, /v1/tools aliases),
// per HIP-0106.
//
@@ -99,7 +99,7 @@ func Mount(app *zip.App, deps cloud.Deps) error {
// must stay hidden across restarts. A non-persistent (in-memory) overlay would
// silently re-expose hidden models on the next pod start — a fail-OPEN
// degradation of a security control. So an empty DataDir is a hard boot error
// (prod sets CLOUD_DATA_DIR), never a silent downgrade. provisioningsvc already
// (prod sets CLOUD_DATA_DIR), never a silent downgrade. provisioning already
// requires DataDir, so the unified binary always provides one.
if deps.DataDir == "" {
return fmt.Errorf("pricing.Mount: empty DataDir — the catalog enablement overlay requires a persistent data dir (set CLOUD_DATA_DIR); refusing to boot with a non-persistent overlay that would re-expose admin-hidden models on restart")
+1 -1
View File
@@ -1,4 +1,4 @@
// Package productsvc exposes the read-only Search and Vector product surfaces
// Package product exposes the read-only Search and Vector product surfaces
// the Hanzo console panels call at api.cloud.hanzo.ai, per HIP-0106.
//
// The console's Search/Indexes and Vector panels call
+7 -7
View File
@@ -98,7 +98,7 @@ func TestStore_InstanceColumnRoundTrips(t *testing.T) {
// and returns a postgres:// DSN authenticated as the "admin" superuser.
func TestDedicated_SQLEngineAssemblesDSN(t *testing.T) {
orch := newFakeOrch()
s := newDedicatedSvc(t, orch)
s := newDedicatedService(t, orch)
resp := postCreate(t, s, "sql", "acme", "orders")
if resp.StatusCode != http.StatusCreated {
@@ -147,7 +147,7 @@ func TestDedicated_SQLEngineAssemblesDSN(t *testing.T) {
// redis://default:… DSN — never an "admin" user that would fail AUTH.
func TestDedicated_KVEngineAssemblesDSN(t *testing.T) {
orch := newFakeOrch()
s := newDedicatedSvc(t, orch)
s := newDedicatedService(t, orch)
resp := postCreate(t, s, "kv", "acme", "sessions")
if resp.StatusCode != http.StatusCreated {
@@ -202,7 +202,7 @@ func TestDedicated_KVEngineAssemblesDSN(t *testing.T) {
// the same instance MERGES (never clobbers the first).
func TestDedicated_InstanceBindingInjectsURL(t *testing.T) {
orch := newFakeOrch()
s := newDedicatedSvc(t, orch)
s := newDedicatedService(t, orch)
r1 := postCreateInstance(t, s, "datastore", "acme", "warehouse", "commerce")
if r1.StatusCode != http.StatusCreated {
@@ -239,7 +239,7 @@ func TestDedicated_InstanceBindingInjectsURL(t *testing.T) {
// instance touches no addons Secret — the pre-binding behavior is unchanged.
func TestDedicated_NotInstanceBoundSkipsInjection(t *testing.T) {
orch := newFakeOrch()
s := newDedicatedSvc(t, orch)
s := newDedicatedService(t, orch)
if resp := postCreate(t, s, "datastore", "acme", "warehouse"); resp.StatusCode != http.StatusCreated {
t.Fatalf("create = %d", resp.StatusCode)
@@ -254,7 +254,7 @@ func TestDedicated_NotInstanceBoundSkipsInjection(t *testing.T) {
// key is gone afterward.
func TestDedicated_DropRemovesURLBeforeTeardown(t *testing.T) {
orch := newFakeOrch()
s := newDedicatedSvc(t, orch)
s := newDedicatedService(t, orch)
if resp := postCreateInstance(t, s, "datastore", "acme", "warehouse", "commerce"); resp.StatusCode != http.StatusCreated {
t.Fatalf("create = %d", resp.StatusCode)
@@ -296,7 +296,7 @@ func TestDedicated_DropRemovesURLBeforeTeardown(t *testing.T) {
func TestDedicated_InjectFailureRollsBack(t *testing.T) {
orch := newFakeOrch()
orch.patchErr = context.DeadlineExceeded // make PatchAddonSecret fail
s := newDedicatedSvc(t, orch)
s := newDedicatedService(t, orch)
resp := postCreateInstance(t, s, "datastore", "acme", "warehouse", "commerce")
if resp.StatusCode != http.StatusBadGateway {
@@ -326,7 +326,7 @@ func TestDedicated_InjectPartialWriteRollsBackOrphanKey(t *testing.T) {
orch := newFakeOrch()
orch.patchErr = context.DeadlineExceeded
orch.patchErrAfterWrite = true // the key lands, THEN the call reports failure
s := newDedicatedSvc(t, orch)
s := newDedicatedService(t, orch)
resp := postCreateInstance(t, s, "datastore", "acme", "warehouse", "commerce")
if resp.StatusCode != http.StatusBadGateway {
+6 -6
View File
@@ -65,9 +65,9 @@ func (b *billServer) lastDebit() (string, []byte) {
return b.usageOrg, b.usageBody
}
// newBilledSvc builds a provisioning Service with a mock provisioner and a real
// newBilledService builds a provisioning Service with a mock provisioner and a real
// metering client pointed at commerceURL (default org "hanzo").
func newBilledSvc(t *testing.T, commerceURL string, kinds ...string) (*cloud.Service[state], *mockProv) {
func newBilledService(t *testing.T, commerceURL string, kinds ...string) (*cloud.Service[state], *mockProv) {
t.Helper()
t.Setenv("CLOUD_KMS_NODES", "")
t.Setenv("CLOUD_KMS_PASSPHRASE", "")
@@ -113,7 +113,7 @@ func postCreate(t *testing.T, s *cloud.Service[state], kind, org, name string) *
// runs before the backend). No free provisioning.
func TestCreate_RefusesUnfundedOrg(t *testing.T) {
bs := &billServer{available: 0}
s, mp := newBilledSvc(t, bs.start(t), "vector")
s, mp := newBilledService(t, bs.start(t), "vector")
resp := postCreate(t, s, "vector", "acme", "orders")
if resp.StatusCode != http.StatusPaymentRequired {
@@ -136,7 +136,7 @@ func TestCreate_RefusesUnfundedOrg(t *testing.T) {
// client default hanzo) is debited the provision fee.
func TestCreate_AllowsAndDebitsCallerOrg(t *testing.T) {
bs := &billServer{available: 100000}
s, mp := newBilledSvc(t, bs.start(t), "vector")
s, mp := newBilledService(t, bs.start(t), "vector")
resp := postCreate(t, s, "vector", "acme", "orders")
if resp.StatusCode != http.StatusCreated {
@@ -171,7 +171,7 @@ func TestCreate_AllowsAndDebitsCallerOrg(t *testing.T) {
func TestCreate_FreeKindUngated(t *testing.T) {
t.Setenv("CLOUD_PROVISION_FEE_CENTS_VECTOR", "0")
bs := &billServer{available: 0}
s, mp := newBilledSvc(t, bs.start(t), "vector")
s, mp := newBilledService(t, bs.start(t), "vector")
resp := postCreate(t, s, "vector", "acme", "orders")
if resp.StatusCode != http.StatusCreated {
@@ -191,7 +191,7 @@ func TestCreate_FreeKindUngated(t *testing.T) {
// Billing unconfigured (no commerce URL) → the gate is a no-op: provisioning
// works and nothing is billed (an unconfigured deployment is never blocked).
func TestCreate_BillingUnconfiguredNoop(t *testing.T) {
s, mp := newBilledSvc(t, "", "vector") // empty commerce URL => !Enabled()
s, mp := newBilledService(t, "", "vector") // empty commerce URL => !Enabled()
resp := postCreate(t, s, "vector", "acme", "orders")
if resp.StatusCode != http.StatusCreated {
body, _ := io.ReadAll(resp.Body)
+5 -5
View File
@@ -109,7 +109,7 @@ func (f *fakeOrch) DeletePVC(_ context.Context, ns, name string) error {
return nil
}
func newDedicatedSvc(t *testing.T, orch orchestrator) *cloud.Service[state] {
func newDedicatedService(t *testing.T, orch orchestrator) *cloud.Service[state] {
t.Helper()
t.Setenv("CLOUD_KMS_NODES", "")
t.Setenv("CLOUD_KMS_PASSPHRASE", "")
@@ -152,7 +152,7 @@ func doReq(t *testing.T, h zip.Handler, method, route, path, org, bodyStr string
// dimension, and returns a DSN pointing at the instance's OWN in-cluster Service.
func TestDedicated_CreateLaunchesInstance(t *testing.T) {
orch := newFakeOrch()
s := newDedicatedSvc(t, orch)
s := newDedicatedService(t, orch)
resp := postCreate(t, s, "datastore", "acme", "analytics")
if resp.StatusCode != http.StatusCreated {
@@ -231,7 +231,7 @@ func TestDedicated_CreateLaunchesInstance(t *testing.T) {
// namespaces — no shared backend, no cross-tenant reachability.
func TestDedicated_TwoOrgsSeparateInstances(t *testing.T) {
orch := newFakeOrch()
s := newDedicatedSvc(t, orch)
s := newDedicatedService(t, orch)
if resp := postCreate(t, s, "docdb", "acme", "events"); resp.StatusCode != http.StatusCreated {
t.Fatalf("acme create = %d", resp.StatusCode)
@@ -261,7 +261,7 @@ func TestDedicated_TwoOrgsSeparateInstances(t *testing.T) {
// operator reports the instance StatefulSet Running — never before.
func TestDedicated_ReadyReconcile(t *testing.T) {
orch := newFakeOrch()
s := newDedicatedSvc(t, orch)
s := newDedicatedService(t, orch)
if resp := postCreate(t, s, "datastore", "acme", "warehouse"); resp.StatusCode != http.StatusCreated {
t.Fatalf("create = %d", resp.StatusCode)
@@ -292,7 +292,7 @@ func TestDedicated_ReadyReconcile(t *testing.T) {
// TestDedicated_DropTearsDownInstance: delete removes the CR + admin Secret + row.
func TestDedicated_DropTearsDownInstance(t *testing.T) {
orch := newFakeOrch()
s := newDedicatedSvc(t, orch)
s := newDedicatedService(t, orch)
if resp := postCreate(t, s, "docdb", "acme", "sessions"); resp.StatusCode != http.StatusCreated {
t.Fatalf("create = %d", resp.StatusCode)
@@ -22,7 +22,7 @@ import (
// magic — no WiredTiger mongod datadir, no Postgres PG_VERSION).
func TestDedicated_DocdbIsFerretOnSQL(t *testing.T) {
orch := newFakeOrch()
s := newDedicatedSvc(t, orch)
s := newDedicatedService(t, orch)
resp := postCreate(t, s, "docdb", "acme", "events")
if resp.StatusCode != http.StatusCreated {
+1 -1
View File
@@ -51,7 +51,7 @@ func TestUnavailableKinds_EmptyAfterDedicated(t *testing.T) {
func TestCreate_DedicatedFailsClosedWithoutCluster(t *testing.T) {
for _, kind := range []string{"datastore", "docdb", "sql", "kv"} {
t.Run(kind, func(t *testing.T) {
s, _ := newTestSvc(t) // no orch, no bill
s, _ := newTestService(t) // no orch, no bill
resp := postCreate(t, s, kind, "acme", "warehouse")
if resp.StatusCode != http.StatusServiceUnavailable {
body, _ := io.ReadAll(resp.Body)
+2 -2
View File
@@ -29,7 +29,7 @@ import (
luxlog "github.com/luxfi/log"
)
func liveSvc(t *testing.T) *cloud.Service[state] {
func liveService(t *testing.T) *cloud.Service[state] {
t.Helper()
t.Setenv("CLOUD_KMS_NODES", "")
t.Setenv("CLOUD_KMS_PASSPHRASE", "")
@@ -83,7 +83,7 @@ func dropLive(t *testing.T, s *cloud.Service[state], kind, org, name string) {
}
func TestLive_DedicatedProvisioning(t *testing.T) {
s := liveSvc(t)
s := liveService(t)
ctx := context.Background()
// Two orgs, each gets its OWN datastore instance in its OWN namespace.
+2 -2
View File
@@ -1,4 +1,4 @@
// Package provisioningsvc is the Hanzo Cloud provisioning control plane. It
// Package provisioning is the Hanzo Cloud provisioning control plane. It
// turns "create a database" into a real logical resource inside an
// already-live, shared product backend, per the unified /v1 binary (HIP-0106).
//
@@ -647,7 +647,7 @@ func genID() (string, error) {
var mounted *cloud.Service[state]
// Shutdown closes the provisioning metadata store. Idempotent. Mirrors the
// plansvc Shutdown contract so the serve layer can release subsystem resources
// plan Shutdown contract so the serve layer can release subsystem resources
// uniformly.
func Shutdown(context.Context) error {
if mounted == nil || mounted.State.store == nil {
+5 -5
View File
@@ -53,9 +53,9 @@ func (m *mockProv) Create(_ context.Context, _, _, pw string) (string, string, i
func (m *mockProv) Drop(_ context.Context, _, _ string) error { m.dropped++; return nil }
// newTestSvc builds a provisioning Service with a temp store, KMS-degraded secrets (no env),
// newTestService builds a provisioning Service with a temp store, KMS-degraded secrets (no env),
// and a mock provisioner under each given kind.
func newTestSvc(t *testing.T, kinds ...string) (*cloud.Service[state], *mockProv) {
func newTestService(t *testing.T, kinds ...string) (*cloud.Service[state], *mockProv) {
t.Helper()
// Force KMS degrade so secret persistence is hermetic and never dials.
t.Setenv("CLOUD_KMS_NODES", "")
@@ -394,7 +394,7 @@ func TestGenToken(t *testing.T) {
// TestCreateOrgGate: a non-admin POST with no X-Org-Id is refused 403 before
// anything is provisioned.
func TestCreateOrgGate(t *testing.T) {
s, mp := newTestSvc(t, "sql")
s, mp := newTestService(t, "sql")
app := zip.New(zip.Config{DisableStartupMessage: true})
app.Post("/v1/sql", create(s, "sql"))
@@ -421,7 +421,7 @@ func TestCreateOrgGate(t *testing.T) {
// gate this forged request would allocate a DB in the victim's namespace and
// return its connection string + generated password, or (on DELETE) destroy it.
func TestForgedOrgWithoutPrincipalRefused(t *testing.T) {
s, mp := newTestSvc(t, "sql")
s, mp := newTestService(t, "sql")
app := zip.New(zip.Config{DisableStartupMessage: true})
app.Post("/v1/sql", create(s, "sql"))
app.Delete("/v1/sql/:name", drop(s, "sql"))
@@ -464,7 +464,7 @@ func TestForgedOrgWithoutPrincipalRefused(t *testing.T) {
// the only kinds that mint a per-resource credential.
func TestCreateKMSDegradePersistsNoPlaintext(t *testing.T) {
orch := newFakeOrch()
s := newDedicatedSvc(t, orch)
s := newDedicatedService(t, orch)
if s.State.sec.Enabled() {
t.Fatal("precondition: KMS must be degraded for this test")
}
+8 -8
View File
@@ -69,10 +69,10 @@ func (b *billServer) lastDebit() (string, []byte) {
return b.usageOrg, b.usageBody
}
// newBilledSvc builds an s3 Service with S3 admin credentials present (so guard does
// newBilledService builds an s3 Service with S3 admin credentials present (so guard does
// not 503 on Configured()) and a metering client pointed at commerceURL (default
// org "hanzo"; empty ⇒ !Enabled()).
func newBilledSvc(t *testing.T, commerceURL string) *cloud.Service[state] {
func newBilledService(t *testing.T, commerceURL string) *cloud.Service[state] {
t.Helper()
t.Setenv("S3_ADMIN_ACCESS_KEY", "AKIATEST")
t.Setenv("S3_ADMIN_SECRET_KEY", "secrettest")
@@ -119,7 +119,7 @@ func callGuard(t *testing.T, s *cloud.Service[state], org string, hErr error) (s
// touched), nothing is debited.
func TestGuard_RefusesUnfundedOrg(t *testing.T) {
bs := &billServer{available: 0}
s := newBilledSvc(t, bs.start(t))
s := newBilledService(t, bs.start(t))
status, ran := callGuard(t, s, "acme", nil)
if status != http.StatusPaymentRequired {
@@ -137,7 +137,7 @@ func TestGuard_RefusesUnfundedOrg(t *testing.T) {
// debited once with product "s3" / unit "op".
func TestGuard_AllowsAndDebitsCallerOrg(t *testing.T) {
bs := &billServer{available: 100000}
s := newBilledSvc(t, bs.start(t))
s := newBilledService(t, bs.start(t))
status, ran := callGuard(t, s, "acme", nil)
if status != http.StatusNoContent {
@@ -178,7 +178,7 @@ func TestGuard_AllowsAndDebitsCallerOrg(t *testing.T) {
// mirrors the edge gate ("do not bill failed work").
func TestGuard_HandlerFailureNotBilled(t *testing.T) {
bs := &billServer{available: 100000}
s := newBilledSvc(t, bs.start(t))
s := newBilledService(t, bs.start(t))
status, ran := callGuard(t, s, "acme", zip.Errorf(http.StatusBadGateway, "s3 down"))
if status != http.StatusBadGateway {
@@ -198,7 +198,7 @@ func TestGuard_HandlerFailureNotBilled(t *testing.T) {
func TestGuard_FreeFeeUngated(t *testing.T) {
t.Setenv("CLOUD_S3_FEE_CENTS", "0")
bs := &billServer{available: 0}
s := newBilledSvc(t, bs.start(t))
s := newBilledService(t, bs.start(t))
status, ran := callGuard(t, s, "acme", nil)
if status != http.StatusNoContent {
@@ -216,7 +216,7 @@ func TestGuard_FreeFeeUngated(t *testing.T) {
// Billing unconfigured (no commerce URL) → the gate is a no-op: the op runs and
// nothing is billed.
func TestGuard_BillingUnconfiguredNoop(t *testing.T) {
s := newBilledSvc(t, "") // empty commerce URL ⇒ !Enabled()
s := newBilledService(t, "") // empty commerce URL ⇒ !Enabled()
status, ran := callGuard(t, s, "acme", nil)
if status != http.StatusNoContent {
@@ -231,7 +231,7 @@ func TestGuard_BillingUnconfiguredNoop(t *testing.T) {
// gate — the tenant boundary precedes billing.
func TestGuard_NoPrincipalRefused(t *testing.T) {
bs := &billServer{available: 100000}
s := newBilledSvc(t, bs.start(t))
s := newBilledService(t, bs.start(t))
status, ran := callGuard(t, s, "", nil)
if status != http.StatusForbidden {
+1 -1
View File
@@ -1,4 +1,4 @@
// Package syncsvc is the universal sync service (/v1/sync): cloud↔cloud data
// Package sync is the universal sync service (/v1/sync): cloud↔cloud data
// sync between connected platforms, expressed as Syncs the engine runs. Git
// (GitHub/GitLab ⇆ native Hanzo Git) is the FIRST provider; storage, db, and other
// kinds are new providers at their own kind with nothing in the engine to change.
+3 -3
View File
@@ -1,4 +1,4 @@
// Package tasksvc mounts the Hanzo Tasks HTTP + UI surface natively onto the
// Package tasks mounts the Hanzo Tasks HTTP + UI surface natively onto the
// unified cloud binary per HIP-0106 — the follow-up named in cloud's durable.go
// ("consolidating that surface into cloud"). Tasks is the durable
// workflow/activity engine (event-sourced, exactly-once, crash-recovering)
@@ -46,10 +46,10 @@ import (
// creates NO engine — the ONE engine lives in cloud.EmbeddedTasks (durable.go).
func Mount(app *zip.App, deps cloud.Deps) error {
if app == nil {
return fmt.Errorf("tasksvc.Mount: nil zip.App")
return fmt.Errorf("tasks.Mount: nil zip.App")
}
if deps.Logger == nil {
return fmt.Errorf("tasksvc.Mount: nil deps.Logger")
return fmt.Errorf("tasks.Mount: nil deps.Logger")
}
h := zip.AdaptNetHTTP(&surface{})
+1 -1
View File
@@ -146,7 +146,7 @@ func TestSafeCustody(t *testing.T) {
if !safeCl.configured() {
t.Fatal("safe client should be configured with base + secret")
}
s, app := newSvc(t, map[Kind]Custody{KindSafe: safeCustody{mpc: mpcCl, safe: safeCl}}, KindSafe)
s, app := newService(t, map[Kind]Custody{KindSafe: safeCustody{mpc: mpcCl, safe: safeCl}}, KindSafe)
acct := mkAccount(t, app, "acme")
w := mkWallet(t, app, "acme", acct, "safe", "warm", "eip155:36963")
+2 -2
View File
@@ -71,7 +71,7 @@ func TestValidNarrowingRejectsInjection(t *testing.T) {
func TestScopedWalletSealsAtScopedRef(t *testing.T) {
k, _ := testKMS(t)
_, app := newSvc(t, map[Kind]Custody{KindKMS: kmsCustody{kms: k}}, KindKMS)
_, app := newService(t, map[Kind]Custody{KindKMS: kmsCustody{kms: k}}, KindKMS)
acct := mkAccount(t, app, "acme")
@@ -120,7 +120,7 @@ func TestScopedWalletSealsAtScopedRef(t *testing.T) {
func TestScopeLookupPath(t *testing.T) {
k, _ := testKMS(t)
s, app := newSvc(t, map[Kind]Custody{KindKMS: kmsCustody{kms: k}}, KindKMS)
s, app := newService(t, map[Kind]Custody{KindKMS: kmsCustody{kms: k}}, KindKMS)
ctx := context.Background()
// Provision four wallets in org "acme" spanning distinct scopes, plus one in a
+6 -6
View File
@@ -24,9 +24,9 @@ import (
// ── harness ──────────────────────────────────────────────────────────────────
// newSvc builds a wallets service over a fresh temp store with the given custody set,
// newService builds a wallets service over a fresh temp store with the given custody set,
// installs it as the process singleton, and mounts the routes on a fresh app.
func newSvc(t *testing.T, custody map[Kind]Custody, def Kind) (*cloud.Service[state], *zip.App) {
func newService(t *testing.T, custody map[Kind]Custody, def Kind) (*cloud.Service[state], *zip.App) {
t.Helper()
st, err := openStore(filepath.Join(t.TempDir(), "wallets.db"))
if err != nil {
@@ -154,7 +154,7 @@ func isHexAddr(s string) bool {
func TestKMSSingleSigEndToEnd(t *testing.T) {
k, dir := testKMS(t)
_, app := newSvc(t, map[Kind]Custody{KindKMS: kmsCustody{kms: k}}, KindKMS)
_, app := newService(t, map[Kind]Custody{KindKMS: kmsCustody{kms: k}}, KindKMS)
acct := mkAccount(t, app, "acme")
w := mkWallet(t, app, "acme", acct, "kms", "hot", "eip155:1")
@@ -242,7 +242,7 @@ func assertSealedAtRest(t *testing.T, dir, plaintextHex string) {
func TestPerTenantIsolation(t *testing.T) {
k, _ := testKMS(t)
_, app := newSvc(t, map[Kind]Custody{KindKMS: kmsCustody{kms: k}}, KindKMS)
_, app := newService(t, map[Kind]Custody{KindKMS: kmsCustody{kms: k}}, KindKMS)
// Org A owns a wallet.
acctA := mkAccount(t, app, "orga")
@@ -289,7 +289,7 @@ func TestPerTenantIsolation(t *testing.T) {
func TestCustodySeamSelectsBackend(t *testing.T) {
k, _ := testKMS(t)
// Only KMS is configured — mpc/treasury must fail closed.
s, app := newSvc(t, map[Kind]Custody{KindKMS: kmsCustody{kms: k}}, KindKMS)
s, app := newService(t, map[Kind]Custody{KindKMS: kmsCustody{kms: k}}, KindKMS)
// Resolver: kms resolves; mpc/treasury fail closed; unknown is a distinct error.
if _, err := custodyFor(s, KindKMS); err != nil {
@@ -371,7 +371,7 @@ func TestMPCPathWiredCompiles(t *testing.T) {
if !client.configured() {
t.Fatal("mpc client should be configured with a node + key")
}
s, app := newSvc(t, map[Kind]Custody{KindMPC: mpcCustody{http: client}}, KindMPC)
s, app := newService(t, map[Kind]Custody{KindMPC: mpcCustody{http: client}}, KindMPC)
acct := mkAccount(t, app, "acme")
w := mkWallet(t, app, "acme", acct, "mpc", "warm", "eip155:1")