109 Commits

Author SHA1 Message Date
862eeebd6d
feat(monorel): auto-discover module root; submodule-aware .git detection
Major refactor: monorel no longer requires being run from the module root.
It now accepts paths to binary packages from any ancestor directory and
walks up from each path to find go.mod (groupByModule / findModuleRoot).

Binaries sharing a module root are grouped together. When the script must
cd into a module directory (multi-module run or different CWD) the per-module
output is wrapped in a bash subshell to prevent directory leakage.

The .git stop-marker now only triggers on a .git DIRECTORY, not a .git FILE.
A .git file means the path is inside a submodule whose real repository root
is further up the tree, so the search continues upward.
2026-03-01 19:13:49 -07:00
5716f0f757
fix(monorel): guard against nested go.mod in binary paths
Any directory on the path from the module root to a binary that
contains its own go.mod is a separate module; monorel should not try
to manage it.  Two cases are now caught with distinct errors:

  ../other              → "outside the module directory"
  ./cmd/go.mod          → "has its own go.mod" (intermediate dir)
  ./cmd/foo/go.mod      → "has its own go.mod" (binary dir itself)

Both suggest the correct fix: cd into that directory and run monorel
from there.
2026-03-01 19:13:49 -07:00
12c025e5e2
feat(monorel): require binary-path args; support multi-binary modules
The tool now requires at least one positional argument — the path(s) to
the Go main package(s) to build — and must be run from the module root
(the directory containing go.mod).

  # single binary (module root is the main package)
  monorel .

  # multiple binaries under one module
  monorel ./cmd/gsheet2csv ./cmd/gsheet2tsv ./cmd/gsheet2env

Changes:
- Add `binary` struct {name, mainPath} and `parseBinaries()`
  - "." is special-cased: binary name is taken from the CWD, not "."
  - filepath.Clean's "./"-stripping is undone so goreleaser sees an
    explicit relative path (./cmd/foo not cmd/foo)
- `goreleaserYAML` now takes `projectName + []binary`
  - Each binary gets its own `builds` entry (with `id:` and `main:`)
    and its own `archives` entry (with `ids:` to link it to the build)
  - `main:` is omitted when mainPath is "." (goreleaser default)
  - Checksum is named <projectName>_VERSION_checksums.txt
- `printScript` takes `projectName + []binary`
  - Summary line says "Binaries:" (plural) when more than one
  - Upload step globs tar.gz + zip for every binary, then the checksum
- Require go.mod in CWD; error out with usage message when no args given

Also regenerates cmd/tcpfwd/.goreleaser.yaml via the new code path
(adds `id: tcpfwd` to builds/archives; no functional change otherwise).
2026-03-01 19:13:45 -07:00
3676ef0f47
feat: add tools/monorel for monorepo submodule releases
Adds a standalone Go CLI tool (tools/monorel) that automates the
goreleaser + gh release workflow for modules living in a subdirectory
of a monorepo where goreleaser Pro is not available.

Run from any module subdirectory (e.g. cmd/tcpfwd):
  monorel          # writes .goreleaser.yaml + prints release script
  monorel --help   # (flag defaults)

What the tool does:
- Detects module path and binary name from git prefix
- Lists and semver-sorts tags matching <prefix>/v* (e.g. cmd/tcpfwd/v*)
- Computes version: exact tag → stable release; commits/dirty → pre-release
- Writes (or updates) .goreleaser.yaml with the binary name hard-coded,
  {{.Env.VERSION}} used for filenames instead of the prefixed tag,
  and release.disable: true (gh handles the GitHub Release)
- Prints a numbered bash script covering env vars, optional git tag,
  goreleaser build, release notes, and gh release create/upload/publish

Also updates cmd/tcpfwd/.goreleaser.yaml (first output from monorel):
- Fixes stray trailing quote in ldflags
- Sets release.disable: true (was release.footer)
- Adds generated-by header comment
2026-03-01 19:13:39 -07:00
968b375221
chore(io/transform/gsheet2csv): update .goreleaser.yaml with more builds io/transform/gsheet2csv/v1.0.5 2026-03-01 02:11:00 -07:00
ae0e02b5aa
chore(io/transform/gsheet2csv): add .goreleaser.yaml io/transform/gsheet2csv/v1.0.4 2026-03-01 01:20:48 -07:00
6e4f25ff5e
chore(release): add .goreleaser.yaml for auth-proxy 2026-03-01 01:20:48 -07:00
18eec1f5cb
chore(release): update .goreleaser.yaml for cmd/tcpfwd cmd/tcpfwd/v1.1.1 2026-03-01 00:29:33 -07:00
fc9f070285
chore(cmd/tcpfwd): update .goreleaser.yaml for monorepo 2026-03-01 00:22:44 -07:00
115efc0afb
chore(cmd/tcpfwd): goreleaser init 2026-03-01 00:18:32 -07:00
698137576a
chore: add 'dist/' to .gitignore 2026-03-01 00:18:32 -07:00
0762e64857
chore(cmd/tcpfwd): add go.mod (for git-tag-based releases) cmd/tcpfwd/v1.1.0 2026-02-27 23:50:37 -07:00
d30ceb004d
chore(cmd/tcpfwd): minor cleanup, add license, lint 2026-02-27 23:35:00 -07:00
3e4ce3ac91
ref(cmd/tcpfwd): extract waitWithTimeout to simplify shutdown block
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 22:52:07 -07:00
0d356c0b26
feat(cmd/tcpfwd): add description to version/help output
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 22:16:49 -07:00
f9e06f131b
ref(cmd/tcpfwd): simplify parseForward with strings.Cut
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 22:13:10 -07:00
3f16e89f5c
ref(cmd/tcpfwd): remove implicit time.Now() for testability
- connEntry.isIdle(now, threshold): caller supplies now instead of time.Since
- connRegistry.closeIdle(now, threshold): passes now through to isIdle
- trackingConn gains a clock func() time.Time field used in Read/Write
- handleConn takes clock func() time.Time; uses it to init lastRead/lastWrite
  and passes it to trackingConn
