Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
59a7082
feat(firewall): opt-in ~ regex marker for egress path rules
schmitthub Jun 23, 2026
de09b51
fix(firewall): honor ~ regex path marker in host-proxy egress gate
schmitthub Jun 23, 2026
cf0f2ce
fix(hostproxy): canonicalize dot-segment dirs to match Envoy normaliz…
schmitthub Jun 23, 2026
315825d
docs(firewall): sharpen domain wildcard and regex path rule guidance
schmitthub Jun 23, 2026
c3f2190
feat(firewall): validate literal path chars, document rule precedence
schmitthub Jun 23, 2026
f42acb1
fix(iostreams): wrap changelog teaser, strip changelog URLs, fix flak…
schmitthub Jun 23, 2026
228b962
fix(hostproxy): fail egress enforcement closed like Envoy
schmitthub Jun 23, 2026
9a83e0a
refactor(controlplane): relocate test mocks to mocks/ subpackages, ha…
schmitthub Jun 23, 2026
cb268bd
chore(golanglint): added draconian linter rules
schmitthub Jun 23, 2026
fb5e07d
chore(golanglint): fixed schema
schmitthub Jun 23, 2026
7fe530c
chore(golanglint): fixed schema
schmitthub Jun 23, 2026
bc95872
chore(golang-lint): removed autofixer
schmitthub Jun 23, 2026
b8a53b2
chore(docs): stale docs
schmitthub Jun 23, 2026
3c29341
chore(golang-lint): added stable config
schmitthub Jun 23, 2026
a2cded2
chore(hooks): added git checks
schmitthub Jun 23, 2026
8ae800a
chore(hooks): hardened checks to prevent pre-commit skip var bypass
schmitthub Jun 23, 2026
d260d46
chore(lint): removed depguard from checks
schmitthub Jun 23, 2026
7ba7d77
chore(lint): added wsl_v5 to disable list
schmitthub Jun 24, 2026
acaedc7
chore(lint): more forgiving rules
schmitthub Jun 24, 2026
fb5dbe3
fix(review): pre-linter fixes
schmitthub Jun 24, 2026
d1020b1
chore(lint): resolve all golangci-lint-full findings on the branch
schmitthub Jun 24, 2026
eee4d6c
chore(linter): relax containedctx et al for stubs and mocks
schmitthub Jun 24, 2026
e37a305
chore(linter): contextcheck on mocks
schmitthub Jun 24, 2026
5a8ae88
chore(linter): revert
schmitthub Jun 24, 2026
088ce13
refactor(mocks): store ctx directly in FakeSessionStream
schmitthub Jun 24, 2026
ea892bb
chore(clawker): regex test
schmitthub Jun 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .clawker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ security:
path: /repos/contributor-assistant/github-action/
- action: allow
path: /repos/actions/checkout/
- action: allow
path: /repos/charmbracelet/
- action: deny
path: /gists
- action: deny
Expand Down
128 changes: 67 additions & 61 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,71 +1,77 @@
# $schema: https://golangci-lint.run/jsonschema/golangci.jsonschema.json
version: "2"

run:
issues-exit-code: 1
tests: true

linters:
default: none
enable:
- asasalint # checks for pass []any as any in variadic func(...any)
- asciicheck # checks that your code does not contain non-ASCII identifiers
- bidichk # checks for dangerous unicode character sequences
- bodyclose # checks whether HTTP response body is closed successfully
- copyloopvar # detects places where loop variables are copied (Go 1.22+)
- durationcheck # checks for two durations multiplied together
- exptostd # detects functions from golang.org/x/exp/ that can be replaced by std functions
- fatcontext # detects nested contexts in loops
- gocheckcompilerdirectives # validates go compiler directive comments (//go:)
- gochecksumtype # checks exhaustiveness on Go "sum types"
- gocritic # provides diagnostics that check for bugs, performance and style issues
- gomoddirectives # manages the use of 'replace', 'retract', and 'excludes' directives in go.mod
- goprintffuncname # checks that printf-like functions are named with f at the end
- govet # reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
- ineffassign # detects when assignments to existing variables are not used
- nilerr # finds the code that returns nil even if it checks that the error is not nil
- nolintlint # reports ill-formed or insufficient nolint directives
- nosprintfhostport # checks for misuse of Sprintf to construct a host with port in a URL
- reassign # checks that package variables are not reassigned
- unused # checks for unused constants, variables, functions and types
# STRICT: Enable everything by default (replaces 'enable-all')
default: all

disable:
# --- TOKEN BURNERS (Subjective formatting rules that cause AI infinite loops) ---
- wsl # AI struggles endlessly with whitespace/blank line rules
- nlreturn # Too pedantic about newlines before return statements
- varnamelen # AI will get stuck in a loop renaming 'i' to 'index'
- lll # Line length limits often conflict with AI's generation style
- godox # We don't care if the AI leaves TODOs; we want it to write code
- tagalign # AI is notoriously bad at aligning struct tags visually

