Skip to content

feat(migration): encrypted credential vault for source-PMS tokens (TEL-70) - #296

Merged
telivity-otaip merged 2 commits into
mainfrom
cursor/migration-credential-vault-d0e7
Aug 11, 2026
Merged

feat(migration): encrypted credential vault for source-PMS tokens (TEL-70)#296
telivity-otaip merged 2 commits into
mainfrom
cursor/migration-credential-vault-d0e7

Conversation

@telivity-otaip

Copy link
Copy Markdown
Collaborator

Summary

Implements an encrypted at-rest credential vault for tier-1 source-PMS migration connectors (Mews, Cloudbeds, Apaleo, OHIP). Unlike channel_connections.config, credentials are AES-256-GCM encrypted before persistence.

Changes

  • Crypto helper (apps/api/src/common/crypto/credential-encryption.ts): AES-256-GCM encrypt/decrypt keyed by MIGRATION_CREDENTIAL_ENCRYPTION_KEY, with rotation seam via encryption_key_id and optional MIGRATION_CREDENTIAL_ENCRYPTION_KEYS JSON map
  • Schema: migration_source_credentials table — property_id, source_pms, ciphertext, encryption_key_id, audit timestamps; unique per property + source PMS
  • Service (MigrationSourceCredentialsService): upsert, listMetadata, decryptForRunner (server-side only), delete (per-source or all-for-property)
  • HTTP API (/api/v1/migration/credentials): metadata-only responses; no endpoint returns decrypted secrets
  • Deletion: DELETE /migration/credentials/:sourcePms and DELETE /migration/credentials for migration completion / GDPR erasure
  • Audit: redacted metadata only — no credential values or ciphertext in audit rows

Acceptance criteria

  • Credentials at rest are ciphertext; round-trip works; wrong-key fails closed
  • No credential value in API responses, logs, or audit rows
  • Tests include GCM tamper detection (auth tag + ciphertext)

Env vars (.env.example)

MIGRATION_CREDENTIAL_ENCRYPTION_KEY=        # openssl rand -hex 32
MIGRATION_CREDENTIAL_ENCRYPTION_KEY_ID=default
MIGRATION_CREDENTIAL_ENCRYPTION_KEYS=       # optional rotation map

Testing

pnpm build
DATABASE_URL=postgresql://haip:haip@localhost:5432/haip_test pnpm db:migrate
pnpm --filter @telivityhaip/api test -- migration
pnpm --filter @telivityhaip/api vitest run src/common/crypto/credential-encryption.spec.ts

Closes TEL-70

Linear Issue: TEL-70

Open in Web Open in Cursor 

…L-70)

Add AES-256-GCM app-level encryption for per-property source-PMS migration
credentials with key-rotation support via encryption_key_id.

- migration_source_credentials table (property-scoped, unique per source PMS)
- MigrationSourceCredentialsService with encrypt/decrypt/upsert/delete APIs
- HTTP endpoints return metadata only; decryptForRunner is server-side only
- Audit logs and API responses never include plaintext secrets or ciphertext
- Tests cover round-trip, wrong-key failure, and GCM tamper detection

Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
@telivity-otaip
telivity-otaip marked this pull request as ready for review August 11, 2026 00:55
Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
@telivity-otaip
telivity-otaip merged commit 2ae62c8 into main Aug 11, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants