217 Commits

Author SHA1 Message Date
a8e108a05b
wip: ipcohort: move atomics to gitdataset 2026-04-19 19:49:52 -06:00
29f9760f4d
wip: feat: add net/gitdataset for data that updates via git 2026-04-19 19:49:52 -06:00
98fb592435
f: ipcohort / blacklist 2026-04-19 19:34:21 -06:00
0f909da44c
feat: add net/ipcohort (for blacklisting, whitelisting, etc) 2026-04-19 19:34:21 -06:00
eb5e1d1336
feat: add net/gitshallow (for incremental updates to data repos) 2026-04-19 19:34:21 -06:00
c2f5dbeeca
doc(skills): pgmigrate clarificaton 2026-04-19 19:25:52 -06:00
65432d7c29
database/sqlmigrate/pgmigrate: add Schema field for qualified _migrations table
Add Schema string field to Migrator. When set, Applied() constructs a
schema-qualified table name via pgx.Identifier.Sanitize() rather than
the bare "_migrations". New() signature is unchanged.

Usage:
    runner := pgmigrate.New(conn)
    runner.Schema = "authz"
database/sqlmigrate/pgmigrate/v1.0.5
2026-04-17 03:53:32 -06:00
17bbc881a9
database/sqlmigrate: allow optional schema prefix in INSERT INTO _migrations
Update idFromInsert regex to match schema-qualified table references
such as INSERT INTO authz._migrations, in addition to the existing
unqualified INSERT INTO _migrations form.
database/sqlmigrate/v1.0.3
2026-04-17 02:30:41 -06:00
02fef67e53
fix(auth/csvauth): ID() returns Name only, not Name~hashID for tokens
Principal identity is the subject (who), not the credential instance
(which token). The hashID suffix was an internal cache fingerprint that
leaked into the public ID. Callers that need to distinguish individual
token instances must use a separate mechanism.

TSV serialization in ToRecord() still writes Name~hashID when hashID is
set so the credential file round-trips correctly.
auth/csvauth/v1.2.9
2026-04-13 22:57:21 -06:00
fbb4a14620
chore(git): ignore worktrees and vim swap files 2026-04-13 17:14:08 -06:00
4abac2a0df
feat(auth/xhubsig): X-Hub-Signature HMAC webhook verification + HTTP middleware
Verify X-Hub-Signature-256 (and SHA-1) webhook signatures. Middleware
buffers and re-exposes the body for downstream handlers. Errors honor
Accept header: TSV default (text/plain for browsers), JSON, CSV, or
Markdown — three fields (error, description, hint) with pseudocode hints.
auth/xhubsig/v0.9.0
2026-04-13 17:04:45 -06:00
aebef71a95
test(sqlmigrate): add ordering, end-to-end, rollback, and dialect-specific tests
Across all four backends:

- TestAppliedOrdering: insert rows out of order, verify Applied()
  returns them sorted by name. Guards against the ORDER BY clause
  being dropped or the query returning rows in arbitrary order.
- TestEndToEndCycle: Collect → Up → Applied → Down → Applied via
  the sqlmigrate orchestrator with real migration files. Catches
  wiring bugs between Migrator and orchestrator that the in-package
  mockMigrator tests cannot.
- TestDMLRollback: multi-statement DML migration where the last
  statement fails, verifies earlier INSERTs are rolled back. MySQL
  note: DML-only because MySQL implicitly commits DDL.

Dialect-specific:

- mymigrate TestMultiStatementsRequired: strip multiStatements=true
  from the DSN, verify ExecUp fails with a clear error mentioning
  multiStatements (rather than silently running only the first
  statement of a multi-statement migration).
- litemigrate TestForeignKeyEnforcement: verifies FK constraints
  are enforced when the DSN includes _pragma=foreign_keys(1).

Test fixture fix: cleanup closures now use context.Background()
instead of the test context. t.Context() is canceled before
t.Cleanup runs, so DB cleanup silently failed. Previously the
_migrations cleanup appeared to work because the next test's
connect() re-ran DROP TABLE at setup, but domain tables (test_*)
leaked across runs. New tests also pre-clean at setup for
self-healing after interrupted runs.
database/sqlmigrate/pgmigrate/v1.0.4 database/sqlmigrate/litemigrate/v1.0.4 database/sqlmigrate/msmigrate/v1.0.4 database/sqlmigrate/mymigrate/v1.0.4
2026-04-10 01:07:58 -06:00
28af8f49b8
test(mymigrate): use single-schema test fixture for hosted MariaDB
Hosted MariaDB users (e.g. todo_test_*) typically have access to a single
database/schema and cannot CREATE/DROP DATABASE. Drop the per-test database
isolation pattern in favour of dropping _migrations directly on entry and
exit, matching msmigrate's approach. Tests must not run concurrently
against the same DSN.
2026-04-10 00:25:29 -06:00
3402b60bc6
fix(sqlmigrate): defensive table-missing check at rows.Err() across backends
Apply the same lazy-error pattern fix to all backends, plus regression
tests that catch the bug.

