• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

safe-global / safe-client-gateway / 36136421482
89%

Build:
DEFAULT BRANCH: main
Ran 25 Sep 2026 12:49PM UTC
Jobs 2
Files 1030
Run time 2min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

25 Sep 2026 12:41PM UTC coverage: 89.292% (+0.1%) from 89.162%
36136421482

push

github

web-flow
feat(policies): serve active spending-limit policies for a space (#3393)

* feat(policies): serve the active policies of a space

One route, reporting the spending limits the indexer holds:

  GET /v1/spaces/{spaceId}/policies/active

Policies are read per Space, never per Safe. A per-Safe route would put the
Policies page back to fanning out one request per Safe - the problem moving this
to the backend was meant to solve, returning as HTTP instead of RPC - and a
caller wanting one Safe passes `?safes=`, which costs the same single read. One
indexer read covers every Safe on every chain, asserted end to end by a Space
holding two Safes on two chains: one upstream POST, two items, each labelled with
its own Safe so nothing merges across chains.

The Space names the set, so nothing is passed in: the caller's membership is
checked against this Space, and the Space's Safes are the query. That is also
what authorises it. `?safes=` narrows the read and can only ever be a subset; a
Safe outside the Space is a 422 rather than a silent narrowing, which would look
like a Space whose Safes hold no policies. A GET with a query filter rather than
a POST body, because one pair is ~53 URL-encoded characters and a Space holds few
Safes.

The route service holds orchestration only. It reads the indexer once, scopes the
rows to each Safe, and hands each assembler a context it cannot widen - which is
what stops an assembler reporting another Safe's limits, asserted by a test that
puts a second Safe's allowance in the response.

The spending-limit assembler applies three rules that are wrong by default:

- the module's pending reset is applied on read. It zeroes `spent` lazily inside
  getAllowance and emits nothing, so a rolled window still reads as spent on the
  stored row; `available` carries the rule, while `spent` and `remaining` stay as
  the indexer reported them.
- an all-zero row is not a limit. resetAllowance and deleteAllowance have no
  registered-delegate c... (continued)

4434 of 5214 branches covered (85.04%)

Branch coverage included in aggregate %.

82 of 82 new or added lines in 6 files covered. (100.0%)

11327 of 12437 relevant lines covered (91.08%)

540.61 hits per line

Jobs
ID Job ID Ran Files Coverage
1 run-integration-tests - 36136421482.1 25 Sep 2026 12:52PM UTC 1030
64.34
GitHub Action Run
2 run-unit-tests - 36136421482.2 25 Sep 2026 12:49PM UTC 1030
66.63
GitHub Action Run
Source Files on build 36136421482
  • Tree
  • List 1030
  • Changed 16
  • Source Changed 6
  • Coverage Changed 12
Coverage ∆ File Lines Relevant Covered Missed Hits/Line Branch Hits Branch Misses
  • Back to Repo
  • Github Actions Build #36136421482
  • 6aab05d0 on github
  • Prev Build on main (#36135650865)
  • Next Build on main (#36137251788)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc