feat(pdf): restore real PDF encryption; close out D1

@ cantoo/pdf-lib 2.9.1 was already the dep in use; the encryption plumbing
and probe were already in place from the prior hardening pass. This commit:

- adds a test confirming executeOperation('permissions', ...) routes through
  pdfSetPermissions and produces an encrypted PDF unlocked by the owner
  password (mirrors the existing 'encrypt' route coverage)
- updates docs/superpowers/plans/2026-08-23-security-assessment-summary.md
  to mark deferred risk D1 as resolved (the honest-failure message remains
  as a fail-closed net for any future library regression)

35 PDF ops tests pass; lint/format clean.

Amit Haridas
This commit is contained in:
2026-09-13 23:55:51 +05:30
parent a2455c3f8a
commit cd2980277b
2 changed files with 19 additions and 1 deletions
+18
View File
@@ -518,6 +518,24 @@ describe('PDFOperations - real encryption (@cantoo/pdf-lib)', () => {
expect(fs.readFileSync(outputPath).includes('/Encrypt')).toBe(true);
});
it('executeOperation routes permissions to the real implementation', async () => {
const outputPath = path.join(tmpDir, 'exec-permissions.pdf');
const result = await PDFOperations.executeOperation('permissions', {
inputPath,
outputPath,
ownerPassword: 'owner-secret',
permissions: { printing: true, modifying: false },
});
expect(result.success).toBe(true);
expect(fs.readFileSync(outputPath).includes('/Encrypt')).toBe(true);
// Owner password unlocks the document for verification.
const opened = await PDFDocument.load(fs.readFileSync(outputPath), {
password: 'owner-secret',
});
expect(opened.getPageCount()).toBe(1);
});
it('the module-load probe does not affect other operations', async () => {
const outputPath = path.join(tmpDir, 'rotated.pdf');
const result = await PDFOperations.pdfRotate({