Skip to content

leonletto/thrum_safe

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

thrum_safe

License CI Release Go Reference Go Report Card Go Version

Compile-time footgun-prevention guardrails for Go. Two packages that make it impossible to forget a context on database calls or git invocations:

  • safedb — wraps *sql.DB and *sql.Tx to expose only context-aware methods. Code that calls the bare Query/Exec/QueryRow variants doesn't compile.
  • safecmd — timeout-bounded exec.CommandContext wrappers for git operations, with injected commit identity for headless/daemon worktrees.

Why compile-time wrappers instead of a linter?

The noctx linter catches context-free database calls at CI time — helpful, but optional. A compiled SDK surfaces as a type error: the dangerous method simply doesn't exist on the type. Useful when you're shipping primitives to consumers who may not lint, or when you want a stronger guarantee for an autonomous agent fleet.

Module path

github.com/leonletto/thrum_safe

Packages

import "github.com/leonletto/thrum_safe/safedb"
import "github.com/leonletto/thrum_safe/safecmd"

Installation

go get github.com/leonletto/thrum_safe@latest

safedb

raw, _ := sql.Open("sqlite", "app.db")
db := safedb.New(raw)

// Only context-aware methods exist on *safedb.DB:
rows, err := db.QueryContext(ctx, "SELECT id, name FROM users WHERE active = ?", true)

// Transactions are also wrapped — bare Exec/Query/QueryRow don't compile:
tx, err := db.BeginTx(ctx, nil)
_, err  = tx.ExecContext(ctx, "UPDATE users SET name = ? WHERE id = ?", name, id)
_      = tx.Commit()

// Need DDL or a migration library? Raw() is the documented escape hatch:
db.Raw().Exec("CREATE TABLE ...")  // red-flag in code review, intentionally verbose

What compiles and what doesn't

db.QueryContext(ctx, ...)    // ✓ compiles
db.ExecContext(ctx, ...)     // ✓ compiles
db.QueryRowContext(ctx, ...) // ✓ compiles
db.BeginTx(ctx, nil)        // ✓ compiles — returns *safedb.Tx

db.Query(...)                // ✗ compile error — method does not exist
db.Exec(...)                 // ✗ compile error — method does not exist
db.QueryRow(...)             // ✗ compile error — method does not exist

tx.ExecContext(ctx, ...)     // ✓ compiles
tx.QueryContext(ctx, ...)    // ✓ compiles
tx.QueryRowContext(ctx, ...) // ✓ compiles
tx.Commit()                  // ✓ compiles
tx.Rollback()                // ✓ compiles

tx.Exec(...)                 // ✗ compile error — method does not exist

safecmd

// Run a git command with a 5-second timeout + injected commit identity:
out, err := safecmd.Git(ctx, "/path/to/repo", "status", "--short")

// For network operations (push, fetch) — 10-second timeout:
out, err = safecmd.GitLong(ctx, "/path/to/repo", "push", "origin", "main")

// Read effective git config without identity injection:
name, err := safecmd.GitConfig(ctx, "/path/to/repo", "user.name")

// List all worktree paths for a repo:
paths := safecmd.WorktreePaths(ctx, "/path/to/repo")

Commit identity injection

Every Git/GitLong call prepends -c user.name=... -c user.email=... args to prevent commit failures in headless or daemon-spawned worktrees where no global git identity is configured. Override the default at package init:

func init() {
    safecmd.DefaultGitIdentity = []string{
        "-c", "user.name=my-agent",
        "-c", "user.email=my-agent@local",
    }
}

GitConfig intentionally does NOT inject these overrides, so you can read the real repo config values.

Zero runtime dependencies

thrum_safe uses only the Go standard library at runtime. Test files use modernc.org/sqlite for an in-process SQLite driver; it is not a runtime dependency of packages that import thrum_safe.

Agent-fleet governance

See docs/enforcement.md for the enforcement rules that instruct an AI coding fleet to route all database/sql access through safedb and all git exec through safecmd.

Documentation

User-facing guides live in docs/:

  • Getting started — wrap *sql.DB once, pass *safedb.DB, override DefaultGitIdentity at init.
  • safedb — full API reference: DB and Tx methods, PingContext, Raw() escape hatch, migration/DDL pattern.
  • safecmdGit, GitLong, GitConfig, WorktreePaths, timeouts, and goroutine-safety note on DefaultGitIdentity.
  • Testinggo test -race ./..., the requireGit skip pattern, and what each package's test suite covers.
  • Enforcement — agent-fleet rules for routing all database and git access through these wrappers.

Contributing? See CONTRIBUTING.md. Security? See SECURITY.md.

About

Compile-time footgun-prevention guardrails for autonomous Go code (safedb + safecmd)

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages