cdf21682d6
AES-256-GCM encryption for credential storage, YAML seed config parser with validation, and transactional import into SQLite. Credentials (registry tokens, NPM password) encrypted before storage.
62 lines
3.4 KiB
Markdown
62 lines
3.4 KiB
Markdown
# Phase 2: Crypto & Config Seed Loader
|
|
|
|
**Status:** ✅ Complete
|
|
**Parent plan:** [PLAN.md](./PLAN.md)
|
|
**Domain:** backend
|
|
|
|
## Objective
|
|
Implement AES-256 encryption for credential storage and the YAML seed config parser that imports into SQLite on first launch.
|
|
|
|
## Tasks
|
|
|
|
- [x] Task 1: Implement AES-256-GCM encrypt/decrypt functions using Go stdlib `crypto/aes` + `crypto/cipher`
|
|
- [x] Task 2: Key derivation from ENCRYPTION_KEY env var (SHA-256 hash to get 32 bytes)
|
|
- [x] Task 3: Define YAML config structs matching the seed format from PLAN.md
|
|
- [x] Task 4: Implement YAML parser — read and validate seed file
|
|
- [x] Task 5: Implement seed importer — checks if DB is empty, if so imports YAML into SQLite via store CRUD
|
|
- [x] Task 6: Encrypt credential fields (registry tokens, NPM password) during import
|
|
- [x] Task 7: Create `docker-watcher.example.yaml` with documented example config
|
|
- [x] Task 8: Wire seed import into `cmd/server/main.go` startup sequence
|
|
|
|
## Files to Modify/Create
|
|
- `internal/crypto/crypto.go` — AES-256-GCM encrypt/decrypt
|
|
- `internal/config/config.go` — YAML structs and parser
|
|
- `internal/config/seed.go` — seed import logic (YAML → SQLite)
|
|
- `docker-watcher.example.yaml` — example seed config
|
|
- `cmd/server/main.go` — add seed import to startup
|
|
|
|
## Acceptance Criteria
|
|
- Encrypt then decrypt round-trips correctly
|
|
- Different plaintexts produce different ciphertexts (random nonce)
|
|
- YAML parsing handles all fields from the seed format
|
|
- Seed import creates projects, stages, registries, and settings in SQLite
|
|
- Credentials are encrypted before storage
|
|
- Import is idempotent — skipped if DB already has data
|
|
|
|
## Notes
|
|
- ENCRYPTION_KEY is the only secret env var — everything else is encrypted in SQLite
|
|
- Use GCM mode for authenticated encryption (integrity + confidentiality)
|
|
- Seed import should be transactional — all or nothing
|
|
- The example YAML should have placeholder values, not real credentials
|
|
|
|
## Review Checklist
|
|
- [x] All tasks completed
|
|
- [x] Crypto uses secure practices (random nonce, GCM, no ECB)
|
|
- [x] No hardcoded keys or secrets
|
|
- [x] YAML parsing validates required fields
|
|
- [x] Import is transactional
|
|
|
|
## Handoff to Next Phase
|
|
|
|
- `crypto.Encrypt(key, plaintext)` and `crypto.Decrypt(key, ciphertextHex)` handle AES-256-GCM encryption; ciphertext is hex-encoded with prepended nonce
|
|
- `crypto.KeyFromEnv()` derives a `[32]byte` key from the `ENCRYPTION_KEY` env var via SHA-256
|
|
- `crypto.EncryptIfNotEmpty(key, value)` is a convenience wrapper that passes through empty strings unchanged
|
|
- `config.ImportSeed(db, seedPath)` is the single entry point for seed import — called from `main.go` at startup
|
|
- Import is idempotent: skipped if the DB already has projects or registries
|
|
- Import is transactional: all inserts happen within a single SQLite transaction (rollback on any failure)
|
|
- Registry `token` and settings `npm_password` are now stored encrypted in SQLite — later phases that read these fields must decrypt with `crypto.Decrypt(key, value)`
|
|
- `store.DB()` method was added to expose the underlying `*sql.DB` for transaction use
|
|
- Seed file path is configurable via `SEED_FILE` env var (default: `./docker-watcher.yaml`)
|
|
- YAML validation ensures: `global.domain` is required, every project needs `image`, project registry references must exist, stages need `tag_pattern`
|
|
- `go.sum` still does not exist — run `go mod tidy` when Go toolchain is available
|