Repository navigation
Releases
v0.1.8
Assure engine e4ed4e8f, served by api.symbolia.ai. The Action built from it is Symbolia-Assurance/assure-action v0.1.8 (@v0 moves with it).
v0.1.8 changes no reading on Python or PostgreSQL apps and nothing in the Action. It prepares the TypeScript/Express reader, which is not served yet, to decide each route on its own.
Pin this release
- uses: Symbolia-Assurance/assure-action@a8da838c8b725429cd9ce6d19de4657bacadaf96 # v0.1.8For customers
- TypeScript/Express (not served yet). When it is served, routes will be decided one at a time: a route whose mount chain, middleware and guards are fully read gets its reading, and a route the reader can't fully read is listed as refused, with the reason, beside the census's own completeness. The scope document says so.
- Every served stack. Readings are unchanged from v0.1.7.
Where we are on the curve
- Decided-row reach on fresh apps: not re-measured at this release; v0.1.5 read 2 of 20 fresh FastAPI apps.
- Decided rows on real outside apps: not re-measured at this release (no served reader changed); v0.1.7 decided 26 of 821 rows across 94 public Python apps.
- False holds on the held-out corpus: no new false hold against v0.1.7 (0 regressions across 89 pre-release gate rows, held-out rows included); planted flaws caught as on v0.1.7 with 0 false alarms (Flask 4 of 15, Python 1 of 97, Node 3 of 37, Go 3 of 20); one coverage row (Python held-out rows, 4 of the 5 the gate asks for) accepted as an exception for this release.
- Usage-weighted coverage: 230 of 507 auth-relevant package uses (45.4%) across 184 apps have a formal model.
- Formal share of CI: not measured at this release; 18 of 18 PostgreSQL HBA-1 readings carry a Lean certificate.
- Tokens per verified change: 41.7 M including cache reads, 1.30 M excluding (24 h to 8 Nov 08:00 UTC); v0.1.5 baseline 17.9 M / 0.90 M.
Self-check
This release's record: https://symbolia.ai/self-check/e4ed4e8f (58 holds, 8 not established, 2 disproven, of 68). The current proof tree: https://symbolia.ai/self-check/latest.
Known issues
- FastAPI: an app that defines or imports its own
DependsorSecuritycan make IDENT-1 read as holding on routes that are open. - Django: a helper that decodes and validates the identity proof, called only under a condition, can make IDENT-7 read as holding.
- Django: an expiry checked through a helper, or a PyJWT decode with a small literal leeway, can read IDENT-7 as disproven on an app that bounds expiry.
- Django: a
jwt.decodecall wherejwtis a local object rather than the imported library can make IDENT-7 read as holding. - Django: a PyJWT 1.x decode passed
verify=False, as a keyword or a third positionalFalse, can make IDENT-7 read as holding. - FastAPI: a decode refused under the signature rules that falls through to a trusted header can make IDENT-9 read as holding.
- FastAPI: a guard whose denial a helper it calls catches, or that wraps a raising helper in
contextlib.suppress, can make IDENT-1 read as holding while the route is open. - Flask: a session signing value written in the repository can make AUTH-1 read as holding while a forged session reaches the view.
- Django: REST framework settings loosened indirectly, through
getattrwith a variable name,attrgetter,vars(), a class-attribute alias, a walrus assignment or amatchcapture, can make IDENT-1 read as holding while anonymous requests succeed. - Django: a settings store through a local bound to an app-class call, a star import that rebinds that class, or a helper that returns settings state can make IDENT-1 read as holding while anonymous requests succeed.
- Django: IDENT-7 can read the expiry as checked when the decode that checks it never runs or is not the library's: a verifier method the call chain never reaches, a decode after a
returnor whose expiry error is caught, a helper its own module rebinds,jwtre-exported from another module or wrapped by a decorator. An expired identity proof is then accepted.
v0.1.7
Assure engine 6a441ba1, served by api.symbolia.ai. The Action built from it is Symbolia-Assurance/assure-action v0.1.7 (@v0 moves with it).
v0.1.7 mostly corrects readings, fixes timeouts on long PostgreSQL migration histories and large Django apps, and reads more libraries. If your app has one of the shapes below, a check you ran on v0.1.6 may have read differently from what your code does. Run it again.
Pin this release
- uses: Symbolia-Assurance/assure-action@0c7ee30c5b9b8346f70e6474c4f003f7deefaacb # v0.1.7For customers
- Django. Expiry is credited only through code that runs: not through a helper under a non-static or class-method decorator, a class method nothing reaches, a reach call on a rebound
self, or a call that resolves to your own code. A store through a binding of library or settings state the reader cannot follow is refused, and pytestmonkeypatchon a library name is read as a store. The first-run draft reads a bareLoginViewsign-in, repository-read app keys and stored-value header comparisons as API-key credentials, and key-row deletion and declared revokers as revocation. A Django app the size of healthchecks reads in about 14 seconds, down from about 40 minutes. - FastAPI. Expiry evidence counts only where it always runs: in reached helpers, verifier classes, inner functions and lambdas. First-run IDENT-3 and declared IDENT-11 now decide where they read not_established. A cookie session id looked up in a database table drafts no credential.
- Flask. A library pinned at a release the catalogue reads is read as that release's code, and guarded fallback imports and
shell_context_processorare read. - Any Python stack.
.decode(algorithms=)is credited only on the JWT module or a barePyJWT(). A file Python's compiler rejects is named as a refusal. A first run with no stack named drafts the framework the repository uses, and a TypeScript/Express repository is refused rather than drafted as Flask. Nine more libraries are read: pyotp, google-auth, oauthlib, ldap3, jwcrypto, python-ldap, django-auth-ldap, argon2-cffi and pynacl. - PostgreSQL. A schema with about 150 migrations no longer times out. A declared PRIV-1 row on a table name two schemas share reads
needs_intent, not a falsefails, and a privilege query naming such a table is dropped with a warning. HBA, LISTEN and TLS baselines read PostgreSQL 15 and 16, and HBA-1 readings carry a Lean certificate. With the opt-in, the Action compares JSONB CHECK constraints with your committed schemas. - The Action. The summary names the stack it read, the log links the kept proposal branch, and a stored result is replayed only when the engine that produced it is still serving. Feedback is accepted without an API key and held apart until it is reviewed.
Where we are on the curve
- Decided-row reach on fresh apps: not re-measured at this release; v0.1.5 read 2 of 20 fresh FastAPI apps.
- Decided rows on real outside apps: 26 of 821 rows across 94 public Python apps (Django 20 of 517, FastAPI 6 of 141, Flask 0 of 163); v0.1.6 decided 14 of 733.
- False holds on the held-out corpus: no new false hold against v0.1.6 (0 regressions across 89 pre-release gate rows, held-out rows included); planted flaws caught as on v0.1.6 with 0 false alarms (one planted app left out of the comparison: v0.1.6 times out on it, v0.1.7 reads it); one coverage row (Python held-out rows, 4 of the 5 the gate asks for) accepted as an exception for this release.
- Usage-weighted coverage: 230 of 507 auth-relevant package uses (45.4%) across 184 apps have a formal model.
- Formal share of CI: not measured at this release; 18 of 18 PostgreSQL HBA-1 readings now carry a Lean certificate.
- Tokens per verified change: 23.4 M including cache reads, 0.95 M excluding (24 h to 8 Nov 05:00 UTC); v0.1.5 baseline 17.9 M / 0.90 M.
Self-check
This release's record: https://symbolia.ai/self-check/6a441ba1 (58 holds, 8 not established, 2 disproven, of 68). The current proof tree: https://symbolia.ai/self-check/latest.
Known issues
- FastAPI: an app that defines or imports its own
DependsorSecuritycan make IDENT-1 read as holding on routes that are open. - Django: a helper that decodes and validates the identity proof, called only under a condition, can make IDENT-7 read as holding.
- Django: an expiry checked through a helper, or a PyJWT decode with a small literal leeway, can read IDENT-7 as disproven on an app that bounds expiry.
- Django: a
jwt.decodecall wherejwtis a local object rather than the imported library can make IDENT-7 read as holding. - Django: a PyJWT 1.x decode passed
verify=False, as a keyword or a third positionalFalse, can make IDENT-7 read as holding. - FastAPI: a decode refused under the signature rules that falls through to a trusted header can make IDENT-9 read as holding.
- FastAPI: a guard whose denial a helper it calls catches, or that wraps a raising helper in
contextlib.suppress, can make IDENT-1 read as holding while the route is open. - Flask: a session signing value written in the repository can make AUTH-1 read as holding while a forged session reaches the view.
- Django: REST framework settings loosened indirectly, through
getattrwith a variable name,attrgetter,vars(), a class-attribute alias, a walrus assignment or amatchcapture, can make IDENT-1 read as holding while anonymous requests succeed. - Django: a settings store through a local bound to an app-class call, a star import that rebinds that class, or a helper that returns settings state can make IDENT-1 read as holding while anonymous requests succeed.
- Django: IDENT-7 can read the expiry as checked when the decode that checks it never runs or is not the library's: a verifier method the call chain never reaches, a decode after a
returnor whose expiry error is caught, a helper its own module rebinds,jwtre-exported from another module or wrapped by a decorator. An expired identity proof is then accepted.
v0.1.6
Assure engine 5feac4f4, served by api.symbolia.ai. The Action built from it is Symbolia-Assurance/assure-action v0.1.6 (@v0 moves with it).
v0.1.6 mostly corrects readings, and fixes three readings v0.1.5 listed as known issues. If your app has one of the shapes below, a check you ran on v0.1.5 may have read differently from what your code does. Run it again.
Pin this release
- uses: Symbolia-Assurance/assure-action@40a54d6b9d89882a9dbb24f3616c0fbd2811531e # v0.1.6For customers
- FastAPI. A guard whose denial a handler swallows is no longer counted. An Authlib check replaced on the claims class gives no expiry credit. The first-run draft withholds routes it cannot read instead of drafting them public, and now drafts routes on prefixed routers, on apps or routers imported from another module, and in app factories, with HTTPBearer subclasses and imported API keys as credentials.
- Django. A decode with options, a leeway, or options that are not written inline gives no expiry credit, and neither does
jwt.api_jws.decode. Avalidate()counts only when it always runs and covers every decode. Test patches of the identity library throughmock.patchand related forms are read. The first-run draft handles a project below the repository root, router-registered viewsets and middleware guards. - Any Python stack. A handler with a return before its raise is not counted as "every handler raises".
- Observed PostgreSQL. Eleven new CVE rows and five login rows are read.
- CVE-2026-2007 (pg_trgm), CVE-2026-2004 (intarray) and CVE-2025-12817 decide from the collected facts.
- CVE-2023-39417, CVE-2024-10979, CVE-2026-14670, CVE-2024-4317, CVE-2026-6469, CVE-2026-14677, CVE-2026-6470 and CVE-2025-8715 read not_observed, naming the fact the collector does not send, until the setup agent's question is answered. Collected facts decide where they can: PL/Perl installed fails CVE-2024-10979 and CVE-2026-14670.
- CVE-2026-14673 (amcheck) is read only from the collected extension list, and holds only while no other database accepts connections.
- Observed first lines now count 72 obligations (was 61).
Where we are on the curve
- Real outside apps read through the API: 2 of 19 Python corpus apps get a reading; the rest name the line Assure could not read (v0.1.6 adds no new reads; scoped reading is the next unit).
- Pre-release corpus gate: 0 regressions across 89 rows, held-out rows included (gate 16725).
Known issues
- FastAPI: an app that defines or imports its own
DependsorSecuritycan make IDENT-1 read as holding on routes that are open. - FastAPI and Django: a helper that decodes and validates the identity proof, called only under a condition, can make IDENT-7 read as holding.
- Django: a
jwt.decodecall wherejwtis a local object rather than the imported library can make IDENT-7 read as holding. - FastAPI: a decode refused under the signature rules that falls through to a trusted header can make IDENT-9 read as holding.
- FastAPI: a guard whose denial a helper it calls catches, or that wraps a raising helper in
contextlib.suppress, can make IDENT-1 read as holding while the route is open. - Flask: a session signing value written in the repository can make AUTH-1 read as holding while a forged session reaches the view.
- Django: REST framework settings loosened indirectly, through
getattrwith a variable name,attrgetter,vars(), a class-attribute alias, a walrus assignment or amatchcapture, can make IDENT-1 read as holding while anonymous requests succeed. - Django: a settings store through a local bound to an app-class call, a star import that rebinds that class, or a helper that returns settings state can make IDENT-1 read as holding while anonymous requests succeed.
- Django: IDENT-7 can read the expiry as checked when the decode that checks it never runs or is not the library's: a verifier method the call chain never reaches, a decode after a
returnor whose expiry error is caught, a helper its own module rebinds,jwtre-exported from another module or wrapped by a decorator. An expired identity proof is then accepted.
v0.1.5
Assure engine 32cfcef5, served by api.symbolia.ai. The Action built from it is Symbolia-Assurance/assure-action v0.1.5 (@v0 moves with it).
v0.1.5 mostly corrects readings. If your app has one of the shapes below, a check you ran on v0.1.4 may have read differently from what your code does. Run it again.
Pin this release
- uses: Symbolia-Assurance/assure-action@d4a80a647c149551cc6b1605f565d250843d9800 # v0.1.5For customers
- FastAPI. Routes are no longer lost through app factories, aliases of
add_api_route, route lists or routers declared in another module; where a composition can't be followed, the check refuses at that line. A guard replaced throughdependency_overridesin an app factory no longer reads as holding. Named router dependencies, route-decorator dependencies and a dependency bound twice now read as what takes effect. Expiry evidence counts only when an exp check takes effect. The first-run draft covers more guard, route and key shapes. - Django. A DRF permission decorator applied outside
api_viewis no longer credited. Role guards proved from the source are recognised. The URL census reads more list forms and refuses the rest. The first-run draft covers class views, viewsets, simplejwt, session sign-in and sign-out, and repository permission classes. - Flask. A decorator between the route and the declared guard leaves the route unread. A blueprint
before_requesthook under a declared Flask-HTTPAuth guard is read as guarding its routes. A route that answers only under testing or debug is no longer a false alarm. - Any Python stack. A guard Assure does not recognise, on a route IDENT-3 or IDENT-5 judges, reads as not established and is named. A data-flow analysis that hits its limit fails closed.
- Python standard-library servers. Routes added with
|=and a second declared server are no longer left out. - Express and TypeScript. No file a route could live in is dropped. Unreadable wrappers mark the route unread, guards are followed through barrel re-exports, computed prefixes refuse, and middleware that only observes the signed-in user is not credited as a guard. One file that does not parse no longer refuses the whole check.
- Go (gin). A session reset to anonymous is read, and a file is no longer skipped because of its path name.
- Observed PostgreSQL. Declared administrators,
sensitive_objects,privilege_queriesanddeclared_predicateare read. New Supabase rows, TENANT-1 and TENANT-2, and a CVE-2021-23214 row are added. A constant-false SELECT policy no longer counts as a read policy. - Declared PostgreSQL. A tenant column compared through a
varchar(N)cast no longer reads as holding. The first-run draft leaves unobserved replication settings unread and asks you. - Premium. A queued build is published, not rehearsed. An image in the repository no longer stops the construct. A Premium method you state is read on your next FastAPI or Django check.
- Accounts. A daily records window per plan (100,000 on Premium, 500,000 on Pro), and an overage budget you set on the account.
- The Action. Local mode runs under the runner's own Python and reads a Python checkout as API mode does. Several profiles or jobs on one PR share one comment, and older comments are marked superseded. Feedback the Action could not send is shown with one step to fix it.
- Wording. Refusals and gaps name what fixes them more often, a 401 says when the value sent is not an Assure key, and the examples pin a commit.
Known issues
Nine readings can show as holding when they do not. The first three were present in v0.1.4. The fixes ship in v0.1.6.
- FastAPI: a guard that catches its own
HTTPException(403)can make IDENT-1 read as holding. - FastAPI first-run draft: a route registered with
add_api_routeand aDepends(<call>)it does not read can be drafted as public. Review drafted public routes before you accept them. - FastAPI: a decode refused under the signature rules that falls through to a trusted header can make IDENT-9 read as holding.
- FastAPI: an app that defines or imports its own
DependsorSecuritycan make IDENT-1 read as holding on routes that are open. - FastAPI and Django: a
validate()call inside atrywhose error handler can return instead of raising can make IDENT-7 read as holding. - FastAPI and Django: a helper that decodes and validates the identity proof, called only under a condition, can make IDENT-7 read as holding.
- Django: a PyJWT
decodewith aleewayabove 300 seconds, or a leeway that is not a number literal, can make IDENT-7 read as holding. - Django: an Authlib
jwt.decodecounts as checking expiry whether or notvalidate()runs, so IDENT-7 can read as holding. - Django: a
jwt.decodecall wherejwtis a local object rather than the imported library can make IDENT-7 read as holding.