pgmigrate is the confirmed-broken case (pgx/v5's Conn.Query is lazy and
surfaces 42P01 at rows.Err() once the prepared statement cache is primed).
The defensive check at rows.Err() is also added to mymigrate and msmigrate
in case their drivers exhibit similar behavior in some configurations.

litemigrate is refactored to probe sqlite_master with errors.Is(sql.ErrNoRows)
instead of string-matching the error message — SQLite returns the generic
SQLITE_ERROR code for "no such table" so a typed-error approach isn't
possible at the driver layer; the probe lets us use idiomatic errors.Is.

Tests:
- litemigrate: in-memory SQLite, runs on every go test (no infra)
- pgmigrate:   PG_TEST_URL env-gated; verified against real Postgres,
               TestAppliedAfterDropTable reproduces the agent's exact error
               message ("reading rows: ... 42P01") without the fix
- mymigrate:   MYSQL_TEST_DSN env-gated
- msmigrate:   MSSQL_TEST_URL env-gated; verified against real SQL Server

Each backend has four cases: missing table, populated table, empty table,
and table-dropped-after-cache-primed (the lazy-error scenario).
2026-04-10 00:15:06 -06:00
e11b228765
fix(pgmigrate): handle 42P01 surfaced lazily at rows.Err()
pgx/v5's Conn.Query is lazy — when the queried table doesn't exist,
the 42P01 error doesn't surface at Query() time, it surfaces at
rows.Err() after the iteration loop. The original code only checked
for 42P01 at the Query() site, so first-run migrations against an
empty database failed with:

    reading rows: ERROR: relation "_migrations" does not exist (SQLSTATE 42P01)

Apply the typed-error check at both sites via a shared helper.
2026-04-10 00:01:55 -06:00
0c1eb1f125
feat(skills): add sqlmigrate skill index and per-database skills
Index skill (use-sqlmigrate) plus focused skills for CLI usage, Go
library integration, and per-database conventions (PostgreSQL,
MySQL/MariaDB, SQLite, SQL Server).
2026-04-09 17:08:32 -06:00
5b3a4be3c2
fix(sql-migrate): remove local replace directives from go.mod
Replace directives pointing to local paths prevent `go install` from
working. Use published module versions (sqlmigrate v1.0.2, shmigrate
v1.0.2) so users can install with:

    go install github.com/therootcompany/golib/cmd/sql-migrate/v2@latest
cmd/sql-migrate/v2.2.4
2026-04-09 16:51:56 -06:00
dda4491c94
chore: golint fixes across all modules
Run scripts/golint: goimports, go fix, go vet, go mod tidy.
2026-04-09 14:23:33 -06:00
2256b12223
feat(sql-migrate): add sqlite and sqlcmd --sql-command aliases
- Use full flag names in command defaults (--no-align, --tuples-only, etc.)
- Add sqlite/sqlite3/lite alias for SQLite
- Add sqlcmd/mssql/sqlserver alias for SQL Server (go-sqlcmd, TDS 8.0)
- Add SQL Server help text with SQLCMD env vars and TLS docs
- Add sqlite and sqlcmd SELECT expressions for id+name migration log
2026-04-09 13:26:40 -06:00
86ff126df0 chore(litemigrate): add go.sum database/sqlmigrate/mymigrate/v1.0.3 database/sqlmigrate/litemigrate/v1.0.3 database/sqlmigrate/msmigrate/v1.0.3 database/sqlmigrate/pgmigrate/v1.0.3 2026-04-09 10:56:47 -06:00
67ad7a9fa2 fix(litemigrate,mymigrate,msmigrate): take *sql.Conn instead of *sql.DB
Same issue as pgmigrate: *sql.DB is a connection pool, so each call
may land on a different connection. Migrations need a pinned connection
for session state (SET search_path, temp tables, etc.) to persist
across sequential calls. *sql.Conn (from db.Conn(ctx)) pins one
underlying connection for its lifetime.
2026-04-09 10:56:47 -06:00
d5d1df060f fix(pgmigrate): take *pgx.Conn instead of *pgxpool.Pool
Migrations run sequentially on a single connection — a pool adds
unnecessary complexity and forces callers to create one. This also
drops the puddle/v2 and x/sync transitive dependencies.
2026-04-09 10:56:47 -06:00
dec11dd6d6
fix(shmigrate): explicit Close throwaway
- Replace bare `defer f.Close()` with `defer func() { _ = f.Close() }()`
  for explicit error throwaway (consistent with other backends)
