Task: Refuse a token with no permissions
Table of Contents
This page documents a task in the Give a person's token the permissions they hold story. It captures the goal, current status, acceptance, and any notes or results.
1. Goal
A token that grants nothing is refused, and every permission check uses one matching rule, as the story's decisions 4 and 5 say. The party-choice token is refused everywhere but party selection.
2. Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | Give a person's token the permissions they hold |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-10-03 |
3. Acceptance
has_permissionrefuses a token with an empty permission list, and both checks use one matching rule that understands*andx::*.- Only a named constructor builds a context with no permission list.
- A service's request context refuses a token with the
select_party_onlyaudience, which no signer or verifier rejects today. - Every new behaviour is proved by a test.
4. Plan
(Implementation strategy. Written when work starts; key decisions
are distilled into the parent story's * Decisions at close, but the
plan itself stays — it is the historical record of what we did.)
5. Measurements
Every number this task claims about a tree, with the command that produced it
and the commit it was measured at. A number without both is not a measurement,
because a clean-up record describes a tree and trunk moves under a branch: a
consumer count, a gate's component count and a suite's size all change with no
code changing, and the reader of a bare number cannot tell which tree it came
from. Where the raw output matters, put it in an evidence/ file beside the
task and name that file in the Command column.
| What | Value | Command | Commit |
|---|---|---|---|
6. Notes
7. Test Scenarios
Manual QA scenarios (scaffolded via compass add test_scenario)
that verify this task. Link
new ones here as they're created; the scenario doc itself links back
via its "Verifies task" field.
| Scenario | State | Notes |
|---|---|---|
8. PRs
| PR | Title |
|---|---|
| #2565 | [service] Refuse a token with no permissions |
9. Review
| Comment summary | File | Decision | Notes |
|---|---|---|---|
10. Result
has_permission refuses a token whose permission list is empty. The database
context's list became optional: a context built from a token carries the
token's list, and a context with no list, which only context_factory builds
for a service's own work, passes. with_tenant and with_party now keep the
list they narrow, so a request's context is never trusted for want of one.
grants in ores.security is the one matching rule, understanding a code, *
and x::*, and both has_permission and authorization_service::check_permission
use it; the database check no longer needs a sorted list and now honours
component wildcards. make_request_context refuses the select_party_only
audience by name, because no signer or verifier sets an audience.
Tests: five cases for grants; has_permission refusing an empty list,
passing the service's own context, and narrowed contexts keeping their list;
the request context refusing the party-choice token. The full build is clean
with no warnings. The full ctest failed 5 suites on a database built before
main added tables and columns (sandbox_id, curve_configurations and
others); all five pass on a recreated database (refdata 286, trading 127, ore
637, reporting 49, analytics 53), as do service 46, iam 192 and security 64
under ctest. Live, with the probes in evidence/: the party-choice token is
refused a parties read and refresh, the same session reads 5 parties after
choosing a party, and the tenant live check passes 15 of 15
(evidence/refuse_task_live.out).