# To enable later due to too many issues, and confirm we need them:
# - gosec
# - staticcheck
# - errcheck
exclusions:
paths:
- third-party
rules:
- path: _test\.go$
linters:
- bodyclose
- gosec
# NOTE: In v2, settings are nested inside the linters block
settings:
gocritic:
disabled-checks:
- appendAssign
disabled-tags:
- style
gosec:
excludes:
- G110
- G204
- G301
- G302
- G304
- G307
- G404
config:
G104:
os:
- Setenv
govet:
enable:
- httpresponse
errcheck:
check-type-assertions: true
# STRICT: Bans `_ = err`. The AI must explicitly handle the error.
check-blank: true

gocognit:
# STRICT: AI naturally writes linear, monolithic code.
# This forces it to extract logic into smaller, testable functions.
min-complexity: 15

formatters:
enable:
- gofmt
exclusions:
paths:
- third-party
funlen:
lines: 60
statements: 40

forbidigo:
forbid:
- pattern: '^fmt\.Print.*$'
msg: "AI INSTRUCTION: Do not use fmt.Print. Use the injected logger or return the value."
- pattern: '^panic$'
msg: "AI INSTRUCTION: Do not panic. Handle the error and return it up the call stack."
- pattern: '^os\.Exit$'
msg: "AI INSTRUCTION: Do not use os.Exit. Return a concrete error."
- pattern: '^log\.Fatal.*$'
msg: "AI INSTRUCTION: Do not use standard log.Fatal. Return the error."
wrapcheck:
# STRICT: Forces the AI to add context to errors (e.g., fmt.Errorf("doing x: %w", err))
ignore-sigs:
- .Errorf(
- errors.New(
- errors.Unwrap(
- errors.Join(

revive:
severity: error
rules:
- name: unexported-return
- name: time-naming
- name: errorf
- name: error-naming
- name: error-strings
- name: receiver-naming
- name: context-as-argument
- name: context-keys-type
- name: import-shadowing

govet:
enable-all: true
disable:
# Prevents AI from infinitely reordering struct fields to save memory
- fieldalignment

issues:
max-issues-per-linter: 0
max-same-issues: 0
fix: true
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ repos:
files: ^\.github/workflows/.*\.ya?ml$
pass_filenames: false

- repo: https://github.com/tekwizely/pre-commit-golang
rev: f298c082154b2cb239fac06a4f452368e66e66dd # frozen: v1.0.0-rc.4
hooks:
- id: go-mod-tidy

# ── Lint ──────────────────────────────────────────────────────────────────
- repo: https://github.com/golangci/golangci-lint
rev: 8f3b0c7ed018e57905fbd873c697e0b1ede605a5 # frozen: v2.11.4
Expand Down
36 changes: 19 additions & 17 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ All notable, user-facing changes to clawker are documented here. This is the
that change the user surface, not every tech-debt or dependency bump. The
exhaustive per-commit list lives in each GitHub release's "Commits" section.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and clawker adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
The format follows Keep a Changelog, and clawker adheres to Semantic Versioning.

A release spans many merged PRs and may mix change kinds — Added, Fixed,
Changed, Removed. Each release section lists those subsections directly; the
clawker CLI's "what's new" teaser renders the section bodies verbatim as
markdown, and the release-notes workflow copies them into the GitHub release.
Link to relevant docs inline in the bullets.
Changed, Removed. Each release section lists those subsections directly.

## [0.12.9] - 2026-06-23

- **Added:** Egress path rule RE2 regex support. Add `~` at the beginning of a `path` rule to match it as a full-string regex instead of a prefix — anchor exactly and use alternation.
- ex: Add two paths sharing a common segment, optional trailing slash: `~/repos/(clawker|anthropic)/?`
- ex: Add the exact path without trailing slash: `~/schmitthub/clawker$`

## [0.12.8] - 2026-06-20

Expand Down Expand Up @@ -50,7 +52,7 @@ Link to relevant docs inline in the bullets.
workspaces copy the project's `.git` directory, so `git log`, `git diff`, and
branch operations work inside the container. Creating a snapshot workspace on
top of a git worktree is now rejected up front with a clear error instead of
producing a broken checkout. [Docs](https://docs.clawker.dev/worktrees)
producing a broken checkout.

## [0.12.0] - 2026-06-11

Expand All @@ -63,7 +65,7 @@ Link to relevant docs inline in the bullets.
branch. Manage aliases with the new `clawker alias` command (`list`, `set`,
`delete`, `export`), and define your own subcommand shortcuts under `aliases:`
in `clawker.yaml` — with positional `$1..$N` argument substitution — invoked
like any built-in command. [Docs](https://docs.clawker.dev/aliases)
like any built-in command.

## [0.11.0] - 2026-06-10

Expand All @@ -74,7 +76,7 @@ Link to relevant docs inline in the bullets.
read-only so container-side writes cannot execute code on the host. Go builds
inside worktree containers no longer fail on VCS stamping, and starting a
second container against an already-checked-out branch is refused instead of
corrupting the worktree. [Docs](https://docs.clawker.dev/worktrees)
corrupting the worktree.
- **Worktrees track their upstream branch.** `clawker worktree add` now pulls
remote-tracking branches with their upstream set, so `git pull`/`git push`
work without manual `--set-upstream`.
Expand All @@ -86,7 +88,7 @@ Link to relevant docs inline in the bullets.
- **Expired-but-refreshable host login is forwarded.** Claude Code credentials
copied from the host are injected even when the host access token has expired,
as long as it is still refreshable — the container refreshes on first use
instead of forcing a fresh `/login`. [Docs](https://docs.clawker.dev/credentials)
instead of forcing a fresh `/login`.

## [0.10.0] - 2026-06-06

Expand All @@ -95,7 +97,7 @@ Link to relevant docs inline in the bullets.
- **`clawker firewall refresh`.** Live-apply egress edits made to
`clawker.yaml` (`security.firewall.add_domains` and `security.firewall.rules`)
into the running firewall without restarting any container. Add/update only —
removing a rule still uses `clawker firewall remove`. [Docs](https://docs.clawker.dev/firewall)
removing a rule still uses `clawker firewall remove`.
- **Every-start container hook (`pre_run`).** The `agent.pre_run` script runs on
every container start (not just the first), complementing the once-only
`post_init` hook.
Expand All @@ -107,15 +109,15 @@ Link to relevant docs inline in the bullets.
- **Monitoring stack moved to OpenSearch + Prometheus.** The bundled
observability stack now uses OpenSearch (logs) and Prometheus (metrics) in
place of the previous Loki/Jaeger/Grafana stack, with a preconfigured
OpenSearch Dashboards setup applied by `clawker monitor up`. [Docs](https://docs.clawker.dev/monitoring)
OpenSearch Dashboards setup applied by `clawker monitor up`.

## [0.8.0] - 2026-05-12

### Removed

- **Looping ("ralph") mode has been retired.** The agent loop subsystem is gone;
drive iteration through your own workflow or Claude Code directly. A
managed-settings `PATH` regression introduced alongside it is also fixed. [Docs](https://docs.clawker.dev/quickstart)
managed-settings `PATH` regression introduced alongside it is also fixed.

## [0.7.0] - 2026-04-03

Expand All @@ -131,7 +133,7 @@ Link to relevant docs inline in the bullets.

- **Preset-based guided `init`.** `clawker init` was rewritten as a guided,
preset-based setup flow, making first-run project configuration substantially
faster and less error-prone. [Docs](https://docs.clawker.dev/quickstart)
faster and less error-prone.

## [0.5.0] - 2026-03-20

Expand All @@ -140,23 +142,23 @@ Link to relevant docs inline in the bullets.
- **Global egress firewall stack.** A shared Envoy + custom CoreDNS + eBPF
egress-enforcement stack governs outbound traffic from every agent container,
with per-project allow rules declared in `clawker.yaml` under
`security.firewall`. [Docs](https://docs.clawker.dev/firewall)
`security.firewall`.

## [0.3.0] - 2026-02-24

### Added

- **Host-path workspace mounts.** Run an agent against a live bind mount of the
host project directory, so changes made in the container are immediately
visible on the host (the alternative to ephemeral snapshot workspaces). [Docs](https://docs.clawker.dev/worktrees)
visible on the host (the alternative to ephemeral snapshot workspaces).

## [0.1.0] - 2026-02-11

### Added

- **Git worktree support.** Run an agent in an isolated git worktree keyed to a
branch, including slashed branch names, via `clawker worktree add` and
`clawker run --worktree`. [Docs](https://docs.clawker.dev/worktrees)
`clawker run --worktree`.
- **Git credential forwarding.** SSH agent, GPG agent, and HTTPS git
credentials are forwarded from the host through a socket bridge, so commits
sign and private repositories clone inside the container.
2 changes: 1 addition & 1 deletion api/admin/v1/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// trust boundary between admin operations (CLI) and agent operations (clawkerd).
package v1

//go:generate moq -rm -pkg mocks -out ../../../internal/controlplane/mocks/admin_client_mock.go . AdminServiceClient
//go:generate moq -rm -pkg mocks -out mocks/admin_client_mock.go . AdminServiceClient

import "github.com/schmitthub/clawker/internal/consts"

Expand Down
10 changes: 7 additions & 3 deletions api/admin/v1/admin.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions api/admin/v1/admin.proto
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ message EgressRule {
}

message PathRule {
// Literal path prefix (must start with "/"), or, when prefixed with "~", an
// RE2 regex matched full-string (exact/anchored — guards the open-prefix
// bypass where /repos/x also permits /repos/x-evil). Validated CP-side; an
// invalid path fails the whole rule-update operation.
string path = 1;
string action = 2;
// HTTP methods this path rule's action applies to (e.g. ["GET", "HEAD"]).
Expand Down
2 changes: 2 additions & 0 deletions api/clawkerd/v1/clawkerd.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@
// streams Responses correlated by command_id.
package v1

//go:generate moq -rm -pkg mocks -out mocks/client_mock.go . ClawkerdServiceClient

// ServiceName is the fully-qualified gRPC service name for ClawkerdService.
const ServiceName = "clawker.clawkerd.v1.ClawkerdService"
Loading
Loading