fix(gateway): restore daemon config discovery (#1138)
ci/woodpecker/pr/ci Pipeline failed

This commit is contained in:
shaggy (mosaic-dev box)
2026-08-10 00:31:58 -05:00
parent bd0ef2ab25
commit 677aeb0c93
2 changed files with 51 additions and 7 deletions
+40 -4
View File
@@ -12,6 +12,7 @@ interface ComposedModuleGraph {
federationModule: unknown; federationModule: unknown;
bootLogLines: readonly string[]; bootLogLines: readonly string[];
mosaicConfig: MosaicConfig; mosaicConfig: MosaicConfig;
resolvedConfigPath: string;
} }
type StorageTier = 'local' | 'standalone' | 'federated'; type StorageTier = 'local' | 'standalone' | 'federated';
@@ -205,6 +206,7 @@ async function loadModuleGraphFromDotenv(
delete process.env['MOSAIC_STORAGE_TIER']; delete process.env['MOSAIC_STORAGE_TIER'];
delete process.env['DATABASE_URL']; delete process.env['DATABASE_URL'];
delete process.env['VALKEY_URL']; delete process.env['VALKEY_URL'];
delete process.env['MOSAIC_GATEWAY_HOME'];
await options.setup?.(fixture); await options.setup?.(fixture);
@@ -235,7 +237,7 @@ async function loadModuleGraphFromDotenv(
expect(process.env['MOSAIC_STORAGE_TIER']).toBe(options.inheritedTier); expect(process.env['MOSAIC_STORAGE_TIER']).toBe(options.inheritedTier);
} }
await import('./env.js'); const envModule = await import('./env.js');
expect(process.env['MOSAIC_STORAGE_TIER']).toBe( expect(process.env['MOSAIC_STORAGE_TIER']).toBe(
options.expectedProcessTier ?? options.rootTier, options.expectedProcessTier ?? options.rootTier,
); );
@@ -270,6 +272,7 @@ async function loadModuleGraphFromDotenv(
args.map((value: unknown): string => String(value)).join(' '), args.map((value: unknown): string => String(value)).join(' '),
), ),
mosaicConfig: configProvider.useFactory(), mosaicConfig: configProvider.useFactory(),
resolvedConfigPath: envModule.resolveGatewayConfigPath(),
}; };
} finally { } finally {
cwdSpy?.mockRestore(); cwdSpy?.mockRestore();
@@ -360,20 +363,53 @@ describe('AppModule federation gating', (): void => {
); );
it( it(
'anchored monorepo-root config wins gateway-local config and registers FederationModule', 'anchored gateway-local config wins monorepo-root config and registers FederationModule',
async (): Promise<void> => { async (): Promise<void> => {
let gatewayLocalConfigPath = '';
const graph = await loadModuleGraphFromDotenv({ const graph = await loadModuleGraphFromDotenv({
rootTier: 'local', rootTier: 'local',
setup: async (fixture: ModuleGraphFixture): Promise<void> => { setup: async (fixture: ModuleGraphFixture): Promise<void> => {
gatewayLocalConfigPath = fixture.gatewayLocalConfigPath;
await writeFixture( await writeFixture(
fixture.monorepoRootConfigPath, fixture.gatewayLocalConfigPath,
configJson('federated'), configJson('federated'),
fixture.tempRoot, fixture.tempRoot,
); );
await writeFixture(fixture.gatewayLocalConfigPath, configJson('local'), fixture.tempRoot); await writeFixture(fixture.monorepoRootConfigPath, configJson('local'), fixture.tempRoot);
}, },
}); });
expect(graph.resolvedConfigPath).toBe(gatewayLocalConfigPath);
expect(graph.mosaicConfig.tier).toBe('federated');
expect(graph.imports).toContain(graph.federationModule);
expectBootLogLine(graph.bootLogLines, 'federated', 'mosaic.config.json');
},
MODULE_IMPORT_TIMEOUT_MS,
);
it(
'resolves the daemon-installed GATEWAY_HOME/mosaic.config.json ahead of gateway-local and monorepo-root configs',
async (): Promise<void> => {
let daemonConfigPath = '';
const graph = await loadModuleGraphFromDotenv({
rootEnvMode: 'absent',
setup: async (fixture: ModuleGraphFixture): Promise<void> => {
const externalGatewayHome = join(fixture.tempRoot, 'external-gateway-home');
daemonConfigPath = join(externalGatewayHome, 'mosaic.config.json');
await writeFixture(daemonConfigPath, configJson('federated'), fixture.tempRoot);
await writeFixture(
fixture.gatewayLocalConfigPath,
configJson('standalone'),
fixture.tempRoot,
);
await writeFixture(fixture.monorepoRootConfigPath, configJson('local'), fixture.tempRoot);
process.env['MOSAIC_GATEWAY_HOME'] = externalGatewayHome;
process.env['DATABASE_URL'] = 'postgresql://fixture.invalid/mosaic';
},
});
expect(graph.resolvedConfigPath).toBe(daemonConfigPath);
expect(graph.mosaicConfig.tier).toBe('federated');
expect(graph.imports).toContain(graph.federationModule); expect(graph.imports).toContain(graph.federationModule);
expectBootLogLine(graph.bootLogLines, 'federated', 'mosaic.config.json'); expectBootLogLine(graph.bootLogLines, 'federated', 'mosaic.config.json');
}, },
+11 -3
View File
@@ -34,15 +34,23 @@ export function resolveGatewayDotenvPaths(
} }
export function resolveGatewayConfigPath(anchor: string = here): string { export function resolveGatewayConfigPath(anchor: string = here): string {
const monorepoRootConfig = resolve(anchor, '../../..', 'mosaic.config.json'); // GATEWAY_HOME is daemon-created 0700; its env override adds no authority because env can set MOSAIC_STORAGE_TIER.
const gatewayHome = resolve(
process.env['MOSAIC_GATEWAY_HOME'] ?? join(homedir(), '.config', 'mosaic', 'gateway'),
);
const daemonConfig = join(gatewayHome, 'mosaic.config.json');
const gatewayLocalConfig = resolve(anchor, '..', 'mosaic.config.json'); const gatewayLocalConfig = resolve(anchor, '..', 'mosaic.config.json');
const monorepoRootConfig = resolve(anchor, '../../..', 'mosaic.config.json');
if (existsSync(monorepoRootConfig)) { if (existsSync(daemonConfig)) {
return monorepoRootConfig; return daemonConfig;
} }
if (existsSync(gatewayLocalConfig)) { if (existsSync(gatewayLocalConfig)) {
return gatewayLocalConfig; return gatewayLocalConfig;
} }
if (existsSync(monorepoRootConfig)) {
return monorepoRootConfig;
}
return monorepoRootConfig; return monorepoRootConfig;
} }