fix: harden three unwrap/expect panic surfaces in request paths #108
No reviewers
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
psa-systems/bunyip!108
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/harden-unwrap-panic-surfaces"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes BUNYIP-87.
Three call sites in request handlers used
.unwrap()/.expect()where a future runtime condition could promote a soft failure into a worker panic. None of these fire today; the fixes preserve happy-path behaviour and replace each panic surface with the smallest safe alternative.bunyip-api/src/handlers/webhook.rs::stripe_webhook: the per-requesttier_config.read().expect("TierConfig lock poisoned")panicked on every Stripe delivery after any panic in the tier-settings write path had poisoned the lock. Recover throughPoisonError::into_inner()(safe here because this path only reads) and log a single error line so ops can grep for the upstream panic.bunyip-web/src/handlers/dashboard.rs::membership: the@else if has { ... }branch did@let m = current.clone().unwrap();wherehaswas driven bymembership_statusandcurrentwas loaded separately. Today they correlate, but a future API hiccup with a fresh enum but a missing membership row would panic the Maud thread. Couple the field access to a matching@if let Some(m) = current.clone()so a missingcurrentsimply renders nothing in this branch.bunyip-api/src/handlers/admin.rs::get_key_health:serde_json::to_value(&check).unwrap()is practically infallible for the currentKeyHealthCheckstruct but the contract leaks a panic surface that a futuref64field (NaN → Err) would expose. Fail-soft with a null entry plus a tracing::error! line; the/admin/key-healthendpoint still returns 200 with the failing key marked null instead of 500-panicking the whole aggregator.No behaviour change on the happy path.
just check-containerclean (modulo the pre-existingtest_config_defaultsparallel-env-var flake onmain; 188 other tests pass; fmt + clippy + build clean).#BUNYIP-87
Closes BUNYIP-87. Three call sites in request handlers used `.unwrap()` / `.expect()` where a future runtime condition could promote a soft failure into a worker panic. None of these fire today; the fixes preserve happy-path behaviour and replace each panic surface with the smallest safe alternative. 1. `bunyip-api/src/handlers/webhook.rs::stripe_webhook`: the per-request `tier_config.read().expect("TierConfig lock poisoned")` panicked on every Stripe delivery after any panic in the tier-settings write path had poisoned the lock. Recover through `PoisonError::into_inner()` (safe here because this path only reads) and log a single error line so ops can grep for the upstream panic. 2. `bunyip-web/src/handlers/dashboard.rs::membership`: the `@else if has { ... }` branch did `@let m = current.clone().unwrap();` where `has` was driven by `membership_status` and `current` was loaded separately. Today they correlate, but a future API hiccup with a fresh enum but a missing membership row would panic the Maud thread. Couple the field access to a matching `@if let Some(m) = current.clone()` so a missing `current` simply renders nothing in this branch. 3. `bunyip-api/src/handlers/admin.rs::get_key_health`: `serde_json::to_value(&check).unwrap()` is practically infallible for the current `KeyHealthCheck` struct but the contract leaks a panic surface that a future `f64` field (NaN → Err) would expose. Fail-soft with a null entry plus a tracing::error! line; the `/admin/key-health` endpoint still returns 200 with the failing key marked null instead of 500-panicking the whole aggregator. No behaviour change on the happy path. `just check-container` clean (modulo the pre-existing `test_config_defaults` parallel-env-var flake on `main`; 188 other tests pass; fmt + clippy + build clean). #BUNYIP-87