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

bleedingdeacons / integrity / 34296310851
91%

Build:
DEFAULT BRANCH: main
Ran 09 Sep 2026 12:50AM UTC
Jobs 1
Files 15
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

09 Sep 2026 12:44AM UTC coverage: 90.05% (-0.2%) from 90.222%
34296310851

push

github

web-flow
fix: bound the Argon2id work an unauthenticated caller can command (#70)

validateKey() deliberately runs a fixed eight password_verify() calls so a
prefix miss costs the same as a hit, and dummyHash() adds a ninth on first
use. All nine are Argon2id at memory_cost 65536 / time_cost 4. The per-key
RateLimiter cannot cover any of it: checkAndIncrement() keys on an id that
only a successful validation produces, so a caller presenting an unknown
key was never counted and had no limit at all. Every rejection also wrote a
row to the audit table.

Three layers, cheapest first.

looksLikeKey() checks the shape generateKey() actually emits — 'int_' plus
64 lowercase hex — and validateKey() refuses anything else before the query
and before any hashing. This does not reopen the oracle dummyHash() closes:
the key format is public, and every well-formed candidate still runs the
full fixed-cost verify loop. A test asserts that, so a later short-circuit
of well-formed keys fails rather than silently restoring the leak.

PreAuthThrottle bounds well-formed but invalid keys at 20 failed attempts
per IP per 15-minute window, answering with 429 and Retry-After. It is
transient-backed rather than a fourth table: the schema is created once in
the activation hook with no version-gated migration, so a new table would
not appear on already-activated installs, which is where this has to work.
It keys on AuditLogger::getClientIp(), which only honours proxy headers
from configured trusted proxies, so the bucket cannot be scattered by
forging X-Forwarded-For. A working key costs one transient read and never
accumulates a count.

The check sits ahead of every rejection path, not just key validation. The
CPU was one of two unbounded costs; the other was an audit insert per
refusal, which a keyless or plain-HTTP flood reached without touching
Argon2id at all. So those paths charge the budget too, and a throttled
request writes nothing to the audit table — the attempts that establis... (continued)

2679 of 2975 relevant lines covered (90.05%)

4.25 hits per line

Coverage Regressions

Lines Coverage ∆ File
31
91.42
-1.37% integrity/integrity/src/Api/RestController.php
30
48.35
0.08% integrity/integrity/src/Plugin.php
7
95.81
0.1% integrity/integrity/src/Auth/ApiKeyManager.php
Jobs
ID Job ID Ran Files Coverage
1 34296310851.1 09 Sep 2026 12:50AM UTC 15
90.05
GitHub Action Run
Source Files on build 34296310851
  • Tree
  • List 15
  • Changed 3
  • Source Changed 0
  • Coverage Changed 3
Coverage ∆ File Lines Relevant Covered Missed Hits/Line
  • Back to Repo
  • Github Actions Build #34296310851
  • c6e54b68 on github
  • Prev Build on main (#34259836179)
  • Next Build on main (#34297109663)
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