sqlite2enveloped

command
v1.31.30 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Command sqlite2enveloped migrates IAM's PLAINTEXT SQLite database (the current production at-rest format) to the ENVELOPED, per-org SQLite layout the running IAM opens under IAM_KMS_MASTER_KEY. It is the keystone of the prod encryption cutover: plaintext-at-rest → SQLCipher-encrypted per-org + global dbs, WITHOUT losing a single NULL.

Usage:

IAM_KMS_MASTER_KEY=<64-hex> \
  sqlite2enveloped -src /path/to/plaintext/iam.db -dst /data/iam

-src is the live plaintext iam.db FILE (read-only; never mutated — point it at a COPY for verification). -dst is a DATA DIRECTORY (not a file); the tool writes the exact shape the daemon reads:

{dst}/iam.db            (+ .dek)  ← GLOBAL: certs (JWT signing keys), apps,
                                    providers, tokens, sessions, roles, … —
                                    every table EXCEPT User. Encrypted at rest.
{dst}/orgs/<slug>/iam.db (+ .dek) ← PER-ORG: that org's User rows.
                                    Encrypted with a per-org DEK.

WHY A SEPARATE TOOL FROM pg2sqlite. pg2sqlite reads Postgres with xorm's QueryInterface, which returns ""/0/false for a SQL NULL — destroying the NULL-vs-empty-vs-zero distinction at the READ step (before the NULL-honouring INSERT ever runs). Prod IAM is plaintext SQLite, not Postgres, and a faithful migration MUST preserve NULLs. This tool reads the source SQLite with a per-column database/sql `*any` scan, which yields a Go nil for SQL NULL, int64/float64/string/[]byte otherwise — then hands those faithful values to the SHARED object.InsertRows / object.CopyUsersPerOrg write path (database/sql honours nil as NULL). There is exactly ONE write path; only the reader differs.

PARITY IS CONTENT, NOT COUNT. After writing, the tool RE-OPENS the encrypted destination (as the daemon would) and compares, per table, the MULTISET of canonical per-row hashes of the source against the destination. A row hash encodes every column's storage class and value with a NULL sentinel, so a single NULL coerced to "", a bool flipped, or a row dropped/added is detected — which count parity cannot. The tool exits non-zero on ANY mismatch.

Routing mirrors the runtime exactly: only the User table is per-org; every other table goes to the global engine. Encryption is mandatory: it FAILS CLOSED without IAM_KMS_MASTER_KEY (object.NewMigrationTarget refuses to write a plaintext destination) and a CGO+libsqlcipher build refuses to start with the key set but no codec linked.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL