Repository navigation
Conversation
…res 17.5.1 runs its server under the app postgres.start ran pg_ctl, which setsid()s the postmaster out of the adapter's process group: it outlived the app's SIGTERM, the supervisor's SIGKILL and daemon death on all 4 platforms. It is now a cli.service that runs the postgres binary itself in the foreground (no pg_ctl, no /bin/sh, so the port/datadir params can no longer reach a shell), TCP only (no Unix socket, so a long datadir no longer hits the sun_path limit). cli.service gains stop_signal (SIGTERM default, SIGINT, SIGQUIT): PostgreSQL's SIGTERM is a smart shutdown that waits for every client; SIGINT is its fast, clean one. postgres.exec gets a bare-name tools allowlist without pg_ctl, pg_upgrade and pg_createsubscriber (each daemonizes a postmaster), which also closes the '../' escape to any host binary; a passthrough postgres is a service. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
TeoSlayer
marked this pull request as draft
October 1, 2026 14:31
Contributor
Author
|
Converted to draft rather than merged. It depends on draft #115 ( |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #115 (
fix/redis-lifecycle, which addscli.service), and through it on #114 and #111. This PR adds one commit. Once those merge, it retargets tomain.Problem
The harness sweep ran the published io.pilot.postgres 17.5.0 bundles on darwin/arm64, darwin/amd64 (Rosetta), linux/arm64 and linux/amd64 (
docker --init, as a non-root user). I reran the published bundle through this PR's harness for a same-harness baseline:postgres.startrunspg_ctl start, whichsetsid()s the postmaster out of the adapter's process group. After the app's SIGTERM:LEFT pid=39689 ppid=1 pgid=39689 …/bin/postgres -D …+ checkpointer, background writer, walwriter, autovacuum launcher, logical replication launcher (darwin-arm64). The same 6 processes are left after a SIGKILL of the app pid (the supervisor's stop path) and on linux-arm64. On Linux with Pdeathsig, the app dies 0 ms after its parent, but the postmaster (pid=62 ppid=1) and 5 children are left. #114's guard, a group kill and reapStale can't reach it.pg_ctlruns-o "-p ${port} -k ${datadir} -h 127.0.0.1"through/bin/sh. A$(…)inportcreated a marker file (audit).pgdispatcher only checks[ -x "$dir/$tool" ], sopostgres.exec ["../../…/bin/echo", …]runs any host binary (audit).-k ${datadir}: the Unix socket path goes over sun_path (103 bytes) and the start fails:pg_ctl: could not start serverwith the 117-byte scratch root.ORPHAN (app 40783 alive 6s later, answering IPC=true), plus the postmaster.Fix
Template (small):
cli.servicegainsstop_signal:SIGTERM(default),SIGINTorSIGQUIT. It replaces SIGTERM in the adapter's clean stop (StopServices) and in a failed readiness wait; SIGKILL still follows after 8 s. PostgreSQL's SIGTERM is a smart shutdown that waits for every client to disconnect. One open connection would run out the grace and end in a SIGKILL and crash recovery on the next start. Its SIGINT is the fast shutdown with a checkpoint. Validation rejects anything else. Documented indocs/CLI-ADAPTER.md, with a note that a server must not be started through a daemonizing wrapper (pg_ctl start).submissions/io.pilot.postgres→ 17.5.1 (the bundled PostgreSQL is still 17.5, same native assets and shas):postgres.startis acli.servicethat runs thepostgresbinary itself in the foreground:postgres -D ${datadir} -p ${port} -h 127.0.0.1 -c unix_socket_directories= -c logging_collector=on -c log_directory=${datadir} -c log_filename=postgres.log, withready_tcp 127.0.0.1:${port},ready_timeout 45s,log_file ${datadir}/postgres.logandstop_signal SIGINT.pg_ctland no/bin/sh:portanddatadirare plain argv, so the injection is gone. postgres rejects a bad port:FATAL: invalid value for parameter "port".<datadir>/postgres.log.postgres.execgets a bare-namecli.toolsallowlist of 21 bundled tools. It leaves outpg_ctl,pg_upgradeandpg_createsubscriber, each of which starts a detached postmaster throughpg_ctl. The allowlist closes the../escape. A passthroughpostgresis a service (ready_port_flag -p,stop_signal SIGINT).postgres.stop/postgres.statusstill usepg_ctl stop/statuson their enumerated routes.postgres.stopstops the service, and a laterpostgres.startworks.pg_ctl -ofor exec.Tests
TestCLIServiceLifetime/stop-signal: a service withstop_signal: SIGINTgets SIGINT and not SIGTERM on the adapter's SIGTERM, and the group is left empty. Mutation check: withStopServicessending SIGTERM again, the subtest fails. Restored, it passes-count=3.TestCLIServiceConfig:stop_signal: SIGINTis ok;SIGKILLis rejected.go vet ./...andgo test ./... -count=1pass on darwin/arm64.internal/scaffoldandinternal/publishpass on linux/arm64 (golang:1.25.13-bookworm, non-root).pilot-app verify-update submissions/io.pilot.postgres/submission.json:UPDATE GATE OK(17.5.1 ≥ 17.5.0).demo-score: postgres 100.0 ok.Verified on real postgres bundles built from this commit
I built all 4
DefaultPlatformswithpublish.BuildBundlefromsubmissions/io.pilot.postgres/submission.jsonat 17.5.1 and signed them with a TEST-ONLY key; nothing was published or uploaded.pilot-app verifypasses on each tarball (VERIFY OK), and the adapter binaries are Mach-O arm64/x86_64 and static ELF aarch64/x86-64. A lifecycle harness drove the real staged PostgreSQL 17.5 from R2, spawning the app with the supervisor's exact flags in its own process group. On Linux it runs indocker --initasnode, with Pdeathsig from a locked thread like the supervisor.received fast shutdown request…database system is shut downpostgres.stop, thenpostgres.startagainpostgres.exec ["postgres",…,"-p",P], then app SIGKILLselect 7; 0 left$(touch …)in port,../…/bin/echo,pg_ctl,sh,./psql; busy portpostgres.query_csv×200The same harness on the published 17.5.0 (darwin-arm64 and linux-arm64): SIGTERM, SIGKILL of the pid, and supervisor death each leave the postmaster plus 5 children (LEAK). darwin's supervisor-death case is also ORPHAN.
Not in this PR
/tmp/pilot-pg/17.5.0symlink remains. The conda-built binaries don't relocate. With no link,initdbfails withfile "/private/tmp/pilot-pg/17.5.0/share/postgres.bki" does not exist(darwin-arm64, reproduced here), so thepgdispatcher keeps creating that shared link in world-writable/tmp. It's never removed. Concurrent installs re-point it, and on a multi-user host a second user's server readsshare/and loads$libdirmodules from whichever tree the link points at. The fix is new, relocatable PostgreSQL 17.5 assets built from upstream source, plus a dispatcher without the link. That needs an R2 upload, so it's tracked separately (see the follow-up comment on this PR).postgres.startagain. The method description says so.ed25519:N1uQkAJ3…) through publish-server, and the catalogue PR.🤖 Generated with Claude Code