Remove backend dev A2A auth fallback
This commit is contained in:
@@ -98,7 +98,7 @@ services:
|
||||
CLERK_SECRET_KEY: ${CLERK_SECRET_KEY}
|
||||
CLERK_PUBLISHABLE_KEY: ${CLERK_PUBLISHABLE_KEY}
|
||||
SERVICE_TOKEN: ${SERVICE_TOKEN:-dev-service-token}
|
||||
A2A_ALLOWED_KEY: ${A2A_ALLOWED_KEY:-dev-a2a-key}
|
||||
A2A_ALLOWED_KEY: ${A2A_ALLOWED_KEY:-}
|
||||
# LLM
|
||||
OPENCODE_API_KEY: ${OPENCODE_API_KEY}
|
||||
LLM_PROVIDER: ${LLM_PROVIDER:-opencode}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { config } from "../src/config.js";
|
||||
import { resolveTrustedServiceTokens } from "../src/auth/clerk.js";
|
||||
import { fetchOnboardingReadProfile, fetchUserProfile, patchPreferencesRequest } from "../src/services/user-profile.js";
|
||||
|
||||
/**
|
||||
@@ -282,5 +283,24 @@ async function runFetchUserProfileAfterBodyConsumed(): Promise<{
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
}
|
||||
// ── 8. trusted token resolution excludes A2A in production ────────────────
|
||||
{
|
||||
assert.equal(config.a2aAllowedKey, process.env.A2A_ALLOWED_KEY ?? "", "A2A config must not have a dev fallback");
|
||||
const production = resolveTrustedServiceTokens({
|
||||
nodeEnv: "production",
|
||||
serviceToken: "service-token",
|
||||
a2aAllowedKey: "a2a-token",
|
||||
});
|
||||
assert.equal(production.has("service-token"), true);
|
||||
assert.equal(production.has("a2a-token"), false, "production must exclude A2A token");
|
||||
|
||||
const development = resolveTrustedServiceTokens({
|
||||
nodeEnv: "development",
|
||||
serviceToken: "service-token",
|
||||
a2aAllowedKey: "a2a-token",
|
||||
});
|
||||
assert.equal(development.has("service-token"), true);
|
||||
assert.equal(development.has("a2a-token"), true, "development must include configured A2A token");
|
||||
}
|
||||
|
||||
console.log("user-profile: all assertions passed");
|
||||
|
||||
@@ -14,6 +14,17 @@ export type AuthContext = {
|
||||
};
|
||||
};
|
||||
|
||||
/** Resolve inbound service tokens without allowing A2A in production. */
|
||||
export function resolveTrustedServiceTokens(input: {
|
||||
nodeEnv: string;
|
||||
serviceToken: string;
|
||||
a2aAllowedKey: string;
|
||||
}): ReadonlySet<string> {
|
||||
return new Set(
|
||||
[input.serviceToken, input.nodeEnv !== "production" ? input.a2aAllowedKey : ""].filter(Boolean),
|
||||
);
|
||||
}
|
||||
|
||||
export const clerk = config.clerkSecretKey
|
||||
? createClerkClient({ secretKey: config.clerkSecretKey })
|
||||
: null;
|
||||
@@ -28,12 +39,7 @@ export const requireUser = createMiddleware<AuthContext>(async (c, next) => {
|
||||
|
||||
// Service-to-service path (Grow stack calling backend).
|
||||
// Header `x-growqr-user` is REQUIRED so we can scope the call.
|
||||
const trustedServiceTokens = new Set(
|
||||
[
|
||||
config.serviceToken,
|
||||
config.nodeEnv !== "production" ? config.a2aAllowedKey : "",
|
||||
].filter(Boolean),
|
||||
);
|
||||
const trustedServiceTokens = resolveTrustedServiceTokens(config);
|
||||
|
||||
if (
|
||||
token &&
|
||||
|
||||
@@ -57,7 +57,8 @@ export const config = {
|
||||
clerkPublishableKey: process.env.CLERK_PUBLISHABLE_KEY ?? "",
|
||||
// Optional: lock service-to-service calls (actor → backend).
|
||||
serviceToken: process.env.SERVICE_TOKEN ?? "",
|
||||
a2aAllowedKey: process.env.A2A_ALLOWED_KEY ?? "dev-a2a-key",
|
||||
// A2A is intentionally unset unless an operator configures it.
|
||||
a2aAllowedKey: process.env.A2A_ALLOWED_KEY ?? "",
|
||||
|
||||
// Service → backend event stream. Redis is optional; HTTP /events/ingest/service is always available.
|
||||
// Explicit opt-in flags: both Redis ingestion paths are default-off. The REST
|
||||
|
||||
Reference in New Issue
Block a user