Add vault secret manager backend with AES-256-GCM encryption

Secrets are encrypted at rest in the database. The derived encryption
key is held in memory only — on reboot, an authorized user must enter
the master password to unlock. Admins can also manually lock the vault.

- vault_config, vault_category, vault_category_permission, vault_entry tables
- AES-256-GCM encryption with PBKDF2-derived key + per-entry IV
- Master password initialize/unlock/lock/change lifecycle
- Category CRUD with role/user permission model (view/edit/admin)
- Entry CRUD with reveal endpoint (POST to avoid caching)
- Secret values never returned in list/detail responses
- vault.view/edit/admin RBAC permissions seeded
- 19 API integration tests covering full lifecycle
This commit is contained in:
Ryan Moon
2026-03-30 06:11:33 -05:00
parent 748ea59c80
commit 7246587955
8 changed files with 993 additions and 0 deletions

View File

@@ -49,6 +49,11 @@ export const SYSTEM_PERMISSIONS = [
{ slug: 'files.upload', domain: 'files', action: 'upload', description: 'Upload files' },
{ slug: 'files.delete', domain: 'files', action: 'delete', description: 'Delete files' },
// Vault
{ slug: 'vault.view', domain: 'vault', action: 'view', description: 'View vault categories and entry names' },
{ slug: 'vault.edit', domain: 'vault', action: 'edit', description: 'Create/edit entries, reveal secret values' },
{ slug: 'vault.admin', domain: 'vault', action: 'admin', description: 'Manage categories, permissions, master password' },
// Email
{ slug: 'email.view', domain: 'email', action: 'view', description: 'View email logs' },
{ slug: 'email.send', domain: 'email', action: 'send', description: 'Send mass emails' },
@@ -99,6 +104,7 @@ export const DEFAULT_ROLES = [
'pos.view', 'pos.edit',
'rentals.view',
'files.view', 'files.upload',
'vault.view',
'reports.view',
],
},
@@ -111,6 +117,7 @@ export const DEFAULT_ROLES = [
'inventory.view',
'accounts.view',
'files.view', 'files.upload',
'vault.view',
],
},
{