Back to socat forwarding, proper upstream tracking#6
Merged
Conversation
- Replaces loose state files with `var/pgdev.db` (SQLite) for atomic, transactional machine tracking. - Implements `internal/socatproxy` using `launchd` and `socat` to serve canonical client ports (5442/5443). - Moves the Go forwarder to ports 5444/5445 to run alongside the socat proxy during the integration phase. - Adds `pgdev proxy` commands for managing the new infrastructure. - Hardens socat reloads with port-free gates and argv verification to prevent stale-mapping bugs.
Remove the `internal/forward` package, its binary, and the Go-based host endpoint logic. All client proxying is now handled by the `socat` LaunchAgents managed via `internal/socatproxy`. - Remove `pgdev forward` commands and related Go code. - Delete `doc/issues/0003-internal-forward.md`. - Update `Makefile` and `README.md` to reflect the removal. - Remove host code-signing logic from `pgdev/Makefile` now that the forwarder binary is gone. - Clean up documentation in `doc/issues/0004-sqlite-socat-proxy.md`.
There was a problem hiding this comment.
Pull request overview
This PR switches the macOS host client endpoint back to a socat-based LaunchAgent proxy and introduces a SQLite-backed tracking store (var/pgdev.db) as the single source of truth for active/staging and machine IPs, removing the in-process Go forwarder and its codesigning workflow.
Changes:
- Replace the Go forwarder (
internal/forward,pgdev forward *) with asocatclient proxy (internal/socatproxy,pgdev proxy *) plus flock-guarded reconcile. - Add
internal/trackSQLite store with schema reset + “carry active slot” behavior, mirroring to legacy flat files for remaining readers. - Update Make targets/docs/env vars to reflect the proxy/DB model (
proxy.*,PG_CLIENT_BIND,PG_PROXY_DEBUG) and remove forwarder-specific bits.
Reviewed changes
Copilot reviewed 27 out of 31 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Documentation updated for socat proxy + reconcile + Local Network grant guidance. |
| pgdev/Makefile | Removes host codesigning step tied to the retired Go forwarder. |
| pgdev/internal/track/track.go | Adds SQLite tracking DB open/migrate/reset logic and schema. |
| pgdev/internal/track/state.go | Adds DB-backed getters/setters for active slot, machine IPs, proxy targets, and mirror-file writes. |
| pgdev/internal/track/track_test.go | Adds unit tests for tracking DB behavior, mirroring, and reset carry-over. |
| pgdev/internal/socatproxy/reconcile.go | Adds flock-guarded reconcile loop and per-role convergence reporting. |
| pgdev/internal/socatproxy/launchd.go | Adds LaunchAgent management, port-free gating, and post-reload verification for socat. |
| pgdev/internal/socatproxy/socatproxy_test.go | Adds unit tests for plist/args parsing, lock behavior, and helper logic. |
| pgdev/internal/forward/state.go | Removes forwarder state/heartbeat implementation. |
| pgdev/internal/forward/router.go | Removes forwarder routing computation. |
| pgdev/internal/forward/router_test.go | Removes routing unit tests for forwarder. |
| pgdev/internal/forward/launchd.go | Removes forwarder LaunchAgent management. |
| pgdev/internal/forward/launchd_test.go | Removes forwarder launchctl parsing/XML escaping tests. |
| pgdev/internal/forward/forward.go | Removes in-process forwarder TCP relay server. |
| pgdev/internal/forward/forward_test.go | Removes forwarder integration-ish tests. |
| pgdev/internal/config/config.go | Replaces forwarder config with socat proxy + tracking DB configuration. |
| pgdev/go.mod | Adds modernc SQLite dependency for tracking DB. |
| pgdev/go.sum | Adds checksums for SQLite dependency chain. |
| pgdev/cmd/pgdev/proxy.go | Adds pgdev proxy command set and integrates reconcile + DB recording. |
| pgdev/cmd/pgdev/main.go | Wires socat proxy command and tracking DB/logger into app lifecycle; removes forwarder wiring. |
| pgdev/cmd/pgdev/forward.go | Removes pgdev forward commands. |
| pgdev/cmd/pgdev/deploy.go | Updates IP caching to write through tracking DB (mirrored to legacy files). |
| pgdev/cmd/pgdev/commands.go | Updates up/status/promote/refresh flows to use proxy reconcile and adds staging purge UX/state handling. |
| pgdev/cmd/pgdev/commands_test.go | Adds tests for new status state labeling and rebuild hints. |
| Makefile | Replaces endpoint.* targets with proxy.* targets and updates status behavior for ABSENT machines. |
| doc/issues/0004-sqlite-socat-proxy.md | Adds spec documenting the SQLite+reconcile design and forwarder removal. |
| doc/issues/0003-internal-forward.md | Removes old spec for the now-deleted Go forwarder. |
| .gitignore | Keeps ignoring etc/keys/* (leftover from removed codesign flow) with explanatory comment. |
| .env.example | Updates env documentation for proxy bind and proxy debug; removes forward bind. |
| etc/keys/.gitkeep | Keeps etc/keys/ directory present while preventing key material commits. |
Comments suppressed due to low confidence (2)
pgdev/internal/socatproxy/launchd.go:135
- Typo in helper name: boototAndWait should be bootoutAndWait (matches launchctl subcommand and improves readability/searchability).
if err := j.boototAndWait(ctx); err != nil {
pgdev/internal/socatproxy/launchd.go:155
- Function name/comment typo: boototAndWait should be bootoutAndWait (the code uses launchctl bootout). Renaming makes it easier to grep and avoids confusion.
// boototAndWait boots the job out and polls until launchd reports it gone, so a
// subsequent bootstrap can't race a still-loaded label and so the forked socat
// children have actually exited before we probe the port. A job that will NOT
// unload is a HARD error, not a warning: the job has KeepAlive, so killing its
// port holder in the gate would just have launchd resurrect it — reporting
// success there would silently pin the old mapping. Better to fail the reconcile
// loudly and let the operator see it.
func (j *job) boototAndWait(ctx context.Context) error {
_ = j.launchctl(ctx, 10*time.Second, "bootout", j.domainTarget()) // tolerate "not loaded"
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Introduce `PG_LOG_COLOR` and `PG_LOG_FORMAT` environment variables to control output appearance. Integrate `lmittmann/tint` for colored terminal logs and add JSON output support for machine-readable logs. Convert existing `Printf` progress messages to use the structured logger.
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.
Go back to the socat based forwarder, since the homegrown Go forwarder and macOS network security, code signing, after each rebuild - sucks. We have proper tracking and reconciliation of the socat forwarder, which should be fine now.
Add the ability to
purgeone instance, to reclaim space (this existed before withrebuild) and don't start the instance; if one wants to safe some resources.Expand logging, have colored logs