feat(migration): add verified import and rollback workflow
This commit is contained in:
@@ -103,6 +103,7 @@ describe('legacy import', () => {
|
||||
description: 'primary',
|
||||
tags: ['prod', 'blue'],
|
||||
capabilities: ['status.read', 'sim.restart'],
|
||||
authMode: 'password',
|
||||
credentialPresent: true,
|
||||
status: 'planned',
|
||||
});
|
||||
@@ -142,6 +143,15 @@ describe('legacy import', () => {
|
||||
expect(scan(error)).not.toContain(password);
|
||||
});
|
||||
|
||||
it('never includes a malformed source excerpt in an error', async () => {
|
||||
const path = await legacyFile({});
|
||||
const marker = 'malformed-secret-never-echo';
|
||||
await writeFile(path, `{"instances":[],"password":"${marker}" trailing`);
|
||||
const error = await rejection(() => previewLegacyImport(path));
|
||||
expect(error.message).toBe('Legacy config is not valid JSON');
|
||||
expect(scan(error)).not.toContain(marker);
|
||||
});
|
||||
|
||||
it('rejects symlinks and non-regular files', async () => {
|
||||
const path = await legacyFile(valid);
|
||||
const link = `${path}.link`;
|
||||
@@ -243,6 +253,23 @@ describe('legacy import', () => {
|
||||
await expect(confirmLegacyImport(fresh, tampered, db)).rejects.toThrow(/digest/i);
|
||||
});
|
||||
|
||||
it('binds status and auth mode into the execution plan digest', async () => {
|
||||
const path = await legacyFile(valid);
|
||||
const db = database();
|
||||
const preview = await previewLegacyImport(path, db);
|
||||
const instance = preview.instances[0]!;
|
||||
const statusTampered = {
|
||||
...preview,
|
||||
instances: [{ ...instance, status: 'unchanged' as const }, ...preview.instances.slice(1)],
|
||||
} as LegacyImportPreview;
|
||||
await expect(confirmLegacyImport(path, statusTampered, db)).rejects.toThrow(/digest/i);
|
||||
const authTampered = {
|
||||
...preview,
|
||||
instances: [{ ...instance, authMode: 'none' as const }, ...preview.instances.slice(1)],
|
||||
} as LegacyImportPreview;
|
||||
await expect(confirmLegacyImport(path, authTampered, db)).rejects.toThrow(/digest/i);
|
||||
});
|
||||
|
||||
it('reports conflicts and confirmation rejects the entire transaction', async () => {
|
||||
const path = await legacyFile(valid);
|
||||
const db = database();
|
||||
|
||||
Reference in New Issue
Block a user