database/sqlmigrate/shmigrate/v1.0.3
2026-04-09 03:53:25 -06:00
9d4b0ab4af
fix(sql-migrate): remove accidental junk from go.* cmd/sql-migrate/v2.2.1 cmd/sql-migrate/v2.1.7-pre10 2026-04-09 03:37:20 -06:00
5783d4fc7a
ref(backends): update all backends and sql-migrate to sqlmigrate v1.0.2
ExecUp/ExecDown now take (ctx, Migration, sql string) instead of
(ctx, Migration) with embedded Up/Down fields. Applied returns
[]Migration instead of []AppliedMigration.

- pgmigrate, mymigrate, litemigrate, msmigrate: new interface, v1.0.2 dep
- shmigrate: v1.0.2 dep, remove temporary replace directive
- cmd/sql-migrate: v1.0.2 dep
database/sqlmigrate/shmigrate/v1.0.2
2026-04-09 03:27:35 -06:00
75e4a883b7
ref(sqlmigrate): split Migration into Migration + Script
Migration{ID, Name} is the identity type returned by Up/Down/Latest/Drop.
Script{Migration, Up, Down} holds collected SQL content from Collect().

Migrator interface now takes SQL as a separate parameter:
  ExecUp(ctx, Migration, sql string)
  ExecDown(ctx, Migration, sql string)

This separates identity from content — callers that track what ran
don't need to carry around SQL strings they'll never use.

Updates shmigrate to match (ignores the sql parameter, references
files on disk instead).
database/sqlmigrate/v1.0.2
2026-04-09 03:21:46 -06:00
285eb0b684 feat(msmigrate): add SQL Server backend for sqlmigrate 2026-04-09 02:39:18 -06:00
9fb5b4eda6 feat(litemigrate): add SQLite backend for sqlmigrate 2026-04-09 02:37:35 -06:00
9614dea7df fix(pgmigrate): update sqlmigrate dep to v1.0.1, replace nolint with explicit throwaway 2026-04-09 02:35:42 -06:00
f89b8115dd feat(mymigrate): add MySQL/MariaDB backend for sqlmigrate 2026-04-09 02:35:42 -06:00
a8bc605ebf
fix(pgmigrate): update sqlmigrate dependency to v1.0.1 2026-04-09 02:20:36 -06:00
b5d9c7fab7
feat(pgmigrate): add PostgreSQL backend for sqlmigrate 2026-04-09 02:14:40 -06:00
a3ecf5ac81
ref(sqlmigrate): add subpath to Collect, add Latest/Drop convenience functions
API changes for v1:
- Collect(fsys, subpath) takes a subdirectory path (use "." for root),
  enabling embed.FS with //go:embed sql/migrations/*.sql
- Latest() applies all pending migrations (shorthand for Up with n=-1)
- Drop() rolls back all applied migrations (shorthand for Down with n=-1)
2026-04-09 02:04:37 -06:00
9c672a9d76
fix(shmigrate): use errors.Is for fs.ErrNotExist compatibility
os.IsNotExist does not recognize fs.ErrNotExist when wrapped by an
fs.FS implementation. Switch to errors.Is(err, fs.ErrNotExist) so
the "file not found" check works for both os.Open and fs.FS.Open.
2026-04-08 17:52:53 -06:00
55298ac018
feat(sql-migrate): add ID-in-log for tab-delimited migration tracking
- logMigrationsSelect() returns DB-specific SELECT for id+name output,
  matching psql explicitly and erroring on unrecognized --sql-command
- logMigrationsQueryNote const for the comment header
- maybeUpgradeLogQuery() auto-upgrades old _migrations.sql on first run,
  replacing only the matching SELECT line
- Add UPGRADING help section pointing to sync subcommand
2026-04-08 17:23:50 -06:00
3e51c7b67a
fix(sqlmigrate): make n=0 an error in Up/Down, use -1 for "all"
Passing 0 to Up() or Down() is an easy mistake — it silently means
"all" which could be destructive. Now n=0 returns ErrInvalidN.
Convention: n > 0 for a specific count, n < 0 (typically -1) for all.
v2.2.0
2026-04-08 15:51:25 -06:00
3547b7e409
ref(database/sqlmigrate): extract migration library with shmigrate backend
Factor the inline migration logic from cmd/sql-migrate into reusable
packages: database/sqlmigrate (core types, matching, file collection)
and database/sqlmigrate/shmigrate (shell script generation backend).

