Files
smirk-backend-core/tests/capabilities.rs
jwinterm 2d0077b2b9 feat(capabilities): honest secret-presence downgrade + admin features view [operator §4]
Make /capabilities fail-closed and add the admin features surface.

- Secret-presence downgrade (§4.2): a chain whose flag is on but whose source is
  unconfigured (btc/ltc no electrum URL, xmr/wow no LWS admin key, grin no owner
  secret) now reports enabled:false — so /capabilities never advertises a chain
  that would 404, and a missing-secret downgrade is indistinguishable from a
  deliberately-off chain. grin_relay requires serviceable Grin; nostr_identity
  requires PUBLIC_API_URL. effective_capabilities() is the single explicit mapper.
- contract_version stamp on the public document (clients soft-notice a higher
  value, ignore unknown additive keys).
- GET /admin/features (admin_guard): the resolved effective state PLUS admin-only
  downgrade reasons (the public surface hides the reason, per §4.3).
- Golden test: the public capabilities JSON, built from a fully-secret-seeded
  config, contains no secret value (asserts no "integration-test-" substring).

openapi regenerated (contract_version). Admin features view stays off the public
OpenAPI.

Deferred (documented): runtime mutation — PUT /admin/features + a DB feature-
override table + resolve() precedence + Arc hot-swap + CLI `features set`. Flags
are env/config-driven for v1; runtime tuning (and its fleet propagation, itself a
deferred LB decision) is a later addition.
2026-06-27 15:35:56 -04:00

56 lines
1.7 KiB
Rust

//! L1 integration: the public capabilities endpoint.
mod common;
use axum::http::StatusCode;
#[tokio::test]
async fn capabilities_is_public_and_well_shaped() {
let app = require_app!();
// No token required — the wallet reads this before/without login.
let (status, body) = app.request("GET", "/api/v1/capabilities", None, None).await;
assert_eq!(status, StatusCode::OK);
assert!(body["version"].as_str().is_some(), "version present");
assert!(
body["contract_version"].as_u64().is_some(),
"contract_version present"
);
// Golden: no server secret may appear in the public capabilities JSON. The
// harness seeds every secret with the "integration-test-" prefix.
let raw = serde_json::to_string(&body).unwrap();
assert!(
!raw.contains("integration-test"),
"no secret leaks into public capabilities: {raw}"
);
// Every chain reports an `enabled` boolean.
for chain in ["btc", "ltc", "xmr", "wow", "grin"] {
assert!(
body["chains"][chain]["enabled"].is_boolean(),
"chain {chain} reports enabled"
);
}
// UTXO chains carry a network; CryptoNote/Grin report null.
for chain in ["btc", "ltc"] {
assert!(
body["chains"][chain]["network"].as_str().is_some(),
"{chain} carries a network"
);
}
for chain in ["xmr", "wow", "grin"] {
assert!(
body["chains"][chain]["network"].is_null(),
"{chain} network is null"
);
}
// Feature flags are present.
for feat in ["grin_relay", "prices", "nostr_identity", "tips"] {
assert!(
body["features"][feat].is_boolean(),
"feature {feat} reports a boolean"
);
}
}