Skip to content

Commit bd6112e

Browse files
carderneTrigger.dev RepoOps
authored andcommitted
fix: support global OIDC defaults with organization overrides
Mono-RevId: 506a4ac59ea98e5da2db5e9d4834c3abe1b69a2c
1 parent e719c68 commit bd6112e

5 files changed

Lines changed: 58 additions & 3 deletions

File tree

‎apps/webapp/app/services/oidc/externalOidc.server.ts‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import { env } from "~/env.server";
1010
import { isCloud } from "~/services/platform.v3.server";
1111
import { createRedisRateLimitClient } from "~/services/rateLimiterCore.server";
1212
import { singleton } from "~/utils/singleton";
13+
import { globalFlagsRegistry } from "~/v3/globalFlagsRegistry.server";
1314
import { runStore } from "~/v3/runStore.server";
15+
import { resolveExternalOidcFlags } from "./externalOidcFeatureFlags";
1416
import { loadExternalOidcPlugin } from "./externalOidcPlugin.server";
1517
import { ExternalOidcRateLimits } from "./externalOidcRateLimit.server";
1618
import { externalOidcSigningService } from "./instance.server";
@@ -37,7 +39,11 @@ export function getExternalOidcController(): Promise<ExternalOidcController | nu
3739
export async function isExternalOidcEnabled(orgFeatureFlags: unknown): Promise<boolean> {
3840
if (!runTokenInjectionEnabled(orgFeatureFlags)) return false;
3941
const controller = await getExternalOidcController();
40-
return controller?.isEnabled(orgFeatureFlags) ?? false;
42+
return (
43+
controller?.isEnabled(
44+
resolveExternalOidcFlags(globalFlagsRegistry.current() ?? {}, orgFeatureFlags)
45+
) ?? false
46+
);
4147
}
4248

4349
async function findEnvironment(
@@ -70,7 +76,10 @@ async function findEnvironment(
7076
organizationId: environment.organizationId,
7177
projectId: environment.projectId,
7278
projectRef: environment.project.externalRef,
73-
orgFeatureFlags: environment.organization.featureFlags,
79+
orgFeatureFlags: resolveExternalOidcFlags(
80+
globalFlagsRegistry.current() ?? {},
81+
environment.organization.featureFlags
82+
),
7483
};
7584
}
7685

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { FeatureFlagCatalog, isPlainFlagObject } from "~/v3/featureFlags";
2+
3+
export function resolveExternalOidcFlags(
4+
globalFlags: Partial<FeatureFlagCatalog>,
5+
orgFeatureFlags: unknown
6+
): { externalOidc: boolean } {
7+
const override = FeatureFlagCatalog.externalOidc.safeParse(
8+
isPlainFlagObject(orgFeatureFlags) ? orgFeatureFlags.externalOidc : undefined
9+
);
10+
return {
11+
externalOidc: override.success ? override.data : (globalFlags.externalOidc ?? false),
12+
};
13+
}

‎apps/webapp/app/v3/featureFlags.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ export const FeatureFlagCatalog = {
236236
// Injects a signed per-attempt TRIGGER_RUN_TOKEN into deployed runs. Org override wins over
237237
// the global value. Requires RUN_TOKEN_ISSUER_URL and an active internal run signing key.
238238
[FEATURE_FLAG.runTokenInjection]: z.boolean(),
239+
// Org override wins over the global value; off by default.
239240
[FEATURE_FLAG.externalOidc]: z.boolean(),
240241
// Shows the session page's Trace tab and serves its routes. Org override wins over the global
241242
// value; off by default. Admins always have it.
@@ -254,7 +255,6 @@ export const GLOBAL_LOCKED_FLAGS: FeatureFlagKey[] = [
254255
FEATURE_FLAG.runOpsMintShard,
255256
FEATURE_FLAG.runOpsMintShardEnvPins,
256257
FEATURE_FLAG.apiRateLimitMetricsEnabled,
257-
FEATURE_FLAG.externalOidc,
258258
FEATURE_FLAG.workerQueueCompatibility,
259259
FEATURE_FLAG.workerQueueChannel,
260260
FEATURE_FLAG.workerQueueEnvironmentOverrides,
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { expect, it } from "vitest";
2+
import { resolveExternalOidcFlags } from "~/services/oidc/externalOidcFeatureFlags";
3+
4+
// Catches: an invalid sibling flag discarding an explicit OIDC authorization override.
5+
it.each([
6+
{ global: true, override: false },
7+
{ global: false, override: true },
8+
{ global: undefined, override: true },
9+
])(
10+
"preserves org OIDC $override over global $global despite an invalid sibling",
11+
({ global, override }) => {
12+
expect(
13+
resolveExternalOidcFlags(
14+
{ externalOidc: global },
15+
{ externalOidc: override, realtimeBackend: "not-a-backend" }
16+
)
17+
).toEqual({ externalOidc: override });
18+
}
19+
);
20+
21+
it.each([
22+
{ global: true, expected: true },
23+
{ global: undefined, expected: false },
24+
])("falls back to global $global for an invalid org OIDC value", ({ global, expected }) => {
25+
expect(
26+
resolveExternalOidcFlags({ externalOidc: global }, { externalOidc: "not-a-boolean" })
27+
).toEqual({ externalOidc: expected });
28+
});

‎apps/webapp/test/globalFlagWriteRouting.test.ts‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ describe("lockedFlagsInPayload — what the global page refuses", () => {
9696
]);
9797
});
9898

99+
// Catches: rejecting the external OIDC global toggle as an org-only flag.
100+
it("allows external OIDC to be configured globally", () => {
101+
expect(lockedFlagsInPayload([FEATURE_FLAG.externalOidc], true)).toEqual([]);
102+
});
103+
99104
it("allows the shard list, because that is the page's ramp lever", () => {
100105
expect(lockedFlagsInPayload([FEATURE_FLAG.runOpsMintShardSet], true)).toEqual([]);
101106
});

0 commit comments

Comments
 (0)