import { randomUUID } from 'node:crypto' import { mkdtemp, rm } from 'node:fs/promises' import { tmpdir } from 'node:os' import path from 'node:path' import { createGeneratedArtifact, downloadGeneratedArtifact, } from '../../packages/application/src/index' import { LocalArtifactStorage } from '../../packages/artifacts/src/index' import { closeDatabase, DrizzleGeneratedArtifactStore, DrizzleWorkspaceAuthorizationLookup, getSqlClient, } from '../../packages/db/src/index' import { afterAll, describe, expect, it } from 'vitest' const databaseUrl = process.env.DATABASE_URL const integration = databaseUrl ? describe : describe.skip const cleanupRoots: string[] = [] afterAll(async () => { await closeDatabase() await Promise.all( cleanupRoots.splice(0).map((root) => rm(root, { recursive: true })), ) }) integration('generated artifact persistence', () => { it('persists authorized metadata and restart-readable verified bytes', async () => { const sql = getSqlClient(databaseUrl) const userId = randomUUID() const workspaceId = randomUUID() const otherWorkspaceId = randomUUID() const playbookId = randomUUID() const versionId = randomUUID() const runId = randomUUID() const artifactId = randomUUID() const namespace = `artifact-integration-${randomUUID()}` const artifactRoot = await mkdtemp( path.join(tmpdir(), 'devrunbook-artifact-integration-'), ) cleanupRoots.push(artifactRoot) await sql.begin(async (transaction) => { await transaction` insert into users (id, email, display_name, password_hash, instance_role) values (${userId}, ${`${userId}@example.invalid`}, 'Artifact Integration', 'not-a-login-credential', 'user') ` await transaction` insert into workspaces (id, name) values (${workspaceId}, 'Artifact Workspace'), (${otherWorkspaceId}, 'Other Workspace') ` await transaction` insert into workspace_memberships (user_id, workspace_id, role) values (${userId}, ${workspaceId}, 'editor') ` await transaction` insert into playbooks (id, workspace_id, logical_id, slug, namespace, source_type) values (${playbookId}, ${workspaceId}, 'artifact-integration', 'artifact-integration', ${namespace}, 'private') ` await transaction` insert into playbook_versions ( id, playbook_id, semantic_version, lifecycle, package_api_version, title, summary, category, risk_tier, package_json, template_text, content_digest, created_by ) values ( ${versionId}, ${playbookId}, '1.0.0', 'validated', 'devrunbook.playbook/v1.2', 'Artifact integration', 'Integration fixture', 'test', 'low', '{}'::jsonb, '# Test', ${'a'.repeat(64)}, ${userId} ) ` await transaction` 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 ) values ( ${runId}, ${workspaceId}, ${versionId}, '{}'::jsonb, null, '{}'::jsonb, '{}'::jsonb, '[]'::jsonb, '{"exportReadiness":"ready","findings":[]}'::jsonb, '# Test', ${'b'.repeat(64)}, ${`artifact-${artifactId}`}, ${userId} ) ` }) const metadata = new DrizzleGeneratedArtifactStore() const authorization = new DrizzleWorkspaceAuthorizationLookup() const content = new TextEncoder().encode('# Test\n') const created = await createGeneratedArtifact( { authorization, metadata, storage: new LocalArtifactStorage(artifactRoot), now: () => new Date('2026-07-27T12:00:00.000Z'), }, { actor: { userId }, workspaceId, artifactId, runId, artifactType: 'markdown', filename: 'test.md', mediaType: 'text/markdown; charset=utf-8', content, }, ) expect(created.created).toBe(true) const [persisted] = await sql< { id: string; runId: string; sha256: string; sizeBytes: string }[] >` select id, run_id as "runId", sha256, size_bytes as "sizeBytes" from generated_artifacts where id = ${artifactId} ` expect(persisted).toMatchObject({ id: artifactId, runId, sha256: created.artifact.sha256, sizeBytes: String(content.byteLength), }) const downloaded = await downloadGeneratedArtifact( { authorization, metadata: new DrizzleGeneratedArtifactStore(), storage: new LocalArtifactStorage(artifactRoot), }, { actor: { userId }, workspaceId, artifactId }, ) expect(downloaded.content).toEqual(content) expect(downloaded.artifact.sha256).toHaveLength(64) await expect( metadata.listByRunInWorkspace(runId, workspaceId), ).resolves.toMatchObject([ { id: artifactId, runId, workspaceId, sha256: created.artifact.sha256 }, ]) await expect( metadata.listByRunInWorkspace(runId, otherWorkspaceId), ).resolves.toEqual([]) await expect( downloadGeneratedArtifact( { authorization, metadata, storage: new LocalArtifactStorage(artifactRoot), }, { actor: { userId }, workspaceId: otherWorkspaceId, artifactId }, ), ).rejects.toMatchObject({ code: 'workspace_access_denied' }) await sql`delete from workspaces where id in (${workspaceId}, ${otherWorkspaceId})` await sql`delete from users where id = ${userId}` }) })