- Call sites in main pass time.Now or time.Now() explicitly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 22:08:56 -07:00
89f6e04516
feat(cmd/tcpfwd): add graceful shutdown with idle connection tracking
On SIGINT/SIGTERM:
- Stop accepting new connections
- Close connections idle longer than --idle-timeout (default 5s),
  determined by LastRead/LastWrite timestamps tracked per connection pair
- Wait for active connections to drain up to --shutdown-timeout (default 30s)
- Force-close any remaining connections if the timeout is exceeded

Also switches isClosedConn to use errors.Is(err, net.ErrClosed) and
exits the accept loop cleanly when a listener is closed during shutdown.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 22:05:04 -07:00
b08525b024
feat(cmd/tcpfwd): add multi-forward positional args and version/help
Accept any number of local-port:remote-host:remote-port forwards as
positional arguments. Backward-compatible with existing --port/--target
flags. Adds --version/-V/version and --help/help handling matching the
auth-proxy pattern, including printVersion printed to stderr at startup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 21:54:51 -07:00
ec64afe390
feat: add tcpfwd to pipe connections 2026-02-27 21:25:33 -07:00
a56f8601f0
chore: add cmd binaries to .gitignore 2026-02-27 02:56:28 -07:00
af6b0eb5a2
feat: add cmd/smsgwhookstocsv for smsapid (android sms gateway) jsonl to tsv 2026-02-27 02:48:13 -07:00
71eceb809f
feat: add cmd/smsapid for use with android-sms-gateway 2026-02-27 02:48:13 -07:00
4176923dd8
ref(cmd/sendsms): separate http/androidsmsgateway into own package 2026-02-27 02:42:50 -07:00
6db9bd805d
chore: remove empty go.sum 2026-02-27 02:42:50 -07:00
c6b55feb78
chore: add .DS_Store to .gitignore 2026-02-27 01:55:24 -07:00
c08f7e342a
feat(cmd/sendsms): add back curl script for testing 2026-02-27 01:52:19 -07:00
de8630c136
fix(cmd/sendsms): send messages again (but not on dry-run), check ENVs 2026-02-27 01:52:19 -07:00
4e5277d133
fix(cmd/sendsms): randomize-csv now keeps header and adds back extension 2026-02-27 01:52:19 -07:00
7b40097396
fix(cmd/auth-proxy): show all working credentials, not just the first one cmd/auth-proxy/v1.0.1 2026-02-27 00:26:43 -07:00
cbacf9ffc9
chore: add credentials.tsv to .gitignore 2026-02-27 00:17:31 -07:00
7a93b333ba
doc(cmd/auth-proxy): add README.md with examples and install instructions 2026-02-27 00:06:58 -07:00
13eeb6793b
feat: add cmd/auth-proxy to add Basic, Bearer, X-API-Key, or access_token auth to routes 2026-02-27 00:06:58 -07:00
8ef2f73cb0
fix(auth/csvauth): oops, should have added as auth.BasicAuthenticator, done auth/csvauth/v1.2.2 2026-02-26 21:12:29 -07:00
ff8cdec1d7
feat(auth): add BasicVerifier, BasicAuthenticator, and BasicPrinciple for interfaces without implementation dependency auth/v1.0.0 2026-02-26 20:03:43 -07:00
d756f205b0
ref(auth/csvauth): create and adhere to Principle interface for verified credential 2026-02-26 16:44:54 -07:00
737f3b0057
fix(auth/csvauth): make username lookups timing safe 2026-02-26 02:23:31 -07:00
1789c92815
fix(auth/csvauth): don't allow BOTH username and password to be empty 2026-02-26 02:23:31 -07:00
3465e9e232
doc(auth/csvauth): update examples 2026-02-26 02:23:31 -07:00
01a4cdda8a
feat(auth/csvauth): add Authenticate(user, pass string) to get verified Credential 2026-02-26 02:23:31 -07:00
7d35551fa7
ref(auth/csvauth): separate Login, Token, and ServiceAccount files 2026-02-26 02:23:31 -07:00
85c7b78ca6
ref(auth/csvauth): enable token use with Verify(dummy, token) auth/csvauth/v1.1.1 2026-02-21 15:41:02 -07:00
85d42550bf
feat(auth/csvauth): add token support,make secrets non-printing auth/csvauth/v1.1.0 2026-02-21 05:49:11 -07:00
dd48b2420b
feat(auth/csvauth): make secrets non-printing 2026-02-21 05:49:11 -07:00
af634f2175
doc+fix(cmd/csvauth): cleanup help, print with bare '--help' 2026-02-21 05:49:11 -07:00
6e0c91feb4
fix(cmd/csvauth): use errors.Is(err, ErrInQuestion) correctly 2026-02-21 05:49:11 -07:00
b4886aa710
feat: add crypto/passphrase encoding/base2048/v1.0.0 crypto/passphrase/v1.0.0 2026-02-12 00:38:04 -07:00
a68cac6529
feat: add encoding/base2048 2026-02-12 00:38:04 -07:00
d2f362ae50
chore: bump go.mod to 1.26.0 2026-02-12 00:38:04 -07:00
21ea2d0613
chore(cmd/sql-migrate): bump v2.0.3 cmd/sql-migrate/v2.0.3 2026-01-31 21:22:42 -07:00