- internal/db/accounts.go: add ListAccountsWithTOTP,
ListAllPGCredentials, TOTPRekeyRow, PGRekeyRow, and
Rekey — atomic transaction that replaces master_key_salt,
signing_key_enc/nonce, all TOTP enc/nonce, and all
pg_password enc/nonce in one SQLite BEGIN/COMMIT
- cmd/mciasdb/rekey.go: runRekey — decrypts all secrets
under old master key, prompts for new passphrase (with
confirmation), derives new key from fresh Argon2id salt,
re-encrypts everything, and commits atomically
- cmd/mciasdb/main.go: wire "rekey" command + update usage
- Tests: DB-layer tests for ListAccountsWithTOTP,
ListAllPGCredentials, Rekey (happy path, empty DB, salt
replacement); command-level TestRekeyCommandRoundTrip
verifies full round-trip and adversarially confirms old
key no longer decrypts after rekey
Security: fresh random salt is always generated so a
reused passphrase still produces an independent key; old
and new master keys are zeroed via defer; no passphrase or
key material appears in logs or audit events; the entire
re-encryption is done in-memory before the single atomic
DB write so the database is never in a mixed state.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Rewrite .golangci.yaml to v2 schema: linters-settings ->
linters.settings, issues.exclude-rules -> issues.exclusions.rules,
issues.exclude-dirs -> issues.exclusions.paths
* Drop deprecated revive exported/package-comments rules: personal
project, not a public library; godoc completeness is not a CI req
* Add //nolint:gosec G101 on PassphraseEnv default in config.go:
environment variable name is not a credential value
* Add //nolint:gosec G101 on EventPGCredUpdated in model.go:
audit event type string, not a credential
Security: no logic changes. gosec G101 suppressions are false
positives confirmed by code inspection: neither constant holds a
credential value.