Implement plan §9 JWT signing-secret rotation with zero-downtime dual-secret overlap window. Primary secret signs new tokens (kid header identifies it), optional previous secret validates old tokens during rotation. Validation tries primary first, falls through to previous on signature mismatch, and propagates Expired immediately when the correct secret is found. Key pieces: - auth.rs: dual-secret JWT validation with kid header, leak response via empty previous, full test coverage (62 tests including e2e rotation scenario) - main.rs: read SEARCH_UI_JWT_SECRET_PREVIOUS, refuse startup without primary - config: jwt_secret_previous_env + jwt_rotation_buffer_s in SearchUiAuthConfig - miroir-ctl: rotate-jwt-secret command (5-step dual-secret overlap procedure) - Helm CronJob: quarterly schedule, suspended by default, Forbid concurrency Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
25 lines
614 B
TOML
25 lines
614 B
TOML
[package]
|
|
name = "miroir-ctl"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
license.workspace = true
|
|
repository.workspace = true
|
|
|
|
[[bin]]
|
|
name = "miroir-ctl"
|
|
path = "src/main.rs"
|
|
|
|
[dependencies]
|
|
base64 = "0.22"
|
|
clap = { version = "4.5", features = ["derive", "env"] }
|
|
reqwest = { version = "0.12", features = ["json", "rustls-tls"], default-features = false }
|
|
serde = { version = "1.0", features = ["derive"] }
|
|
serde_json = "1.0"
|
|
tokio = { version = "1.42", features = ["full"] }
|
|
miroir-core = { path = "../miroir-core" }
|
|
dirs = "5.0"
|
|
toml = "0.8"
|
|
|
|
[dev-dependencies]
|
|
pretty_assertions = "1"
|
|
tempfile = "3.14"
|