Skip to content

Remove nullable plaintext column ApiKey.key from Prisma and create a strict migration #209

Description

@kilodesodiq-arch

Problem Statement. app/backend/prisma/schema.prisma declares ApiKey.key as a nullable
legacy plaintext column alongside keyHash and keyPreview. Code paths reading ApiKey.key
can still leak raw secrets if downstream services (e.g. an admin export job, an audit dump)
select that column. Continuing to model the legacy column in the canonical schema is also a
permanent regression risk: a future contributor refreshing the schema re-introduces plaintext
storage.

Why it matters. This is a humanitarian-aid PII-adjacent system whose security policy
outlaws storing raw credentials. A plain column also defeats hashing, rotation, and
keyPreview-based redacted logging.

Technical Context. prisma/schema.prisma has:

model ApiKey {
  key         String?  @unique   // legacy plaintext, retained “for migration”
  keyHash     String?  @unique
  keyPreview  String?

}

The ApiKey model is consumed by src/api-keys/* and by src/common/guards/api-key.guard.ts.

Expected Outcome. The ApiKey.key column is dropped in a single migration after a one-time
rehash job. Schema validates that no controller or service reads ApiKey.key after the
migration lands.

Acceptance Criteria.

  • key removed from prisma/schema.prisma.
  • A migration script hashes every remaining plaintext value and stores the resulting SHA-256 in
    keyHash with a keyPreview of prefix…last4.
  • A repository-wide grep proves no prisma.apiKey.select({ key: … remains.
  • A new test in app/backend/test/api-keys/*.e2e-spec.ts covers rotation: revoke → reissue →
    validate old key rejected, new key accepted.

Implementation Notes. Use prisma migrate to add a NOT NULL keyHash constraint with a
default empty string, backfill, then drop the column. Add a guard-level hash compare using
crypto.timingSafeEqual.

Files or modules likely to be affected. prisma/schema.prisma, prisma/migrations/*,
src/api-keys/*, src/common/guards/api-key.guard.ts,
app/backend/test/api-keys/* (new).

Dependencies. Issue #2 (legacy keystore).

Difficulty. Medium
Estimated effort. M


Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions