Unify bridge sync contract names

This commit is contained in:
Haitao Pan 2026-04-11 20:25:40 +08:00
parent 412573bdbd
commit 9b0d99c7f0
9 changed files with 205 additions and 204 deletions

View File

@ -26,14 +26,14 @@ type xworkmateAccessContext struct {
} }
type xworkmateProfilePayload struct { type xworkmateProfilePayload struct {
OpenclawURL string `json:"openclawUrl"` BridgeServerURL string `json:"BRIDGE_SERVER_URL"`
OpenclawOrigin string `json:"openclawOrigin"` BridgeServerOrigin string `json:"bridgeServerOrigin"`
VaultURL string `json:"vaultUrl"` VaultURL string `json:"vaultUrl"`
VaultNamespace string `json:"vaultNamespace"` VaultNamespace string `json:"vaultNamespace"`
VaultSecretPath string `json:"vaultSecretPath"` VaultSecretPath string `json:"vaultSecretPath"`
VaultSecretKey string `json:"vaultSecretKey"` VaultSecretKey string `json:"vaultSecretKey"`
SecretLocators []xworkmateSecretLocatorPayload `json:"secretLocators"` SecretLocators []xworkmateSecretLocatorPayload `json:"secretLocators"`
ApisixURL string `json:"apisixUrl"` ApisixURL string `json:"apisixUrl"`
} }
type xworkmateSecretLocatorPayload struct { type xworkmateSecretLocatorPayload struct {
@ -46,10 +46,11 @@ type xworkmateSecretLocatorPayload struct {
} }
var xworkmateForbiddenTokenFields = map[string]struct{}{ var xworkmateForbiddenTokenFields = map[string]struct{}{
"openclawtoken": {}, "bridge_auth_token": {},
"gatewaytoken": {}, "bridgeauthtoken": {},
"vaulttoken": {}, "gatewaytoken": {},
"apisixtoken": {}, "vaulttoken": {},
"apisixtoken": {},
} }
func (h *handler) ensureSharedXWorkmateTenant(ctx context.Context) error { 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 { func buildXWorkmateTokenConfigured(profile *store.XWorkmateProfile) gin.H {
result := gin.H{ result := gin.H{
"openclaw": false, "bridge": false,
"vault": false, "vault": false,
"apisix": false, "apisix": false,
} }
if profile == nil { if profile == nil {
return result return result
} }
if hasOpenclawXWorkmateSecretLocator(profile) { if hasBridgeAuthTokenXWorkmateSecretLocator(profile) {
result["openclaw"] = true result["bridge"] = true
} }
return result return result
@ -277,8 +278,8 @@ func buildXWorkmateTokenConfiguredWithVaultStatus(profile *store.XWorkmateProfil
return result return result
} }
if configured, ok := vaultStatus[store.XWorkmateSecretLocatorTargetOpenclawGatewayToken]; ok { if configured, ok := vaultStatus[store.XWorkmateSecretLocatorTargetBridgeAuthToken]; ok {
result["openclaw"] = configured result["bridge"] = configured
} }
if configured, ok := vaultStatus[store.XWorkmateSecretLocatorTargetVaultRootToken]; ok { if configured, ok := vaultStatus[store.XWorkmateSecretLocatorTargetVaultRootToken]; ok {
result["vault"] = configured result["vault"] = configured
@ -290,7 +291,7 @@ func buildXWorkmateTokenConfiguredWithVaultStatus(profile *store.XWorkmateProfil
return result return result
} }
func hasOpenclawXWorkmateSecretLocator(profile *store.XWorkmateProfile) bool { func hasBridgeAuthTokenXWorkmateSecretLocator(profile *store.XWorkmateProfile) bool {
if profile == nil { if profile == nil {
return false return false
} }
@ -299,7 +300,7 @@ func hasOpenclawXWorkmateSecretLocator(profile *store.XWorkmateProfile) bool {
return true return true
} }
for _, locator := range profile.SecretLocators { for _, locator := range profile.SecretLocators {
if locator.Target != store.XWorkmateSecretLocatorTargetOpenclawGatewayToken { if locator.Target != store.XWorkmateSecretLocatorTargetBridgeAuthToken {
continue continue
} }
if strings.TrimSpace(locator.SecretPath) != "" && strings.TrimSpace(locator.SecretKey) != "" { 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 { func buildXWorkmateProfileResponse(access *xworkmateAccessContext, profile *store.XWorkmateProfile, tokenConfigured gin.H) gin.H {
resolvedProfile := gin.H{ resolvedProfile := gin.H{
"openclawUrl": "", "BRIDGE_SERVER_URL": "",
"openclawOrigin": "", "bridgeServerOrigin": "",
"vaultUrl": "", "vaultUrl": "",
"vaultNamespace": "", "vaultNamespace": "",
"vaultSecretPath": "", "vaultSecretPath": "",
"vaultSecretKey": "", "vaultSecretKey": "",
"secretLocators": []gin.H{}, "secretLocators": []gin.H{},
"apisixUrl": "", "apisixUrl": "",
} }
if profile != nil { if profile != nil {
resolvedProfile["openclawUrl"] = profile.OpenclawURL resolvedProfile["BRIDGE_SERVER_URL"] = profile.BridgeServerURL
resolvedProfile["openclawOrigin"] = profile.OpenclawOrigin resolvedProfile["bridgeServerOrigin"] = profile.BridgeServerOrigin
resolvedProfile["vaultUrl"] = profile.VaultURL resolvedProfile["vaultUrl"] = profile.VaultURL
resolvedProfile["vaultNamespace"] = profile.VaultNamespace resolvedProfile["vaultNamespace"] = profile.VaultNamespace
resolvedProfile["vaultSecretPath"] = profile.VaultSecretPath resolvedProfile["vaultSecretPath"] = profile.VaultSecretPath
@ -546,8 +547,8 @@ func statusByTargetFromMetadata(profile *store.XWorkmateProfile, target string)
if profile == nil { if profile == nil {
return false return false
} }
if target == store.XWorkmateSecretLocatorTargetOpenclawGatewayToken { if target == store.XWorkmateSecretLocatorTargetBridgeAuthToken {
return hasOpenclawXWorkmateSecretLocator(profile) return hasBridgeAuthTokenXWorkmateSecretLocator(profile)
} }
for _, locator := range profile.SecretLocators { for _, locator := range profile.SecretLocators {
if locator.Target == strings.ToLower(strings.TrimSpace(target)) && if locator.Target == strings.ToLower(strings.TrimSpace(target)) &&
@ -677,17 +678,17 @@ func (h *handler) updateXWorkmateProfile(c *gin.Context) {
profileUserID := resolvedXWorkmateProfileUserID(access, user) profileUserID := resolvedXWorkmateProfileUserID(access, user)
profile := &store.XWorkmateProfile{ profile := &store.XWorkmateProfile{
TenantID: access.Tenant.ID, TenantID: access.Tenant.ID,
UserID: profileUserID, UserID: profileUserID,
Scope: access.ProfileScope, Scope: access.ProfileScope,
OpenclawURL: payload.OpenclawURL, BridgeServerURL: payload.BridgeServerURL,
OpenclawOrigin: payload.OpenclawOrigin, BridgeServerOrigin: payload.BridgeServerOrigin,
VaultURL: payload.VaultURL, VaultURL: payload.VaultURL,
VaultNamespace: payload.VaultNamespace, VaultNamespace: payload.VaultNamespace,
VaultSecretPath: payload.VaultSecretPath, VaultSecretPath: payload.VaultSecretPath,
VaultSecretKey: payload.VaultSecretKey, VaultSecretKey: payload.VaultSecretKey,
SecretLocators: buildStoreXWorkmateSecretLocators(payload.SecretLocators), SecretLocators: buildStoreXWorkmateSecretLocators(payload.SecretLocators),
ApisixURL: payload.ApisixURL, ApisixURL: payload.ApisixURL,
} }
if err := h.store.UpsertXWorkmateProfile(c.Request.Context(), profile); err != nil { if err := h.store.UpsertXWorkmateProfile(c.Request.Context(), profile); err != nil {
respondError(c, http.StatusInternalServerError, "xworkmate_profile_write_failed", "failed to save xworkmate profile") respondError(c, http.StatusInternalServerError, "xworkmate_profile_write_failed", "failed to save xworkmate profile")

View File

@ -50,13 +50,13 @@ type bridgeBootstrapIssueResponse struct {
} }
type bridgeBootstrapConsumeResponse struct { type bridgeBootstrapConsumeResponse struct {
TicketID string `json:"ticketId"` TicketID string `json:"ticketId"`
TargetBridge string `json:"targetBridge"` TargetBridge string `json:"targetBridge"`
OpenclawURL string `json:"openclawUrl"` BridgeServerURL string `json:"BRIDGE_SERVER_URL"`
AuthMode string `json:"authMode"` AuthMode string `json:"authMode"`
ExchangeToken string `json:"exchangeToken"` BridgeAuthToken string `json:"BRIDGE_AUTH_TOKEN"`
ExpiresAt string `json:"expiresAt"` ExpiresAt string `json:"expiresAt"`
Scopes []string `json:"scopes"` Scopes []string `json:"scopes"`
} }
func sanitizeBridgeTarget(raw string) string { 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") respondError(c, http.StatusNotFound, "xworkmate_profile_not_found", "xworkmate profile not found")
return return
} }
locator, ok := findStoredXWorkmateSecretLocator(profile, store.XWorkmateSecretLocatorTargetOpenclawGatewayToken) locator, ok := findStoredXWorkmateSecretLocator(profile, store.XWorkmateSecretLocatorTargetBridgeAuthToken)
if !ok { if !ok {
respondError(c, http.StatusConflict, "gateway_token_not_configured", "gateway token is not configured") respondError(c, http.StatusConflict, "gateway_token_not_configured", "gateway token is not configured")
return return
@ -298,8 +298,8 @@ func (h *handler) internalConsumeXWorkmateBridgeBootstrapTicket(c *gin.Context)
respondError(c, http.StatusConflict, "gateway_token_unavailable", "gateway token is unavailable") respondError(c, http.StatusConflict, "gateway_token_unavailable", "gateway token is unavailable")
return return
} }
openclawURL := strings.TrimSpace(profile.OpenclawURL) bridgeServerURL := strings.TrimSpace(profile.BridgeServerURL)
if openclawURL == "" { if bridgeServerURL == "" {
respondError(c, http.StatusConflict, "gateway_endpoint_not_configured", "gateway endpoint is not configured") respondError(c, http.StatusConflict, "gateway_endpoint_not_configured", "gateway endpoint is not configured")
return return
} }
@ -308,12 +308,12 @@ func (h *handler) internalConsumeXWorkmateBridgeBootstrapTicket(c *gin.Context)
h.updateBridgeBootstrapTicket(ticket) h.updateBridgeBootstrapTicket(ticket)
c.JSON(http.StatusOK, bridgeBootstrapConsumeResponse{ c.JSON(http.StatusOK, bridgeBootstrapConsumeResponse{
TicketID: ticket.TicketID, TicketID: ticket.TicketID,
TargetBridge: ticket.TargetBridge, TargetBridge: ticket.TargetBridge,
OpenclawURL: openclawURL, BridgeServerURL: bridgeServerURL,
AuthMode: "shared-token", AuthMode: "shared-token",
ExchangeToken: gatewayToken, BridgeAuthToken: gatewayToken,
ExpiresAt: ticket.ExpiresAt.Format(time.RFC3339), ExpiresAt: ticket.ExpiresAt.Format(time.RFC3339),
Scopes: append([]string(nil), ticket.Scopes...), Scopes: append([]string(nil), ticket.Scopes...),
}) })
} }

View File

@ -83,11 +83,11 @@ func TestBuildXWorkmateTokenConfiguredUsesSecretLocators(t *testing.T) {
t.Parallel() t.Parallel()
tests := []struct { tests := []struct {
name string name string
profile *store.XWorkmateProfile profile *store.XWorkmateProfile
openclaw bool bridge bool
vault bool vault bool
apisix bool apisix bool
}{ }{
{ {
name: "missing secret key stays false", 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{ profile: &store.XWorkmateProfile{
VaultSecretPath: "kv/openclaw", VaultSecretPath: "kv/openclaw",
VaultSecretKey: "token", VaultSecretKey: "token",
}, },
openclaw: true, bridge: true,
}, },
{ {
name: "explicit openclaw locator marks openclaw configured", name: "explicit bridge locator marks bridge configured",
profile: &store.XWorkmateProfile{ profile: &store.XWorkmateProfile{
SecretLocators: []store.XWorkmateSecretLocator{ SecretLocators: []store.XWorkmateSecretLocator{
{ {
Provider: "vault", Provider: "vault",
SecretPath: "kv/openclaw", SecretPath: "kv/openclaw",
SecretKey: "token", SecretKey: "token",
Target: store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, Target: store.XWorkmateSecretLocatorTargetBridgeAuthToken,
}, },
}, },
}, },
openclaw: true, bridge: true,
}, },
{ {
name: "other locator stays false", name: "other locator stays false",
@ -142,8 +142,8 @@ func TestBuildXWorkmateTokenConfiguredUsesSecretLocators(t *testing.T) {
t.Parallel() t.Parallel()
result := buildXWorkmateTokenConfigured(tt.profile) result := buildXWorkmateTokenConfigured(tt.profile)
if got := result["openclaw"].(bool); got != tt.openclaw { if got := result["bridge"].(bool); got != tt.bridge {
t.Fatalf("expected openclaw=%v, got %v", tt.openclaw, got) t.Fatalf("expected bridge=%v, got %v", tt.bridge, got)
} }
if got := result["vault"].(bool); got != tt.vault { if got := result["vault"].(bool); got != tt.vault {
t.Fatalf("expected vault=%v, got %v", tt.vault, got) 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{ profileBody, err := json.Marshal(map[string]any{
"profile": map[string]any{ "profile": map[string]any{
"openclawUrl": "wss://openclaw.example.com", "BRIDGE_SERVER_URL": "wss://openclaw.example.com",
"secretLocators": []map[string]any{ "secretLocators": []map[string]any{
{ {
"id": "locator-openclaw", "id": "locator-openclaw",
"provider": "vault", "provider": "vault",
"secretPath": "kv/openclaw", "secretPath": "kv/openclaw",
"secretKey": "token", "secretKey": "token",
"target": store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, "target": store.XWorkmateSecretLocatorTargetBridgeAuthToken,
"required": true, "required": true,
}, },
}, },
@ -193,7 +193,7 @@ func TestXWorkmateBridgeBootstrapTicketLifecycle(t *testing.T) {
Provider: "vault", Provider: "vault",
SecretPath: "kv/openclaw", SecretPath: "kv/openclaw",
SecretKey: "token", SecretKey: "token",
Target: store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, Target: store.XWorkmateSecretLocatorTargetBridgeAuthToken,
}, "shared-token-value"); err != nil { }, "shared-token-value"); err != nil {
t.Fatalf("write secret: %v", err) 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 { if err := json.Unmarshal(consumeRec.Body.Bytes(), &consumed); err != nil {
t.Fatalf("decode bootstrap consume response: %v", err) t.Fatalf("decode bootstrap consume response: %v", err)
} }
if consumed.ExchangeToken != "shared-token-value" { if consumed.BridgeAuthToken != "shared-token-value" {
t.Fatalf("expected returned exchange token, got %#v", consumed) t.Fatalf("expected returned bridge auth token, got %#v", consumed)
} }
if consumed.OpenclawURL != "wss://openclaw.example.com" { if consumed.BridgeServerURL != "wss://openclaw.example.com" {
t.Fatalf("expected returned openclaw url, got %#v", consumed) 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)))) 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) router, _, token := newXWorkmateTestHarness(t)
body, err := json.Marshal(map[string]any{ body, err := json.Marshal(map[string]any{
"profile": map[string]any{ "profile": map[string]any{
"openclawUrl": "wss://gateway.example.com", "BRIDGE_SERVER_URL": "wss://gateway.example.com",
"openclawOrigin": "https://gateway.example.com", "bridgeServerOrigin": "https://gateway.example.com",
"vaultUrl": "https://vault.example.com", "vaultUrl": "https://vault.example.com",
"vaultNamespace": "team-a", "vaultNamespace": "team-a",
"secretLocators": []map[string]any{ "secretLocators": []map[string]any{
{ {
"id": "locator-openclaw", "id": "locator-openclaw",
"provider": "vault", "provider": "vault",
"secretPath": "kv/openclaw", "secretPath": "kv/openclaw",
"secretKey": "token", "secretKey": "token",
"target": store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, "target": store.XWorkmateSecretLocatorTargetBridgeAuthToken,
"required": true, "required": true,
}, },
{ {
@ -345,11 +345,11 @@ func TestUpdateAndGetXWorkmateProfileRoundTripsSecretLocators(t *testing.T) {
var resp struct { var resp struct {
Profile struct { Profile struct {
OpenclawURL string `json:"openclawUrl"` BridgeServerURL string `json:"BRIDGE_SERVER_URL"`
OpenclawOrigin string `json:"openclawOrigin"` BridgeServerOrigin string `json:"bridgeServerOrigin"`
VaultURL string `json:"vaultUrl"` VaultURL string `json:"vaultUrl"`
VaultNamespace string `json:"vaultNamespace"` VaultNamespace string `json:"vaultNamespace"`
SecretLocators []struct { SecretLocators []struct {
ID string `json:"id"` ID string `json:"id"`
Provider string `json:"provider"` Provider string `json:"provider"`
SecretPath string `json:"secretPath"` SecretPath string `json:"secretPath"`
@ -362,9 +362,9 @@ func TestUpdateAndGetXWorkmateProfileRoundTripsSecretLocators(t *testing.T) {
ApisixURL string `json:"apisixUrl"` ApisixURL string `json:"apisixUrl"`
} `json:"profile"` } `json:"profile"`
TokenConfigured struct { TokenConfigured struct {
Openclaw bool `json:"openclaw"` Bridge bool `json:"bridge"`
Vault bool `json:"vault"` Vault bool `json:"vault"`
Apisix bool `json:"apisix"` Apisix bool `json:"apisix"`
} `json:"tokenConfigured"` } `json:"tokenConfigured"`
} }
if err := json.Unmarshal(getRec.Body.Bytes(), &resp); err != nil { 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 { 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]) t.Fatalf("expected openclaw locator to round-trip, got %#v", resp.Profile.SecretLocators[0])
} }
if resp.Profile.SecretLocators[0].Target != store.XWorkmateSecretLocatorTargetOpenclawGatewayToken { if resp.Profile.SecretLocators[0].Target != store.XWorkmateSecretLocatorTargetBridgeAuthToken {
t.Fatalf("expected openclaw target, got %#v", resp.Profile.SecretLocators[0]) t.Fatalf("expected bridge target, got %#v", resp.Profile.SecretLocators[0])
} }
if resp.Profile.SecretLocators[1].Target != store.XWorkmateSecretLocatorTargetAIGatewayAccessToken { if resp.Profile.SecretLocators[1].Target != store.XWorkmateSecretLocatorTargetAIGatewayAccessToken {
t.Fatalf("expected ai gateway target, got %#v", resp.Profile.SecretLocators[1]) t.Fatalf("expected ai gateway target, got %#v", resp.Profile.SecretLocators[1])
} }
if resp.TokenConfigured.Openclaw { if resp.TokenConfigured.Bridge {
t.Fatalf("expected openclaw tokenConfigured=false until a vault-backed secret exists") t.Fatalf("expected bridge tokenConfigured=false until a vault-backed secret exists")
} }
if resp.TokenConfigured.Vault { if resp.TokenConfigured.Vault {
t.Fatalf("expected vault tokenConfigured=false without a vault-backed token locator") t.Fatalf("expected vault tokenConfigured=false without a vault-backed token locator")
@ -403,13 +403,13 @@ func TestUpdateXWorkmateProfileSynthesizesSecretLocatorsFromLegacyFields(t *test
router, _, token := newXWorkmateTestHarness(t) router, _, token := newXWorkmateTestHarness(t)
body, err := json.Marshal(map[string]any{ body, err := json.Marshal(map[string]any{
"profile": map[string]any{ "profile": map[string]any{
"openclawUrl": "wss://gateway.example.com", "BRIDGE_SERVER_URL": "wss://gateway.example.com",
"openclawOrigin": "https://gateway.example.com", "bridgeServerOrigin": "https://gateway.example.com",
"vaultUrl": "https://vault.example.com", "vaultUrl": "https://vault.example.com",
"vaultNamespace": "team-a", "vaultNamespace": "team-a",
"vaultSecretPath": "kv/openclaw", "vaultSecretPath": "kv/openclaw",
"vaultSecretKey": "token", "vaultSecretKey": "token",
"apisixUrl": "https://apigw.example.com", "apisixUrl": "https://apigw.example.com",
}, },
}) })
if err != nil { if err != nil {
@ -454,8 +454,8 @@ func TestUpdateXWorkmateProfileSynthesizesSecretLocatorsFromLegacyFields(t *test
if len(resp.Profile.SecretLocators) != 1 { if len(resp.Profile.SecretLocators) != 1 {
t.Fatalf("expected synthesized single locator, got %#v", resp.Profile.SecretLocators) 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 { if resp.Profile.SecretLocators[0].Provider != "vault" || resp.Profile.SecretLocators[0].Target != store.XWorkmateSecretLocatorTargetBridgeAuthToken {
t.Fatalf("expected synthesized openclaw vault locator, got %#v", resp.Profile.SecretLocators[0]) t.Fatalf("expected synthesized bridge vault locator, got %#v", resp.Profile.SecretLocators[0])
} }
if resp.Profile.VaultSecretPath != "kv/openclaw" || resp.Profile.VaultSecretKey != "token" { if resp.Profile.VaultSecretPath != "kv/openclaw" || resp.Profile.VaultSecretKey != "token" {
t.Fatalf("expected legacy fields to remain readable, got %#v", resp.Profile) 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{ body, err := json.Marshal(map[string]any{
"profile": map[string]any{ "profile": map[string]any{
"openclawUrl": "wss://gateway.example.com", "BRIDGE_SERVER_URL": "wss://gateway.example.com",
"openclawOrigin": "https://gateway.example.com", "bridgeServerOrigin": "https://gateway.example.com",
"vaultUrl": "https://vault.example.com", "vaultUrl": "https://vault.example.com",
"vaultNamespace": "team-a", "vaultNamespace": "team-a",
"secretLocators": []map[string]any{ "secretLocators": []map[string]any{
{ {
"id": "locator-openclaw", "id": "locator-openclaw",
"provider": "vault", "provider": "vault",
"secretPath": "kv/openclaw", "secretPath": "kv/openclaw",
"secretKey": "token", "secretKey": "token",
"target": store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, "target": store.XWorkmateSecretLocatorTargetBridgeAuthToken,
"required": true, "required": true,
}, },
}, },
@ -513,23 +513,23 @@ func TestGetXWorkmateProfileFallsBackWhenVaultStatusReadFails(t *testing.T) {
var resp struct { var resp struct {
Profile struct { Profile struct {
OpenclawURL string `json:"openclawUrl"` BridgeServerURL string `json:"BRIDGE_SERVER_URL"`
} `json:"profile"` } `json:"profile"`
TokenConfigured struct { TokenConfigured struct {
Openclaw bool `json:"openclaw"` Bridge bool `json:"bridge"`
Vault bool `json:"vault"` Vault bool `json:"vault"`
Apisix bool `json:"apisix"` Apisix bool `json:"apisix"`
} `json:"tokenConfigured"` } `json:"tokenConfigured"`
} }
if err := json.Unmarshal(getRec.Body.Bytes(), &resp); err != nil { if err := json.Unmarshal(getRec.Body.Bytes(), &resp); err != nil {
t.Fatalf("decode profile response: %v", err) 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) t.Fatalf("expected profile payload to survive vault read failure, got %#v", resp.Profile)
} }
if !resp.TokenConfigured.Openclaw { if !resp.TokenConfigured.Bridge {
t.Fatalf("expected locator-derived openclaw tokenConfigured fallback, got %#v", resp.TokenConfigured) t.Fatalf("expected locator-derived bridge tokenConfigured fallback, got %#v", resp.TokenConfigured)
} }
if resp.TokenConfigured.Vault { if resp.TokenConfigured.Vault {
t.Fatalf("expected vault tokenConfigured fallback to stay false, got %#v", resp.TokenConfigured) 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{ body, err := json.Marshal(map[string]any{
"profile": map[string]any{ "profile": map[string]any{
"openclawUrl": "wss://gateway.example.com", "BRIDGE_SERVER_URL": "wss://gateway.example.com",
"security": map[string]any{ "security": map[string]any{
"gatewayToken": "secret-value", "gatewayToken": "secret-value",
}, },
@ -618,11 +618,11 @@ func TestXWorkmateSecretsWriteReadDeleteAndKeepLocatorMetadata(t *testing.T) {
router, _, token := newXWorkmateTestHarness(t) router, _, token := newXWorkmateTestHarness(t)
profileBody, err := json.Marshal(map[string]any{ profileBody, err := json.Marshal(map[string]any{
"profile": map[string]any{ "profile": map[string]any{
"openclawUrl": "wss://gateway.example.com", "BRIDGE_SERVER_URL": "wss://gateway.example.com",
"openclawOrigin": "https://gateway.example.com", "bridgeServerOrigin": "https://gateway.example.com",
"vaultUrl": "https://vault.example.com", "vaultUrl": "https://vault.example.com",
"vaultNamespace": "team-a", "vaultNamespace": "team-a",
"apisixUrl": "https://apigw.example.com", "apisixUrl": "https://apigw.example.com",
}, },
}) })
if err != nil { if err != nil {
@ -640,7 +640,7 @@ func TestXWorkmateSecretsWriteReadDeleteAndKeepLocatorMetadata(t *testing.T) {
} }
for _, target := range []string{ for _, target := range []string{
store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, store.XWorkmateSecretLocatorTargetBridgeAuthToken,
store.XWorkmateSecretLocatorTargetVaultRootToken, store.XWorkmateSecretLocatorTargetVaultRootToken,
store.XWorkmateSecretLocatorTargetAIGatewayAccessToken, store.XWorkmateSecretLocatorTargetAIGatewayAccessToken,
} { } {
@ -693,15 +693,15 @@ func TestXWorkmateSecretsWriteReadDeleteAndKeepLocatorMetadata(t *testing.T) {
} `json:"secretLocators"` } `json:"secretLocators"`
} `json:"profile"` } `json:"profile"`
TokenConfigured struct { TokenConfigured struct {
Openclaw bool `json:"openclaw"` Bridge bool `json:"bridge"`
Vault bool `json:"vault"` Vault bool `json:"vault"`
Apisix bool `json:"apisix"` Apisix bool `json:"apisix"`
} `json:"tokenConfigured"` } `json:"tokenConfigured"`
} }
if err := json.Unmarshal(getProfileRec.Body.Bytes(), &profileResp); err != nil { if err := json.Unmarshal(getProfileRec.Body.Bytes(), &profileResp); err != nil {
t.Fatalf("decode profile response: %v", err) 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) t.Fatalf("expected all synced tokenConfigured fields true, got %#v", profileResp.TokenConfigured)
} }
if len(profileResp.Profile.SecretLocators) != 3 { 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) 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("Authorization", "Bearer "+token)
deleteReq.Header.Set("X-Forwarded-Host", store.SharedXWorkmateDomain) deleteReq.Header.Set("X-Forwarded-Host", store.SharedXWorkmateDomain)
deleteRec := httptest.NewRecorder() deleteRec := httptest.NewRecorder()
@ -736,16 +736,16 @@ func TestXWorkmateSecretsWriteReadDeleteAndKeepLocatorMetadata(t *testing.T) {
} `json:"secretLocators"` } `json:"secretLocators"`
} `json:"profile"` } `json:"profile"`
TokenConfigured struct { TokenConfigured struct {
Openclaw bool `json:"openclaw"` Bridge bool `json:"bridge"`
Vault bool `json:"vault"` Vault bool `json:"vault"`
Apisix bool `json:"apisix"` Apisix bool `json:"apisix"`
} `json:"tokenConfigured"` } `json:"tokenConfigured"`
} }
if err := json.Unmarshal(getProfileAfterDeleteRec.Body.Bytes(), &afterDeleteResp); err != nil { if err := json.Unmarshal(getProfileAfterDeleteRec.Body.Bytes(), &afterDeleteResp); err != nil {
t.Fatalf("decode post-delete profile response: %v", err) t.Fatalf("decode post-delete profile response: %v", err)
} }
if afterDeleteResp.TokenConfigured.Openclaw { if afterDeleteResp.TokenConfigured.Bridge {
t.Fatalf("expected deleted openclaw secret to report missing, got %#v", afterDeleteResp.TokenConfigured) t.Fatalf("expected deleted bridge secret to report missing, got %#v", afterDeleteResp.TokenConfigured)
} }
if !afterDeleteResp.TokenConfigured.Vault || !afterDeleteResp.TokenConfigured.Apisix { if !afterDeleteResp.TokenConfigured.Vault || !afterDeleteResp.TokenConfigured.Apisix {
t.Fatalf("expected unrelated secret statuses to remain true, got %#v", afterDeleteResp.TokenConfigured) 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) 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("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token) req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("X-Forwarded-Host", store.SharedXWorkmateDomain) req.Header.Set("X-Forwarded-Host", store.SharedXWorkmateDomain)
@ -867,7 +867,7 @@ func TestXWorkmatePrivateSecretsAreScopedPerUser(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("marshal secret payload: %v", err) 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("Content-Type", "application/json")
writeReq.Header.Set("Authorization", "Bearer "+tokenA) writeReq.Header.Set("Authorization", "Bearer "+tokenA)
writeReq.Header.Set("X-Forwarded-Host", "tenant-private-1.svc.plus") writeReq.Header.Set("X-Forwarded-Host", "tenant-private-1.svc.plus")
@ -897,25 +897,25 @@ func TestXWorkmatePrivateSecretsAreScopedPerUser(t *testing.T) {
var userAResp struct { var userAResp struct {
TokenConfigured struct { TokenConfigured struct {
Openclaw bool `json:"openclaw"` Bridge bool `json:"bridge"`
} `json:"tokenConfigured"` } `json:"tokenConfigured"`
} }
if err := json.Unmarshal(getARec.Body.Bytes(), &userAResp); err != nil { if err := json.Unmarshal(getARec.Body.Bytes(), &userAResp); err != nil {
t.Fatalf("decode user A profile response: %v", err) 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) t.Fatalf("expected user A secret to be configured, got %#v", userAResp.TokenConfigured)
} }
var userBResp struct { var userBResp struct {
TokenConfigured struct { TokenConfigured struct {
Openclaw bool `json:"openclaw"` Bridge bool `json:"bridge"`
} `json:"tokenConfigured"` } `json:"tokenConfigured"`
} }
if err := json.Unmarshal(getBRec.Body.Bytes(), &userBResp); err != nil { if err := json.Unmarshal(getBRec.Body.Bytes(), &userBResp); err != nil {
t.Fatalf("decode user B profile response: %v", err) 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) t.Fatalf("expected user B to remain isolated from user A secret, got %#v", userBResp.TokenConfigured)
} }
} }

View File

@ -54,9 +54,9 @@ type xworkmateManagedSecretTarget struct {
var xworkmateManagedSecretTargets = []xworkmateManagedSecretTarget{ var xworkmateManagedSecretTargets = []xworkmateManagedSecretTarget{
{ {
Target: store.XWorkmateSecretLocatorTargetOpenclawGatewayToken, Target: store.XWorkmateSecretLocatorTargetBridgeAuthToken,
Required: true, Required: true,
TokenConfiguredID: "openclaw", TokenConfiguredID: "bridge",
}, },
{ {
Target: store.XWorkmateSecretLocatorTargetVaultRootToken, Target: store.XWorkmateSecretLocatorTargetVaultRootToken,

View File

@ -56,20 +56,20 @@ type TenantMembership struct {
func (TenantMembership) TableName() string { return "tenant_memberships" } func (TenantMembership) TableName() string { return "tenant_memberships" }
type XWorkmateProfile struct { type XWorkmateProfile struct {
ID string `gorm:"column:id;type:text;primaryKey"` ID string `gorm:"column:id;type:text;primaryKey"`
TenantID string `gorm:"column:tenant_id;type:text;not null;uniqueIndex:idx_xworkmate_profiles_scope"` 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"` 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"` 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:''"` BridgeServerURL string `gorm:"column:openclaw_url;type:text;not null;default:''"`
OpenclawOrigin string `gorm:"column:openclaw_origin;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:''"` VaultURL string `gorm:"column:vault_url;type:text;not null;default:''"`
VaultNamespace string `gorm:"column:vault_namespace;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:''"` VaultSecretPath string `gorm:"column:vault_secret_path;type:text;not null;default:''"`
VaultSecretKey string `gorm:"column:vault_secret_key;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:'[]'"` SecretLocators []XWorkmateSecretLocator `gorm:"column:secret_locators;type:text;not null;serializer:json;default:'[]'"`
ApisixURL string `gorm:"column:apisix_url;type:text;not null;default:''"` ApisixURL string `gorm:"column:apisix_url;type:text;not null;default:''"`
CreatedAt time.Time `gorm:"column:created_at;not null;autoCreateTime"` CreatedAt time.Time `gorm:"column:created_at;not null;autoCreateTime"`
UpdatedAt time.Time `gorm:"column:updated_at;not null;autoUpdateTime"` UpdatedAt time.Time `gorm:"column:updated_at;not null;autoUpdateTime"`
} }
type XWorkmateSecretLocator struct { type XWorkmateSecretLocator struct {

View File

@ -32,7 +32,7 @@ const (
XWorkmateSecretLocatorProviderVault = "vault" XWorkmateSecretLocatorProviderVault = "vault"
XWorkmateSecretLocatorTargetOpenclawGatewayToken = "openclaw.gateway_token" XWorkmateSecretLocatorTargetBridgeAuthToken = "bridge.auth_token"
XWorkmateSecretLocatorTargetVaultRootToken = "vault.root_token" XWorkmateSecretLocatorTargetVaultRootToken = "vault.root_token"
XWorkmateSecretLocatorTargetAIGatewayAccessToken = "ai_gateway.access_token" XWorkmateSecretLocatorTargetAIGatewayAccessToken = "ai_gateway.access_token"
XWorkmateSecretLocatorTargetOllamaCloudAPIKey = "ollama_cloud.api_key" XWorkmateSecretLocatorTargetOllamaCloudAPIKey = "ollama_cloud.api_key"
@ -79,20 +79,20 @@ type TenantMembership struct {
} }
type XWorkmateProfile struct { type XWorkmateProfile struct {
ID string ID string
TenantID string TenantID string
UserID string UserID string
Scope string Scope string
OpenclawURL string BridgeServerURL string
OpenclawOrigin string BridgeServerOrigin string
VaultURL string VaultURL string
VaultNamespace string VaultNamespace string
VaultSecretPath string VaultSecretPath string
VaultSecretKey string VaultSecretKey string
SecretLocators []XWorkmateSecretLocator SecretLocators []XWorkmateSecretLocator
ApisixURL string ApisixURL string
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time
} }
type XWorkmateSecretLocator struct { type XWorkmateSecretLocator struct {
@ -179,7 +179,7 @@ func cloneXWorkmateSecretLocators(locators []XWorkmateSecretLocator) []XWorkmate
func legacyXWorkmateSecretLocatorID(profile *XWorkmateProfile) string { func legacyXWorkmateSecretLocatorID(profile *XWorkmateProfile) string {
if profile == nil { if profile == nil {
return "legacy|xworkmate|openclaw.gateway_token" return "legacy|xworkmate|bridge.auth_token"
} }
return strings.Join([]string{ return strings.Join([]string{
@ -187,7 +187,7 @@ func legacyXWorkmateSecretLocatorID(profile *XWorkmateProfile) string {
strings.TrimSpace(profile.TenantID), strings.TrimSpace(profile.TenantID),
strings.TrimSpace(profile.UserID), strings.TrimSpace(profile.UserID),
NormalizeXWorkmateProfileScope(profile.Scope), NormalizeXWorkmateProfileScope(profile.Scope),
XWorkmateSecretLocatorTargetOpenclawGatewayToken, XWorkmateSecretLocatorTargetBridgeAuthToken,
}, "|") }, "|")
} }
@ -197,13 +197,13 @@ func synthesizeXWorkmateSecretLocatorFromLegacy(profile *XWorkmateProfile) XWork
Provider: XWorkmateSecretLocatorProviderVault, Provider: XWorkmateSecretLocatorProviderVault,
SecretPath: profile.VaultSecretPath, SecretPath: profile.VaultSecretPath,
SecretKey: profile.VaultSecretKey, SecretKey: profile.VaultSecretKey,
Target: XWorkmateSecretLocatorTargetOpenclawGatewayToken, Target: XWorkmateSecretLocatorTargetBridgeAuthToken,
} }
} }
func compatibilityXWorkmateSecretLocator(locators []XWorkmateSecretLocator) (string, string, bool) { func compatibilityXWorkmateSecretLocator(locators []XWorkmateSecretLocator) (string, string, bool) {
for _, locator := range locators { for _, locator := range locators {
if locator.Target == XWorkmateSecretLocatorTargetOpenclawGatewayToken && if locator.Target == XWorkmateSecretLocatorTargetBridgeAuthToken &&
locator.SecretPath != "" && locator.SecretKey != "" { locator.SecretPath != "" && locator.SecretKey != "" {
return locator.SecretPath, locator.SecretKey, true return locator.SecretPath, locator.SecretKey, true
} }
@ -292,8 +292,8 @@ func NormalizeXWorkmateProfile(profile *XWorkmateProfile) {
profile.TenantID = strings.TrimSpace(profile.TenantID) profile.TenantID = strings.TrimSpace(profile.TenantID)
profile.UserID = strings.TrimSpace(profile.UserID) profile.UserID = strings.TrimSpace(profile.UserID)
profile.Scope = NormalizeXWorkmateProfileScope(profile.Scope) profile.Scope = NormalizeXWorkmateProfileScope(profile.Scope)
profile.OpenclawURL = strings.TrimSpace(profile.OpenclawURL) profile.BridgeServerURL = strings.TrimSpace(profile.BridgeServerURL)
profile.OpenclawOrigin = strings.TrimSpace(profile.OpenclawOrigin) profile.BridgeServerOrigin = strings.TrimSpace(profile.BridgeServerOrigin)
profile.VaultURL = strings.TrimSpace(profile.VaultURL) profile.VaultURL = strings.TrimSpace(profile.VaultURL)
profile.VaultNamespace = strings.TrimSpace(profile.VaultNamespace) profile.VaultNamespace = strings.TrimSpace(profile.VaultNamespace)
profile.VaultSecretPath = strings.Trim(strings.TrimSpace(profile.VaultSecretPath), "/") profile.VaultSecretPath = strings.Trim(strings.TrimSpace(profile.VaultSecretPath), "/")

View File

@ -290,8 +290,8 @@ func (s *memoryStore) UpsertXWorkmateProfile(ctx context.Context, profile *XWork
defer s.mu.Unlock() defer s.mu.Unlock()
if existing, ok := s.xworkmateProfiles[key]; ok { if existing, ok := s.xworkmateProfiles[key]; ok {
existing.OpenclawURL = profile.OpenclawURL existing.BridgeServerURL = profile.BridgeServerURL
existing.OpenclawOrigin = profile.OpenclawOrigin existing.BridgeServerOrigin = profile.BridgeServerOrigin
existing.VaultURL = profile.VaultURL existing.VaultURL = profile.VaultURL
existing.VaultNamespace = profile.VaultNamespace existing.VaultNamespace = profile.VaultNamespace
existing.VaultSecretPath = profile.VaultSecretPath existing.VaultSecretPath = profile.VaultSecretPath
@ -305,20 +305,20 @@ func (s *memoryStore) UpsertXWorkmateProfile(ctx context.Context, profile *XWork
} }
stored := &XWorkmateProfile{ stored := &XWorkmateProfile{
ID: profile.ID, ID: profile.ID,
TenantID: profile.TenantID, TenantID: profile.TenantID,
UserID: profile.UserID, UserID: profile.UserID,
Scope: profile.Scope, Scope: profile.Scope,
OpenclawURL: profile.OpenclawURL, BridgeServerURL: profile.BridgeServerURL,
OpenclawOrigin: profile.OpenclawOrigin, BridgeServerOrigin: profile.BridgeServerOrigin,
VaultURL: profile.VaultURL, VaultURL: profile.VaultURL,
VaultNamespace: profile.VaultNamespace, VaultNamespace: profile.VaultNamespace,
VaultSecretPath: profile.VaultSecretPath, VaultSecretPath: profile.VaultSecretPath,
VaultSecretKey: profile.VaultSecretKey, VaultSecretKey: profile.VaultSecretKey,
SecretLocators: cloneXWorkmateSecretLocators(profile.SecretLocators), SecretLocators: cloneXWorkmateSecretLocators(profile.SecretLocators),
ApisixURL: profile.ApisixURL, ApisixURL: profile.ApisixURL,
CreatedAt: now, CreatedAt: now,
UpdatedAt: now, UpdatedAt: now,
} }
s.xworkmateProfiles[key] = stored s.xworkmateProfiles[key] = stored
profile.CreatedAt = stored.CreatedAt profile.CreatedAt = stored.CreatedAt

View File

@ -242,8 +242,8 @@ LIMIT 1`
&profile.TenantID, &profile.TenantID,
&profile.UserID, &profile.UserID,
&profile.Scope, &profile.Scope,
&profile.OpenclawURL, &profile.BridgeServerURL,
&profile.OpenclawOrigin, &profile.BridgeServerOrigin,
&profile.VaultURL, &profile.VaultURL,
&profile.VaultNamespace, &profile.VaultNamespace,
&profile.VaultSecretPath, &profile.VaultSecretPath,
@ -304,8 +304,8 @@ RETURNING created_at, updated_at`
profile.TenantID, profile.TenantID,
profile.UserID, profile.UserID,
profile.Scope, profile.Scope,
profile.OpenclawURL, profile.BridgeServerURL,
profile.OpenclawOrigin, profile.BridgeServerOrigin,
profile.VaultURL, profile.VaultURL,
profile.VaultNamespace, profile.VaultNamespace,
profile.VaultSecretPath, profile.VaultSecretPath,

View File

@ -87,7 +87,7 @@ func TestMemoryStoreResolveTenantAndProfile(t *testing.T) {
TenantID: privateTenant.ID, TenantID: privateTenant.ID,
UserID: "user-1", UserID: "user-1",
Scope: XWorkmateProfileScopeUserPrivate, Scope: XWorkmateProfileScopeUserPrivate,
OpenclawURL: "wss://openclaw.tenant-one.svc.plus", BridgeServerURL: "wss://openclaw.tenant-one.svc.plus",
VaultSecretPath: "kv/openclaw", VaultSecretPath: "kv/openclaw",
VaultSecretKey: "token", VaultSecretKey: "token",
}); err != nil { }); err != nil {
@ -109,8 +109,8 @@ func TestMemoryStoreResolveTenantAndProfile(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("get private profile: %v", err) t.Fatalf("get private profile: %v", err)
} }
if profile.OpenclawURL != "wss://openclaw.tenant-one.svc.plus" { if profile.BridgeServerURL != "wss://openclaw.tenant-one.svc.plus" {
t.Fatalf("expected persisted openclaw url, got %q", profile.OpenclawURL) t.Fatalf("expected persisted bridge server url, got %q", profile.BridgeServerURL)
} }
if profile.VaultSecretPath != "kv/openclaw" || profile.VaultSecretKey != "token" { if profile.VaultSecretPath != "kv/openclaw" || profile.VaultSecretKey != "token" {
t.Fatalf("expected legacy secret fields to round-trip, got %#v", profile) 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 { if profile.SecretLocators[0].Provider != XWorkmateSecretLocatorProviderVault {
t.Fatalf("expected vault provider, got %#v", profile.SecretLocators[0]) t.Fatalf("expected vault provider, got %#v", profile.SecretLocators[0])
} }
if profile.SecretLocators[0].Target != XWorkmateSecretLocatorTargetOpenclawGatewayToken { if profile.SecretLocators[0].Target != XWorkmateSecretLocatorTargetBridgeAuthToken {
t.Fatalf("expected openclaw target, got %#v", profile.SecretLocators[0]) t.Fatalf("expected bridge auth token target, got %#v", profile.SecretLocators[0])
} }
if profile.SecretLocators[0].SecretPath != "kv/openclaw" || profile.SecretLocators[0].SecretKey != "token" { 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]) t.Fatalf("expected synthesized secret locator path/key, got %#v", profile.SecretLocators[0])
@ -158,7 +158,7 @@ func TestMemoryStorePersistsExplicitSecretLocators(t *testing.T) {
Provider: "vault", Provider: "vault",
SecretPath: "kv/openclaw", SecretPath: "kv/openclaw",
SecretKey: "gateway-token", SecretKey: "gateway-token",
Target: XWorkmateSecretLocatorTargetOpenclawGatewayToken, Target: XWorkmateSecretLocatorTargetBridgeAuthToken,
Required: true, Required: true,
}, },
{ {