ci/woodpecker/push/publish Pipeline failed
Co-authored-by: Jason Woltje <[email protected]>
115 lines
4.7 KiB
TypeScript
115 lines
4.7 KiB
TypeScript
import { mkdir, mkdtemp, rm } from 'node:fs/promises';
|
|
import { homedir, tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
import {
|
|
brainHomeIsActive,
|
|
fleetAgentEnvDir,
|
|
fleetProfilesDir,
|
|
fleetRolesLocalDir,
|
|
fleetStateDir,
|
|
resolveBrainHome,
|
|
type BrainHomeOptions,
|
|
} from './brain-home.js';
|
|
|
|
describe('fleet brain-home resolution', (): void => {
|
|
let cleanup: string | undefined;
|
|
|
|
const savedBrainEnv = process.env['MOSAIC_BRAIN_HOME'];
|
|
|
|
beforeEach((): void => {
|
|
delete process.env['MOSAIC_BRAIN_HOME'];
|
|
});
|
|
|
|
afterEach(async (): Promise<void> => {
|
|
if (savedBrainEnv === undefined) {
|
|
delete process.env['MOSAIC_BRAIN_HOME'];
|
|
} else {
|
|
process.env['MOSAIC_BRAIN_HOME'] = savedBrainEnv;
|
|
}
|
|
if (cleanup !== undefined) {
|
|
await rm(cleanup, { recursive: true, force: true });
|
|
cleanup = undefined;
|
|
}
|
|
});
|
|
|
|
async function makeTmp(): Promise<string> {
|
|
const root = await mkdtemp(join(tmpdir(), 'mosaic-brain-home-'));
|
|
cleanup = root;
|
|
return root;
|
|
}
|
|
|
|
it('MOSAIC_BRAIN_HOME env wins over every other signal', (): void => {
|
|
process.env['MOSAIC_BRAIN_HOME'] = '/explicit/brain';
|
|
expect(resolveBrainHome('/any/mosaic-home')).toBe('/explicit/brain');
|
|
expect(fleetAgentEnvDir('/any/mosaic-home')).toBe('/explicit/brain/fleet/agents');
|
|
expect(brainHomeIsActive('/any/mosaic-home')).toBe(true);
|
|
});
|
|
|
|
it('injected envBrainHome wins identically (test seam)', (): void => {
|
|
const opts: BrainHomeOptions = { envBrainHome: '/injected/brain' };
|
|
expect(resolveBrainHome('/any/mosaic-home', opts)).toBe('/injected/brain');
|
|
expect(fleetAgentEnvDir('/any/mosaic-home', opts)).toBe('/injected/brain/fleet/agents');
|
|
});
|
|
|
|
it('a non-default mosaicHome never adopts the canonical brain (hermetic legacy)', (): void => {
|
|
const mosaicHome = '/tmp/not-the-default-config-home';
|
|
expect(resolveBrainHome(mosaicHome)).toBe(mosaicHome);
|
|
expect(brainHomeIsActive(mosaicHome)).toBe(false);
|
|
expect(fleetAgentEnvDir(mosaicHome)).toBe(join(mosaicHome, 'fleet', 'agents'));
|
|
});
|
|
|
|
it('the default config home adopts the brain when it carries fleet/agents', async (): Promise<void> => {
|
|
const root = await makeTmp();
|
|
const brain = join(root, 'brain');
|
|
await mkdir(join(brain, 'fleet', 'agents'), { recursive: true });
|
|
const configHome = join(root, 'config', 'mosaic');
|
|
const opts: BrainHomeOptions = { homes: { brain, configDefault: configHome } };
|
|
|
|
expect(resolveBrainHome(configHome, opts)).toBe(brain);
|
|
expect(fleetAgentEnvDir(configHome, opts)).toBe(join(brain, 'fleet', 'agents'));
|
|
expect(fleetRolesLocalDir(configHome, opts)).toBe(join(brain, 'fleet', 'roles.local'));
|
|
expect(fleetProfilesDir(configHome, opts)).toBe(join(brain, 'fleet', 'profiles'));
|
|
expect(fleetStateDir(configHome, opts)).toBe(join(brain, 'fleet'));
|
|
expect(brainHomeIsActive(configHome, opts)).toBe(true);
|
|
});
|
|
|
|
it('the default config home stays legacy when no brain exists', async (): Promise<void> => {
|
|
const root = await makeTmp();
|
|
const configHome = join(root, 'config', 'mosaic');
|
|
const opts: BrainHomeOptions = {
|
|
homes: { brain: join(root, 'brain'), configDefault: configHome },
|
|
};
|
|
|
|
expect(resolveBrainHome(configHome, opts)).toBe(configHome);
|
|
expect(brainHomeIsActive(configHome, opts)).toBe(false);
|
|
});
|
|
|
|
it('an empty MOSAIC_BRAIN_HOME is ignored, not treated as set', (): void => {
|
|
process.env['MOSAIC_BRAIN_HOME'] = ' ';
|
|
expect(resolveBrainHome('/tmp/legacy-home')).toBe('/tmp/legacy-home');
|
|
});
|
|
|
|
it('adoption requires fleet/agents specifically, not any brain content', async (): Promise<void> => {
|
|
const root = await makeTmp();
|
|
const brain = join(root, 'brain');
|
|
await mkdir(join(brain, 'fleet'), { recursive: true }); // fleet without agents
|
|
const configHome = join(root, 'config', 'mosaic');
|
|
const opts: BrainHomeOptions = { homes: { brain, configDefault: configHome } };
|
|
|
|
expect(resolveBrainHome(configHome, opts)).toBe(configHome);
|
|
});
|
|
|
|
it('real-home control: a host brain is adopted only through the default home', (): void => {
|
|
// Control on the un-injected path: this host carries ~/.mosaic/fleet/agents,
|
|
// so the default config home resolves to the brain or legacy — both valid
|
|
// canonical endpoints — while a non-default home never adopts.
|
|
const defaultHome = join(homedir(), '.config', 'mosaic');
|
|
const resolved = resolveBrainHome(defaultHome);
|
|
expect([defaultHome, join(homedir(), '.mosaic')]).toContain(resolved);
|
|
expect(resolveBrainHome(join(homedir(), 'elsewhere', 'mosaic'))).toBe(
|
|
join(homedir(), 'elsewhere', 'mosaic'),
|
|
);
|
|
});
|
|
});
|