feat: automated CI/CD with GitHub native release notes#1
Conversation
The @embedded-postgres binaries are compiled against ICU 60, but modern Linux distros (Ubuntu 22.04+, Debian 12+) ship with ICU 70+. The binaries have RUNPATH=$ORIGIN/../lib, but this fails when package managers (pnpm, yarn PnP) use symlinks/hardlinks that break the relative path resolution. Solution: Explicitly set LD_LIBRARY_PATH (Linux) and DYLD_LIBRARY_PATH (macOS) to include the bundled ICU libraries from @embedded-postgres. This ensures pgserve works across: - npm, pnpm, yarn, and yarn PnP installations - Ubuntu 22.04+, 24.04, Debian 12+ - Any Linux distro with ICU 70+
Bun migration: - Use bun:test for test runner - Update Makefile to use bun install/test - Add GitHub Actions CI with Bun - Add bun.lock for dependency pinning - Update README with Bun installation RAM mode (--ram flag): - Use /dev/shm for true RAM storage on Linux - 2x performance improvement over disk mode - Updated benchmarks to show RAM mode results Fixes: - Add password auth to test clients - Update multi-tenant test assertions
- Add PR label-triggered releases (rc → @next, stable → @latest) - Add cross-platform Bun builds (Linux, macOS, Windows) - Add GitHub native release notes via .github/release.yml - Remove custom changelog generation from release script - Update README with benchmark results - Update Makefile with release-rc, release-stable, release-dry targets - Fix deadcode check (remove unused export, update knip config)
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 18760271 | Triggered | Generic Password | 2c8812a | tests/multi-tenant.test.js | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
Summary of ChangesHello @namastex888, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the project's CI/CD pipeline by introducing automated release management and native GitHub release notes. It also improves developer experience and runtime performance by migrating to Bun for various tasks and introducing a new RAM-based storage option for PostgreSQL on Linux. These changes streamline the release process, provide better insights into changes, and offer substantial speed improvements for users. Highlights
Ignored Files
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a sophisticated CI/CD pipeline using GitHub Actions and Bun, which is a significant improvement. The migration to Bun for builds and scripting, along with the new --ram feature, brings impressive performance gains that are well-documented in the README. The new release process based on PR labels is a great step towards automation. The code is well-structured, and the changes are thoughtfully implemented. I've provided a few suggestions to improve maintainability and robustness. Overall, this is an excellent contribution.
| .PHONY: build build-linux build-macos build-windows build-all clean-dist | ||
|
|
||
| build: ## Build standalone executable for current platform | ||
| @echo "$(CYAN)🔨 Building standalone executable...$(RESET)" | ||
| @mkdir -p $(DIST_DIR) | ||
| @bun build --compile bin/pglite-server.js --outfile $(DIST_DIR)/pgserve | ||
| @echo "$(GREEN)✅ Built: $(DIST_DIR)/pgserve$(RESET)" | ||
|
|
||
| build-linux: ## Build for Linux (x64 + arm64) | ||
| @echo "$(CYAN)🐧 Building for Linux...$(RESET)" | ||
| @mkdir -p $(DIST_DIR) | ||
| @bun build --compile --target=bun-linux-x64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-linux-x64 | ||
| @bun build --compile --target=bun-linux-arm64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-linux-arm64 | ||
| @echo "$(GREEN)✅ Built: $(DIST_DIR)/pgserve-linux-x64$(RESET)" | ||
| @echo "$(GREEN)✅ Built: $(DIST_DIR)/pgserve-linux-arm64$(RESET)" | ||
|
|
||
| build-macos: ## Build for macOS (x64 + arm64) | ||
| @echo "$(CYAN)🍎 Building for macOS...$(RESET)" | ||
| @mkdir -p $(DIST_DIR) | ||
| @bun build --compile --target=bun-darwin-x64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-darwin-x64 | ||
| @bun build --compile --target=bun-darwin-arm64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-darwin-arm64 | ||
| @echo "$(GREEN)✅ Built: $(DIST_DIR)/pgserve-darwin-x64$(RESET)" | ||
| @echo "$(GREEN)✅ Built: $(DIST_DIR)/pgserve-darwin-arm64$(RESET)" | ||
|
|
||
| build-windows: ## Build for Windows (x64) | ||
| @echo "$(CYAN)🪟 Building for Windows...$(RESET)" | ||
| @mkdir -p $(DIST_DIR) | ||
| @bun build --compile --target=bun-windows-x64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-windows-x64.exe | ||
| @echo "$(GREEN)✅ Built: $(DIST_DIR)/pgserve-windows-x64.exe$(RESET)" |
There was a problem hiding this comment.
To avoid repeating mkdir -p $(DIST_DIR) in each build target (build, build-linux, build-macos, build-windows), you can use a prerequisite target. This makes the Makefile cleaner and easier to maintain.
By creating a target for $(DIST_DIR), you can ensure the directory is created once before any build commands that need it are run.
.PHONY: build build-linux build-macos build-windows build-all clean-dist
$(DIST_DIR):
@mkdir -p $(DIST_DIR)
build: $(DIST_DIR) ## Build standalone executable for current platform
@echo "$(CYAN)🔨 Building standalone executable...$(RESET)"
@bun build --compile bin/pglite-server.js --outfile $(DIST_DIR)/pgserve
@echo "$(GREEN)✅ Built: $(DIST_DIR)/pgserve$(RESET)"
build-linux: $(DIST_DIR) ## Build for Linux (x64 + arm64)
@echo "$(CYAN)🐧 Building for Linux...$(RESET)"
@bun build --compile --target=bun-linux-x64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-linux-x64
@bun build --compile --target=bun-linux-arm64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-linux-arm64
@echo "$(GREEN)✅ Built: $(DIST_DIR)/pgserve-linux-x64$(RESET)"
@echo "$(GREEN)✅ Built: $(DIST_DIR)/pgserve-linux-arm64$(RESET)"
build-macos: $(DIST_DIR) ## Build for macOS (x64 + arm64)
@echo "$(CYAN)🍎 Building for macOS...$(RESET)"
@bun build --compile --target=bun-darwin-x64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-darwin-x64
@bun build --compile --target=bun-darwin-arm64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-darwin-arm64
@echo "$(GREEN)✅ Built: $(DIST_DIR)/pgserve-darwin-x64$(RESET)"
@echo "$(GREEN)✅ Built: $(DIST_DIR)/pgserve-darwin-arm64$(RESET)"
build-windows: $(DIST_DIR) ## Build for Windows (x64)
@echo "$(CYAN)🪟 Building for Windows...$(RESET)"
@bun build --compile --target=bun-windows-x64 bin/pglite-server.js --outfile $(DIST_DIR)/pgserve-windows-x64.exe
@echo "$(GREEN)✅ Built: $(DIST_DIR)/pgserve-windows-x64.exe$(RESET)"
| const storageType = options.dataDir | ||
| ? options.dataDir | ||
| : (options.useRam ? '/dev/shm (RAM)' : '(temp directory)'); |
| } | ||
|
|
||
| // Stage and commit | ||
| exec('git add -A'); |
There was a problem hiding this comment.
Using git add -A is a bit broad and could potentially stage unrelated files if any are present in the working directory during the release process. To make the script more robust and explicit, it's better to stage only the file that is expected to change, which is package.json.
exec('git add package.json');
- Makefile: use prerequisite target for dist directory - release.cjs: use explicit git add package.json instead of -A
…2.4 dream-readiness V2.4 cohort framing: - Status row: peer wish (one of three) for v2.4; separate branch + PR + /dream slot. - v2.4 cohort field cross-linking sibling wishes (pgserve-singleton-no-proxy, canonical-pgserve-pm2-supervision). - Date row notes 2026-05-08 refinement adding G19/G20 + cohort framing. - Branch row notes active WIP branch (wish/autopg-cutover-transport-absorb) vs canonical wish branch (wish/autopg-distribution-cutover). Group renumbering for lint compliance: - Decimal numbers (Group 11.5, Group 11.6) rejected by genie wish lint. - Renumbered: 11.5 → 19 (autopg serve), 11.6 → 20 (autopg service install). - Existing G1-G18 commit history preserved (WIP commits #1-#11 remain valid). - Strategy table annotated: "ships between G11 and G12; numbered 19 to preserve audit trail; depends-on graph drives execution order, not group numbers". - depends-on lines on G12 + G13 updated: 11.5 → 19. Cross-wish dependencies block expanded: - Added paired-with section listing v2.4 cohort siblings. - Added blocks entry for pgserve/autopg-service-install-system (parked next-version wish that extends G20's --user mode to --system mode). genie wish lint: clean (no violations). Felipe directives baked in (2026-05-08): 1) Separate /dream slot per cohort wish. 2) Separate branches/wishes/PRs. 3) Tier B systemd-user only in v2.4; --system mode parked. 4) doctor reports passively + service install MUST migrate (already in G20). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…installer
Felipe directive: don't deprecate, replace. Single install.sh.
The earlier shape (3 files: install.sh shim + install-autopg.sh +
install-pgserve-legacy.sh) was the wrong tradeoff. Replacing
in-place is cleaner — operators with bookmarked
`curl … main/install.sh | bash` invocations get the new behavior
directly, no migration step. The npm + pm2 install path is preserved
via the existing `pgserve install` CLI verb (operators who want it
do `npm install -g pgserve && pgserve install`).
Changes:
- install-autopg.sh: deleted (its body became install.sh).
- install-pgserve-legacy.sh: deleted (no legacy file kept).
- install.sh: replaced with the GitHub Releases + gh-attestation
body. 74 lines (≤80 spec ✓), shellcheck clean,
`bash install.sh --dry-run` resolves the latest version via the
GitHub releases API and prints the fetch URL + verify command
without executing.
- README.md: install section references install.sh (no autopg
name, no legacy note).
Wish-side note: this overrides Decision #1 in the merged
autopg-distribution-cutover-finalize wish, which prescribed the
3-file split. Decision needs an update — separate follow-up commit
to the wish file.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…tation
D5 of pgserve create-app + manifest LOCK 1
(autopg-distribution-cutover-finalize wish G3).
Round-trip integration smoke that exercises the lock-vs-live trust
differential — the WHOLE point of the manifest LOCK 1 design.
Pipeline:
1) Start ephemeral postgres on a high port (mirrors
gc-provision.test.sh setup).
2) `pgserve create-app demo --port $PORT` — registers slug; freezes
live TRUSTED_IDENTITIES into autopg_meta.locked_roots.
3) Direct UPDATE replaces the freshly frozen list with a SYNTHETIC
single-entry locked_roots ({"id":"frozen-test", regex
"^FROZEN-LOCK$"}). This is the test's stand-in for "operator
rotated live; the slug's lock is now divergent". When verify
--slug demo loads locked_roots, it gets THIS list.
4) Stub cosign on PATH succeeds ONLY when --certificate-identity-regexp
is exactly `^FROZEN-LOCK$` AND the binary's first bytes are
`FROZEN-LOCK`. Anything else: exit non-zero.
5) Three verify scenarios:
a) FROZEN-LOCK binary + --slug demo → exit 0 (lock matched)
b) LIVE-IDENTITY binary + --slug demo → exit ≥2 (lock rejected)
c) any binary + --slug nonexistent_slug → exit 3 (loader rejected
BEFORE cosign — invocation error)
6) Idempotent re-run preserves locked_roots — the synthetic
'frozen-test' id stays after a second create-app demo invocation,
proving BRIEF v5 A6 lock preservation is live.
Together those steps cover acceptance criteria #1, #3, #4, #5 from
WISH L142-L147 (idempotent re-run, verify rejection, verify success
against frozen lock, upgrade-after-trust-rotation).
Skips gracefully on hosts without initdb/pg_ctl/psql on PATH (mirrors
gc-provision.test.sh's contract). Wired into .github/workflows/ci.yml
as a new continue-on-error job — non-blocking until the GHA postgres
cache warms, identical to gc-provision job's policy.
Local skip path verified on this dev host (no initdb installed):
$ bash tests/integration/verify-slug-rotation.test.sh
• initdb not on PATH — skipping (suite needs a postgres install)
…d + tag-creation gap + stale comment Addresses 4 of 5 bot review comments. All three HIGH-severity findings would have broken the workflow at runtime; the MEDIUM defensive nit (semver validation on workflow_run.head_branch) is deferred to PR-A3 since the current build-tarballs.yml tag-only producer trigger makes branch refs impossible on the workflow_run path today. codex P1 #1 — Add `actions: read` to permissions block - release-publish.yml: cross-workflow `actions/download-artifact@v4` with `run-id` + `github-token` requires `actions: read`. When ANY permissions are listed explicitly, unlisted scopes are denied. The pre-fix block had contents/id-token/attestations but not actions, so the download would have failed at runtime before the release upload step. Bot caught this cleanly; trivial fix with explanatory comment. coderabbit major — Manual dispatch path can't download signed bundle - release-publish.yml: workflow_dispatch fallback `run-id: github.run_id` resolves to the CURRENT release-publish run, not the upstream sign-attest run where the bundle actually exists. Bot's analysis is correct. - Fix per bot's suggested diff: add required `sign_run_id` input to workflow_dispatch, and switch `run-id:` expression to `${{ github.event_name == 'workflow_run' && github.event.workflow_run.id || inputs.sign_run_id }}`. Manual operators get a clear required-input with discovery instructions in the description. codex P1 #2 — Push-to-main releases lose tag-creation path - release.yml: the dropped `release` job's `gh release create` was the ONLY tag-creation path on the push event (workflow_dispatch path is fine — bump job creates and pushes the tag). Push-to-main runs of release.yml will now npm-publish but produce no tag → no build-tarballs → no sign-attest → no GitHub Release. - Operational reality: all recent v2.x releases (v2.6.0, v2.6.1, etc.) were cut via workflow_dispatch per Felipe's release practice. The push-to-main release path was de-facto deprecated already. - Fix: document the known limitation prominently in the build job comments + the release-job-removed comment. Operators routing through workflow_dispatch are unaffected; push-path operators get a clear upgrade-path pointer (use workflow_dispatch). - A future PR-A3 D7 can re-add tag creation in the prepare/bump job if push-path releases need to be reinstated. coderabbit minor — release.yml:261 stale comment about release-publish trigger - Comment still referenced `on: push: tags: ['v*']` which is what release-publish.yml USED to have (pre-PR-A2). After this PR-A2 it triggers on `workflow_run` from sign-attest. Same-PR text drift; updated to describe the new chain accurately. NOT fixed (deferred): coderabbit minor — Validate workflow_run.head_branch as semver before use - Defensive only. build-tarballs.yml currently has `push: tags: ['v*', 'autopg-v*']` so the workflow_run chain ONLY fires from tag pushes; head_branch is always a tag name in practice. Worth adding as a defense-in-depth guard for future producer changes (e.g. if build-tarballs ever grows a branch-push trigger), but doesn't cause incorrect behavior today. Defer to PR-A3. Tests: 100 cosign tests pass, zero regressions. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…serve → automagik-dev/autopg) (#129) Repo transferred namastexlabs/pgserve → automagik-dev/autopg + renamed. Makes the codebase consistent with the new identity and repairs the fresh-host bootstrap, broken independent of the transfer. Org rewrite (10 code files + ~14 docs): - src/cosign/trust-list.js single-flip to automagik-dev/autopg (v3 binary verifies v3+ releases; per POST-TRANSFER-RUNBOOK) - scripts/, .github/workflows/release-publish.yml, package.json, src/security, src/update, tests/cosign fixtures - bin/autopg-wrapper.cjs — MISSED by runbook's 9-file inventory; caught by the zero-stray-ref gate (10th non-doc file) install.sh — full rewrite (sed-insufficient; 5 bugs, only #1 in runbook): 1. REPO → automagik-dev/autopg 2. tarball name pgserve-*-linux-x64 → autopg-*-linux-x64-{glibc,musl} with libc detection (matched real release assets) 3. latest-resolution: unauth curl|sed empty → gh api primary, curl fb 4. extracted layout autopg/autopg (not bin/pgserve) + ~/.local/bin symlink 5. gh attestation hard-dep (gh<2.49) → cosign verify-blob fallback with DUAL-org identity regexp (asymmetric-cohort: bootstrap consumer accepts both orgs; latest v2.6.10 signed pre-transfer). Proven: cosign verify-blob "Verified OK" vs real old-org-signed v2.6.10. Verification: lint clean; 692 pass / 3 skip / 0 fail; trust-list 11/11. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
rc→@next,stable→@latest).github/release.ymlrelease-rc,release-stable,release-drytargetsGitHub Configuration Required
Before testing, configure in repo settings:
npm-publishNPM_TOKEN(npm access token)rc,stableTest Plan
rclabel to this PR and merge@nexttag