Files
DevRunbook-Public/packages/db/src/generated-runs/generated-run-history.integration.test.ts
T
DevRunbook release export cfd2804e27
Managed validation / full (push) Successful in 3m18s
Publish DevRunbook source
2026-09-03 04:09:17 +02:00

293 lines
9.9 KiB
TypeScript

import { createHash, randomUUID } from 'node:crypto'
import {
applyRepositoryProfileServerMetadata,
type RepositoryProfile,
} from '@devrunbook/repository-intel'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import { closeDatabase, getSqlClient } from '../index'
import { DrizzleGeneratedRunStore } from './generated-run-store'
const databaseIntegration =
process.env.DEVRUNBOOK_DATABASE_INTEGRATION === 'true' &&
Boolean(process.env.DATABASE_URL)
function profile(name: string): RepositoryProfile {
return applyRepositoryProfileServerMetadata(
{
apiVersion: 'devrunbook.io/v1alpha1',
kind: 'RepositoryProfile',
metadata: { name, revision: 1, source: 'manual' },
spec: {
repositoryType: 'single-app',
stack: {
languages: ['TypeScript'],
frameworks: [],
packageManagers: ['pnpm'],
databases: ['PostgreSQL'],
deploymentTypes: ['Docker'],
testFrameworks: ['Vitest'],
},
commands: [],
paths: {
applicationRoots: ['apps/web'],
testRoots: ['tests'],
documentationRoots: ['docs'],
generated: ['dist'],
protected: ['runtime'],
excluded: ['node_modules'],
},
policies: {
preserveBackwardCompatibility: true,
newDependencies: 'justify',
gitWrite: 'none',
migrations: 'reversible-only',
documentationRequired: true,
networkAccess: 'forbidden',
productionDataAccess: 'forbidden',
},
},
},
1,
)
}
describe.skipIf(!databaseIntegration)(
'generated-run history integration',
() => {
const workspaceA = randomUUID()
const workspaceB = randomUUID()
const userId = randomUUID()
const repositoryA = randomUUID()
const repositoryB = randomUUID()
const alphaSlug = `history-alpha-${randomUUID()}`
const betaSlug = `history-beta-${randomUUID()}`
let alphaVersionId: string
let betaVersionId: string
let profileRevisionA: string
let profileRevisionB: string
let store: DrizzleGeneratedRunStore
const runIds = [randomUUID(), randomUUID(), randomUUID()]
async function insertVersion(slug: string) {
const sql = getSqlClient()
const [playbook] = await sql<{ id: string }[]>`
insert into playbooks (
workspace_id, logical_id, slug, namespace, source_type
) values (
${workspaceA}, ${slug}, ${slug}, ${`private-${workspaceA}`}, 'private'
) returning id
`
const manifest = {
metadata: { slug, version: '1.0.0', title: 'History fixture' },
spec: { intent: { outcome: 'Verify history.' } },
}
const [version] = await sql<{ id: string }[]>`
insert into playbook_versions (
playbook_id, semantic_version, lifecycle, package_api_version,
title, summary, category, risk_tier, package_json, template_text,
content_digest, published_at, created_by
) values (
${playbook!.id}, '1.0.0', 'validated', 'devrunbook.io/v1alpha1',
'History fixture', 'History fixture', 'testing', 'low',
${JSON.stringify(manifest)}::jsonb, '# Task', ${'a'.repeat(64)},
'2026-07-27T12:00:00.000Z', ${userId}
) returning id
`
return version!.id
}
async function insertRun(input: {
id: string
workspaceId: string
playbookVersionId: string
slug: string
generatedAt: string
repository?: {
id: string
revisionId: string
document: RepositoryProfile
}
corruptRepository?: boolean
}) {
const sql = getSqlClient()
const prompt = `# ${input.id}\n`
const digest = createHash('sha256').update(prompt, 'utf8').digest('hex')
const repositorySnapshot = input.corruptRepository
? {
revisionId: input.repository!.revisionId,
repositoryId: input.repository!.id,
revisionNumber: 1,
contentDigest: input.repository!.document.metadata.contentDigest,
profile: {},
}
: input.repository
? {
revisionId: input.repository.revisionId,
repositoryId: input.repository.id,
revisionNumber: 1,
contentDigest: input.repository.document.metadata.contentDigest,
profile: input.repository.document,
}
: null
await sql`
insert into generated_runs (
id, workspace_id, playbook_version_id, playbook_snapshot_json,
repository_profile_snapshot_json, normalized_input_json,
policy_snapshot_json, provenance_json, lint_result_json,
rendered_prompt, render_digest, idempotency_key, generated_by,
generated_at
) values (
${input.id}, ${input.workspaceId}, ${input.playbookVersionId},
${JSON.stringify({ slug: input.slug })}::jsonb,
${repositorySnapshot === null ? null : JSON.stringify(repositorySnapshot)}::jsonb,
'{}'::jsonb, '{}'::jsonb, '[]'::jsonb,
${JSON.stringify({ exportReadiness: 'ready', findings: [] })}::jsonb,
${prompt}, ${digest}, ${randomUUID()}, ${userId}, ${input.generatedAt}
)
`
}
beforeAll(async () => {
const sql = getSqlClient()
await sql`
insert into users (
id, email, display_name, password_hash, instance_role, status
) values (
${userId}, ${`run-history-${userId}@example.invalid`}, 'Run history',
'not-a-real-password-hash', 'user', 'active'
)
`
await sql`
insert into workspaces (id, name, type)
values
(${workspaceA}, 'Run history A', 'team'),
(${workspaceB}, 'Run history B', 'team')
`
await sql`
insert into repositories (id, workspace_id, display_name, source_type)
values
(${repositoryA}, ${workspaceA}, 'Repository A', 'manual'),
(${repositoryB}, ${workspaceA}, 'Repository B', 'manual')
`
alphaVersionId = await insertVersion(alphaSlug)
betaVersionId = await insertVersion(betaSlug)
const profileA = profile('Repository A')
const profileB = profile('Repository B')
const [revisionA] = await sql<{ id: string }[]>`
insert into repository_profile_revisions (
repository_id, revision_number, profile_json, content_digest, created_by
) values (
${repositoryA}, 1, ${JSON.stringify(profileA)}::jsonb,
${profileA.metadata.contentDigest!}, ${userId}
) returning id
`
const [revisionB] = await sql<{ id: string }[]>`
insert into repository_profile_revisions (
repository_id, revision_number, profile_json, content_digest, created_by
) values (
${repositoryB}, 1, ${JSON.stringify(profileB)}::jsonb,
${profileB.metadata.contentDigest!}, ${userId}
) returning id
`
profileRevisionA = revisionA!.id
profileRevisionB = revisionB!.id
await insertRun({
id: runIds[0]!,
workspaceId: workspaceA,
playbookVersionId: alphaVersionId,
slug: alphaSlug,
generatedAt: '2026-07-27T12:00:00.000Z',
repository: {
id: repositoryA,
revisionId: profileRevisionA,
document: profileA,
},
})
await insertRun({
id: runIds[1]!,
workspaceId: workspaceA,
playbookVersionId: alphaVersionId,
slug: alphaSlug,
generatedAt: '2026-07-27T12:00:00.000Z',
})
await insertRun({
id: runIds[2]!,
workspaceId: workspaceA,
playbookVersionId: betaVersionId,
slug: betaSlug,
generatedAt: '2026-07-26T12:00:00.000Z',
repository: {
id: repositoryB,
revisionId: profileRevisionB,
document: profileB,
},
})
store = new DrizzleGeneratedRunStore()
})
afterAll(async () => {
const sql = getSqlClient()
await sql`delete from workspaces where id in (${workspaceA}, ${workspaceB})`
await sql`delete from users where id = ${userId}`
await closeDatabase()
})
it('paginates generatedAt plus ID without duplicates or omissions', async () => {
const seen: string[] = []
let cursor: string | null = null
do {
const page = await store.listForWorkspace(workspaceA, {
limit: 1,
cursor,
})
seen.push(...page.items.map((item) => item.id))
cursor = page.nextCursor
} while (cursor)
const tied = runIds
.slice(0, 2)
.sort((left, right) => left.localeCompare(right, 'en'))
expect(seen).toEqual([...tied, runIds[2]])
expect(new Set(seen).size).toBe(3)
await expect(store.listForWorkspace(workspaceB, {})).resolves.toEqual({
items: [],
nextCursor: null,
})
})
it('filters playbooks relationally and repositories through validated snapshots', async () => {
const byPlaybook = await store.listForWorkspace(workspaceA, {
playbookSlug: alphaSlug,
})
expect(byPlaybook.items.map((item) => item.id).sort()).toEqual(
runIds.slice(0, 2).sort(),
)
const byRepository = await store.listForWorkspace(workspaceA, {
repositoryId: repositoryA,
})
expect(byRepository.items.map((item) => item.id)).toEqual([runIds[0]])
})
it('fails closed when a repository filter encounters a corrupt frozen snapshot', async () => {
const corruptId = randomUUID()
await insertRun({
id: corruptId,
workspaceId: workspaceA,
playbookVersionId: alphaVersionId,
slug: alphaSlug,
generatedAt: '2026-07-28T12:00:00.000Z',
repository: {
id: repositoryA,
revisionId: profileRevisionA,
document: profile('Repository A'),
},
corruptRepository: true,
})
await expect(
store.listForWorkspace(workspaceA, { repositoryId: repositoryA }),
).rejects.toMatchObject({ code: 'generated_run_persistence_corrupt' })
})
},
)