WORKSPACE-GUARD wraps the most abusable surfaces of an agent dev machine in compiled Rust guards, vetting every git invocation for destructive history and policy bypass while containing GTFOBins-class SUID and file-capability binaries behind per-binary policy wrappers.
It then root-locks .git/ trees
and fleet identity files so agents cannot tamper with enforcement, and keeps
a continuous record of the result through GTFOBins baselines, drift checks,
and auditd/AIDE rules.
It is organized into four deployed programs:
/usr/bin/git and execs the real
binary (/usr/bin/git.original, root-only, mode 0700) only after
argument, configuration-key, and environment checks pass. It root-locks
.git/, enforces forward-only history, and delegates hook-based quality
checks to WORKSPACE-CI.workspace-binary-guard at each contained path, exec of <path>.real).~/.gitconfig, ~/.ssh/*, and
declared config globs inside fleet accounts.Program II-B - Sandbox is roadmap: a hardened systemd unit template ships, but the launcher binary that would apply Landlock, seccomp, and namespace isolation is not yet built.
Enforcement rests on three ideas:
--no-verify). git commit --amend is available only to operators via sudo..git/ inside workspace
repos and provisioned-host clones; Program III root-locks user-global
identity files and declared config globs. Locks are not applied to
temporary sandboxes outside these scopes.workspace-yaml-edit binary (sudo make yaml-add /
yaml-remove), which manipulates YAML contents directly while the
files stay root-owned at all times. Files are never released or relocked.Blocks are audited to ~/.workspace-guard.log and /dev/tty. Full policy
detail is in docs/specifications/; operator workflow in
docs/OPERATOR.md.
| Surface | Program | Status | Install |
|---|---|---|---|
| Git wrapper | I - Git Guard | Deployed | sudo make reconcile-guard-host-exec |
| SUID and file-cap binaries | II-A - Binary lock | Deployed | make install-lock |
| Long-running agents under systemd | II-B - Sandbox | Roadmap: unit template shipped, launcher not built | make install-sandbox (unit only) |
| Audit and inventory | II-C + II-D | Deployed | make install-auditd, make sync-gtfobins |
| Home-directory identity files | III - Home lock | Deployed | make install-home-lock |
Programs compose on one host. Each has its own install target, spec, and operational lifecycle.
| Class | Mechanism | Use |
|---|---|---|
host-exec |
File capabilities on /usr/bin/git via setcap |
Primary. Agent dev hosts; IDE terminals do not run PAM login, so ambient caps are unavailable |
sandbox-service |
systemd AmbientCapabilities on workspace-agent@ |
Program II-B runtime only; installed by make install-sandbox, never by git install |
root-only |
BUILD_MODE=root-only in the harness |
CI soft barrier (Podman Tier 2 / PRoot / macOS); no host git guard |
The installed class is recorded at /usr/lib/workspace-guard/deployment-class,
which is the source of truth for drift, check, and runtime. Per-host binding:
config/shared_host_profiles.yaml (hostname -s to class). See
SPEC-GIT-GUARD-DEPLOYMENT.
flowchart TB
subgraph host [Framework dev host]
P1[Program I - Git Guard]
P2A[Program II-A - Binary lock]
P2B[Program II-B - Sandbox]
P3[Program III - Home lock]
end
P1 --> S1["/usr/bin/git"]
S1 --> E1["workspace-guard → git.original"]
P1 --> C1["workspace-yaml-edit operator intents"]
P1 --> C2["ci_integrity: deployed CI content check"]
P2A --> S2["GTFOBins SUID/CAP paths"]
S2 --> E2["workspace-binary-guard → path.real"]
P2B --> S3["[email protected]"]
S3 --> E3["unit template; launcher roadmap"]
P3 --> S4["~/.gitconfig · ~/.ssh/*"]
S4 --> E4["root-owned identity files"]
subgraph ops [Program II - Operations]
P2C[II-C Audit]
P2D[II-D Inventory]
end
P2C --> D1["auditd · AIDE · drift-check"]
P2D --> D2["sync-gtfobins → res/*-baseline.yaml"]
Invariants enforced by the current code:
AT_SECURE), exit code 3.0 success, 1 policy block,
2 infrastructure, 4 contract failure.PATH.-c / --config / --config-env
(config/git_guard_policy_matrix.yaml).RLIMIT_NOFILE clamp on guard children (4096, from
config/git_guard_resource_limits.yaml).git fetch refspecs restricted to ref names; arbitrary URL refspecs are
blocked..git/ ownership lock scoped to workspace repos and clones whose remotes
point at provisioned hosts; everything else is untouched.src/ci_integrity.rs).config/git_ssh_allowlist.yaml).Replaces /usr/bin/git with a Rust guard that enforces repository policy
before delegating to git.original.
Policy scope:
reset, clean, restore, rebase, gc, and related
destructive operations; sudo-gated checkout / submodule; flag gates on
--hard, --no-verify, force push, protected-branch pull/merge; --amend
sudo-gated.-c / --config / --config-env.CAP_DAC_OVERRIDE..git/ ownership lock in host-exec mode, scoped as described in
Security properties.Config lock and CI integrity:
workspace-yaml-edit gives operators sudo-gated add/remove/set/get/list
over root-owned policy YAMLs (*_exceptions.yaml, thresholds, excludes,
gate configs). The guard's glob lock is unconditional; edits happen as
root via atomic, fail-closed transforms (see SPEC-YAML-EDIT).ci_integrity verifies that deployed WORKSPACE-CI mirror content matches
the expected tree, so an agent-modified deployment is detected even when
file ownership still looks correct.| Document | Content |
|---|---|
| SPEC-GIT-GUARD | Policy engine, rules, config keys |
| SPEC-GIT-GUARD-DEPLOYMENT | Install classes, host profiles, drift |
| SPEC-GIT-GUARD-HARDENING | .git lock, capability flow, threat model |
| SPEC-YAML-EDIT | Sudo-gated YAML policy editor |
workspace-binary-guard is built once and installed at each contained path.
At runtime it resolves policy from basename(argv[0]), validates arguments
and environment, and either blocks or execve()s <path>.real. Policies are
compile-time baked from config/binary_guard_policy_rules.yaml and
res/binary-lock.yaml (generated by sync).
Typical dispositions: deny-non-root, deny-all-non-root, arg-validate
(for example sudo, passwd), pass-through for vetted helpers.
config/systemd/[email protected] ships the hardened unit template
(capability bounding set, NoNewPrivileges, seccomp filter, address-family
restriction, PrivateDevices, resource limits), and make install-sandbox
installs it. The unit's ExecStart launcher
(/usr/local/bin/workspace-sandbox-launcher) is not built yet, so the unit
cannot be started. Do not run install-sandbox on IDE-shell hosts.
make sync-gtfobins: fetch GTFOBins and konstruktoid, match live SUID/CAP
surface, emit res/suid-baseline.yaml, res/fcap-baseline.yaml,
res/binary-lock.yaml, res/cve-catalog.yaml.make drift-check: compare live host to committed baselines; exit non-zero
on CRITICAL drift.make install-auditd: deploy config/auditd/99-workspace-guard.rules and
AIDE configuration.| Document | Content |
|---|---|
| SPEC-BINARY-LOCK | Contain-via-guard procedure |
| SPEC-SANDBOX | Profiles and systemd unit |
| SPEC-AUDIT | auditd and integrity monitoring |
| SPEC-CAP-THROTTLE | Capability allowlists |
| RESEARCH-SYSTEM-BINARIES | CVE catalog and layer rationale |
Locks user-global git and SSH identity files by transferring ownership to
root. Agents cannot open ~/.gitconfig or ~/.ssh/authorized_keys for write;
per-repo .git/config is already covered by Program I. Paths and modes are
defined in config/shared_locked_paths.yaml, which declares four categories:
recursive tree paths, recursive tree globs, individual files, and filename
globs.
sudo make install-home-lock
make home-drift-check
| Document | Content |
|---|---|
| SPEC-HOME-LOCK | Install, uninstall, drift |
| REQ-HOME-LOCK | Requirements (REQ-HL-*) |
Recommended on agent dev hosts: one-shot stack (admin break-glass, fleet user hardening, git/SSH identity, guard programs). See SPEC-HOST-PROVISION.
cp config/host-provision.yaml.example config/host-provision.yaml
cp config/home-lock-users.yaml.example config/home-lock-users.yaml
# edit locally; live files are gitignored
sudo make guard-up # idempotent fleet bring-up (from workspace root)
# Or with a chosen admin password:
# export WORKSPACE_ADMIN_PASSWORD='...' && sudo -E make guard-up
# Preflight (read-only): sudo make provision-host-preflight
make guard-check
sudo make install-hooks # root: .git/hooks is root-owned in host-exec
For a guard code change, force a rebuild and reinstall; the plain install is drift-aware and may skip a stale binary:
sudo make reconcile-guard-host-exec
If make build-guard was run as root, target/ is left root-owned and later
agent runs of cargo fail; hand it back with
sudo chown -R "$(id -u):$(id -g)" target/.
Phase 1 of provisioning prints a one-time admin password; phase 2 prompts
for it before phase 3 fleet account setup. Fleet sudo is never modified.
Mandatory audit: RED CRITICAL if a provisioned fleet user exists and has
sudo (group, sudoers, or sudo -l); YELLOW WARN if the user exists
without sudo. Unmanaged direct-root sudoers grants block phase 3 until removed
or acknowledged.
Run from the workspace root; full detail in docs/OPERATOR.md.
| Command | Purpose |
|---|---|
sudo make guard-up |
Idempotent bring-up (provision plus git guard plus shell guard as needed) |
sudo make guard-refresh |
Reinstall after pulling guard code (alias refresh-guard) |
make guard-check |
Read-only health check (git guard plus shell guard) |
sudo make guard-down |
Remove shell guard and git guard (provision state preserved) |
sudo GUARD_PURGE_CONFIRM=1 make guard-reset |
Factory reset then bring-up |
sudo make install-shell-guard |
Install the bash/sh shell guard (also part of guard-up; SPEC-SHELL-GUARD) |
sudo make yaml-add FILE=.. KEY=.. FIELDS=".." |
Append a YAML policy entry |
sudo make yaml-remove FILE=.. KEY=.. FIELDS=".." |
Remove matching YAML policy entries |
sudo make yaml-set FILE=.. KEY=.. VALUE=.. |
Set a YAML policy scalar |
make yaml-list FILE=.. / make yaml-validate FILE=.. |
Print / schema-validate a YAML policy file |
Crate and harness development for WORKSPACE-GUARD itself (not guard install on dev hosts; see Host install).
make check-push # fmt, clippy, check, cargo test, host-provision Podman E2E
make test-shell # bats suite (scripts and helpers)
make test-podman-provision # host-provision E2E only (also in check-push on Linux)
make test-podman-quick # Podman tiers 0-2
make test-podman # + Tier 3 host-exec E2E
make test-qemu-guest # Authoritative host-exec E2E in QEMU guest
cargo build --release
cargo build --release --no-default-features --features root-only
make lint
make sync-gtfobins-linux # Regenerate baselines inside Linux container
macOS hosts use make init and the Podman harness for Linux-kernel tests.
See SPEC-PODMAN-TESTING.
| Area | Requirements | Specifications |
|---|---|---|
| Git guard | REQ-GIT-GUARD | SPEC-GIT-GUARD, SPEC-GIT-GUARD-IMPL, SPEC-GIT-GUARD-DEPLOYMENT |
| System surface | REQ-SANDBOX | SPEC-BINARY-LOCK, SPEC-SANDBOX, SPEC-AUDIT |
| Home lock | REQ-HOME-LOCK | SPEC-HOME-LOCK |
| Shell guard | REQ-SHELL-GUARD | SPEC-SHELL-GUARD |
| Host provision | n/a | SPEC-HOST-PROVISION |
| Podman / QEMU testing | REQ-PODMAN-TESTING | SPEC-PODMAN-TESTING |
Canonical reference sources: docs/references/SOURCES.md.
Internal. Independent AI Labs.