Files
DevRunbook-Public/packages/application/src/artifacts/generated-artifact.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

174 lines
5.2 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import type {
GeneratedArtifactMetadata,
GeneratedArtifactMetadataStore,
ImmutableArtifactStorage,
StoreGeneratedArtifactResult,
WorkspaceAuthorizationRecord,
} from '..'
import {
createGeneratedArtifact,
downloadGeneratedArtifact,
} from './generated-artifact'
const workspaceId = '00000000-0000-4000-8000-000000000101'
const userId = '00000000-0000-4000-8000-000000000102'
const runId = '00000000-0000-4000-8000-000000000103'
const artifactId = '00000000-0000-4000-8000-000000000104'
class MemoryMetadata implements GeneratedArtifactMetadataStore {
artifact: GeneratedArtifactMetadata | null = null
async createIdempotently(
artifact: GeneratedArtifactMetadata,
): Promise<StoreGeneratedArtifactResult> {
if (!this.artifact) {
this.artifact = artifact
return { artifact, created: true }
}
return { artifact: this.artifact, created: false }
}
async findByIdInWorkspace(id: string, workspace: string) {
return this.artifact?.id === id && this.artifact.workspaceId === workspace
? this.artifact
: null
}
async listByRunInWorkspace(runId: string, workspace: string) {
return this.artifact?.runId === runId &&
this.artifact.workspaceId === workspace
? [this.artifact]
: []
}
}
class MemoryStorage implements ImmutableArtifactStorage {
readonly bytes = new Map<string, Uint8Array>()
async putImmutable(key: string, content: Uint8Array) {
const created = !this.bytes.has(key)
if (created) this.bytes.set(key, new Uint8Array(content))
return { created }
}
async read(key: string) {
const content = this.bytes.get(key)
if (!content) throw new Error('missing')
return new Uint8Array(content)
}
}
function authorization(role: 'viewer' | 'editor' | 'owner') {
return {
async findWorkspaceAuthorization(): Promise<WorkspaceAuthorizationRecord> {
return {
userId,
workspaceId,
instanceRole: 'user',
workspaceRole: role,
userStatus: 'active',
}
},
}
}
function request(content = new TextEncoder().encode('# Run\n')) {
return {
actor: { userId },
workspaceId,
artifactId,
runId,
artifactType: 'markdown' as const,
filename: 'run.md',
mediaType: 'text/markdown; charset=utf-8',
content,
}
}
describe('generated artifact use cases', () => {
it('creates immutable bytes and metadata idempotently', async () => {
const metadata = new MemoryMetadata()
const storage = new MemoryStorage()
const dependencies = {
authorization: authorization('editor'),
metadata,
storage,
now: () => new Date('2026-07-27T12:00:00.000Z'),
}
await expect(
createGeneratedArtifact(dependencies, request()),
).resolves.toMatchObject({ created: true })
await expect(
createGeneratedArtifact(dependencies, request()),
).resolves.toMatchObject({ created: false })
expect(metadata.artifact?.sha256).toHaveLength(64)
expect(metadata.artifact?.sizeBytes).toBe(6n)
expect(metadata.artifact?.storageKey).toMatch(/^[0-9a-f]{64}$/)
expect(storage.bytes).toHaveLength(1)
})
it('allows a viewer to download only from the authorized workspace', async () => {
const metadata = new MemoryMetadata()
const storage = new MemoryStorage()
await createGeneratedArtifact(
{
authorization: authorization('editor'),
metadata,
storage,
now: () => new Date('2026-07-27T12:00:00.000Z'),
},
request(),
)
const download = await downloadGeneratedArtifact(
{ authorization: authorization('viewer'), metadata, storage },
{ actor: { userId }, workspaceId, artifactId },
)
expect(new TextDecoder().decode(download.content)).toBe('# Run\n')
await expect(
downloadGeneratedArtifact(
{ authorization: authorization('viewer'), metadata, storage },
{
actor: { userId },
workspaceId: '00000000-0000-4000-8000-000000000999',
artifactId,
},
),
).rejects.toMatchObject({ code: 'workspace_access_denied' })
})
it('rejects unsafe filenames, viewer creation, and corrupted bytes', async () => {
const metadata = new MemoryMetadata()
const storage = new MemoryStorage()
const base = {
authorization: authorization('editor'),
metadata,
storage,
now: () => new Date('2026-07-27T12:00:00.000Z'),
}
await expect(
createGeneratedArtifact(base, { ...request(), filename: '../run.md' }),
).rejects.toMatchObject({ code: 'generated_artifact_filename_invalid' })
await expect(
createGeneratedArtifact(
{ ...base, authorization: authorization('viewer') },
request(),
),
).rejects.toMatchObject({ code: 'workspace_access_denied' })
await createGeneratedArtifact(base, request())
const key = metadata.artifact?.storageKey
if (!key) throw new Error('expected storage key')
storage.bytes.set(key, new TextEncoder().encode('tampered'))
await expect(
downloadGeneratedArtifact(
{ authorization: authorization('viewer'), metadata, storage },
{ actor: { userId }, workspaceId, artifactId },
),
).rejects.toMatchObject({ code: 'generated_artifact_integrity_failed' })
})
})