fix: enforce rollout gates across backend entry points
This commit is contained in:
@@ -5,6 +5,7 @@ import schema from "../src/convex/schema";
|
||||
import type { Asset } from "../src/lib/domain/model";
|
||||
|
||||
process.env.CONVEX_BRIDGE_SECRET = "test-bridge-secret";
|
||||
process.env.APP_CAPABILITY_ALLOWLIST = "asset_search,asset_valuation,asset_sync,assistant_dispatch,session_token,identity,subscriptions";
|
||||
|
||||
const modules = {
|
||||
"src/convex/functions.ts": () => import("../src/convex/functions"),
|
||||
@@ -47,6 +48,7 @@ async function login(t: ReturnType<typeof convexTest>, input: Partial<any> = {})
|
||||
describe("Convex persistence", () => {
|
||||
beforeEach(() => {
|
||||
process.env.CONVEX_BRIDGE_SECRET = "test-bridge-secret";
|
||||
process.env.APP_CAPABILITY_ALLOWLIST = "asset_search,asset_valuation,asset_sync,assistant_dispatch,session_token,identity,subscriptions";
|
||||
});
|
||||
|
||||
test("rejects unauthenticated bridge calls and keeps tenants separate", async () => {
|
||||
@@ -445,4 +447,28 @@ describe("Convex persistence", () => {
|
||||
await t.mutation(mutation("bridgeDeleteSession"), { ...bridge, sessionHash: "session-hash" });
|
||||
await expect(browser.query(statusQuery("characters"), {})).resolves.toBeNull();
|
||||
});
|
||||
|
||||
test("backend rollout gate blocks status subscriptions and sync mutations", async () => {
|
||||
const previous = process.env.APP_CAPABILITY_ALLOWLIST;
|
||||
process.env.APP_CAPABILITY_ALLOWLIST = "";
|
||||
try {
|
||||
process.env.APP_AUTH_ISSUER = "https://auth.example.test";
|
||||
const t = convexTest({ schema, modules });
|
||||
const loggedIn = await login(t, { sessionHash: "gated-session" });
|
||||
const browser = t.withIdentity({
|
||||
subject: loggedIn.userId,
|
||||
issuer: "https://auth.example.test",
|
||||
sid: loggedIn.sessionId,
|
||||
} as any);
|
||||
await expect(browser.query(statusQuery("characters"), {})).resolves.toBeNull();
|
||||
await expect(t.mutation(mutation("bridgeBeginSync"), {
|
||||
...bridge,
|
||||
userId: loggedIn.userId,
|
||||
characterId: 100,
|
||||
})).rejects.toThrow("asset_sync");
|
||||
} finally {
|
||||
if (previous === undefined) delete process.env.APP_CAPABILITY_ALLOWLIST;
|
||||
else process.env.APP_CAPABILITY_ALLOWLIST = previous;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,11 +13,12 @@ describe('deployment rollout gate', () => {
|
||||
expect(baseline).toEqual(BASELINE_RELEASE_CAPABILITIES);
|
||||
expect(capabilityEnabled('asset_search', baseline)).toBe(true);
|
||||
expect(capabilityEnabled('wallet_balance', baseline)).toBe(false);
|
||||
expect(capabilityEnabled('subscriptions', baseline)).toBe(false);
|
||||
expect(capabilityEnabled('subscriptions', baseline)).toBe(true);
|
||||
});
|
||||
|
||||
test('supports explicit narrowing and rejects unknown or empty names', () => {
|
||||
expect(parseCapabilityAllowlist('asset_search, asset_search,session_token')).toEqual(['asset_search', 'session_token']);
|
||||
expect(parseCapabilityAllowlist('subscriptions')).toEqual(['subscriptions']);
|
||||
expect(parseCapabilityAllowlist('')).toEqual([]);
|
||||
expect(() => parseCapabilityAllowlist('asset_search,typo')).toThrow('Unknown deployment capability');
|
||||
expect(() => parseCapabilityAllowlist('asset_search,')).toThrow('Unknown deployment capability');
|
||||
|
||||
Reference in New Issue
Block a user