Skip to content

feat(watch): --watch observability mode and greywatch alias#94

Merged
tito merged 4 commits into
mainfrom
have-a-mode-that-doe_k28
May 20, 2026
Merged

feat(watch): --watch observability mode and greywatch alias#94
tito merged 4 commits into
mainfrom
have-a-mode-that-doe_k28

Conversation

@tito
Copy link
Copy Markdown
Contributor

@tito tito commented May 20, 2026

Summary

Adds a --watch flag that turns greywall into an observability layer instead of a deny-by-default sandbox, plus a greywatch alias that auto-applies it.

In --watch mode:

  • No profile loading (skipped entirely — starts from blank default config).
  • All network requests allowed by registering a single */* allow rule with greyproxy per session. Every request is logged on the dashboard but reaches its destination. Greyproxy's pattern matcher already treats * as match-all for both destination and port, so no greyproxy changes are needed.
  • Permissive filesystem and command policy: deny-by-default reads off, no command deny list. The hard-coded mandatory denies (.ssh/authorized_keys, git hooks, etc.) are preserved as a safety floor.
  • Network containment is unchanged: --unshare-net + tun2socks on Linux and Seatbelt (deny default) + proxy allow on macOS still force every connection through greyproxy.
  • No -m implied — combine --watch -m if you want violation monitoring on top.
  • --blank untouched.
  • Credential substitution stays on by default (disable with --no-credential-protection).

greywatch alias

Same binary, dispatched via argv[0]. Running greywatch <cmd> is equivalent to greywall --watch -- <cmd>. The symlink is created by:

  • Makefile (build, build-linux, build-darwin)
  • install.sh (after binary extraction)
  • Homebrew cask post-install hook

Manual tarball users can create the symlink themselves: ln -s greywall greywatch.

Drive-by bug fix

The existing fallback session-registration was gated on credSessionID == "", but the credential block always pre-generates a session id even when no credentials are detected — so any session that needed network rules but had no credentials silently never registered. Now gated on credSubstitutionActive, the source of truth for whether registration actually happened. Without this fix, --watch (and --learning --blank in some setups) wouldn't push their rules to greyproxy.

Test plan

  • make build produces both greywall and greywatch (symlink)
  • golangci-lint run — 0 issues
  • go test ./... — all packages pass
  • ./greywall --watch -- echo hello prints watch-mode banner and runs
  • ./greywatch -- echo hello (via symlink) dispatches identically
  • ./greywall --watch -d -- echo test confirms session registration is attempted against greyproxy (HTTP error when greyproxy is not running, as expected)
  • ./greywall --help lists the --watch flag with a clear description
  • End-to-end with a running greyproxy: verify the */* allow rule appears in the dashboard and all traffic is logged but not denied
  • Linux smoke test inside bwrap: verify --unshare-net is still applied and tun2socks routes traffic through greyproxy

tito added 4 commits May 20, 2026 15:56
--watch flag turns greywall into an observation layer instead of a
deny-by-default sandbox: it skips profile loading, registers a single
*/* allow rule with greyproxy so every request is visible on the
dashboard but reaches its destination, and relaxes local filesystem and
command policies (mandatory denies like .ssh/authorized_keys and git
hooks are preserved as a safety floor).

Network containment is unchanged: --unshare-net + tun2socks on Linux,
Seatbelt deny-default-with-proxy-allow on macOS still force all traffic
through greyproxy.

Invoking the binary as "greywatch" auto-injects --watch via argv[0]
dispatch, so installing a "greywatch -> greywall" symlink gives users a
dedicated entry point. The Makefile, install.sh, and Homebrew cask
post-install hook now create the symlink.

Also fix a pre-existing edge case where a session with network rules
but no detected credentials would never register with greyproxy: the
fallback registration was gated on credSessionID being empty, but the
credential block always pre-generates a session id. Gate on
credSubstitutionActive instead.
Reframe the README so the two modes are clear from the first paragraph:
greywall as the deny-by-default sandbox, greywatch (alias for
"greywall --watch") as the allow-by-default observability layer that
surfaces every request on the greyproxy dashboard without denying
anything.

Adds:
- two-mode lead paragraph
- "Observability mode" key feature bullet
- greywatch example in the quickstart block
- install note that greywatch ships alongside greywall (Homebrew,
  install.sh, make build) plus the manual "ln -s greywall greywatch"
  step for "go install" and manual tarball downloads
- new "Watch mode (observability)" usage subsection covering the
  unchanged network containment, retained safety floor, and how it
  differs from normal mode
CI's gofumpt is newer than what most contributors have locally and now
flags pre-existing multi-line call formatting across the profiles and
sandbox packages. Run the formatter and shift one //nolint:gosec
directive (monitor.go) onto the exec.CommandContext( line so it still
attaches after the reformat. No behavior changes.
@tito tito merged commit efde7de into main May 20, 2026
4 checks passed
@tito tito deleted the have-a-mode-that-doe_k28 branch May 20, 2026 22:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant