Skip to content

fix(api): distinguished a token-fetch failure from an unconfigured party - #360

Merged
schronck merged 1 commit into
mainfrom
fix/api/party-credentials-error-plumbing
Aug 19, 2026
Merged

fix(api): distinguished a token-fetch failure from an unconfigured party#360
schronck merged 1 commit into
mainfrom
fix/api/party-credentials-error-plumbing

Conversation

@schronck

Copy link
Copy Markdown
Collaborator

What

get_party_credentials collapsed three outcomes into a single Option::None:

  1. no auth configured (data.auth is None)
  2. the registry does not know the party (registry.get(party_id))
  3. the token fetch failed (tm.get_token().await) — an actual error, previously discarded via .ok()? with no logging

Changed the return type to Result<Option<(String, CantonId)>>:

  • Case 1 and 2 (Ok(None)): unchanged behavior everywhere — both are ordinary "this party has no usable credentials" outcomes callers never needed to tell apart.
  • Case 3 (Err): now logged with tracing::warn!(%party_id, error = %e, ...) at the point the error is available, and returned instead of silently discarded.

Call sites

Updated all 7 call sites in handlers/governance.rs (propose_action, confirm_action, execute_action, expire_confirmation, cancel_confirmation, cancel_proposal, get_coupon_reassignment_delegation) to answer a token-fetch failure with 500 Internal Server Error (a new, distinct response from the existing 401 Unauthorized used for "no credentials configured"), matching the precedent already used for the same failure in handlers/auth.rs.

The reward automation call site (reward_automation.rs::run_once_for_party) keeps its exact prior behavior — both Ok(None) and Err still fold into a no-op Ok(()) — since #325 already gives that path its own handling for this failure mode; this PR only keeps the call site compiling against the new signature. The warning is still logged from inside get_party_credentials regardless.

Tests

Added get_party_credentials_tests in governance.rs covering all three outcomes against a real AppState:

  • no auth configured → Ok(None)
  • unknown party (empty registry) → Ok(None)
  • a token fetch that fails after a successful initial auth (via a two-stage wiremock Keycloak stand-in) → Err, with the warning log asserted to contain the party id

Verification

  • cargo fmt --check — clean
  • DECMAN_SKIP_FRONTEND=1 cargo clippy --all-targets --all-features --no-deps -- -D warnings — clean
  • DECMAN_SKIP_FRONTEND=1 cargo test -p decman --lib — 424 passed

Closes #326

get_party_credentials returned Option<(String, CantonId)>, collapsing "no
auth configured", "party unknown", and "token fetch failed" into one None
with the underlying error silently discarded. Changed the return type to
Result<Option<(String, CantonId)>>: Ok(None) still covers the first two
(both are ordinary, non-error outcomes), while Err now carries the token
fetch failure and is logged with the party id before being returned.

Updated all seven governance.rs call sites plus the reward automation call
site to match: the six action handlers and the coupon-reassignment-delegation
read now answer a token fetch failure with 500 instead of folding it into
the existing 401, while the reward automation loop keeps its no-op behavior
for both non-credential outcomes since it already handles this failure mode
separately.
@schronck
schronck requested review from a team and sosaucily August 19, 2026 08:51
@schronck schronck self-assigned this Aug 19, 2026
@schronck
schronck requested review from scolear and a lite review from Copilot August 19, 2026 08:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refines the server-side auth credential lookup flow by distinguishing “no credentials available” from “token fetch failed,” allowing callers (notably governance endpoints) to respond with an actual server error instead of silently treating token acquisition failures as missing configuration.

Changes:

  • Changed get_party_credentials to return Result<Option<(String, CantonId)>>, returning Err on token-fetch failures and logging a warning with the party id.
  • Updated all governance handler call sites to treat Ok(None) as 401 Unauthorized (unchanged behavior) and Err(_) as 500 Internal Server Error.
  • Added unit/integration-style tests in governance.rs to cover: no auth configured, unknown party, and token fetch failure (including asserting the warning log contains the party id).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
crates/decman/src/server/reward_automation.rs Adapts reward automation to the new get_party_credentials signature while preserving prior no-op behavior on missing/failed credentials.
crates/decman/src/server/handlers/governance.rs Implements the new Result<Option<_>> credential API, updates governance endpoints’ error handling, and adds tests for the three credential outcomes.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@schronck
schronck merged commit f52b4ee into main Aug 19, 2026
11 checks passed
@schronck
schronck deleted the fix/api/party-credentials-error-plumbing branch August 19, 2026 15:35
schronck added a commit that referenced this pull request Aug 24, 2026
#353, #355, #360 and #361 landed since the last sync. The only conflict was
fetch_governance_with_wildcard: this branch still carried it, adapted to
DomainConfirmation, while #355 deleted every test-mode wildcard path on
main. Took the deletion.

Verified after: clippy clean, gen-types 0 warnings, 477 tests pass, and the
placeholder action is still absent.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

get_party_credentials swallows token errors and conflates three failures

3 participants