Skip to main content

Advisory data

One rule needs to know something SQLens cannot read off your database: SEC.CFG.PATCH_EOL asks whether your server's release series still receives security fixes, and the answer lives in a vendor's support policy rather than in pg_catalog.

So the package ships that answer as data, and this page is about where that data comes from, what it can and cannot say, and how you keep it current.

Nothing is fetched unless you ask

SQLens makes no network request during a check. Not to look up a version, not to report a result, not to count a run.

That is not caution for its own sake. A tool you install to audit your database security is a tool with credentials and catalog access, and one that quietly talks to a third party is a supply-chain risk wearing a safety label. There is also nothing to switch off: the package carries no telemetry, so it carries no opt-out either — an opt-out is a confession.

The one exception is a command you type, described below.

How you can check rather than take our word for it. tests/Feature/NoImplicitNetworkTest.php runs sqlens:lint, sqlens:audit and sqlens:security with a handler in front of the HTTP client and fails if any of them reaches it even once. A static scan of src and config runs beside it, naming the only files allowed to contain a network call at all.

The three files that can answer, in order

A run resolves the advisory data through a fixed order and stops at the first candidate:

  1. sqlens.security.advisories.path — a path you configured.
  2. Your application's published copy, at resources/data/eol.json under your base path.
  3. The copy bundled with the package.

The order matters more than it looks. Two of those files can exist at once, both perfectly valid, and only one of them is being read — so the file that actually answered is named in every finding:

judged from the published end-of-life data at "/app/resources/data/eol.json", compiled 2026-08-03

Without that line, a refresh that landed somewhere nothing reads would look exactly like a refresh that changed nothing.

A configured path that does not answer is a hard stop

If you set sqlens.security.advisories.path and the file is missing or unreadable, the run does not fall through to the next candidate. It reports an undetermined naming the path.

Falling through would mean reading a different file than the one you deliberately named — and you would see verdicts from data you thought you had replaced, with nothing on screen to say so.

What the bundled data can and cannot tell you

It records, per release series: the release date, the end-of-support date, and whether the series is long-term support.

It records no patch level, and that is deliberate. A patch number shipped inside a package is wrong within a month of any release, and a wrong "latest" produces either invented findings or invented confidence. So the package answers the question it can answer — is this series still supported — and does not answer the one it cannot.

For MySQL the dates are premier support, not extended. Extended support exists, is purchased separately, and is not what most projects are on; recording the later date would let a server that stopped receiving routine fixes read as supported.

Refreshing, when you decide to

php artisan sqlens:security --refresh-advisories

It fetches, validates, writes, and prints what moved. It never runs as part of a check.

There is no default source, on purpose

// config/sqlens.php
'security' => [
'advisories' => [
'source' => env('SQLENS_ADVISORIES_SOURCE'),
],
],

Out of the box that is null, and the refresh says so rather than fetching from somewhere we picked. Shipping an endpoint would mean this package accepting a third party's license, rate limit and attribution on behalf of you — none of which are ours to agree to.

The URL must serve a document in this package's own advisory format. That keeps SQLens from ever parsing somebody else's shape, so it never inherits a change to that shape, and it leaves you free to generate the file from whatever source your own terms allow.

https only. A security baseline fetched over plain HTTP can be answered by anybody on the path with a file the package then trusts.

Where it writes

The path you configured, or your application's published copy. Never into the installed package: the next composer install would undo it silently, and you would be certain you had refreshed data that is old again. Asked to write there, the refresh refuses and names the two places it will write instead.

Reviewing the diff

The output is a line per release series rather than a line per file line, because this file is meant to be committed:

Wrote /app/resources/data/eol.json:
+ postgresql 19 — new, supported until 2031-11-13
~ postgresql 14 — end of life 2026-11-12 → 2026-12-10
- postgresql 12 — no longer in the data

Read the removals. A series that vanished is either a vendor retiring it or a source that broke, and those are different problems with the same shape.

When it fails, your file is untouched

An unreachable source, an error response, or a document the package cannot read all end the same way: the refresh stops, says which of those happened, and leaves the existing file exactly as it was. A half-written advisory file would replace a working security baseline with one the next run cannot read.

Validation is done by reading the response with the same parser the rules judge from, so a refresh can never accept a document a later run would reject.