From e63984e99bef66cb05d7bcf781812ea5e6276fa8 Mon Sep 17 00:00:00 2001 From: tv Date: Sun, 8 Nov 2026 09:44:28 +0000 Subject: access: a node judges its own changes before they leave The API checks the path a request asks for; the rules judge everything the change does. Where they disagreed, the honest node's change was refused by every other node, and with signatures required the node was refused as a whole. The plan had both gates run the same judgement. Under a policy, each change a node makes (its own writes and those through the API) is now judged by rules::judge as receivers will judge it, before it is signed or sent; one every node would refuse is rolled back (the document forked at the heads before it, same actor: the change never left) and the request refused with 403 (StoreError:: Refused). rules::judge_held, judging a change the document holds, moves from swarm::refusals to access::rules for both. The simulations that play a member past its own checks write with a helper that bypasses them (forge). Review finding 3 (the same judgement at both gates). --- src/api/mod.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/api/mod.rs') diff --git a/src/api/mod.rs b/src/api/mod.rs index 9405a06..0e7fc21 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -335,6 +335,7 @@ pub(crate) fn store_status(error: StoreError, context: &str) -> ApiError { StoreError::NotFound | StoreError::UnknownHeads => StatusCode::NOT_FOUND, StoreError::Rejoining => StatusCode::SERVICE_UNAVAILABLE, StoreError::UnknownPolicy(_) => StatusCode::CONFLICT, + StoreError::Refused(_) => StatusCode::FORBIDDEN, other => { error!(error = %format!("{other:#}"), "{context}"); return StatusCode::INTERNAL_SERVER_ERROR.into(); -- cgit v1.3.1