Skip to content

test-mode ACS queries return empty for interface queries instead of failing #272

Description

@gyorgybalazsi

Summary

Under --features test-mode, the ACS query helpers in crates/decman/src/server/queries.rs ignore the requested Template/Interface filter and instead issue a WildcardFilter, then match rows in memory against the concrete template's module_name/entity_name. The stated rationale is "mock auth doesn't have TemplateFilter permissions".

An interface query passes the interface's module/entity (e.g. Splice.Api.RewardAssignmentV1 / RewardCoupon), which never equals any concrete template's name (e.g. Splice.Amulet / RewardCouponV2). Every row is therefore dropped and the query returns [] with no error — a result indistinguishable from "the party holds no such contracts". Silent-empty is the core defect: a caller cannot tell an unsupported query from a genuinely empty one.

Scope

Eleven test_mode branches across ten functions, not one:

Function Line
get_contracts 273
get_governance_confirmations 659
get_governance_state 1488
get_vaults 1927
get_provider_services 2143
get_user_services 2313
get_credential_offers 2489
get_registrar_services 2665
get_instruments 2851
query_contracts_by_template 3067, 3113

Most use TemplateFilter in their production path; query_contracts_by_template is the one that also serves interface queries and so is where the silent-empty surfaces.

State of the rationale

The rationale does not hold for interface filters. reward_automation::active_created_records builds a real InterfaceFilter unconditionally, including under test-mode, and works on localnet: the reward IT reads unassigned RewardCouponV2 contracts through the RewardCoupon interface and assigns 60 of them on every CI run.

Filter type is not a Canton auth capability. The mock token (crates/decman/src/auth/mock.rs, UnsafeClaims { aud, sub, iat }, sub = ledger-api-user) authorizes a user whose party read-rights resolve server-side, so "TemplateFilter permissions" does not describe a real gate.

Whether TemplateFilter also works under the mock token is not established. That is the open question, and it governs most of the call sites above.

Impact

Test-only. Production uses JwtValidator with real filters and is unaffected. The cost is a latent trap: any future code path that queries by interface and is exercised on localnet returns silent-empty, and the localnet ITs can only approximate the production interface-query path rather than exercise it.

Requirements

  1. Establish whether a real TemplateFilter ACS query succeeds under the mock token on a localnet participant. (InterfaceFilter is already known to.)
  2. If it does: remove the test_mode branches at all eleven sites and use the real filters. The full localnet IT — /contracts/query, governance confirmations, vaults, services, instruments, rewards — must pass afterwards.
  3. If a genuine asymmetry remains at some sites: the in-memory fallback must either match a contract whose concrete template implements the requested interface, or return an error for an unsupported interface query. Returning [] for a query the code cannot serve is not acceptable in either outcome.
  4. The reward IT then queries the RewardCoupon interface on both targets, dropping its localnet-only concrete-template path: crates/decman/tests/common/phases/coupon_reassignment.rsreward_coupon_v2_query_path and the target-aware branch in query_reward_coupons.

References

  • crates/decman/src/server/queries.rs — the eleven test_mode branches above; the "mock auth doesn't have TemplateFilter permissions" comment at get_contracts (~247).
  • crates/decman/src/server/reward_automation/mod.rsactive_created_records, interface_view = trueInterfaceFilter regardless of test_mode.
  • crates/decman/src/auth/mock.rs — the mock token.

Metadata

Metadata

Assignees

No one assigned

    Labels

    maintenanceMaintenance and hardening workrustPull requests that update rust code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions