fix: fail closed on invalid launch inputs
ci/woodpecker/pr/ci Pipeline was successful

This commit is contained in:
be-coder-06
2026-08-12 20:41:24 -05:00
parent 216cd72226
commit 55f2ec3dbc
10 changed files with 507 additions and 35 deletions
+14 -5
View File
@@ -451,15 +451,24 @@ describe('AppModule federation gating', (): void => {
);
it(
'attributes an invalid monorepo-root dotenv tier to the default',
'rejects an invalid explicit monorepo-root dotenv tier with a typed startup refusal',
async (): Promise<void> => {
const graph = await loadModuleGraphFromDotenv({
const failure = await loadModuleGraphFromDotenv({
rootEnvContents: 'MOSAIC_STORAGE_TIER=invalid\n',
expectedProcessTier: 'invalid',
});
}).then(
(): undefined => undefined,
(error: unknown): unknown => error,
);
expect(graph.imports).not.toContain(graph.federationModule);
expectBootLogLine(graph.bootLogLines, 'local', 'default');
expect(failure).toBeInstanceOf(Error);
expect(failure).toMatchObject({
name: 'MosaicConfigEnvironmentError',
code: 'invalid_storage_tier',
});
expect((failure as Error).message).toBe(
'Invalid MOSAIC_STORAGE_TIER; expected "local", "standalone", or "federated".',
);
},
MODULE_IMPORT_TIMEOUT_MS,
);
@@ -0,0 +1,51 @@
import { readFileSync } from 'node:fs';
import { describe, expect, it } from 'vitest';
import { resolveChatRuntimeMode } from './chat-runtime.js';
interface TypedSelectionFailure {
readonly name: string;
readonly code: string;
}
describe('#1182 fail closed — a wrong answer must not be read as no answer', () => {
it('FL-07 rejects an invalid explicit CHAT_HARNESS_RUNTIME before embedded construction', () => {
let embeddedConstructionCount = 0;
let failure: unknown;
try {
const mode = resolveChatRuntimeMode({ CHAT_HARNESS_RUNTIME: 'pi-rpc-typo' });
if (mode === 'legacy') {
embeddedConstructionCount += 1;
}
} catch (error: unknown) {
failure = error;
}
expect
.soft(failure, 'invalid explicit runtime must produce a typed selection failure')
.toMatchObject({
name: 'ChatRuntimeConfigurationError',
code: 'invalid_chat_harness_runtime',
} satisfies TypedSelectionFailure);
expect(
embeddedConstructionCount,
'invalid explicit runtime must fail before the embedded runtime is constructed',
).toBe(0);
});
it.each([{}, { CHAT_HARNESS_RUNTIME: '' }])(
'preserves the documented transitional legacy default for true absence: %j',
(env) => {
expect(resolveChatRuntimeMode(env)).toBe('legacy');
},
);
it('anti-drift: runtime selection has no invalid-enum-to-legacy catch-all', () => {
const source = readFileSync(new URL('./chat-runtime.ts', import.meta.url), 'utf8');
expect(
source.includes("env['CHAT_HARNESS_RUNTIME'] === 'pi-rpc' ? 'pi-rpc' : 'legacy'"),
'closed runtime enums must distinguish invalid explicit input from absence',
).toBe(false);
});
});
+17 -3
View File
@@ -41,14 +41,28 @@ export class ChatRuntimeUnavailableError extends Error {
}
}
/** Typed startup refusal for an invalid explicit chat-runtime selection. */
export class ChatRuntimeConfigurationError extends Error {
readonly code = 'invalid_chat_harness_runtime' as const;
constructor() {
super('Invalid CHAT_HARNESS_RUNTIME; expected "legacy" or "pi-rpc".');
this.name = 'ChatRuntimeConfigurationError';
}
}
/**
* Resolves the process-wide chat runtime mode from the environment. Anything other
* than the exact opt-in token `pi-rpc` keeps the legacy embedded runtime.
* Resolves the process-wide chat runtime mode from the environment. Only true
* absence (unset or empty) retains the documented transitional legacy default;
* any other explicit value must be a member of the closed runtime enum.
*/
export function resolveChatRuntimeMode(
env: Record<string, string | undefined> = process.env,
): ChatRuntimeMode {
return env['CHAT_HARNESS_RUNTIME'] === 'pi-rpc' ? 'pi-rpc' : 'legacy';
const runtime = env['CHAT_HARNESS_RUNTIME'];
if (runtime === undefined || runtime === '') return 'legacy';
if (runtime === 'legacy' || runtime === 'pi-rpc') return runtime;
throw new ChatRuntimeConfigurationError();
}
// ---------------------------------------------------------------------------