fix(mosaic): exclude nested secret migration paths
This commit is contained in:
@@ -658,6 +658,15 @@ describe('R7 — migration is non-destructive, append-only, and explicit', (): v
|
||||
for (const name of secretNames) {
|
||||
writeFileSync(join(laneRoot, name), 'DO-NOT-MIGRATE\n');
|
||||
}
|
||||
const nestedSecretPaths = [
|
||||
join('.env.d', 'database.txt'),
|
||||
join('credentials.d', 'token.txt'),
|
||||
join('secrets', 'private.txt'),
|
||||
];
|
||||
for (const path of nestedSecretPaths) {
|
||||
mkdirSync(join(laneRoot, path, '..'), { recursive: true });
|
||||
writeFileSync(join(laneRoot, path), 'NESTED-SECRET-MARKER\n');
|
||||
}
|
||||
|
||||
const plan = sut.discoverBrainMigration(
|
||||
{ sourceRoot, brainRoot, seat: 'seat-a', lane: 'lane-a', laneActive: true },
|
||||
@@ -666,8 +675,9 @@ describe('R7 — migration is non-destructive, append-only, and explicit', (): v
|
||||
|
||||
expect(plan.status).toBe('ready');
|
||||
expect(plan.candidates).toHaveLength(0);
|
||||
expect(plan.reported).toHaveLength(secretNames.length);
|
||||
expect(plan.reported).toHaveLength(secretNames.length + nestedSecretPaths.length);
|
||||
expect(plan.reported.every((entry) => /secret/i.test(entry.reason))).toBe(true);
|
||||
expect(JSON.stringify(plan)).not.toContain('NESTED-SECRET-MARKER');
|
||||
expect(existsSync(brainRoot)).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
@@ -630,8 +630,8 @@ function migrationCandidate(
|
||||
};
|
||||
}
|
||||
|
||||
function secretShapedPath(path: string): boolean {
|
||||
const name = basename(path).toLowerCase();
|
||||
function secretShapedName(value: string): boolean {
|
||||
const name = value.toLowerCase();
|
||||
return (
|
||||
name === '.env' ||
|
||||
name.startsWith('.env.') ||
|
||||
@@ -648,6 +648,10 @@ function secretShapedPath(path: string): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function secretShapedPath(sourceRoot: string, path: string): boolean {
|
||||
return relative(sourceRoot, path).split(sep).filter(Boolean).some(secretShapedName);
|
||||
}
|
||||
|
||||
function reportAll(paths: readonly string[], reason: string): MigrationReport[] {
|
||||
return paths.map((path: string): MigrationReport => ({ path, reason }));
|
||||
}
|
||||
@@ -708,7 +712,7 @@ export function discoverBrainMigration(
|
||||
'Ownership or supported migration shape was not established; retained and reported.',
|
||||
);
|
||||
for (const path of laneFiles) {
|
||||
if (secretShapedPath(path)) {
|
||||
if (secretShapedPath(input.sourceRoot, path)) {
|
||||
reported.push({
|
||||
path,
|
||||
reason: 'Secret-shaped state is forbidden in the brain; retained and reported.',
|
||||
@@ -724,7 +728,7 @@ export function discoverBrainMigration(
|
||||
}
|
||||
}
|
||||
for (const path of seatFiles) {
|
||||
if (secretShapedPath(path)) {
|
||||
if (secretShapedPath(input.sourceRoot, path)) {
|
||||
reported.push({
|
||||
path,
|
||||
reason: 'Secret-shaped state is forbidden in the brain; retained and reported.',
|
||||
|
||||
Reference in New Issue
Block a user