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

archetech / archon / 31848665615
95%

Build:
DEFAULT BRANCH: main
Ran 14 Aug 2026 11:01PM UTC
Jobs 1
Files 88
Run time 1min
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

14 Aug 2026 10:58PM UTC coverage: 94.175% (+0.04%) from 94.133%
31848665615

push

github

web-flow
fix: Bound DIDComm mailbox growth and make memory TTLs real (#887)

* fix: Bound DIDComm mailbox growth and make memory TTLs real

Two defects in the DIDComm relay's storage, one security and one
correctness.

Growth was unbounded on both backends. Deposit (POST /messages) and
challenge issuance (GET /challenge) are unauthenticated by design -- a
sender must be able to reach a stranger's mailbox, and the challenge is
the first step of proving DID control -- so TTLs bound retention but not
growth. Within the retention window an anonymous caller could deposit
without limit, and because routing is by the JWE recipient kids the
depositor chooses the recipient DID, so a per-recipient cap alone would
have been no bound at all.

Add byte-based caps: ARCHON_DIDCOMM_MAX_RECIPIENT_BYTES (16MB) and
ARCHON_DIDCOMM_MAX_TOTAL_BYTES (256MB). Byte-based rather than message
counts because the upload limit allows multi-MB envelopes, so a count
says nothing about the resource that runs out. Exceeding a cap rejects
the deposit with 429 rather than evicting older messages: evicting would
let an attacker push a recipient's real mail out of their mailbox, and
400 would report a capacity condition as the sender's mistake.

The memory backend never actually enforced its TTLs. prune() was reachable
only from list(), so a mailbox nobody polled kept its envelopes forever,
and the challenge map -- the one an anonymous caller can grow -- was never
swept at all, since entries were deleted only when someone tried to use
that specific challenge.

Sweep on write instead, in add() and issueChallenge(), amortised. Writes
are the only thing that grows either map, so an idle store needs no
sweeping. Deliberately not an interval, even unref()'d: no timer means no
handle to leak into a Jest run that uses --runInBand without --forceExit.

A cap is never hit on stale accounting: the amortised sweep is throttled,
so add() re-checks after a definitive sweep before rejecting. (Caught by
the test... (continued)

3685 of 4145 branches covered (88.9%)

Branch coverage included in aggregate %.

70 of 72 new or added lines in 2 files covered. (97.22%)

8344 of 8628 relevant lines covered (96.71%)

684.2 hits per line

Uncovered Changes

Lines Coverage ∆ File
1
92.86
3.97% services/didcomm/server/src/config.js
1
96.14
2.17% services/didcomm/server/src/store.ts
Jobs
ID Job ID Ran Files Coverage
1 31848665615.1 14 Aug 2026 11:01PM UTC 176
95.19
GitHub Action Run
Source Files on build 31848665615
  • Tree
  • List 88
  • Changed 74
  • Source Changed 2
  • Coverage Changed 74
Coverage ∆ File Lines Relevant Covered Missed Hits/Line Branch Hits Branch Misses
  • Back to Repo
  • Github Actions Build #31848665615
  • c1192320 on github
  • Prev Build on main (#31838413435)
  • Next Build on main (#31860777326)
  • Delete
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