No behavior changes — the CLI produces identical output. The shmigrate
package implements the sqlmigrate.Migrator interface so other backends
(pgmigrate, mymigrate, etc.) can follow the same pattern.
2026-04-08 15:37:03 -06:00
c4964a5b65
chore(sql-migrate): remove dead subcmd != "create" checks in status/list cases
Go switch cases don't fall through, so subcmd can never be "create"
when we're inside the "status" or "list" case.
2026-04-08 15:21:04 -06:00
da7f45438c
doc(sql-migrate): add PGOPTIONS multi-tenant schema docs to help text
Document how to use PGOPTIONS="-c search_path=..." for multi-tenant
PostgreSQL migrations. Each schema gets its own _migrations table,
so tenants are migrated independently.
2026-04-08 15:06:41 -06:00
2080ae223d
fix(sql-migrate): reject explicit 'up 0' and 'down 0' as invalid
An explicit 0 argument should error, not silently run all pending (up)
or get handled as a special case (down). Change the guard from < 0 to
< 1 in both subcommands so '0' is treated as invalid input.
2026-04-08 14:57:55 -06:00
03d81a2b76
fix(sql-migrate): reject explicit 'up 0' as invalid
An explicit 0 argument to 'up' should error (like 'down 0' already
does), not silently run all pending migrations. Change the guard
from < 0 to < 1 to match 'down' behavior.
2026-04-08 14:41:09 -06:00
40fa1e876c
fix(sql-migrate): add missing --tuples-only to psql examples in help text
The psql command constant uses -A -t (--no-align --tuples-only) but
the help text and code comments only showed --no-align. Without
--tuples-only, psql prints column headers into migrations.log,
corrupting it.
cmd/sql-migrate/v2.1.6
2026-04-08 13:45:11 -06:00
404079f154
fix(sql-migrate): use goreleaser ldflags for version info
Replace hardcoded version const with var block populated by goreleaser
ldflags (version, commit, date). Add printVersion() matching the pattern
used by sibling commands (tcpfwd, smsapid, auth-proxy). Fix date var
shadowing in main() by renaming local to today.
cmd/sql-migrate/v2.1.5
2026-04-08 02:57:53 -06:00
075cc7b286
fix(sql-migrate): add missing ! to shebang in generated scripts
Generated shell scripts had `#/bin/sh` instead of `#!/bin/sh`,
meaning the shebang was treated as a comment rather than an
interpreter directive.
cmd/sql-migrate/v2.1.4
2026-04-06 00:39:36 -06:00
4a9c331ef9
Fix INSERT INTO _migrations ordering in create and fixup
The create subcommand generated .up.sql files with INSERT INTO
_migrations as the FIRST statement, before the actual DDL. If the
DDL fails, the migration is incorrectly marked as applied. Move the
INSERT to be the LAST statement, matching how .down.sql already puts
DELETE FROM _migrations last.

Also fix the automatic fixup logic to append (not prepend) missing
INSERT statements to existing .up.sql files.

Fixes #86
cmd/sql-migrate/v2.1.3
2026-03-30 15:58:21 -06:00
87b666ffd3
chore(cmd/sql-migrate): add .goreleaser.yaml cmd/sql-migrate/v2.1.2 2026-03-28 17:16:40 -06:00
a4c4deabfa
chore(tools/monorel): re-init .goreleaser.yaml tools/monorel/v0.6.7 2026-03-28 17:15:38 -06:00
9d11500cd6
feat(monorel): separate Windows builds and full goamd64 v1-v4 matrix
Go 1.23+ changed Windows target naming so x86_64 builds now carry a
micro-architecture suffix (e.g. _v2).  Update the goreleaser YAML
generator and monorel's own .goreleaser.yaml to match:

- Remove windows from defaultGoos/almostAllGoos; emit a dedicated
  <name>-windows build entry per binary.  Windows is kept in a separate
  build because it does not support ARM v6/v7, so it cannot share the
  same goarch matrix as non-Windows builds.
- Add defaultWindowsGoarch [amd64, arm64] and almostAllWindowsGoarch
  [386, amd64, arm64] for the Windows-specific architecture lists.
- Promote defaultGoamd64 from [v1, v2] to [v1, v2, v3, v4] so the
  full amd64 micro-architecture matrix is always generated.
- Update the archive name_template to include
  {{ if .Amd64 }}_{{ .Amd64 }}{{ end }} after x86_64.
- Include both <name> and <name>-windows in archive ids.
- Regenerate tools/monorel/.goreleaser.yaml and
  cmd/sql-migrate/.goreleaser.yaml with the new format.
2026-03-28 17:15:33 -06:00
690cf90d67
chore(cmd/sql-migrate): add .goreleaser.yaml 2026-03-23 11:43:08 -06:00
1f61095873
feat(sql-migrate): add sync subcommand
Adds `sql-migrate sync` which outputs a shell script that refreshes
the local migrations.log from the DB by running _migrations.sql.
Uses `|| true` so a fresh DB with no _migrations table yields an
empty log (all migrations pending) rather than an error.

Usage:
  sql-migrate -d ./db/migrations sync | sh
  sql-migrate -d ./db/migrations up | sh
cmd/sql-migrate/v2.1.0
2026-03-23 11:42:23 -06:00