Tighten bridge endpoint and auth contracts
This commit is contained in:
parent
095ef07b61
commit
8e24b697a7
@ -4,13 +4,13 @@
|
||||
# BRIDGE_CONFIG_PATH=config.yaml ./xworkmate-bridge serve
|
||||
|
||||
# Upstream provider endpoints
|
||||
# Priority: YAML > Environment Variable (e.g. OPENCLAW_CODEX_URL) > Default Constants
|
||||
# Priority: YAML > Environment Variable (e.g. CODEX_RPC_URL) > Default Constants
|
||||
upstream:
|
||||
gateway_url: "ws://127.0.0.1:18789/"
|
||||
codex_url: "http://127.0.0.1:9001/acp/rpc"
|
||||
opencode_url: "http://127.0.0.1:38992/acp/rpc"
|
||||
gemini_url: "http://127.0.0.1:8791/acp/rpc"
|
||||
hermes_url: "http://127.0.0.1:3920/acp/rpc"
|
||||
codex_url: "ws://127.0.0.1:9001/acp"
|
||||
opencode_url: "http://127.0.0.1:38992"
|
||||
gemini_url: "http://127.0.0.1:8791"
|
||||
hermes_url: "http://127.0.0.1:3920"
|
||||
|
||||
# Legacy/Reference structure (Normally managed via code constants or environment)
|
||||
bridge:
|
||||
|
||||
@ -16,10 +16,10 @@ func TestResolveSingleAgentForwardEndpointFromExampleConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
expectedEndpoints := map[string]string{
|
||||
"codex": "http://127.0.0.1:9001/acp/rpc",
|
||||
"opencode": "http://127.0.0.1:38992/acp/rpc",
|
||||
"gemini": "http://127.0.0.1:8791/acp/rpc",
|
||||
"hermes": "http://127.0.0.1:3920/acp/rpc",
|
||||
"codex": "ws://127.0.0.1:9001/acp",
|
||||
"opencode": "http://127.0.0.1:38992",
|
||||
"gemini": "http://127.0.0.1:8791",
|
||||
"hermes": "http://127.0.0.1:3920",
|
||||
}
|
||||
|
||||
for _, id := range order {
|
||||
|
||||
@ -59,9 +59,6 @@ func resolveURL(yamlVal string, defaultVal string, envKeys ...string) string {
|
||||
|
||||
func bridgeUpstreamAuthorizationHeader() string {
|
||||
token := strings.TrimSpace(shared.EnvOrDefault("BRIDGE_AUTH_TOKEN", ""))
|
||||
if token == "" {
|
||||
token = strings.TrimSpace(shared.EnvOrDefault("INTERNAL_SERVICE_TOKEN", ""))
|
||||
}
|
||||
if token != "" && !strings.HasPrefix(strings.ToLower(token), "bearer ") {
|
||||
return "Bearer " + token
|
||||
}
|
||||
@ -91,21 +88,21 @@ func newProductionProviderCatalog() (map[string]syncedProvider, []string) {
|
||||
label: "OpenCode",
|
||||
yaml: config.Upstream.OpenCodeURL,
|
||||
envKeys: []string{"OPENCODE_RPC_URL"},
|
||||
defaultURL: "http://127.0.0.1:38992/acp/rpc",
|
||||
defaultURL: "http://127.0.0.1:38992",
|
||||
},
|
||||
{
|
||||
id: "gemini",
|
||||
label: "Gemini",
|
||||
yaml: config.Upstream.GeminiURL,
|
||||
envKeys: []string{"GEMINI_RPC_URL"},
|
||||
defaultURL: "http://127.0.0.1:8791/acp/rpc",
|
||||
defaultURL: "http://127.0.0.1:8791",
|
||||
},
|
||||
{
|
||||
id: "hermes",
|
||||
label: "Hermes",
|
||||
yaml: config.Upstream.HermesURL,
|
||||
envKeys: []string{"HERMES_RPC_URL"},
|
||||
defaultURL: "http://127.0.0.1:3920/acp/rpc",
|
||||
defaultURL: "http://127.0.0.1:3920",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -108,3 +108,18 @@ func TestProductionProviderCatalogPrefersDedicatedBridgeAuthToken(t *testing.T)
|
||||
t.Fatalf("expected dedicated bearer header, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProductionProviderCatalogIgnoresInternalServiceToken(t *testing.T) {
|
||||
t.Setenv("BRIDGE_AUTH_TOKEN", "")
|
||||
t.Setenv("INTERNAL_SERVICE_TOKEN", "legacy-token")
|
||||
|
||||
catalog, _ := newProductionProviderCatalog()
|
||||
p, ok := catalog["codex"]
|
||||
if !ok {
|
||||
t.Fatal("missing codex")
|
||||
}
|
||||
|
||||
if got := p.AuthorizationHeader; got != "" {
|
||||
t.Fatalf("expected empty auth header when BRIDGE_AUTH_TOKEN is unset, got %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
@ -442,7 +442,7 @@ func TestHandleRPCCapabilitiesReturnsCanonicalProviderContract(t *testing.T) {
|
||||
|
||||
func TestHandleRPCSessionStartSucceedsWithExplicitProvider(t *testing.T) {
|
||||
externalServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if got := r.Header.Get("Authorization"); got != "Bearer internal-test-token" {
|
||||
if got := r.Header.Get("Authorization"); got != "Bearer bridge-test-token" {
|
||||
t.Fatalf("unexpected auth header: %q", got)
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||
@ -457,8 +457,7 @@ func TestHandleRPCSessionStartSucceedsWithExplicitProvider(t *testing.T) {
|
||||
}))
|
||||
defer externalServer.Close()
|
||||
|
||||
t.Setenv("INTERNAL_SERVICE_TOKEN", "internal-test-token")
|
||||
t.Setenv("BRIDGE_AUTH_TOKEN", "")
|
||||
t.Setenv("BRIDGE_AUTH_TOKEN", "bridge-test-token")
|
||||
|
||||
t.Setenv("BRIDGE_CONFIG_PATH", "../../example/config.yaml")
|
||||
server := NewServer()
|
||||
@ -466,7 +465,7 @@ func TestHandleRPCSessionStartSucceedsWithExplicitProvider(t *testing.T) {
|
||||
ProviderID: "opencode",
|
||||
Label: "OpenCode",
|
||||
Endpoint: externalServer.URL,
|
||||
AuthorizationHeader: "Bearer internal-test-token",
|
||||
AuthorizationHeader: "Bearer bridge-test-token",
|
||||
Enabled: true,
|
||||
})
|
||||
|
||||
@ -477,7 +476,7 @@ func TestHandleRPCSessionStartSucceedsWithExplicitProvider(t *testing.T) {
|
||||
strings.NewReader(`{"jsonrpc":"2.0","id":"task-1","method":"session.start","params":{"sessionId":"s1","threadId":"t1","taskPrompt":"Reply with exactly pong","workingDirectory":"`+t.TempDir()+`","routing":{"routingMode":"explicit","explicitExecutionTarget":"singleAgent","explicitProviderId":"opencode"}}}`),
|
||||
)
|
||||
request.Header.Set("Content-Type", "application/json")
|
||||
request.Header.Set("Authorization", "Bearer bridge-token")
|
||||
request.Header.Set("Authorization", "Bearer bridge-test-token")
|
||||
|
||||
server.HandleRPC(recorder, request)
|
||||
|
||||
|
||||
@ -112,6 +112,12 @@ case "${scenario}" in
|
||||
https://xworkmate-bridge.svc.plus/acp-server/*/acp/rpc)
|
||||
printf '{"jsonrpc":"2.0","result":{"providers":["ok"]}}\n'
|
||||
;;
|
||||
https://xworkmate-bridge.svc.plus/acp-server/*)
|
||||
printf '{"jsonrpc":"2.0","result":{"providers":["ok"]}}\n'
|
||||
;;
|
||||
https://xworkmate-bridge.svc.plus/gateway/openclaw)
|
||||
printf '{"jsonrpc":"2.0","result":{"providers":["ok"]}}\n'
|
||||
;;
|
||||
https://xworkmate-bridge.svc.plus/acp/rpc)
|
||||
printf 'curl: (28) Operation timed out after 20001 milliseconds with 0 bytes received\n' >&2
|
||||
exit 1
|
||||
@ -138,6 +144,12 @@ case "${scenario}" in
|
||||
https://xworkmate-bridge.svc.plus/acp-server/*/acp/rpc)
|
||||
printf '{"jsonrpc":"2.0","result":{"providers":["ok"]}}\n'
|
||||
;;
|
||||
https://xworkmate-bridge.svc.plus/acp-server/*)
|
||||
printf '{"jsonrpc":"2.0","result":{"providers":["ok"]}}\n'
|
||||
;;
|
||||
https://xworkmate-bridge.svc.plus/gateway/openclaw)
|
||||
printf '{"jsonrpc":"2.0","result":{"providers":["ok"]}}\n'
|
||||
;;
|
||||
https://xworkmate-bridge.svc.plus/acp/rpc)
|
||||
if [[ "${data}" == *'"providerId":"codex"'* ]]; then
|
||||
printf '{"jsonrpc":"2.0","result":{"success":true,"providerId":"codex","capabilities":{"providers":["codex"]}}}\n'
|
||||
@ -194,12 +206,12 @@ run_validate_capture() {
|
||||
FAKE_CURL_SCENARIO="${scenario}" \
|
||||
FAKE_CURL_STATE_DIR="${RUN_STATE_DIR}" \
|
||||
BRIDGE_SERVER_URL="https://xworkmate-bridge.svc.plus" \
|
||||
OPENCLAW_URL="wss://openclaw.svc.plus" \
|
||||
CODEX_RPC_URL="https://xworkmate-bridge.svc.plus/acp-server/codex/acp/rpc" \
|
||||
OPENCODE_RPC_URL="https://xworkmate-bridge.svc.plus/acp-server/opencode/acp/rpc" \
|
||||
GEMINI_RPC_URL="https://xworkmate-bridge.svc.plus/acp-server/gemini/acp/rpc" \
|
||||
HERMES_RPC_URL="https://xworkmate-bridge.svc.plus/acp-server/hermes/acp/rpc" \
|
||||
INTERNAL_SERVICE_TOKEN="test-token" \
|
||||
OPENCLAW_URL="https://xworkmate-bridge.svc.plus/gateway/openclaw" \
|
||||
CODEX_RPC_URL="https://xworkmate-bridge.svc.plus/acp-server/codex" \
|
||||
OPENCODE_RPC_URL="https://xworkmate-bridge.svc.plus/acp-server/opencode" \
|
||||
GEMINI_RPC_URL="https://xworkmate-bridge.svc.plus/acp-server/gemini" \
|
||||
HERMES_RPC_URL="https://xworkmate-bridge.svc.plus/acp-server/hermes" \
|
||||
BRIDGE_AUTH_TOKEN="test-token" \
|
||||
bash "${SCRIPT_PATH}" "${IMAGE_REF}" 2>&1
|
||||
)"
|
||||
RUN_STATUS=$?
|
||||
|
||||
@ -54,26 +54,22 @@ fi
|
||||
|
||||
BASE_URL="$(normalize_url "${BRIDGE_SERVER_URL:-${2:-https://xworkmate-bridge.svc.plus}}")"
|
||||
OPENCLAW_BASE_URL="$(normalize_url "${OPENCLAW_URL:-${3:-${BASE_URL}/gateway/openclaw}}")"
|
||||
CODEX_BASE_URL="$(normalize_url "${CODEX_RPC_URL:-${4:-${BASE_URL}/acp-server/codex/acp/rpc}}")"
|
||||
OPENCODE_BASE_URL="$(normalize_url "${OPENCODE_RPC_URL:-${5:-${BASE_URL}/acp-server/opencode/acp/rpc}}")"
|
||||
GEMINI_BASE_URL="$(normalize_url "${GEMINI_RPC_URL:-${6:-${BASE_URL}/acp-server/gemini/acp/rpc}}")"
|
||||
HERMES_BASE_URL="$(normalize_url "${HERMES_RPC_URL:-${7:-${BASE_URL}/acp-server/hermes/acp/rpc}}")"
|
||||
AUTH_TOKEN="${BRIDGE_AUTH_TOKEN:-${INTERNAL_SERVICE_TOKEN:-${7:-}}}"
|
||||
CODEX_BASE_URL="$(normalize_url "${CODEX_RPC_URL:-${4:-${BASE_URL}/acp-server/codex}}")"
|
||||
OPENCODE_BASE_URL="$(normalize_url "${OPENCODE_RPC_URL:-${5:-${BASE_URL}/acp-server/opencode}}")"
|
||||
GEMINI_BASE_URL="$(normalize_url "${GEMINI_RPC_URL:-${6:-${BASE_URL}/acp-server/gemini}}")"
|
||||
HERMES_BASE_URL="$(normalize_url "${HERMES_RPC_URL:-${7:-${BASE_URL}/acp-server/hermes}}")"
|
||||
AUTH_TOKEN="${BRIDGE_AUTH_TOKEN:?BRIDGE_AUTH_TOKEN is required}"
|
||||
|
||||
ensure_rpc_path() {
|
||||
append_rpc_path() {
|
||||
local url="$1"
|
||||
if [[ "${url}" == */acp/rpc ]]; then
|
||||
printf '%s\n' "${url}"
|
||||
else
|
||||
printf '%s/acp/rpc\n' "${url%/}"
|
||||
fi
|
||||
printf '%s/acp/rpc\n' "${url%/}"
|
||||
}
|
||||
|
||||
OPENCLAW_HTTP_PROBE_URL="$(websocket_probe_url "${OPENCLAW_BASE_URL}")"
|
||||
CODEX_RPC_ENDPOINT="$(ensure_rpc_path "${CODEX_BASE_URL}")"
|
||||
OPENCODE_RPC_ENDPOINT="$(ensure_rpc_path "${OPENCODE_BASE_URL}")"
|
||||
GEMINI_RPC_ENDPOINT="$(ensure_rpc_path "${GEMINI_BASE_URL}")"
|
||||
HERMES_RPC_ENDPOINT="$(ensure_rpc_path "${HERMES_BASE_URL}")"
|
||||
CODEX_RPC_ENDPOINT="$(append_rpc_path "${CODEX_BASE_URL}")"
|
||||
OPENCODE_RPC_ENDPOINT="$(append_rpc_path "${OPENCODE_BASE_URL}")"
|
||||
GEMINI_RPC_ENDPOINT="$(append_rpc_path "${GEMINI_BASE_URL}")"
|
||||
HERMES_RPC_ENDPOINT="$(append_rpc_path "${HERMES_BASE_URL}")"
|
||||
|
||||
fast_http_curl_common=(
|
||||
--silent
|
||||
|
||||
Loading…
Reference in New Issue
Block a user