Skip to content

Commit fb27e1b

Browse files
committed
fix(projects): reject verification of conflicted plans
1 parent 454e2e2 commit fb27e1b

2 files changed

Lines changed: 44 additions & 0 deletions

File tree

‎apps/sim/scripts/backfill-projects.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ Defaults: --batch-size 50 (1–50), --max-batches 100 (1–10000), --seconds 60
230230
counts.pendingCleanup = manifest.repairs.filter(
231231
(repair) => !report.repairsCompleted.includes(repair.workspaceId)
232232
).length
233+
counts.conflicts = manifest.conflicts.length
233234
logger.info('Project verification', { databaseId, ...counts })
234235
if (Object.values(counts).some((count) => count !== 0)) process.exitCode = 2
235236
return

‎packages/db/scripts/project-contract.integration.ts‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,49 @@ describe('Project expand/backfill/contract against PostgreSQL', () => {
298298
})
299299
}, 60000)
300300

301+
it('refuses a conflicted manifest even after its database invariants have been repaired', async () => {
302+
await database(async (sql, url) => {
303+
const directory = await mkdtemp(join(tmpdir(), 'project-conflict-verify-test-'))
304+
const run = (command: string, plan: string) =>
305+
promisify(execFile)(
306+
'bun',
307+
[
308+
'--no-env-file',
309+
'scripts/backfill-projects.ts',
310+
command,
311+
'--manifest',
312+
join(directory, `${plan}-manifest.json`),
313+
'--report',
314+
join(directory, `${plan}-report.json`),
315+
'--ack-release-drained',
316+
],
317+
{
318+
cwd: new URL('../../../apps/sim/', import.meta.url),
319+
env: { ...process.env, MIGRATION_DATABASE_URL: url },
320+
timeout: 15000,
321+
}
322+
)
323+
try {
324+
await sql`INSERT INTO "user" VALUES ('other-owner')`
325+
await sql`INSERT INTO workspace (id,name,owner_id) VALUES ('root','Root','owner')`
326+
await sql`INSERT INTO workspace (id,name,owner_id,forked_from_workspace_id)
327+
VALUES ('child','Child','other-owner','root')`
328+
await expect(run('plan', 'conflicted')).rejects.toMatchObject({ code: 2 })
329+
await expect(run('apply', 'conflicted')).rejects.toMatchObject({ code: 2 })
330+
await sql`UPDATE workspace SET owner_id = 'owner' WHERE id = 'child'`
331+
await run('plan', 'repaired')
332+
await run('apply', 'repaired')
333+
expect(Object.values(await verifyProjectBackfill(sql)).every((count) => count === 0)).toBe(
334+
true
335+
)
336+
await run('verify', 'repaired')
337+
await expect(run('verify', 'conflicted')).rejects.toMatchObject({ code: 2 })
338+
} finally {
339+
await rm(directory, { recursive: true, force: true })
340+
}
341+
})
342+
}, 30000)
343+
301344
it.each([
302345
['plan', 'SIGINT'],
303346
['verify', 'SIGTERM'],

0 commit comments

Comments
 (0)