pgserve 2.6.0 → 2.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +181 -0
- package/README.md +20 -0
- package/bin/pgserve-wrapper.cjs +56 -2
- package/console/dist/app.js +7 -7
- package/package.json +1 -1
- package/scripts/aggregate-manifest.sh +42 -26
- package/scripts/verify-published-artifacts.sh +85 -32
- package/src/admin/admin-bootstrap.js +296 -0
- package/src/cli-config.cjs +37 -0
- package/src/cli-install.cjs +175 -0
- package/src/commands/create-app.js +387 -0
- package/src/commands/doctor.js +65 -0
- package/src/commands/gc.js +16 -1
- package/src/commands/verify.js +94 -4
- package/src/cosign/locked-roots.js +141 -0
- package/src/cosign/trust-list.js +29 -6
- package/src/cosign/verify-binary.js +162 -12
- package/src/gc/audit-log.js +92 -0
- package/src/postgres.js +16 -1
- package/src/schema/autopg-meta.js +120 -0
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,187 @@ All notable changes to `pgserve` are documented here. The format follows
|
|
|
14
14
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres
|
|
15
15
|
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
16
16
|
|
|
17
|
+
## [2.6.4] - 2026-05-12
|
|
18
|
+
|
|
19
|
+
**Final v2.x maintenance release** — the last `pgserve`-named npm publish.
|
|
20
|
+
Cut from the `release/v2.6.x` maintenance branch (off `1489d7d`, pre-V3
|
|
21
|
+
cutover) so consumers like `@withone/cli` (and any other `pgserve: ^2.x`
|
|
22
|
+
dependent) continue to receive backward-compatible updates without the
|
|
23
|
+
V3 rename, V3-1 verb cutover, or npm-publish drop. **Future development
|
|
24
|
+
moves to the `autopg` package starting at v3.0.0** (see
|
|
25
|
+
`distribution-exodus` wish in main).
|
|
26
|
+
|
|
27
|
+
### Added (since 2.6.1)
|
|
28
|
+
|
|
29
|
+
- **Signed-app delivery pipeline** — `pgserve create-app <slug>` writes a
|
|
30
|
+
per-consumer manifest with cosign locked trust roots; `pgserve verify
|
|
31
|
+
--slug <slug>` differentiates lock-vs-live identities and exit-codes
|
|
32
|
+
per outcome.
|
|
33
|
+
- **Cosign keyless OIDC signing** for release tarballs — Sigstore bundles
|
|
34
|
+
+ SLSA L3 provenance + GitHub Attestations API attestation per
|
|
35
|
+
platform tarball. Verifiable via `cosign verify-blob`, `slsa-verifier
|
|
36
|
+
verify-artifact`, or `gh attestation verify`.
|
|
37
|
+
- **Trust-list hardcoded roots** — `automagik-genie-release`,
|
|
38
|
+
`automagik-omni-release`, and `automagik-pgserve-release` entries in
|
|
39
|
+
`src/cosign/trust-list.js`. All three anchor on `sign-attest.yml@`
|
|
40
|
+
(the canonical Fulcio SAN URI shape across Namastex automagik
|
|
41
|
+
signed apps).
|
|
42
|
+
- **`pgserve gc`** — orphan-DB sweep + per-day rotating audit log under
|
|
43
|
+
`~/.pgserve/audit/` (90-day retention, current-day boundary guard).
|
|
44
|
+
- **Console + docs** — operator-facing migration guide
|
|
45
|
+
(`docs/migrations/v2.6-from-v2.5.md`), cosign trust reference
|
|
46
|
+
(`docs/security/cosign-trust.md`), schema docs (`pgserve_meta`,
|
|
47
|
+
trust-store, signed-app delivery).
|
|
48
|
+
- **Integration test scaffolds** — `tests/integration/gc-provision.test.sh`,
|
|
49
|
+
`tests/integration/verify-slug-rotation.test.sh`,
|
|
50
|
+
`tests/integration/wave-a-e2e.test.sh`,
|
|
51
|
+
`tests/integration/v2.6-cohort-smoke.sh`.
|
|
52
|
+
- **Postinstall guardrail** — soft-fails on git-worktree dev installs
|
|
53
|
+
with a stderr warning, preventing accidental `~/.pgserve` mutation
|
|
54
|
+
during package development.
|
|
55
|
+
|
|
56
|
+
### Fixed (since 2.6.1)
|
|
57
|
+
|
|
58
|
+
- **CV-1**: `pgserve provision` / `pgserve gc` no longer auth-fail on
|
|
59
|
+
fresh installs (hot-fix from PR #101).
|
|
60
|
+
- **B5/B6/B7 trio** — audit-log rotation boundary, dual-mode keyless
|
|
61
|
+
verify, JSON-escape OIDC issuer in aggregate manifest.
|
|
62
|
+
- **CV-VERIFY-BUNDLE-NAMING** — consumer-side bundle resolve falls
|
|
63
|
+
through `.bundle` → `.sig` + `.cert` detached pair when the bundle
|
|
64
|
+
filename doesn't match, so older signing artifacts continue to verify.
|
|
65
|
+
- **Wave B bundle-format** — `pgserve verify` accepts both sigstore
|
|
66
|
+
bundle (`.bundle`) and detached cosign (`<tarball>.sig` +
|
|
67
|
+
`<tarball>.cert`) artifact shapes.
|
|
68
|
+
|
|
69
|
+
### Preserved (intentional — for backward compatibility)
|
|
70
|
+
|
|
71
|
+
- **`pgserve` CLI bin** — both `pgserve` and `autopg` bins remain
|
|
72
|
+
declared in package.json. `pgserve <verb>` works the same as it did
|
|
73
|
+
in v2.6.1.
|
|
74
|
+
- **`pgserve upgrade` verb** — V3-1's clean cutover to `pgserve update`
|
|
75
|
+
was reverted on this maintenance branch (V3-1 is a v3.0.0 breaking
|
|
76
|
+
change, not safe for a patch release). Operators continue to use
|
|
77
|
+
`pgserve upgrade` on v2.x.
|
|
78
|
+
- **npm publish workflow** — V3-2 dropped npm publishing from main's
|
|
79
|
+
release path; reverted on this maintenance branch so v2.6.4 publishes
|
|
80
|
+
to npm normally via the existing OIDC trusted publisher entry.
|
|
81
|
+
- **Default port 8432** — unchanged from v2.6.1.
|
|
82
|
+
|
|
83
|
+
### Removed
|
|
84
|
+
|
|
85
|
+
(none — additive release)
|
|
86
|
+
|
|
87
|
+
### Notes for `@withone/cli` + other npm dependents
|
|
88
|
+
|
|
89
|
+
- `pgserve: ^2.2.3` satisfies — semver range resolves to 2.6.4.
|
|
90
|
+
- No code changes required on the consumer side.
|
|
91
|
+
- The next major (`autopg@v3.0.0`) ships from the new
|
|
92
|
+
`automagik-dev/autopg` repo + drops npm; if/when you migrate, switch
|
|
93
|
+
to `install.sh` + GitHub Releases per the autopg distribution model.
|
|
94
|
+
|
|
95
|
+
## [2.6.0] / [2.6.1] - 2026-05-09
|
|
96
|
+
|
|
97
|
+
The 2.6 cohort closes the singleton-G3 sprint and the
|
|
98
|
+
`autopg-distribution-cutover-finalize` Wave 1+2 work. v2.6.0 cut the singleton
|
|
99
|
+
verbs to npm; v2.6.1 followed with the B2/B3/B4 CLI fix trio.
|
|
100
|
+
|
|
101
|
+
### Added
|
|
102
|
+
|
|
103
|
+
- **`pgserve doctor`** — read-only health probe for postmaster, pm2 supervision,
|
|
104
|
+
on-disk roots, and trust store. JSON output via `--json`. See
|
|
105
|
+
[`docs/migrations/v2.6-from-v2.5.md`](docs/migrations/v2.6-from-v2.5.md).
|
|
106
|
+
- **`pgserve trust add | list | remove`** — manage the user-extensible cosign
|
|
107
|
+
trust store at `~/.pgserve/trust/identities.json`. Layered on top of the
|
|
108
|
+
hardcoded `TRUSTED_IDENTITIES` (frozen at build time). See
|
|
109
|
+
[`docs/trust-store.md`](docs/trust-store.md).
|
|
110
|
+
- **`pgserve gc [--dry-run | --apply]`** — sweep orphan databases (rows in
|
|
111
|
+
`pgserve_meta` whose `source_path` no longer exists). One-line-per-event audit
|
|
112
|
+
log at `~/.pgserve/audit/gc-<YYYY-MM-DD>.log`. Rotates files >90 days old at
|
|
113
|
+
start of each run. See [`docs/pgserve-meta.md`](docs/pgserve-meta.md) for the
|
|
114
|
+
underlying schema.
|
|
115
|
+
- **`pgserve provision <fingerprint>`** — idempotent DB + role provisioning for
|
|
116
|
+
an app fingerprint. Concurrency-safe via `pg_advisory_lock` keyed on
|
|
117
|
+
fingerprint hash; `42P04` ("database already exists") accepted as success.
|
|
118
|
+
- **`pgserve create-app <slug>`** — per-consumer app registration with manifest
|
|
119
|
+
LOCK 1 cosign verifier. Writes `~/.autopg/<slug>/admin.json` + sibling
|
|
120
|
+
`manifest.json`, registers in `autopg_meta`, freezes `TRUSTED_IDENTITIES` for
|
|
121
|
+
this consumer at create time. `pgserve verify --slug <slug>` consults the
|
|
122
|
+
frozen snapshot.
|
|
123
|
+
- **`pgserve verify --slug <slug>`** — verify a binary against an app's locked
|
|
124
|
+
roots (instead of the live `TRUSTED_IDENTITIES`). Allows trust rotation
|
|
125
|
+
without invalidating already-registered consumers.
|
|
126
|
+
- **`pgserve_meta` schema** — base table for `provision`/`gc`. Cosign verification
|
|
127
|
+
columns (`verified_at`, `verified_identity`, `verified_tier`) layered on top
|
|
128
|
+
via additive ALTER TABLE migration. Schema reference at
|
|
129
|
+
[`docs/pgserve-meta.md`](docs/pgserve-meta.md).
|
|
130
|
+
- **`autopg_meta` schema** — separate table keyed on `slug` for `create-app`
|
|
131
|
+
registrations. Frozen `locked_roots` JSONB. Idempotent re-runs preserve
|
|
132
|
+
`locked_roots` and only touch `last_updated`.
|
|
133
|
+
- **GitHub Releases as the canonical distribution channel** — `install.sh`
|
|
134
|
+
fetches per-platform binaries from
|
|
135
|
+
`github.com/namastexlabs/pgserve/releases/download/v<version>/`. Cosign
|
|
136
|
+
attestations live in Sigstore Rekor; verification via `gh attestation verify`
|
|
137
|
+
(no custom verifier server). See
|
|
138
|
+
[`.github/workflows/release-publish.yml`](.github/workflows/release-publish.yml).
|
|
139
|
+
- **Hardcoded blocklist** — `pgserve install` refuses to start against known-bad
|
|
140
|
+
versions with exit code `EBLOCKEDVERSION`.
|
|
141
|
+
|
|
142
|
+
### Changed
|
|
143
|
+
|
|
144
|
+
- **`pgserve install`** now runs port pre-flight (IPv4 + IPv6 connect probe on
|
|
145
|
+
5432) and refuses to start on collision. Closes the silent-failure mode
|
|
146
|
+
where pm2 reported `online` while postgres had crashed.
|
|
147
|
+
- **`pgserve install --help`** respects `--help` / `-h` and exits 0 without
|
|
148
|
+
performing the install.
|
|
149
|
+
- **Unknown verbs** (`pgserve foo`) exit non-zero with an "unknown verb" error
|
|
150
|
+
instead of printing top-level help and exiting 0.
|
|
151
|
+
- **`pgserve doctor`** surfaces a missing `pgaudit` extension as a non-PASS
|
|
152
|
+
finding (was silently fall-through).
|
|
153
|
+
- **`pgserve config --help`** exits 0 with a usage block instead of running the
|
|
154
|
+
config logic against `--help` as if it were a key.
|
|
155
|
+
- **`install.sh`** replaced in-place with the ≤80-line GitHub Releases path.
|
|
156
|
+
No legacy or shim companions; the npm + pm2 install path is preserved via
|
|
157
|
+
`pgserve install` (`npm install -g pgserve && pgserve install`).
|
|
158
|
+
|
|
159
|
+
### Fixed
|
|
160
|
+
|
|
161
|
+
- **`fix(pg-query)`** — default `PGPASSWORD` to `'postgres'` on fresh install
|
|
162
|
+
(CV-1 release blocker).
|
|
163
|
+
- **`fix(cosign)`** — correct trust-list github org refs (omni →
|
|
164
|
+
`automagik-dev`, pgserve → `namastexlabs`).
|
|
165
|
+
- **`fix(cosign)`** — correct `publisher` field for pgserve + reconcile
|
|
166
|
+
`SHARED-DESIGN.md` org refs.
|
|
167
|
+
- **`fix(postinstall)`** — worktree guard + non-CI pre-warning + dev-setup
|
|
168
|
+
docs. Closes the bug where every `bun install` in a pgserve worktree
|
|
169
|
+
triggered `autopg upgrade` against the real `~/.autopg/data/`.
|
|
170
|
+
- **`fix(verify-binary)`** — `resolveBundlePath` fall-through to
|
|
171
|
+
`provenance.intoto.jsonl` and sibling provenance.
|
|
172
|
+
- **`fix(verify-binary)`** — support detached `<tarball>.sig` +
|
|
173
|
+
`<tarball>.cert` cosign format alongside `<tarball>.bundle`.
|
|
174
|
+
- **`fix(cli-install)`** — use `process.exitCode + throw` to avoid stdio-pipe
|
|
175
|
+
race on `process.exit(1)` against piped stdout.
|
|
176
|
+
- **`fix(doctor)`** — timeout supervisor probes + `pgserve upgrade` hint when
|
|
177
|
+
pm2 is missing.
|
|
178
|
+
- **`fix(install)`** — drop npm references in `install.sh`; canonical path is
|
|
179
|
+
the GitHub Releases curl-pipe.
|
|
180
|
+
|
|
181
|
+
### Notes
|
|
182
|
+
|
|
183
|
+
- The 2.6 cohort lands as **additive** changes — existing `pgserve` invocations
|
|
184
|
+
continue to work unchanged. See
|
|
185
|
+
[`docs/migrations/v2.6-from-v2.5.md`](docs/migrations/v2.6-from-v2.5.md) for
|
|
186
|
+
the operator action checklist.
|
|
187
|
+
- **Signing artifacts on GitHub Releases are NOT yet shipping** as of v2.6.1.
|
|
188
|
+
The release workflow's `sign-attest.yml` produces cosign signatures + SLSA
|
|
189
|
+
L3 provenance, but the `release-publish.yml` upload step does not yet wire
|
|
190
|
+
those artifacts into the published release. Tracked as Wave A in
|
|
191
|
+
`agents/genie-pgserve/SIGNED-APPS-MISSION-STATE.md`. Will land in a follow-up
|
|
192
|
+
patch release.
|
|
193
|
+
- **Connectivity fanout test** — `tests/integration/consumer-fanout.sh`
|
|
194
|
+
(verifying brain / omni / rlmx / hapvida-eugenia / email all reach the
|
|
195
|
+
postmaster) is owned by `pgserve-singleton-no-proxy` Group 9 and ships in a
|
|
196
|
+
separate cohort.
|
|
197
|
+
|
|
17
198
|
## [2.2.3] - 2026-05-03
|
|
18
199
|
|
|
19
200
|
### Changed
|
package/README.md
CHANGED
|
@@ -141,6 +141,26 @@ autopg restart # pm2-aware: pm2 restart pgserve, else SI
|
|
|
141
141
|
autopg ui [--port N] [--no-open] # local web console on 127.0.0.1
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
+
### v2.6 cohort verbs
|
|
145
|
+
|
|
146
|
+
The 2.6 release adds five operator-facing verbs for health probing, trust-store
|
|
147
|
+
management, orphan-database GC, fingerprint provisioning, and per-consumer app
|
|
148
|
+
registration:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
pgserve doctor [--json] # read-only health probe
|
|
152
|
+
pgserve trust <list|add|remove> [...] # manage ~/.pgserve/trust/identities.json
|
|
153
|
+
pgserve gc [--dry-run|--apply] # sweep orphan databases (audit log)
|
|
154
|
+
pgserve provision <fingerprint> # idempotent DB + role provisioning
|
|
155
|
+
pgserve create-app <slug> # per-consumer manifest LOCK 1
|
|
156
|
+
pgserve verify [--slug <slug>] <bin> # cosign verify against trust list or locked roots
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Full reference:
|
|
160
|
+
[`docs/migrations/v2.6-from-v2.5.md`](docs/migrations/v2.6-from-v2.5.md) ·
|
|
161
|
+
[`docs/pgserve-meta.md`](docs/pgserve-meta.md) ·
|
|
162
|
+
[`docs/trust-store.md`](docs/trust-store.md).
|
|
163
|
+
|
|
144
164
|
Foreground options accepted by `autopg` / `pgserve` (no subcommand):
|
|
145
165
|
|
|
146
166
|
```
|
package/bin/pgserve-wrapper.cjs
CHANGED
|
@@ -66,6 +66,15 @@ const __installSubcommands = new Set([
|
|
|
66
66
|
// src/commands/provision.js header for why). Pure node + child_process,
|
|
67
67
|
// must skip bun probe.
|
|
68
68
|
'provision',
|
|
69
|
+
// autopg-distribution-cutover-finalize (v2.6) — wish Group 3.
|
|
70
|
+
// `create-app` registers a consumer slug in autopg_meta + writes the
|
|
71
|
+
// per-consumer admin.json + manifest.json under ~/.autopg/<slug>/,
|
|
72
|
+
// freezing TRUSTED_IDENTITIES into locked_roots at create time. Pure
|
|
73
|
+
// node + psql shellout — must skip bun probe like the rest of the G3
|
|
74
|
+
// verbs. Adding here makes BOTH `pgserve create-app` and
|
|
75
|
+
// `autopg create-app` work via the same dispatcher (autopg-wrapper.cjs
|
|
76
|
+
// delegates to pgserve-wrapper.cjs per Decision #7).
|
|
77
|
+
'create-app',
|
|
69
78
|
]);
|
|
70
79
|
if (__subcommand && __installSubcommands.has(__subcommand)) {
|
|
71
80
|
const cli = require(path.join(__dirname, '..', 'src', 'cli-install.cjs'));
|
|
@@ -79,8 +88,24 @@ if (__subcommand && __installSubcommands.has(__subcommand)) {
|
|
|
79
88
|
result.then(
|
|
80
89
|
(code) => process.exit(typeof code === 'number' ? code : 0),
|
|
81
90
|
(err) => {
|
|
82
|
-
|
|
83
|
-
process.
|
|
91
|
+
// CV103-2 (v2.6.2): the cli-install.cjs EADDRINUSE catch handler
|
|
92
|
+
// already wrote the message to stderr AND set process.exitCode = 1
|
|
93
|
+
// before throwing. If we ALSO write here we'd double-print, AND
|
|
94
|
+
// if we call process.exit(1) we re-introduce the stdio-pipe race
|
|
95
|
+
// the catch handler avoided by switching to exitCode + throw.
|
|
96
|
+
//
|
|
97
|
+
// Suppress the duplicate stderr write for already-handled error
|
|
98
|
+
// codes. Don't call process.exit() — Node will exit naturally
|
|
99
|
+
// once the event loop drains, using process.exitCode (which the
|
|
100
|
+
// throwing handler already set) so stderr flushes cleanly even
|
|
101
|
+
// under the piped-stdout / inherited-stderr shape that exposed
|
|
102
|
+
// the race (qa repro R6: `pgserve install | cat`).
|
|
103
|
+
if (err && err.code !== 'EADDRINUSE') {
|
|
104
|
+
process.stderr.write(`pgserve: ${err?.message ?? err}\n`);
|
|
105
|
+
}
|
|
106
|
+
if (process.exitCode === undefined || process.exitCode === 0) {
|
|
107
|
+
process.exitCode = 1;
|
|
108
|
+
}
|
|
84
109
|
},
|
|
85
110
|
);
|
|
86
111
|
return;
|
|
@@ -95,6 +120,35 @@ if (__subcommand === 'serve') {
|
|
|
95
120
|
process.argv[2] = 'postmaster';
|
|
96
121
|
}
|
|
97
122
|
|
|
123
|
+
// B4 (v2.6.1): unknown-verb guard. Prior behavior fell through to the
|
|
124
|
+
// bun probe + postgres-server.js which prints help and exits 0 on any
|
|
125
|
+
// argv shape it didn't understand — that masked typos as silent
|
|
126
|
+
// successes (`pgserve doctorr` → exits 0 with help banner; the operator
|
|
127
|
+
// thinks doctor ran). Now we emit a clear `unknown verb` error and
|
|
128
|
+
// exit EX_USAGE (64 per sysexits.h).
|
|
129
|
+
//
|
|
130
|
+
// Allowed shapes that MUST still flow through:
|
|
131
|
+
// - empty argv (no subcommand) → top-level help via postgres-server.js
|
|
132
|
+
// - flags starting with `-` (e.g. `--help`, `--version`) → top-level
|
|
133
|
+
// handlers in postgres-server.js
|
|
134
|
+
// - `postmaster` (canonical long-running entry) + `serve` (alias,
|
|
135
|
+
// already rewritten above)
|
|
136
|
+
// - allowlisted install-subcommands (already dispatched above; if
|
|
137
|
+
// control reaches here with one in __subcommand it means the
|
|
138
|
+
// dispatch path returned without exiting — keep the fallthrough).
|
|
139
|
+
if (
|
|
140
|
+
__subcommand &&
|
|
141
|
+
!__subcommand.startsWith('-') &&
|
|
142
|
+
__subcommand !== 'postmaster' &&
|
|
143
|
+
__subcommand !== 'serve' &&
|
|
144
|
+
!__installSubcommands.has(__subcommand)
|
|
145
|
+
) {
|
|
146
|
+
process.stderr.write(
|
|
147
|
+
`pgserve: unknown verb "${__subcommand}". Run \`pgserve --help\` for the supported verb list.\n`,
|
|
148
|
+
);
|
|
149
|
+
process.exit(64); // EX_USAGE per sysexits.h
|
|
150
|
+
}
|
|
151
|
+
|
|
98
152
|
// Detect platform
|
|
99
153
|
const isWindows = process.platform === 'win32';
|
|
100
154
|
const bunBin = isWindows ? 'bun.exe' : 'bun';
|