feat(P02): HCL config file parsing — internal/config package (REQ-054)

New internal/config package: Config struct (HCL tags), Load(paths...),
MergeOverrides(flags, env) with flag>env>file>default precedence (D-039).
No package-level state (AD-023). --config persistent flag on root command;
daemon uses cfg.ListenAddr when flag at default. 11 config tests + 2 cli tests.

---ci---
project: orca
phase: 2
milestone: v0.7
status: verify
requirements:
  covered: [REQ-054]
  partial: []
---/ci---
This commit is contained in:
Jon Chery
2026-08-04 00:09:33 +00:00
parent 27f2abf8fb
commit cd07e435d9
7 changed files with 475 additions and 1 deletions
+68
View File
@@ -0,0 +1,68 @@
# Phase 2 Verification Report — v0.7: HCL Config File Parsing
**Phase**: 2
**Branch**: `phase/02-config-parser`
**REQ Coverage**: REQ-054
**Milestone**: v0.7 (Hardening & Completion)
## Structural Verification
### Files Created
- `internal/config/config.go``Config` struct (HCL tags), `CapacityConfig`, `Flags`, `Environ`, `Load(paths...)`, `(*Config).MergeOverrides(flags, env)`
- `internal/config/config_test.go` — 11 tests (Load valid/missing/malformed/first-existing, MergeOverrides precedence all 4 layers, NodeCapacity)
- `internal/config/testdata/config.hcl` — example fixture
### Files Modified
- `internal/cli/root.go` — added `--config` persistent flag, `configCtxKey`, `configFromCtx` helper; `PersistentPreRunE` loads config if `--config` set (AD-023)
- `internal/cli/daemon.go` — daemon uses `cfg.ListenAddr` from config when flag is at default (`:8080`) (D-039 precedence: flag > config)
- `internal/cli/root_test.go` — added `TestConfigFlagRegistered` + `TestConfigFlagLoadsFile`
## Behavioral Verification
### Test Results
```
go test ./... → all PASS (exit 0)
go test -race ./internal/config/... ./internal/cli/... → all PASS
go vet ./... → clean
make build → clean (v0.6.1)
```
### API Surface
```go
func Load(paths ...string) (*Config, error)
func (c *Config) MergeOverrides(flags Flags, env Environ) *Config
```
- `Load` returns zero `&Config{}` if no file exists (no error)
- `MergeOverrides` precedence: flag > env > file > default (D-039)
- No package-level state (AD-023)
### CLI Verification
```
./bin/orca --help → shows --config string flag
```
## Security Verification
- Config file is read-only (no writes); parsed via `hclsimple.Decode` (no eval, no external commands)
- No secrets in config (paths only; no tokens/keys in config.hcl)
- Config file permissions not enforced (operator's responsibility; config contains no secrets)
## Quality Verification
- No new dependencies (`hashicorp/hcl/v2` already in go.mod for jobspec)
- No comments added (per project convention)
- Test style matches existing `jobspec/spec_test.go` + `cli/root_test.go`
- `go.mod` unchanged
## Must-Haves Checklist
- [x] `internal/config/config.go` — Config struct + Load + MergeOverrides
- [x] `internal/config/config_test.go` — 11 tests (all 4 precedence layers)
- [x] `internal/config/testdata/config.hcl` — example fixture
- [x] `internal/cli/root.go``--config` persistent flag + context wiring
- [x] `internal/cli/daemon.go` — uses `cfg.ListenAddr` (flag still wins)
- [x] `internal/cli/root_test.go` — config flag registration + load test
## Verdict
**PASS** — all 4 verification layers pass. REQ-054 is fully covered. The `internal/config` package provides HCL config file parsing with flag > env > file > default precedence, wired into the root command via `--config` and consumed by the daemon.