From 9b0d99c7f00c8ad742dd35bdd7053d3c3bc632ef Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Sat, 11 Apr 2026 20:25:40 +0800 Subject: [PATCH] Unify bridge sync contract names --- api/xworkmate.go | 89 +++++++-------- api/xworkmate_bridge_bootstrap.go | 34 +++--- api/xworkmate_test.go | 160 +++++++++++++-------------- api/xworkmate_vault.go | 4 +- internal/model/xworkmate_tenant.go | 28 ++--- internal/store/xworkmate.go | 42 +++---- internal/store/xworkmate_memory.go | 32 +++--- internal/store/xworkmate_postgres.go | 8 +- internal/store/xworkmate_test.go | 12 +- 9 files changed, 205 insertions(+), 204 deletions(-) diff --git a/api/xworkmate.go b/api/xworkmate.go index 1e6f00d..8666a62 100644 --- a/api/xworkmate.go +++ b/api/xworkmate.go @@ -26,14 +26,14 @@ type xworkmateAccessContext struct { } type xworkmateProfilePayload struct { - OpenclawURL string `json:"openclawUrl"` - OpenclawOrigin string `json:"openclawOrigin"` - VaultURL string `json:"vaultUrl"` - VaultNamespace string `json:"vaultNamespace"` - VaultSecretPath string `json:"vaultSecretPath"` - VaultSecretKey string `json:"vaultSecretKey"` - SecretLocators []xworkmateSecretLocatorPayload `json:"secretLocators"` - ApisixURL string `json:"apisixUrl"` + BridgeServerURL string `json:"BRIDGE_SERVER_URL"` + BridgeServerOrigin string `json:"bridgeServerOrigin"` + VaultURL string `json:"vaultUrl"` + VaultNamespace string `json:"vaultNamespace"` + VaultSecretPath string `json:"vaultSecretPath"` + VaultSecretKey string `json:"vaultSecretKey"` + SecretLocators []xworkmateSecretLocatorPayload `json:"secretLocators"` + ApisixURL string `json:"apisixUrl"` } type xworkmateSecretLocatorPayload struct { @@ -46,10 +46,11 @@ type xworkmateSecretLocatorPayload struct { } var xworkmateForbiddenTokenFields = map[string]struct{}{ - "openclawtoken": {}, - "gatewaytoken": {}, - "vaulttoken": {}, - "apisixtoken": {}, + "bridge_auth_token": {}, + "bridgeauthtoken": {}, + "gatewaytoken": {}, + "vaulttoken": {}, + "apisixtoken": {}, } func (h *handler) ensureSharedXWorkmateTenant(ctx context.Context) error { @@ -256,16 +257,16 @@ func buildSessionTenantEntries(memberships []store.TenantMembership) []gin.H { func buildXWorkmateTokenConfigured(profile *store.XWorkmateProfile) gin.H { result := gin.H{ - "openclaw": false, - "vault": false, - "apisix": false, + "bridge": false, + "vault": false, + "apisix": false, } if profile == nil { return result } - if hasOpenclawXWorkmateSecretLocator(profile) { - result["openclaw"] = true + if hasBridgeAuthTokenXWorkmateSecretLocator(profile) { + result["bridge"] = true } return result @@ -277,8 +278,8 @@ func buildXWorkmateTokenConfiguredWithVaultStatus(profile *store.XWorkmateProfil return result } - if configured, ok := vaultStatus[store.XWorkmateSecretLocatorTargetOpenclawGatewayToken]; ok { - result["openclaw"] = configured + if configured, ok := vaultStatus[store.XWorkmateSecretLocatorTargetBridgeAuthToken]; ok { + result["bridge"] = configured } if configured, ok := vaultStatus[store.XWorkmateSecretLocatorTargetVaultRootToken]; ok { result["vault"] = configured @@ -290,7 +291,7 @@ func buildXWorkmateTokenConfiguredWithVaultStatus(profile *store.XWorkmateProfil return result } -func hasOpenclawXWorkmateSecretLocator(profile *store.XWorkmateProfile) bool { +func hasBridgeAuthTokenXWorkmateSecretLocator(profile *store.XWorkmateProfile) bool { if profile == nil { return false } @@ -299,7 +300,7 @@ func hasOpenclawXWorkmateSecretLocator(profile *store.XWorkmateProfile) bool { return true } for _, locator := range profile.SecretLocators { - if locator.Target != store.XWorkmateSecretLocatorTargetOpenclawGatewayToken { + if locator.Target != store.XWorkmateSecretLocatorTargetBridgeAuthToken { continue } if strings.TrimSpace(locator.SecretPath) != "" && strings.TrimSpace(locator.SecretKey) != "" { @@ -367,18 +368,18 @@ func (h *handler) buildSessionUser(ctx context.Context, host string, user *store func buildXWorkmateProfileResponse(access *xworkmateAccessContext, profile *store.XWorkmateProfile, tokenConfigured gin.H) gin.H { resolvedProfile := gin.H{ - "openclawUrl": "", - "openclawOrigin": "", - "vaultUrl": "", - "vaultNamespace": "", - "vaultSecretPath": "", - "vaultSecretKey": "", - "secretLocators": []gin.H{}, - "apisixUrl": "", + "BRIDGE_SERVER_URL": "", + "bridgeServerOrigin": "", + "vaultUrl": "", + "vaultNamespace": "", + "vaultSecretPath": "", + "vaultSecretKey": "", + "secretLocators": []gin.H{}, + "apisixUrl": "", } if profile != nil { - resolvedProfile["openclawUrl"] = profile.OpenclawURL - resolvedProfile["openclawOrigin"] = profile.OpenclawOrigin + resolvedProfile["BRIDGE_SERVER_URL"] = profile.BridgeServerURL + resolvedProfile["bridgeServerOrigin"] = profile.BridgeServerOrigin resolvedProfile["vaultUrl"] = profile.VaultURL resolvedProfile["vaultNamespace"] = profile.VaultNamespace resolvedProfile["vaultSecretPath"] = profile.VaultSecretPath @@ -546,8 +547,8 @@ func statusByTargetFromMetadata(profile *store.XWorkmateProfile, target string) if profile == nil { return false } - if target == store.XWorkmateSecretLocatorTargetOpenclawGatewayToken { - return hasOpenclawXWorkmateSecretLocator(profile) + if target == store.XWorkmateSecretLocatorTargetBridgeAuthToken { + return hasBridgeAuthTokenXWorkmateSecretLocator(profile) } for _, locator := range profile.SecretLocators { if locator.Target == strings.ToLower(strings.TrimSpace(target)) && @@ -677,17 +678,17 @@ func (h *handler) updateXWorkmateProfile(c *gin.Context) { profileUserID := resolvedXWorkmateProfileUserID(access, user) profile := &store.XWorkmateProfile{ - TenantID: access.Tenant.ID, - UserID: profileUserID, - Scope: access.ProfileScope, - OpenclawURL: payload.OpenclawURL, - OpenclawOrigin: payload.OpenclawOrigin, - VaultURL: payload.VaultURL, - VaultNamespace: payload.VaultNamespace, - VaultSecretPath: payload.VaultSecretPath, - VaultSecretKey: payload.VaultSecretKey, - SecretLocators: buildStoreXWorkmateSecretLocators(payload.SecretLocators), - ApisixURL: payload.ApisixURL, + TenantID: access.Tenant.ID, + UserID: profileUserID, + Scope: access.ProfileScope, + BridgeServerURL: payload.BridgeServerURL, + BridgeServerOrigin: payload.BridgeServerOrigin, + VaultURL: payload.VaultURL, + VaultNamespace: payload.VaultNamespace, + VaultSecretPath: payload.VaultSecretPath, + VaultSecretKey: payload.VaultSecretKey, + SecretLocators: buildStoreXWorkmateSecretLocators(payload.SecretLocators), + ApisixURL: payload.ApisixURL, } if err := h.store.UpsertXWorkmateProfile(c.Request.Context(), profile); err != nil { respondError(c, http.StatusInternalServerError, "xworkmate_profile_write_failed", "failed to save xworkmate profile") diff --git a/api/xworkmate_bridge_bootstrap.go b/api/xworkmate_bridge_bootstrap.go index 6adb4e2..adc77a1 100644 --- a/api/xworkmate_bridge_bootstrap.go +++ b/api/xworkmate_bridge_bootstrap.go @@ -50,13 +50,13 @@ type bridgeBootstrapIssueResponse struct { } type bridgeBootstrapConsumeResponse struct { - TicketID string `json:"ticketId"` - TargetBridge string `json:"targetBridge"` - OpenclawURL string `json:"openclawUrl"` - AuthMode string `json:"authMode"` - ExchangeToken string `json:"exchangeToken"` - ExpiresAt string `json:"expiresAt"` - Scopes []string `json:"scopes"` + TicketID string `json:"ticketId"` + TargetBridge string `json:"targetBridge"` + BridgeServerURL string `json:"BRIDGE_SERVER_URL"` + AuthMode string `json:"authMode"` + BridgeAuthToken string `json:"BRIDGE_AUTH_TOKEN"` + ExpiresAt string `json:"expiresAt"` + Scopes []string `json:"scopes"` } func sanitizeBridgeTarget(raw string) string { @@ -288,7 +288,7 @@ func (h *handler) internalConsumeXWorkmateBridgeBootstrapTicket(c *gin.Context) respondError(c, http.StatusNotFound, "xworkmate_profile_not_found", "xworkmate profile not found") return } - locator, ok := findStoredXWorkmateSecretLocator(profile, store.XWorkmateSecretLocatorTargetOpenclawGatewayToken) + locator, ok := findStoredXWorkmateSecretLocator(profile, store.XWorkmateSecretLocatorTargetBridgeAuthToken) if !ok { respondError(c, http.StatusConflict, "gateway_token_not_configured", "gateway token is not configured") return @@ -298,8 +298,8 @@ func (h *handler) internalConsumeXWorkmateBridgeBootstrapTicket(c *gin.Context) respondError(c, http.StatusConflict, "gateway_token_unavailable", "gateway token is unavailable") return } - openclawURL := strings.TrimSpace(profile.OpenclawURL) - if openclawURL == "" { + bridgeServerURL := strings.TrimSpace(profile.BridgeServerURL) + if bridgeServerURL == "" { respondError(c, http.StatusConflict, "gateway_endpoint_not_configured", "gateway endpoint is not configured") return } @@ -308,12 +308,12 @@ func (h *handler) internalConsumeXWorkmateBridgeBootstrapTicket(c *gin.Context) h.updateBridgeBootstrapTicket(ticket) c.JSON(http.StatusOK, bridgeBootstrapConsumeResponse{ - TicketID: ticket.TicketID, - TargetBridge: ticket.TargetBridge, - OpenclawURL: openclawURL, - AuthMode: "shared-token", - ExchangeToken: gatewayToken, - ExpiresAt: ticket.ExpiresAt.Format(time.RFC3339), - Scopes: append([]string(nil), ticket.Scopes...), + TicketID: ticket.TicketID, + TargetBridge: ticket.TargetBridge, + BridgeServerURL: bridgeServerURL, + AuthMode: "shared-token", + BridgeAuthToken: gatewayToken, + ExpiresAt: ticket.ExpiresAt.Format(time.RFC3339), + Scopes: append([]string(nil), ticket.Scopes...), }) } diff --git a/api/xworkmate_test.go b/api/xworkmate_test.go index 7a09d46..851de05 100644 --- a/api/xworkmate_test.go +++ b/api/xworkmate_test.go @@ -83,11 +83,11 @@ func TestBuildXWorkmateTokenConfiguredUsesSecretLocators(t *testing.T) { t.Parallel() tests := []struct { - name string - profile *store.XWorkmateProfile - openclaw bool - vault bool - apisix bool + name string + profile *store.XWorkmateProfile + bridge bool + vault bool + apisix bool }{ { name: "missing secret key stays false", @@ -96,26 +96,26 @@ func TestBuildXWorkmateTokenConfiguredUsesSecretLocators(t *testing.T) { }, }, { - name: "legacy path and key mark openclaw configured", + name: "legacy path and key mark bridge configured", profile: &store.XWorkmateProfile{ VaultSecretPath: "kv/openclaw", VaultSecretKey: "token", }, - openclaw: true, + bridge: true, }, { - name: "explicit openclaw locator marks openclaw configured", + name: "explicit bridge locator marks bridge configured", profile: &store.XWorkmateProfile{ SecretLocators: []store.XWorkmateSecretLocator{ { Provider: "vault", SecretPath: "kv/openclaw", SecretKey: "token", - Target: store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, + Target: store.XWorkmateSecretLocatorTargetBridgeAuthToken, }, }, }, - openclaw: true, + bridge: true, }, { name: "other locator stays false", @@ -142,8 +142,8 @@ func TestBuildXWorkmateTokenConfiguredUsesSecretLocators(t *testing.T) { t.Parallel() result := buildXWorkmateTokenConfigured(tt.profile) - if got := result["openclaw"].(bool); got != tt.openclaw { - t.Fatalf("expected openclaw=%v, got %v", tt.openclaw, got) + if got := result["bridge"].(bool); got != tt.bridge { + t.Fatalf("expected bridge=%v, got %v", tt.bridge, got) } if got := result["vault"].(bool); got != tt.vault { t.Fatalf("expected vault=%v, got %v", tt.vault, got) @@ -163,14 +163,14 @@ func TestXWorkmateBridgeBootstrapTicketLifecycle(t *testing.T) { profileBody, err := json.Marshal(map[string]any{ "profile": map[string]any{ - "openclawUrl": "wss://openclaw.example.com", + "BRIDGE_SERVER_URL": "wss://openclaw.example.com", "secretLocators": []map[string]any{ { "id": "locator-openclaw", "provider": "vault", "secretPath": "kv/openclaw", "secretKey": "token", - "target": store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, + "target": store.XWorkmateSecretLocatorTargetBridgeAuthToken, "required": true, }, }, @@ -193,7 +193,7 @@ func TestXWorkmateBridgeBootstrapTicketLifecycle(t *testing.T) { Provider: "vault", SecretPath: "kv/openclaw", SecretKey: "token", - Target: store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, + Target: store.XWorkmateSecretLocatorTargetBridgeAuthToken, }, "shared-token-value"); err != nil { t.Fatalf("write secret: %v", err) } @@ -237,11 +237,11 @@ func TestXWorkmateBridgeBootstrapTicketLifecycle(t *testing.T) { if err := json.Unmarshal(consumeRec.Body.Bytes(), &consumed); err != nil { t.Fatalf("decode bootstrap consume response: %v", err) } - if consumed.ExchangeToken != "shared-token-value" { - t.Fatalf("expected returned exchange token, got %#v", consumed) + if consumed.BridgeAuthToken != "shared-token-value" { + t.Fatalf("expected returned bridge auth token, got %#v", consumed) } - if consumed.OpenclawURL != "wss://openclaw.example.com" { - t.Fatalf("expected returned openclaw url, got %#v", consumed) + if consumed.BridgeServerURL != "wss://openclaw.example.com" { + t.Fatalf("expected returned bridge server url, got %#v", consumed) } replayReq := httptest.NewRequest(http.MethodPost, "/api/internal/xworkmate/bridge/bootstrap/consume", bytes.NewReader([]byte(fmt.Sprintf(`{"ticket":%q,"bridge":%q}`, created.Ticket, created.Bridge)))) @@ -296,17 +296,17 @@ func TestUpdateAndGetXWorkmateProfileRoundTripsSecretLocators(t *testing.T) { router, _, token := newXWorkmateTestHarness(t) body, err := json.Marshal(map[string]any{ "profile": map[string]any{ - "openclawUrl": "wss://gateway.example.com", - "openclawOrigin": "https://gateway.example.com", - "vaultUrl": "https://vault.example.com", - "vaultNamespace": "team-a", + "BRIDGE_SERVER_URL": "wss://gateway.example.com", + "bridgeServerOrigin": "https://gateway.example.com", + "vaultUrl": "https://vault.example.com", + "vaultNamespace": "team-a", "secretLocators": []map[string]any{ { "id": "locator-openclaw", "provider": "vault", "secretPath": "kv/openclaw", "secretKey": "token", - "target": store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, + "target": store.XWorkmateSecretLocatorTargetBridgeAuthToken, "required": true, }, { @@ -345,11 +345,11 @@ func TestUpdateAndGetXWorkmateProfileRoundTripsSecretLocators(t *testing.T) { var resp struct { Profile struct { - OpenclawURL string `json:"openclawUrl"` - OpenclawOrigin string `json:"openclawOrigin"` - VaultURL string `json:"vaultUrl"` - VaultNamespace string `json:"vaultNamespace"` - SecretLocators []struct { + BridgeServerURL string `json:"BRIDGE_SERVER_URL"` + BridgeServerOrigin string `json:"bridgeServerOrigin"` + VaultURL string `json:"vaultUrl"` + VaultNamespace string `json:"vaultNamespace"` + SecretLocators []struct { ID string `json:"id"` Provider string `json:"provider"` SecretPath string `json:"secretPath"` @@ -362,9 +362,9 @@ func TestUpdateAndGetXWorkmateProfileRoundTripsSecretLocators(t *testing.T) { ApisixURL string `json:"apisixUrl"` } `json:"profile"` TokenConfigured struct { - Openclaw bool `json:"openclaw"` - Vault bool `json:"vault"` - Apisix bool `json:"apisix"` + Bridge bool `json:"bridge"` + Vault bool `json:"vault"` + Apisix bool `json:"apisix"` } `json:"tokenConfigured"` } if err := json.Unmarshal(getRec.Body.Bytes(), &resp); err != nil { @@ -380,14 +380,14 @@ func TestUpdateAndGetXWorkmateProfileRoundTripsSecretLocators(t *testing.T) { if resp.Profile.SecretLocators[0].ID != "locator-openclaw" || !resp.Profile.SecretLocators[0].Required { t.Fatalf("expected openclaw locator to round-trip, got %#v", resp.Profile.SecretLocators[0]) } - if resp.Profile.SecretLocators[0].Target != store.XWorkmateSecretLocatorTargetOpenclawGatewayToken { - t.Fatalf("expected openclaw target, got %#v", resp.Profile.SecretLocators[0]) + if resp.Profile.SecretLocators[0].Target != store.XWorkmateSecretLocatorTargetBridgeAuthToken { + t.Fatalf("expected bridge target, got %#v", resp.Profile.SecretLocators[0]) } if resp.Profile.SecretLocators[1].Target != store.XWorkmateSecretLocatorTargetAIGatewayAccessToken { t.Fatalf("expected ai gateway target, got %#v", resp.Profile.SecretLocators[1]) } - if resp.TokenConfigured.Openclaw { - t.Fatalf("expected openclaw tokenConfigured=false until a vault-backed secret exists") + if resp.TokenConfigured.Bridge { + t.Fatalf("expected bridge tokenConfigured=false until a vault-backed secret exists") } if resp.TokenConfigured.Vault { t.Fatalf("expected vault tokenConfigured=false without a vault-backed token locator") @@ -403,13 +403,13 @@ func TestUpdateXWorkmateProfileSynthesizesSecretLocatorsFromLegacyFields(t *test router, _, token := newXWorkmateTestHarness(t) body, err := json.Marshal(map[string]any{ "profile": map[string]any{ - "openclawUrl": "wss://gateway.example.com", - "openclawOrigin": "https://gateway.example.com", - "vaultUrl": "https://vault.example.com", - "vaultNamespace": "team-a", - "vaultSecretPath": "kv/openclaw", - "vaultSecretKey": "token", - "apisixUrl": "https://apigw.example.com", + "BRIDGE_SERVER_URL": "wss://gateway.example.com", + "bridgeServerOrigin": "https://gateway.example.com", + "vaultUrl": "https://vault.example.com", + "vaultNamespace": "team-a", + "vaultSecretPath": "kv/openclaw", + "vaultSecretKey": "token", + "apisixUrl": "https://apigw.example.com", }, }) if err != nil { @@ -454,8 +454,8 @@ func TestUpdateXWorkmateProfileSynthesizesSecretLocatorsFromLegacyFields(t *test if len(resp.Profile.SecretLocators) != 1 { t.Fatalf("expected synthesized single locator, got %#v", resp.Profile.SecretLocators) } - if resp.Profile.SecretLocators[0].Provider != "vault" || resp.Profile.SecretLocators[0].Target != store.XWorkmateSecretLocatorTargetOpenclawGatewayToken { - t.Fatalf("expected synthesized openclaw vault locator, got %#v", resp.Profile.SecretLocators[0]) + if resp.Profile.SecretLocators[0].Provider != "vault" || resp.Profile.SecretLocators[0].Target != store.XWorkmateSecretLocatorTargetBridgeAuthToken { + t.Fatalf("expected synthesized bridge vault locator, got %#v", resp.Profile.SecretLocators[0]) } if resp.Profile.VaultSecretPath != "kv/openclaw" || resp.Profile.VaultSecretKey != "token" { t.Fatalf("expected legacy fields to remain readable, got %#v", resp.Profile) @@ -472,17 +472,17 @@ func TestGetXWorkmateProfileFallsBackWhenVaultStatusReadFails(t *testing.T) { ) body, err := json.Marshal(map[string]any{ "profile": map[string]any{ - "openclawUrl": "wss://gateway.example.com", - "openclawOrigin": "https://gateway.example.com", - "vaultUrl": "https://vault.example.com", - "vaultNamespace": "team-a", + "BRIDGE_SERVER_URL": "wss://gateway.example.com", + "bridgeServerOrigin": "https://gateway.example.com", + "vaultUrl": "https://vault.example.com", + "vaultNamespace": "team-a", "secretLocators": []map[string]any{ { "id": "locator-openclaw", "provider": "vault", "secretPath": "kv/openclaw", "secretKey": "token", - "target": store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, + "target": store.XWorkmateSecretLocatorTargetBridgeAuthToken, "required": true, }, }, @@ -513,23 +513,23 @@ func TestGetXWorkmateProfileFallsBackWhenVaultStatusReadFails(t *testing.T) { var resp struct { Profile struct { - OpenclawURL string `json:"openclawUrl"` + BridgeServerURL string `json:"BRIDGE_SERVER_URL"` } `json:"profile"` TokenConfigured struct { - Openclaw bool `json:"openclaw"` - Vault bool `json:"vault"` - Apisix bool `json:"apisix"` + Bridge bool `json:"bridge"` + Vault bool `json:"vault"` + Apisix bool `json:"apisix"` } `json:"tokenConfigured"` } if err := json.Unmarshal(getRec.Body.Bytes(), &resp); err != nil { t.Fatalf("decode profile response: %v", err) } - if resp.Profile.OpenclawURL != "wss://gateway.example.com" { + if resp.Profile.BridgeServerURL != "wss://gateway.example.com" { t.Fatalf("expected profile payload to survive vault read failure, got %#v", resp.Profile) } - if !resp.TokenConfigured.Openclaw { - t.Fatalf("expected locator-derived openclaw tokenConfigured fallback, got %#v", resp.TokenConfigured) + if !resp.TokenConfigured.Bridge { + t.Fatalf("expected locator-derived bridge tokenConfigured fallback, got %#v", resp.TokenConfigured) } if resp.TokenConfigured.Vault { t.Fatalf("expected vault tokenConfigured fallback to stay false, got %#v", resp.TokenConfigured) @@ -580,7 +580,7 @@ func TestUpdateXWorkmateProfileRejectsNestedRawTokenFields(t *testing.T) { body, err := json.Marshal(map[string]any{ "profile": map[string]any{ - "openclawUrl": "wss://gateway.example.com", + "BRIDGE_SERVER_URL": "wss://gateway.example.com", "security": map[string]any{ "gatewayToken": "secret-value", }, @@ -618,11 +618,11 @@ func TestXWorkmateSecretsWriteReadDeleteAndKeepLocatorMetadata(t *testing.T) { router, _, token := newXWorkmateTestHarness(t) profileBody, err := json.Marshal(map[string]any{ "profile": map[string]any{ - "openclawUrl": "wss://gateway.example.com", - "openclawOrigin": "https://gateway.example.com", - "vaultUrl": "https://vault.example.com", - "vaultNamespace": "team-a", - "apisixUrl": "https://apigw.example.com", + "BRIDGE_SERVER_URL": "wss://gateway.example.com", + "bridgeServerOrigin": "https://gateway.example.com", + "vaultUrl": "https://vault.example.com", + "vaultNamespace": "team-a", + "apisixUrl": "https://apigw.example.com", }, }) if err != nil { @@ -640,7 +640,7 @@ func TestXWorkmateSecretsWriteReadDeleteAndKeepLocatorMetadata(t *testing.T) { } for _, target := range []string{ - store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, + store.XWorkmateSecretLocatorTargetBridgeAuthToken, store.XWorkmateSecretLocatorTargetVaultRootToken, store.XWorkmateSecretLocatorTargetAIGatewayAccessToken, } { @@ -693,15 +693,15 @@ func TestXWorkmateSecretsWriteReadDeleteAndKeepLocatorMetadata(t *testing.T) { } `json:"secretLocators"` } `json:"profile"` TokenConfigured struct { - Openclaw bool `json:"openclaw"` - Vault bool `json:"vault"` - Apisix bool `json:"apisix"` + Bridge bool `json:"bridge"` + Vault bool `json:"vault"` + Apisix bool `json:"apisix"` } `json:"tokenConfigured"` } if err := json.Unmarshal(getProfileRec.Body.Bytes(), &profileResp); err != nil { t.Fatalf("decode profile response: %v", err) } - if !profileResp.TokenConfigured.Openclaw || !profileResp.TokenConfigured.Vault || !profileResp.TokenConfigured.Apisix { + if !profileResp.TokenConfigured.Bridge || !profileResp.TokenConfigured.Vault || !profileResp.TokenConfigured.Apisix { t.Fatalf("expected all synced tokenConfigured fields true, got %#v", profileResp.TokenConfigured) } if len(profileResp.Profile.SecretLocators) != 3 { @@ -711,7 +711,7 @@ func TestXWorkmateSecretsWriteReadDeleteAndKeepLocatorMetadata(t *testing.T) { t.Fatalf("expected openclaw legacy compatibility fields to remain readable, got %#v", profileResp.Profile) } - deleteReq := httptest.NewRequest(http.MethodDelete, "/api/auth/xworkmate/secrets/"+store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, nil) + deleteReq := httptest.NewRequest(http.MethodDelete, "/api/auth/xworkmate/secrets/"+store.XWorkmateSecretLocatorTargetBridgeAuthToken, nil) deleteReq.Header.Set("Authorization", "Bearer "+token) deleteReq.Header.Set("X-Forwarded-Host", store.SharedXWorkmateDomain) deleteRec := httptest.NewRecorder() @@ -736,16 +736,16 @@ func TestXWorkmateSecretsWriteReadDeleteAndKeepLocatorMetadata(t *testing.T) { } `json:"secretLocators"` } `json:"profile"` TokenConfigured struct { - Openclaw bool `json:"openclaw"` - Vault bool `json:"vault"` - Apisix bool `json:"apisix"` + Bridge bool `json:"bridge"` + Vault bool `json:"vault"` + Apisix bool `json:"apisix"` } `json:"tokenConfigured"` } if err := json.Unmarshal(getProfileAfterDeleteRec.Body.Bytes(), &afterDeleteResp); err != nil { t.Fatalf("decode post-delete profile response: %v", err) } - if afterDeleteResp.TokenConfigured.Openclaw { - t.Fatalf("expected deleted openclaw secret to report missing, got %#v", afterDeleteResp.TokenConfigured) + if afterDeleteResp.TokenConfigured.Bridge { + t.Fatalf("expected deleted bridge secret to report missing, got %#v", afterDeleteResp.TokenConfigured) } if !afterDeleteResp.TokenConfigured.Vault || !afterDeleteResp.TokenConfigured.Apisix { t.Fatalf("expected unrelated secret statuses to remain true, got %#v", afterDeleteResp.TokenConfigured) @@ -772,7 +772,7 @@ func TestXWorkmateSharedSecretsRequireAdminMembershipForWrites(t *testing.T) { t.Fatalf("marshal secret payload: %v", err) } - req := httptest.NewRequest(http.MethodPut, "/api/auth/xworkmate/secrets/"+store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, bytes.NewReader(body)) + req := httptest.NewRequest(http.MethodPut, "/api/auth/xworkmate/secrets/"+store.XWorkmateSecretLocatorTargetBridgeAuthToken, bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("X-Forwarded-Host", store.SharedXWorkmateDomain) @@ -867,7 +867,7 @@ func TestXWorkmatePrivateSecretsAreScopedPerUser(t *testing.T) { if err != nil { t.Fatalf("marshal secret payload: %v", err) } - writeReq := httptest.NewRequest(http.MethodPut, "/api/auth/xworkmate/secrets/"+store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, bytes.NewReader(body)) + writeReq := httptest.NewRequest(http.MethodPut, "/api/auth/xworkmate/secrets/"+store.XWorkmateSecretLocatorTargetBridgeAuthToken, bytes.NewReader(body)) writeReq.Header.Set("Content-Type", "application/json") writeReq.Header.Set("Authorization", "Bearer "+tokenA) writeReq.Header.Set("X-Forwarded-Host", "tenant-private-1.svc.plus") @@ -897,25 +897,25 @@ func TestXWorkmatePrivateSecretsAreScopedPerUser(t *testing.T) { var userAResp struct { TokenConfigured struct { - Openclaw bool `json:"openclaw"` + Bridge bool `json:"bridge"` } `json:"tokenConfigured"` } if err := json.Unmarshal(getARec.Body.Bytes(), &userAResp); err != nil { t.Fatalf("decode user A profile response: %v", err) } - if !userAResp.TokenConfigured.Openclaw { + if !userAResp.TokenConfigured.Bridge { t.Fatalf("expected user A secret to be configured, got %#v", userAResp.TokenConfigured) } var userBResp struct { TokenConfigured struct { - Openclaw bool `json:"openclaw"` + Bridge bool `json:"bridge"` } `json:"tokenConfigured"` } if err := json.Unmarshal(getBRec.Body.Bytes(), &userBResp); err != nil { t.Fatalf("decode user B profile response: %v", err) } - if userBResp.TokenConfigured.Openclaw { + if userBResp.TokenConfigured.Bridge { t.Fatalf("expected user B to remain isolated from user A secret, got %#v", userBResp.TokenConfigured) } } diff --git a/api/xworkmate_vault.go b/api/xworkmate_vault.go index 9889b74..40a6394 100644 --- a/api/xworkmate_vault.go +++ b/api/xworkmate_vault.go @@ -54,9 +54,9 @@ type xworkmateManagedSecretTarget struct { var xworkmateManagedSecretTargets = []xworkmateManagedSecretTarget{ { - Target: store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, + Target: store.XWorkmateSecretLocatorTargetBridgeAuthToken, Required: true, - TokenConfiguredID: "openclaw", + TokenConfiguredID: "bridge", }, { Target: store.XWorkmateSecretLocatorTargetVaultRootToken, diff --git a/internal/model/xworkmate_tenant.go b/internal/model/xworkmate_tenant.go index e971bf3..dcf4a4a 100644 --- a/internal/model/xworkmate_tenant.go +++ b/internal/model/xworkmate_tenant.go @@ -56,20 +56,20 @@ type TenantMembership struct { func (TenantMembership) TableName() string { return "tenant_memberships" } type XWorkmateProfile struct { - ID string `gorm:"column:id;type:text;primaryKey"` - TenantID string `gorm:"column:tenant_id;type:text;not null;uniqueIndex:idx_xworkmate_profiles_scope"` - UserID string `gorm:"column:user_id;type:text;not null;default:'';uniqueIndex:idx_xworkmate_profiles_scope"` - Scope string `gorm:"column:scope;type:text;not null;uniqueIndex:idx_xworkmate_profiles_scope"` - OpenclawURL string `gorm:"column:openclaw_url;type:text;not null;default:''"` - OpenclawOrigin string `gorm:"column:openclaw_origin;type:text;not null;default:''"` - VaultURL string `gorm:"column:vault_url;type:text;not null;default:''"` - VaultNamespace string `gorm:"column:vault_namespace;type:text;not null;default:''"` - VaultSecretPath string `gorm:"column:vault_secret_path;type:text;not null;default:''"` - VaultSecretKey string `gorm:"column:vault_secret_key;type:text;not null;default:''"` - SecretLocators []XWorkmateSecretLocator `gorm:"column:secret_locators;type:text;not null;serializer:json;default:'[]'"` - ApisixURL string `gorm:"column:apisix_url;type:text;not null;default:''"` - CreatedAt time.Time `gorm:"column:created_at;not null;autoCreateTime"` - UpdatedAt time.Time `gorm:"column:updated_at;not null;autoUpdateTime"` + ID string `gorm:"column:id;type:text;primaryKey"` + TenantID string `gorm:"column:tenant_id;type:text;not null;uniqueIndex:idx_xworkmate_profiles_scope"` + UserID string `gorm:"column:user_id;type:text;not null;default:'';uniqueIndex:idx_xworkmate_profiles_scope"` + Scope string `gorm:"column:scope;type:text;not null;uniqueIndex:idx_xworkmate_profiles_scope"` + BridgeServerURL string `gorm:"column:openclaw_url;type:text;not null;default:''"` + BridgeServerOrigin string `gorm:"column:openclaw_origin;type:text;not null;default:''"` + VaultURL string `gorm:"column:vault_url;type:text;not null;default:''"` + VaultNamespace string `gorm:"column:vault_namespace;type:text;not null;default:''"` + VaultSecretPath string `gorm:"column:vault_secret_path;type:text;not null;default:''"` + VaultSecretKey string `gorm:"column:vault_secret_key;type:text;not null;default:''"` + SecretLocators []XWorkmateSecretLocator `gorm:"column:secret_locators;type:text;not null;serializer:json;default:'[]'"` + ApisixURL string `gorm:"column:apisix_url;type:text;not null;default:''"` + CreatedAt time.Time `gorm:"column:created_at;not null;autoCreateTime"` + UpdatedAt time.Time `gorm:"column:updated_at;not null;autoUpdateTime"` } type XWorkmateSecretLocator struct { diff --git a/internal/store/xworkmate.go b/internal/store/xworkmate.go index 03db152..3a63a59 100644 --- a/internal/store/xworkmate.go +++ b/internal/store/xworkmate.go @@ -32,7 +32,7 @@ const ( XWorkmateSecretLocatorProviderVault = "vault" - XWorkmateSecretLocatorTargetOpenclawGatewayToken = "openclaw.gateway_token" + XWorkmateSecretLocatorTargetBridgeAuthToken = "bridge.auth_token" XWorkmateSecretLocatorTargetVaultRootToken = "vault.root_token" XWorkmateSecretLocatorTargetAIGatewayAccessToken = "ai_gateway.access_token" XWorkmateSecretLocatorTargetOllamaCloudAPIKey = "ollama_cloud.api_key" @@ -79,20 +79,20 @@ type TenantMembership struct { } type XWorkmateProfile struct { - ID string - TenantID string - UserID string - Scope string - OpenclawURL string - OpenclawOrigin string - VaultURL string - VaultNamespace string - VaultSecretPath string - VaultSecretKey string - SecretLocators []XWorkmateSecretLocator - ApisixURL string - CreatedAt time.Time - UpdatedAt time.Time + ID string + TenantID string + UserID string + Scope string + BridgeServerURL string + BridgeServerOrigin string + VaultURL string + VaultNamespace string + VaultSecretPath string + VaultSecretKey string + SecretLocators []XWorkmateSecretLocator + ApisixURL string + CreatedAt time.Time + UpdatedAt time.Time } type XWorkmateSecretLocator struct { @@ -179,7 +179,7 @@ func cloneXWorkmateSecretLocators(locators []XWorkmateSecretLocator) []XWorkmate func legacyXWorkmateSecretLocatorID(profile *XWorkmateProfile) string { if profile == nil { - return "legacy|xworkmate|openclaw.gateway_token" + return "legacy|xworkmate|bridge.auth_token" } return strings.Join([]string{ @@ -187,7 +187,7 @@ func legacyXWorkmateSecretLocatorID(profile *XWorkmateProfile) string { strings.TrimSpace(profile.TenantID), strings.TrimSpace(profile.UserID), NormalizeXWorkmateProfileScope(profile.Scope), - XWorkmateSecretLocatorTargetOpenclawGatewayToken, + XWorkmateSecretLocatorTargetBridgeAuthToken, }, "|") } @@ -197,13 +197,13 @@ func synthesizeXWorkmateSecretLocatorFromLegacy(profile *XWorkmateProfile) XWork Provider: XWorkmateSecretLocatorProviderVault, SecretPath: profile.VaultSecretPath, SecretKey: profile.VaultSecretKey, - Target: XWorkmateSecretLocatorTargetOpenclawGatewayToken, + Target: XWorkmateSecretLocatorTargetBridgeAuthToken, } } func compatibilityXWorkmateSecretLocator(locators []XWorkmateSecretLocator) (string, string, bool) { for _, locator := range locators { - if locator.Target == XWorkmateSecretLocatorTargetOpenclawGatewayToken && + if locator.Target == XWorkmateSecretLocatorTargetBridgeAuthToken && locator.SecretPath != "" && locator.SecretKey != "" { return locator.SecretPath, locator.SecretKey, true } @@ -292,8 +292,8 @@ func NormalizeXWorkmateProfile(profile *XWorkmateProfile) { profile.TenantID = strings.TrimSpace(profile.TenantID) profile.UserID = strings.TrimSpace(profile.UserID) profile.Scope = NormalizeXWorkmateProfileScope(profile.Scope) - profile.OpenclawURL = strings.TrimSpace(profile.OpenclawURL) - profile.OpenclawOrigin = strings.TrimSpace(profile.OpenclawOrigin) + profile.BridgeServerURL = strings.TrimSpace(profile.BridgeServerURL) + profile.BridgeServerOrigin = strings.TrimSpace(profile.BridgeServerOrigin) profile.VaultURL = strings.TrimSpace(profile.VaultURL) profile.VaultNamespace = strings.TrimSpace(profile.VaultNamespace) profile.VaultSecretPath = strings.Trim(strings.TrimSpace(profile.VaultSecretPath), "/") diff --git a/internal/store/xworkmate_memory.go b/internal/store/xworkmate_memory.go index 8927f1f..5d3a19e 100644 --- a/internal/store/xworkmate_memory.go +++ b/internal/store/xworkmate_memory.go @@ -290,8 +290,8 @@ func (s *memoryStore) UpsertXWorkmateProfile(ctx context.Context, profile *XWork defer s.mu.Unlock() if existing, ok := s.xworkmateProfiles[key]; ok { - existing.OpenclawURL = profile.OpenclawURL - existing.OpenclawOrigin = profile.OpenclawOrigin + existing.BridgeServerURL = profile.BridgeServerURL + existing.BridgeServerOrigin = profile.BridgeServerOrigin existing.VaultURL = profile.VaultURL existing.VaultNamespace = profile.VaultNamespace existing.VaultSecretPath = profile.VaultSecretPath @@ -305,20 +305,20 @@ func (s *memoryStore) UpsertXWorkmateProfile(ctx context.Context, profile *XWork } stored := &XWorkmateProfile{ - ID: profile.ID, - TenantID: profile.TenantID, - UserID: profile.UserID, - Scope: profile.Scope, - OpenclawURL: profile.OpenclawURL, - OpenclawOrigin: profile.OpenclawOrigin, - VaultURL: profile.VaultURL, - VaultNamespace: profile.VaultNamespace, - VaultSecretPath: profile.VaultSecretPath, - VaultSecretKey: profile.VaultSecretKey, - SecretLocators: cloneXWorkmateSecretLocators(profile.SecretLocators), - ApisixURL: profile.ApisixURL, - CreatedAt: now, - UpdatedAt: now, + ID: profile.ID, + TenantID: profile.TenantID, + UserID: profile.UserID, + Scope: profile.Scope, + BridgeServerURL: profile.BridgeServerURL, + BridgeServerOrigin: profile.BridgeServerOrigin, + VaultURL: profile.VaultURL, + VaultNamespace: profile.VaultNamespace, + VaultSecretPath: profile.VaultSecretPath, + VaultSecretKey: profile.VaultSecretKey, + SecretLocators: cloneXWorkmateSecretLocators(profile.SecretLocators), + ApisixURL: profile.ApisixURL, + CreatedAt: now, + UpdatedAt: now, } s.xworkmateProfiles[key] = stored profile.CreatedAt = stored.CreatedAt diff --git a/internal/store/xworkmate_postgres.go b/internal/store/xworkmate_postgres.go index 4409e7f..6c04ccf 100644 --- a/internal/store/xworkmate_postgres.go +++ b/internal/store/xworkmate_postgres.go @@ -242,8 +242,8 @@ LIMIT 1` &profile.TenantID, &profile.UserID, &profile.Scope, - &profile.OpenclawURL, - &profile.OpenclawOrigin, + &profile.BridgeServerURL, + &profile.BridgeServerOrigin, &profile.VaultURL, &profile.VaultNamespace, &profile.VaultSecretPath, @@ -304,8 +304,8 @@ RETURNING created_at, updated_at` profile.TenantID, profile.UserID, profile.Scope, - profile.OpenclawURL, - profile.OpenclawOrigin, + profile.BridgeServerURL, + profile.BridgeServerOrigin, profile.VaultURL, profile.VaultNamespace, profile.VaultSecretPath, diff --git a/internal/store/xworkmate_test.go b/internal/store/xworkmate_test.go index ab10f49..bded73b 100644 --- a/internal/store/xworkmate_test.go +++ b/internal/store/xworkmate_test.go @@ -87,7 +87,7 @@ func TestMemoryStoreResolveTenantAndProfile(t *testing.T) { TenantID: privateTenant.ID, UserID: "user-1", Scope: XWorkmateProfileScopeUserPrivate, - OpenclawURL: "wss://openclaw.tenant-one.svc.plus", + BridgeServerURL: "wss://openclaw.tenant-one.svc.plus", VaultSecretPath: "kv/openclaw", VaultSecretKey: "token", }); err != nil { @@ -109,8 +109,8 @@ func TestMemoryStoreResolveTenantAndProfile(t *testing.T) { if err != nil { t.Fatalf("get private profile: %v", err) } - if profile.OpenclawURL != "wss://openclaw.tenant-one.svc.plus" { - t.Fatalf("expected persisted openclaw url, got %q", profile.OpenclawURL) + if profile.BridgeServerURL != "wss://openclaw.tenant-one.svc.plus" { + t.Fatalf("expected persisted bridge server url, got %q", profile.BridgeServerURL) } if profile.VaultSecretPath != "kv/openclaw" || profile.VaultSecretKey != "token" { t.Fatalf("expected legacy secret fields to round-trip, got %#v", profile) @@ -121,8 +121,8 @@ func TestMemoryStoreResolveTenantAndProfile(t *testing.T) { if profile.SecretLocators[0].Provider != XWorkmateSecretLocatorProviderVault { t.Fatalf("expected vault provider, got %#v", profile.SecretLocators[0]) } - if profile.SecretLocators[0].Target != XWorkmateSecretLocatorTargetOpenclawGatewayToken { - t.Fatalf("expected openclaw target, got %#v", profile.SecretLocators[0]) + if profile.SecretLocators[0].Target != XWorkmateSecretLocatorTargetBridgeAuthToken { + t.Fatalf("expected bridge auth token target, got %#v", profile.SecretLocators[0]) } if profile.SecretLocators[0].SecretPath != "kv/openclaw" || profile.SecretLocators[0].SecretKey != "token" { t.Fatalf("expected synthesized secret locator path/key, got %#v", profile.SecretLocators[0]) @@ -158,7 +158,7 @@ func TestMemoryStorePersistsExplicitSecretLocators(t *testing.T) { Provider: "vault", SecretPath: "kv/openclaw", SecretKey: "gateway-token", - Target: XWorkmateSecretLocatorTargetOpenclawGatewayToken, + Target: XWorkmateSecretLocatorTargetBridgeAuthToken, Required: true, }, {