Repository navigation
Releases
Releases · YawLabs/postgres-mcp
v0.13.12
Changed
- The oam floor moves from 0.19.1 to 0.19.5, so the
postgres-mcplauncher
no longer runs the server on an older oam. 0.19.5 is verified through the
launcher withOAM_BINpointing at it and a local PostgreSQL 18.3: an MCP
handshake listing all 23 tools and apg_readonlyquery, under
POSTGRES_MCP_RUNTIME=oamand again underPOSTGRES_MCP_SANDBOX=1, with
the server process confirmed as that binary (oam run .../dist/index.js,
andoam --permission --allow-net=localhost:5432 ... runfor the sandbox).
An oam 0.19.4 set asOAM_BINis now passed over for a 0.19.5 when one is
installed, and otherwise refused (RUNTIME=oam, the sandbox) or replaced by
Node (auto). TheNODE_OPTIONSpermission-flag measurements behind the
launcher's strip were re-run on 0.19.5 and still hold.
Fixed
- The sandbox docs no longer claim network access is limited to the database
endpoint. From oam 0.19.3,dns.setServers()works under--permission
with no net check, so sandboxed code can send DNS queries to any server it
names. Measured on 0.19.5 with no--allow-net: a query carrying a chosen
name reached a listener on an arbitrary local port. The README now says TCP
connections are pinned to the one host and port, and that the sandbox is not
an exfiltration boundary. Two launcher comments that described oam
behavior that has since changed are corrected too: a permission flag written
afterrunhas been lifted and applied since oam 0.19.4 instead of rejected,
and a repeated list flag has added to the earlier grant since 0.19.1 instead
of replacing it.
v0.13.11
Security
- The bundled MCP server SDK moves from 2.0.0 to 2.4.0, and zod from 4.4.3
to 4.6.7. This clears GHSA advisories for@modelcontextprotocol/server
< 2.3.0 (cross-client message delivery on shared HTTP transports; bearer
tokens issued for another service accepted) and zod < 4.6.6 (memory
exhaustion validating oversized constrained collections). postgres-mcp
serves over stdio only and does no bearer auth, so neither SDK issue was
reachable here; both packages are bundled intodist/, so the fix ships
with the next release.
v0.13.10
Changed
- The oam floor moves from 0.18.0 to 0.19.1, so the
postgres-mcplauncher
no longer runs the server on an older oam. 0.19.1 is verified through the
launcher withOAM_BINpointing at it and a local PostgreSQL 18.3: an MCP
handshake listing all 23 tools and apg_readonlyquery, under
POSTGRES_MCP_RUNTIME=oamand again underPOSTGRES_MCP_SANDBOX=1, with
the server process confirmed as that binary (oam run .../dist/index.js,
andoam --permission --allow-net=localhost:5432 ... runfor the sandbox).
0.19.0 and its -dev builds now sit below the floor. ALLOW_WRITESandPOSTGRES_SSL_REJECT_UNAUTHORIZEDare trimmed and
case-insensitive.ALLOW_WRITES=TRUEor"1 "now allows writes, where it
used to stay read-only without a word. Any value other than1,trueor
an off value (0,false,off, empty) still stays read-only, and now
says so once on stderr.
Security
- The sandbox's
NODE_OPTIONSstrip is now the only thing keeping an
inherited grant out. From oam 0.19.1 (#363) a--allow-fs-read,
--allow-fs-write,--allow-netor--allow-envinNODE_OPTIONSadds
its entries to the command line's instead of yielding to them: re-measured,
NODE_OPTIONS=--allow-fs-read=<file>beside the launcher's own
--allow-fs-readlist reads that file too. The launcher already removed
every such token from the sandboxed oam's environment; the comments and
README now say why that is load-bearing, and a unit test pins the strip for
each list flag.
Fixed
scripts/check-oam-floor.mjsruns from a junctioned or symlinked
checkout. It decided whether it was the main module by comparing
resolve(process.argv[1])with its own path, but Node realpaths the main
module and notargv[1], so through a link the check was skipped and the
script exited 0 with no output -- including fromrelease.sh. Both sides
are now realpath'd.
v0.13.9
Security
POSTGRES_MCP_SANDBOX=1no longer lets an inheritedNODE_OPTIONSwiden
the sandbox. oam 0.18.0 reads--permissionand--allow-*flags from
NODE_OPTIONSas well as from its command line, and takes every one the
command line leaves out from there: measured,
NODE_OPTIONS=--allow-fs-read=*beside the launcher's
oam --permission ... runlet the server read any file. The launcher now
removes those flags from the sandboxed oam's copy ofNODE_OPTIONS-- judged
on the value oam reads, so a quoted"--allow-fs-read=*"goes too -- and
keeps every other token.
Fixed
- A Node handoff from an oam 0.18.0 host running under
--permissionnow
says why it cannot work, instead of Node exiting 9. oam 0.18.0 hands its
--permissionand--allow-*flags to every child inNODE_OPTIONS, after
any environment the launcher passes, and Node rejects the oam-only ones
(--allow-net= is not allowed in NODE_OPTIONS). With
POSTGRES_MCP_RUNTIME=nodeon such a host the launcher now exits with a
message naming the fix. Every other Node handoff gets aNODE_OPTIONSwith
oam's permission flags removed, so one inherited from an oam further up the
tree does not stop Node either. - "No usable oam" now names the fix that fits what was found. An oam that
is too old gets "Runoam self-updateto get oam 0.18.0 or newer", one that
would not run gets a check of the binary, and a missingOAM_BINgets a
pointer to fix it. Only when no oam was found at all does the message say to
install from oamjs.org -- and on Linux off x64, where oam publishes no
build, it says so instead. Both messages changed:POSTGRES_MCP_RUNTIME=oam
andPOSTGRES_MCP_SANDBOX=1. They used to say "Install or update oam from
https://oamjs.org" in every case. - The Unix-socket sandbox refusal no longer says oam cannot connect to a
socket. oam has dialled Unix sockets since 0.18.0; what the sandbox cannot
do is pin one, because the launcher only grants a TCP host and port. The
refusal now says that, and its remedy is "connect over TCP, or unset
POSTGRES_MCP_SANDBOX" -- it no longer sends you to
POSTGRES_MCP_RUNTIME=node, which the socket does not need. - The launcher finds an oam installed to
OAM_INSTALL_DIR. That variable
is where oam's installers andoam self-updateput the binary, but discovery
only checked the default directories andPATH, so an oam installed
somewhere custom and not onPATHwas never found.$OAM_INSTALL_DIRis now
checked first.
Added
- An integration test runs the sandbox against a real oam and database.
WithOAM_BINandDATABASE_URLboth set, it completes an MCP handshake and
aselect 1through the launcher withPOSTGRES_MCP_SANDBOX=1 POSTGRES_MCP_RUNTIME=oam, then checks under the launcher's own flags that
the pinned port connects and the port next to it is refused with
ERR_ACCESS_DENIED. The grant semantics oam 0.18.0 changed were measured by
hand until now. scripts/check-oam-floor.mjs, ported from aws-mcp. It checks that every
floor claim in the launcher, the README and the suite names the same version
asOAM_MIN(on everynpm test, throughsrc/oam-floor.test.ts), and,
fromrelease.sh, that the floor is not behind the latest oam release.
POSTGRES_MCP_ALLOW_STALE_OAM=1releases on an old floor deliberately; no
network is not a failure.
v0.13.8
Changed
- The oam floor moves from 0.15.2 to 0.18.0, so the
postgres-mcplauncher
no longer runs the server on an older oam. This server is verified on one
oam release at a time, and the floor keeps the launcher off anything older
than that release. 0.18.0 is verified on the published
aarch64-pc-windows-msvc binary, checksum matched against the release
SHA256SUMS, through the launcher withOAM_BINpointing at it and a local
PostgreSQL 18.3: a full MCP handshake listing all 23 tools (the same 23 as on
Node), apg_readonlyquery answering byte-for-byte as it does on Node (same
rows, samedataTypeNamevalues), and the server process confirmed as that
binary (oam run .../dist/index.jsas the launcher's child). The sandbox the
README documents was re-measured on it: withPOSTGRES_MCP_SANDBOX=1 POSTGRES_MCP_RUNTIME=oamthe launcher spawnsoam --permission --allow-net=localhost:5432 --allow-env=... run, the same query answers as it
does on Node, and under the same flags a connect to port 5433 and a file read
are refused withERR_ACCESS_DENIED. If the launcher finds only an oam from
0.15.2 to 0.17.x, it now falls back to Node under the default
POSTGRES_MCP_RUNTIME=auto, and exits with an error under
POSTGRES_MCP_RUNTIME=oamorPOSTGRES_MCP_SANDBOX=1-- it says so on
stderr, naming the version it found and the floor (measured with oam 0.17.0:
is oam 0.17.0, older than 0.18.0; using Node instead.). On Node every tool
answers the same; what is lost is the sandbox, which needs a fresh oam at the
floor and refuses to start without one. A host that launches the command with
oam runon 0.15.2 to 0.17.x now hands off to a newer oam or to Node instead
of serving in-process. A client that runsoam run /path/to/postgres-mcp/dist/index.jsdirectly bypasses the launcher and keeps
the oam it names. Runoam self-update, or setPOSTGRES_MCP_RUNTIME=nodeto
make the choice explicit.
Fixed
release.shwaits up to 600 s, not 300, for npm to serve a new version before
the MCP Registry step, and polls npm up to 120 times 5 s apart in its final
check, not five times.scripts/post-publish-smoke.shtries itsnpm install
of the new version up to 60 times, 10 s apart, instead of once. On 2026-09-29
the @yawlabs/fetch-mcp 0.8.2 release spent 295 s of its 300 s gate waiting for
npm to serve the new version, andnpxneeded 313 s, 24 of its 30 attempts,
to install @yawlabs/lemonsqueezy-mcp 1.0.1. Release tooling only; the server
itself is unchanged.release.shruns every mcp-publisher call to the MCP Registry, each login and
each publish attempt, under coreutilstimeout(MCP_PUBLISH_TIMEOUT_S,
default 90 s) where one (or Homebrew'sgtimeout) is on PATH -- without one
the call runs unbounded, and a warning says so -- because mcp-publisher waits
for the registry's answer with no limit of its own and a registry that never
answered would have hung the release. A publish attempt that gets no answer is
retried on the same 30, 60 and 90 s clock as the registry's own 429-504: one
the limit stopped, which used to hang the step, and one whose connection
failed or dropped (the client'serror sending requestor
error reading response), which used to fail it at once. A login the limit
stopped says the registry did not answer; one that failed any other way says
how to read mcp-publisher's output (a 401 is the registry refusing the token
exchange; a 429, a 5xx or a connection error is the registry or the network)
instead of naming token scopes, which never fail a login: the registry reads
the org role at login and refuses only at publish. A publish refused with a
403 says what the io.github.YawLabs namespace takes: a YawLabs org Owner whose
token can read org roles. Release tooling only; the server itself is
unchanged.
v0.13.7
Fixed
release.shreads npm's per-version document and retries the MCP Registry
publish. Every "is x.y.z on npm?" check -- the step-5 skip, the CI hand-off
poll, the npm propagation wait and the step-8 verify -- now goes through one
helper that reads the per-version document the MCP Registry's validator
fetches, notnpm view's whole packument, which Cloudflare's edge can serve
up to 5 minutes stale after a publish. A re-run whosenpm publishstill
gets npm's E403 "cannot publish over the previously published versions"
treats the version as published instead of failing with the token-error
message. The MCP Registry publish is attempted up to four times, 30/60/90 s
apart, but only on the answers waiting cures -- the version not found yet,
"Likely transient, retry later", a failed npm metadata fetch, or the
registry's own HTTP 429, 502, 503 or 504 -- with a fresh registry login
before each retry; any other error still fails at once, and a
duplicate-version answer counts as done.
Documentation
- The README's Add to Yaw MCP button now sits directly under the title, and
the follow badge links to @YawLabs. The one-click install button and its
one-line caption moved up from further down the page, so they are the first
thing under the name on npm and GitHub, and the X badge at the bottom points
at @YawLabs instead of @TokenLimitNews. npm shows the
README from the published package, which is why it takes a release to carry
this there; the package's code is unchanged from 0.13.6.
v0.13.6
v0.13.5
Fixed
- Agent SQL that never ran now leaves an audit line (#42). Whether a call
that failed before its statement was sent wrote a line depended on which
helper it went through.runInternalconnects inside its audited step, so
a refused connection wrote aninternalline withok: falseand
sqlstate: "ECONNREFUSED"for every tool that starts with a catalog query.
The three runners behind agent SQL checked the connection out, opened the
transaction and ran any hooks BEFORE the audited step, sopg_query,
pg_readonlyandpg_explain-- the tools the trail exists for -- wrote
nothing, and so didpg_kill, whose checkout sat before its audit too.
Measured by calling all 23 tools over stdio against
postgres://u:p@127.0.0.1:1/xwithPOSTGRES_AUDIT_LOG=stderr(24 calls;
pg_explainonce plain and once withhypothetical_indexes): 13 lines,
none of themuser, and 11 calls with no line at all. An operator asking
"what did the agent try to run during the outage" found nothing for
exactly the tools that carry agent SQL. The same shape hid a failed
BEGINand a hook setup that threw: apg_explainwhose hypothetical
index could not be created never ran its statement, and its only line was
the HypoPG-installed check, withok: true. The checkout, theBEGIN, the
hook savepoint and the hypothetical-index setup now sit inside the
statement's audited span, so whichever of them fails writes the
statement's oneuserline:ok: false, the agent'ssql(its keyword
and hash underPOSTGRES_AUDIT_REDACT),paramsas a count, thetool,
and the code where there is one -- the Node code for a refused or
unresolvable connection, none for a connect timeout or a missing
DATABASE_URL, the SQLSTATE for aBEGINor a setup the server refused
(42P01for a hypothetical index on a table that does not exist). Never
two: the span is one wrapper and nothing inside it audits on its own, so a
statement that is sent and fails writes exactly the line it always did.
pg_kill's signal statement gets the same treatment. Review of the fix
found two more silent paths with the same shape.pg_explainwith a
version-floored option (settings,wal,generic_plan,memory,
serialize,bufferswithoutanalyze) probesserver_version_num
before composing its statement, the probe swallowed every failure into its
"assume oldest" sentinel, and the gate then answered "the server version
could not be determined ... drop the option and re-run" with no line
written -- the wrong remediation for an outage, and the same unaudited
probe is what six other tools ran first. The probe is now aninternal
line like the catalog SQLrunInternalsends: once per successful
reading, which is then cached for the life of the process (calls that
race the first reading share one probe and one line), and on every probing
call while the server is unreachable, since a failure is not cached. And
the two gates that turn the sentinel into an error,pg_explain's and
pg_io_stats's, now report the probe's own failure when it threw (connect ECONNREFUSED ...,DATABASE_URL is not set), keeping "could not be
determined" for a server that answered something unparsable. The second
path: the seven tools that run several catalog queries on one shared
connection (pg_describe_table,pg_health,pg_advisor,
pg_replication_status,pg_seq_scan_tables,pg_unused_indexes,
pg_io_stats) checked that connection out before composing their first
statement, so once the version was cached -- an outage that begins
mid-session, the case the trail exists for -- a refused connection wrote
nothing for any of them.withSharedClientnow checks the connection out
inside its first statement's audited step, so the refusal is that
statement'sok: falseline; statements waiting on the same checkout, or
issued after it failed, fail with the same error and write nothing, and
the failure still propagates as the exception every caller handles. The
same 24 calls now write 30 lines (a tool that probes and then queries logs
a failed probe and then its failed first statement), three of themuser,
and no call is silent; with the version cached beforehand, each of the
seven writes its first statement's line. The README's "Audit logging"
section says which line each tool writes for a refused connection -- for
pg_explainthat is theEXPLAINitself unless a version-floored option
orhypothetical_indexeswas passed, when the probe's or the HypoPG
check's line is the record and theEXPLAINtext is not on it. Two things
follow for readers of the trail.mson auserline (and onpg_kill's)
now runs from the checkout to the statement's completion, so it includes
waiting for a pooled connection and the transaction setup, asinternal
lines already could. And a refused connection comes back from
runReadOnly,runReadWrite,runReadWriteRollbackandpg_kill's
handler as{ok: false}like every other failure, where it used to
propagate as an exception; over MCP that is the sameisErrorenvelope,
its message now ending in the code,(code: ECONNREFUSED). Tests drive
each of the three runners against a pool whoseconnect()rejects and
against a client whoseBEGINis refused,runReadOnlyagainst a connect
timeout, a missingDATABASE_URLand a hook setup that throws,pg_query
andpg_readonlythrough the MCP wrapper for thetooltag,pg_kill
against a rejectingconnect(),pg_explainagainst a stubbed server that
refuseshypopg_create_indexand against a probe that fails, the probe
itself for its shared, once-per-reading line,withSharedClientfor the
first statement's line under a fan-out, and each of the seven
shared-connection tools with the version cached and the connection then
refused; every fake client also records when it was released, so the
restructured release paths are checked against their last statement.
v0.13.4
Security
-
POSTGRES_MCP_SANDBOXno longer turns itself off without a word; when
the sandbox cannot be applied, the launcher refuses to start (#41). Four
paths left an operator believing they were sandboxed when they were not, and
none of them printed anything.- The value. Only the exact value
1enabled the sandbox, sotrue,
1andTRUEran unsandboxed. It now reads like the audit variables:
1ortrueon,0,falseoroffoff, trimmed and case-insensitive.
Any other value (yes,on) stops the launcher with a message naming the
accepted ones. So does a value that is set but empty or only whitespace,
as the audit variables have done since 0.13.3: that is what
"POSTGRES_MCP_SANDBOX": "${SANDBOX}"becomes when the variable is unset
where the MCP client runs, and reading it as unset ran the server
unsandboxed for an operator who had asked for the sandbox. Only a variable
that is not set at all counts as unset. - The runtime.
POSTGRES_MCP_RUNTIME=node, no usable oam underauto,
and an oam that failed to spawn all served without--permission-- in
the launcher's own process, or handed off to Node -- with no message at all
when no oam existed. Each now refuses, in every mode and on every host,
with the fix named. - The network grant. An unset
DATABASE_URL, a URL with no host
(postgres:///dbleaning onPGHOST,postgres://u@/db), a host list
with ports, or anythingnew URL()rejected produced a bare--allow-net:
every host on the internet.postgres://h1,h2/dbproduced
--allow-net=h1,h2:5432, which oam reads ash1on every port plus
h2:5432. And?host=,?port=,PGPORTand percent-encoded hosts were
ignored, which denied working setups their own database. The grant is now
the onehost:portthe pg driver dials, resolved the driver's way --
?host=/?port=, then the URL, thenPGHOST/PGPORT, then
localhost:5432-- and the suite checks it against the bundled pg on
thousands of generated connection strings. WithDATABASE_URLunset no
--allow-netis passed at all, so every connection is denied and the
server reports the missing variable as it does unsandboxed. A Unix socket,
a host list, a port outside 1-65535, a host an exact grant cannot match, or
an unreadable or non-postgres://URL now refuses;DATABASE_URLis never
printed. - Windows. An allowlisted variable spelled in another case (
pghost,
postgres_audit_log) reached the launcher, because Node reads names
case-insensitively there, and was then stripped from the sandboxed server,
because oam matches them exactly -- so a lower-case audit variable silently
switched the audit trail off. Each is now passed in its exact spelling.
Upgrading: this stops setups that only appeared to be sandboxed: the
sandbox set with no usable oam underauto, with
POSTGRES_MCP_RUNTIME=node, to a value such asyes, or to an empty value.
Each now gets a message naming the fix; removePOSTGRES_MCP_SANDBOXor set
it to0to keep running without it. - The value. Only the exact value
v0.13.3
Fixed
pg_killnow writes an audit line. The other tools audit their SQL
throughrunUserQueryAudited,runInternalorwithSharedClient.
pg_killuses none of them -- it needs the raw client, to capture the NOTICE
that explains afalseanswer -- and queried that client directly, so with
POSTGRES_AUDIT_LOGon, cancelling a query or terminating a backend left no
line at all. Measured on PostgreSQL 17: one statement sent, zero lines
written, and the cancelled statement's own57014line tied to nothing. It
was the one tool whose whole purpose is to affect sessions other than its
own. The signal call is now wrapped in place, on the same client, so NOTICE
capture is unchanged. The line carriestool: "pg_kill"and
source: "internal"(the server composes the statement; the agent supplies
only the pid), andparams: 1-- the pid is a bound parameter, and the
trail logs parameter counts, never values, with no exception carved out for
a harmless one.okreports whether the statement ran, so a
signaled: falseanswer still readsok: true. Checked on PostgreSQL 15,
17 and 18: exactly one line for each cancel, terminate and unknown-pid call,
with the NOTICE still in the tool'snoteand absent from the log. The
README's "What the trail does not show" list is updated to match (#39).
It also says whatokcannot tell you, and how to find the target's own
line, the latter from 600 cancel and terminate calls measured over loopback
TCP on PostgreSQL 15, 17 and 18. With the pid unlogged,tsis all that
pairs the two lines: 81% of target lines carried thepg_killline's
millisecond or the next, but terminating a CPU-bound target took up to
271 ms, and a statement timeout writes the same57014a cancel does.
ok: truedoes not show that the target stopped: postgres answerstrue
once the signal is sent, and on all three versions a session idle in a
transaction ignored the cancel and carried on. And when the pid names the
connectionpg_killitself runs on, its own line readsok: falsewith
57014or57P01-- after a terminate, with that backend gone.- A cancel or a statement timeout that lands inside the row-cap
DECLAREis
no longer swallowed. Agent SQL runs through a cursor so the row cap is
enforced by postgres, and a statement that cannot be a cursor (DDL, DML)
fails atDECLAREand is run directly instead. That fallback fired on ANY
DECLAREfailure.DECLAREplans the query and locks every relation it
reads, so a statement blocked on a table lock -- the "app is frozen" case
pg_inspect_locksandpg_killexist for -- is blocked inside it. Measured
on PostgreSQL 15, 17 and 18, identically: cancelling such apg_readonly
call answeredsignaled: true, the backend went fromDECLARE ...straight
to the bare statement and blocked again, and when the lock was released the
call returned rows, withok: truein the audit log. A 3000 ms
statement timeout fired, was swallowed, and the statement waited another
3000 (6003 ms measured), holding its pooled connection for both. The
second attempt ran outside the row cap, on the unbounded path the cursor
exists to avoid. And a terminate had its57P01replaced by the error of a
ROLLBACK TOsent down the dead socket, so the agent read "Connection
terminated unexpectedly" and the audit line carried nosqlstate. The
fallback now runs only for the two SQLSTATEs with which postgres says a
statement cannot be a cursor:42601and0A000. That set was measured,
not assumed: 69 statement classes on each of the three versions, and every
DECLAREfailure outside it (42P01,42703,42883,22012,42P18,
08P01) failed the same way on a direct run, so surfacing it at once
changes no outcome. After the fix the cancel returns57014in under
200 ms, the timeout fires once (3009 to 3027 ms), and the terminate reports
57P01. Affectspg_readonly,pg_queryandpg_explain. pg_killno longer takes the server down when its connection drops
mid-call. 0.13.2 gave every checked-out connection anerrorlistener,
because pg-pool removes its own while a client is out and node-pg's emit
with no listener is an uncaught exception. "Every" missed one:pg_kill
needs the raw client for its NOTICE listener and called
getPool().connect()itself. With a connection dropped while its query was
in flight the process exited, 7 of 7, and the tool call was never answered;
the same drop underpg_readonlyreturned an error and kept serving.
pg_killnow checks out throughacquireClient()like everything else
(7 of 7 survive, the error is returned, the next call succeeds), and a test
fails if any source file checks a client out of the pool on its own (#57).pg_killsays what a permission denial looks like. Its description,
which is what an agent plans from, said a denied signal comes back as
signaled: falsewith postgres's NOTICE innote. Postgres raises instead
--42501, in every branch ofsignalfuncs.con 15 through 18, and
measured on 18 -- so the call returns an error and the target keeps
running. The string the code quoted as that NOTICE was PostgreSQL 15's
ERROR message. The description, the schema comments and the handler comment
now say so, and say thatsignaled: truemeans the signal was sent, not
that the target stopped. The fallbacknotefor a barefalseno longer
lists a missing permission as a cause, which could send an agent looking
for a grant that was never the problem (#56).- An empty
POSTGRES_AUDIT_LOGorPOSTGRES_AUDIT_REDACTstops the server
at startup instead of counting as unset. An MCP client config entry such
as"POSTGRES_AUDIT_REDACT": "${AUDIT_REDACT}", whose variable is unset
where the client runs, can reach the server as present and empty -- and with
auditing on, that logged full SQL for an operator who had asked for hashes,
with no warning. An emptyPOSTGRES_AUDIT_LOGwas read as unset too:
auditing silently stayed off, or -- next to aPOSTGRES_AUDIT_LOG_FILE--
stayed on through the file, a guess either way. Both now refuse to start,
whitespace-only values included, asPOSTGRES_AUDIT_LOG_FILEalready did;
only a variable that is not set at all counts as unset. Upgrading: a
config that sets either flag to an empty value started on 0.13.2 and will
not start now. Remove the variable, or set it to0or1-- and next to a
POSTGRES_AUDIT_LOG_FILE, remove it or set1, since0with a file set
is refused as before. The error for an unrecognized
POSTGRES_AUDIT_REDACTnow names the real risk, unredacted SQL, instead of
a silently disabled audit trail (#40).