Files
AfiS-Aktensystem/web/tests/anhaenge.test.ts
T
Harlekin e0b03ea336
Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
Gedankenstriche durch Bindestriche ersetzt
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die
README; an keiner Stelle Bedeutung, nur Zeichensetzung.
2026-09-04 08:54:52 +02:00

153 lines
5.1 KiB
TypeScript

// @vitest-environment node
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import { db } from '@/lib/db'
import { visibleAttachmentWhere } from '@/lib/access/attachmentFilter'
import { loadDeliverable } from '@/lib/files/service'
import type { EffectivePermissions, Permission } from '@/lib/auth/permissions'
/**
* Ein Anhang hat keine eigene Freigabestufe, er erbt die seines Besitzers.
* Diese Tests prüfen beide Seiten davon: dass die Stufe wirklich durchschlägt,
* und dass eine Datei, die die Prüfkette nicht bestanden hat, gar nicht erst
* ausgeliefert wird - auch nicht an einen Administrator.
*/
const url = process.env.DIRECT_DATABASE_URL ?? process.env.DATABASE_URL
const suite = url ? describe : describe.skip
const marke = `anhang-${Date.now()}`
function perms(
userId: string,
clearanceLevel: number,
options: { isAdmin?: boolean; permissions?: Permission[] } = {},
): EffectivePermissions {
return {
userId,
clearanceLevel,
permissions: new Set<Permission>(options.permissions ?? []),
isAdmin: options.isAdmin ?? false,
hasMembership: true,
}
}
suite('Sichtbarkeit von Anhängen', () => {
const nutzer = { stufe1: `${marke}-stufe1`, stufe4: `${marke}-stufe4` }
const anhang = { offen: '', geheim: '', imEintrag: '', inQuarantaene: '' }
beforeAll(async () => {
const vorlage = await db.documentTemplate.create({
data: { key: `${marke}-vorlage`, version: 1, name: 'Prüfvorlage', fields: [] },
})
for (const id of Object.values(nutzer)) {
await db.user.create({ data: { id, username: id, displayName: id } })
}
const gemeinsam = {
templateId: vorlage.id,
templateKey: vorlage.key,
createdById: nutzer.stufe4,
}
const offen = await db.case.create({
data: {
...gemeinsam,
caseNumber: `${marke}-o`.slice(0, 40),
title: 'Offen',
classification: 1,
status: 'OPEN',
},
})
const geheim = await db.case.create({
data: {
...gemeinsam,
caseNumber: `${marke}-g`.slice(0, 40),
title: 'Geheim',
classification: 4,
status: 'OPEN',
},
})
const eintrag = await db.caseEntry.create({
data: {
id: `${marke}-eintrag`,
caseId: offen.id,
type: 'NOTE',
body: 'Nur ab Stufe 4',
authorId: nutzer.stufe4,
minClearance: 4,
},
})
const anlegen = async (
name: string,
besitzer: { caseId?: string; entryId?: string },
scanStatus: 'CLEAN' | 'PENDING' = 'CLEAN',
) =>
(
await db.attachment.create({
data: {
originalName: `${name}.png`,
mimeType: 'image/png',
sizeBytes: 100,
sha256: `${marke}-${name}`,
storageKey: `store/aa/bb/${marke}-${name}`,
uploadedById: nutzer.stufe4,
scanStatus,
...besitzer,
},
select: { id: true },
})
).id
anhang.offen = await anlegen('offen', { caseId: offen.id })
anhang.geheim = await anlegen('geheim', { caseId: geheim.id })
anhang.imEintrag = await anlegen('eintrag', { entryId: eintrag.id })
anhang.inQuarantaene = await anlegen('quarantaene', { caseId: offen.id }, 'PENDING')
})
afterAll(async () => {
await db.$disconnect()
})
async function sichtbar(p: EffectivePermissions): Promise<string[]> {
const rows = await db.attachment.findMany({
where: { AND: [visibleAttachmentWhere(p), { id: { in: Object.values(anhang) } }] },
select: { id: true },
})
return rows.map((r) => r.id).sort()
}
it('verbirgt den Anhang einer zu hoch eingestuften Akte, auch in der Zählung', async () => {
const p = perms(nutzer.stufe1, 1)
const treffer = await sichtbar(p)
expect(treffer).toContain(anhang.offen)
expect(treffer).not.toContain(anhang.geheim)
const anzahl = await db.attachment.count({
where: { AND: [visibleAttachmentWhere(p), { id: { in: Object.values(anhang) } }] },
})
expect(anzahl).toBe(treffer.length)
})
it('verbirgt den Anhang eines Eintrags über der Stufe des Lesers', async () => {
// Die Akte darf er sehen, den Eintrag nicht - und damit auch dessen Datei
// nicht. Sonst verriete die Anhangsliste den Inhalt des Eintrags.
expect(await sichtbar(perms(nutzer.stufe1, 1))).not.toContain(anhang.imEintrag)
expect(await sichtbar(perms(nutzer.stufe4, 4))).toContain(anhang.imEintrag)
})
it('liefert nichts aus, was die Prüfkette nicht bestanden hat', async () => {
// Auch nicht dem Administrator: die Datei liegt in der Quarantäne, dort
// führt kein Auslieferungspfad hin.
expect(await loadDeliverable(perms(nutzer.stufe4, 5, { isAdmin: true }), anhang.inQuarantaene))
.toBeNull()
expect(await loadDeliverable(perms(nutzer.stufe4, 4), anhang.offen)).not.toBeNull()
})
it('liefert einem zu niedrig eingestuften Leser nichts, sondern nichts Findbares', async () => {
// `null` und nicht "verboten": der Endpunkt macht daraus 404, die Existenz
// der Datei bleibt verborgen.
expect(await loadDeliverable(perms(nutzer.stufe1, 1), anhang.geheim)).toBeNull()
})
})