Watch
0
0
Fork
You've already forked hyperhive
0

swarm-controller: inject the account store so link-route tests use the fake

The seven linked-account handlers (matrix, forge and github link and
delete, and the list) read their store from `AppState::accounts` instead
of calling `store::connect()` themselves. In production that is
`Accounts::Live`, which still logs in to the swarm's secret store on
every request: a `SecretStore` holds a token it never renews, and a store
that is down at startup must fail only the requests made while it is
down.

Tests set `Accounts::Fake` over the in-memory `FakeStore`. The eight
handler tests that proved validation passed by expecting the store
connect to fail with 500 now assert that the write or delete landed in
the fake, and lose their `BAO_*`-must-be-unset guards: with `BAO_*` set
they no longer reach a real store.
This commit is contained in:
atlas 2026-10-04 08:03:05 +02:00
commit dceb803bca
5 changed files with 184 additions and 98 deletions

View file

@ -72,7 +72,7 @@ pub async fn put_forge_account(
.map_err(|e| error_problem(StatusCode::BAD_REQUEST, &e.to_string()))?;
let account = account(req).map_err(|e| error_problem(StatusCode::BAD_REQUEST, e))?;
let store = crate::store::connect().await.map_err(|e| {
let store = state.accounts.open().await.map_err(|e| {
tracing::warn!(error = %e, "connecting to the swarm secret store failed");
error_problem(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string())
})?;
@ -108,6 +108,9 @@ fn account(req: PutForgeAccountRequest) -> Result<forge::Account, &'static str>
#[cfg(test)]
mod tests {
use std::sync::Arc;
use super::super::linked_accounts::{Accounts, tests::FakeStore};
use super::{PutForgeAccountRequest, account};
fn request(url: &str, token: &str) -> PutForgeAccountRequest {
@ -138,7 +141,7 @@ mod tests {
}
/// Bare-minimum `AppState`, as `matrix_account`'s tests build it.
fn state() -> super::super::AppState {
fn state(store: &Arc<FakeStore>) -> super::super::AppState {
super::super::AppState {
hives: std::sync::Arc::new(vec![super::super::HiveEntry {
name: "pr1ma".to_owned(),
@ -159,53 +162,49 @@ mod tests {
auth: None,
forge: None,
create_gate: std::sync::Arc::default(),
accounts: Accounts::Fake(Arc::clone(store)),
}
}
async fn put(label: &str) -> problem_details::ProblemDetails {
async fn put(
store: &Arc<FakeStore>,
label: &str,
) -> Result<axum::Json<super::PutForgeAccountResponse>, problem_details::ProblemDetails> {
super::put_forge_account(
axum::extract::State(state()),
axum::extract::State(state(store)),
axum::extract::Path(("pr1ma".to_owned(), "atlas".to_owned(), label.to_owned())),
axum::Json(request("https://codeberg.org", "t0k3n")),
)
.await
.expect_err("no store is configured in a test")
}
/// A label `hive-forge -f` could not name is refused before the store: with
/// `BAO_*` unset a store connect would answer 500.
/// A label `hive-forge -f` could not name is refused before the store.
#[tokio::test]
async fn a_label_hive_forge_cannot_name_is_refused_before_the_store() {
for var in ["BAO_ADDR", "BAO_CLIENT_CERT", "BAO_CLIENT_KEY"] {
assert!(
std::env::var(var).is_err(),
"{var} must be unset for this test to prove anything"
);
}
let store = Arc::default();
for bad in ["Codeberg", "code_berg", "../x"] {
let problem = put(bad).await;
let problem = put(&store, bad).await.expect_err("refused");
assert_eq!(
problem.status,
Some(axum::http::StatusCode::BAD_REQUEST),
"{bad}: {problem:?}"
);
}
assert!(store.written().is_empty());
}
/// The control: a plain label reaches the store connect.
/// The control: a plain label is written.
#[tokio::test]
async fn a_plain_label_reaches_the_store() {
let problem = put("codeberg").await;
assert_eq!(
problem.status,
Some(axum::http::StatusCode::INTERNAL_SERVER_ERROR),
"{problem:?}"
);
let store = Arc::default();
let stored = put(&store, "codeberg").await.expect("nothing is stored");
assert_eq!(stored.url, "https://codeberg.org");
assert_eq!(store.written(), ["swarm/agents/atlas/forge/codeberg"]);
}
#[tokio::test]
async fn linking_a_label_twice_is_a_409_and_the_first_account_stays() {
use super::super::linked_accounts::{AccountStore, link, tests::FakeStore};
use super::super::linked_accounts::{AccountStore, link};
use swarm_secret_client::forge;
let store = FakeStore::default();