Skip to content

sugiyama34/cc_harness

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Claude Code Harness

A reusable set of hooks, scripts, and guardrails for running Claude Code safely and autonomously β€” including under auto mode β€” in private repositories.

Overview

Features

The following harness features are currently built in:

  1. Secret commit prevention
  2. git commit --no-verify prevention
  3. Command execution via allowlist
  4. Bulk git add prevention (., -A, --all)
  5. Destructive git guard (force push, push to main/master, gh pr merge --admin)
  6. Tool-call audit log (allowed calls + auto-mode classifier denials)

Supporting Skills

The following three skills are configured so that Claude Code can invoke them automatically:

  1. /lock-settings: Register files that should be locked from modification
  2. /report-hook-block: Open an Issue when command restrictions are too strict
  3. /report-doc-conflict: Open an Issue when markdown files contradict each other

Design Principles

This harness is built on the following design principles:

  1. Development Automation: Claude Code handles tasks autonomously, including under auto mode
  2. Secret Protection: Secrets must never be read or pushed
  3. Never-events, not perfection: High friction on catastrophic actions (force push, push to main, admin merge, secret reads); low friction elsewhere
  4. Defense in depth: Every never-event is covered by at least one mechanism independent of the auto-mode classifier
  5. Thorough Reviews: PR reviews are performed carefully by humans
  6. Private Repository: Designed for use in private repositories (PRs serve as the last line of defense; the design does not guarantee 100% prevention of secret commits and pushes)

See ADR-001 for the full rationale behind the layered defense model.

Features

This harness lets Claude Code use a wide range of shell commands β€” but strictly on an allowlist basis, paired with OS-level sandboxing and hook-based checks. Nothing runs unless you explicitly permit it, and every permitted command must have its exact usage defined.

The harness provides multiple layers of protection so Claude Code can operate under auto mode with minimal manual intervention:

  • Enforced command allowlist β€” The core design. When you authorize a command in settings.json, the test suite (settings_allowlist_sync.bats) will fail unless you also define exactly how that command may be used in the allowlist (command-allowlist.sh). Permitted usage is filtered with regular expressions. Compound commands (cmd1 && cmd2 | cmd3) are split and each segment validated independently so you cannot chain an approved command with an unapproved one.
  • Destructive git guard β€” Blocks force push (--force, -f, --force-with-lease, +refspec), direct push to main/master (explicit or via current branch), gh pr merge --admin, and bulk git add ./-A/--all. Fails closed on shell wrappers (bash -c, eval) carrying destructive tokens.
  • Secret leak prevention β€” Git pre-commit hook scans staged diffs for API keys, tokens, and credentials. A Claude Code PreToolUse hook blocks commits with sensitive filenames staged. Permissions deny and sandbox denyRead block reads of common secret locations (.env, *.pem, *.key, ~/.aws, ~/.kube, ~/.netrc, etc.) before Claude Code can even stage them for leak.
  • Hook bypass prevention β€” Blocks --no-verify and similar flags that would skip safety checks.
  • File protection β€” Security-critical files (hooks, settings, scripts/install-hooks.sh, .github/workflows/**, tests/hooks/**) are locked via permission deny rules and OS-level sandbox denyWrite globs.
  • Audit log β€” A PostToolUse hook appends every allowed tool call (command / file path / URL) to docs/logs/audit/YYYY-MM-DD.jsonl (gitignored); a PermissionDenied hook records auto-mode classifier denials. File contents and command output are not captured, to bound secret leakage into the log.
  • PR-based review workflow β€” All changes go through pull requests with automated Claude Code review.

Usage

1. Clone this template

git clone https://github.com/<your-org>/cc_harness.git my-project
cd my-project

2. Rewrite CLAUDE.md for your project

CLAUDE.md is the file Claude Code reads to understand your project. Open it and fill in the placeholder sections β€” project overview, tech stack, and any project-specific conventions. The harness-related sections (hooks, git workflow, error messages) are already set up and can be kept as-is or adjusted to fit your needs.

3. Install prerequisites

# macOS
brew install jq bats-core

# Debian / Ubuntu
sudo apt-get update && sudo apt-get install -y jq bats

4. Set up git hooks

./scripts/install-hooks.sh

5. Verify the setup

bats tests/hooks/

6. Start building

Create a feature branch and start working. The harness hooks and CI workflows will protect you from there.

Directory Structure

.claude/
  hooks/                 Claude Code hook scripts
    lib/
      shell-parse.sh       Shared parser: split compound commands on unquoted operators
    block-no-verify.sh     PreToolUse: block --no-verify flag on git commit
    block-add-all.sh       PreToolUse: block `git add .`, `-A`, `--all`
    block-dangerous-git.sh PreToolUse: block force push, push to main/master, `gh pr merge --admin`
    command-allowlist.sh   PreToolUse: regex-based command allowlist with compound splitting
    prevent-secret-commit.sh  PreToolUse: block commits with sensitive filenames staged
    log-tool-call.sh       PostToolUse: append allowed tool calls to the audit log
    log-permission-denied.sh  PermissionDenied: append classifier denials to the audit log
  skills/                Claude Code skill definitions
    lock-settings/         Lock security-critical files from modification
    report-doc-conflict/   Report contradictory documentation as GitHub Issues
    report-hook-block/     Report overly restrictive hook blocks as GitHub Issues
  settings.json          Permissions, sandbox rules, and hook registration
.githooks/
  pre-commit             Scans staged diffs for secret patterns
.github/workflows/
  claude.yml             Claude Code agent (responds to @claude mentions)
  claude-code-review.yml Automated PR review via Claude Code
  hook-tests.yml         CI for hook test suite
scripts/
  install-hooks.sh       Configures git core.hooksPath
tests/hooks/             Bats-core test suite for all hooks
docs/adr/                Architecture Decision Records
  001-auto-mode-harness-defense-in-depth.md β€” layered defense for auto mode
docs/logs/audit/         Gitignored JSONL log of tool calls (written by PostToolUse hook)
CLAUDE.md                Project instructions for Claude Code (rewrite for your project)

How It Works

Command Allowlist: Authorize, Then Define

This is the central mechanism of the harness. The workflow is:

  1. Authorize a command β€” Add Bash(<command>:*) to permissions.allow in settings.json. This tells Claude Code it may use the command.
  2. Define allowed usage β€” Add the command prefix to GOVERNED_PREFIXES and regex patterns for its permitted forms to ALLOWED_PATTERNS in command-allowlist.sh. This controls how the command can be used.
  3. Tests enforce the link β€” settings_allowlist_sync.bats verifies that every authorized command has a governed prefix and at least one allowed pattern. If you add a permission without defining its usage, tests fail.

For example, to allow gh pr create but not gh pr merge --admin:

# settings.json β€” authorize the "gh pr" command family
"Bash(gh pr:*)"

# command-allowlist.sh β€” define exactly which forms are allowed
'^gh pr (create|checkout|comment|edit|ready)( |$)'

Compound commands (cmd1 && cmd2 | cmd3) are automatically split, and each segment is validated independently. This prevents bypassing the allowlist by chaining an approved command with an unapproved one.

Defense in Depth

Four layers, from softest to hardest (per ADR-001):

Layer Mechanism Role
1 autoMode.environment (prose in settings.local.json) Tells the auto-mode classifier what's trusted. Not enforceable β€” prompt injection can reframe intent.
2 permissions.allow / ask / deny Hard rules on tool calls. deny is evaluated before the classifier and cannot be bypassed by conversation.
3 sandbox.filesystem (denyRead / denyWrite / network allowlist) OS-level enforcement via Seatbelt / bubblewrap. Applies to every Bash subprocess, not only Claude's built-in tools.
4 PreToolUse / PostToolUse / PermissionDenied hooks Regex-based checks and observability. Can parse argument content that permission-rule globs cannot.

Every "never-event" (force push, push to main, gh pr merge --admin, reads of secret paths, edits to locked files) is covered by at least one mechanism independent of the auto-mode classifier.

Per-concern mapping for this repo:

What it guards Mechanism
Every Bash command Claude Code runs PreToolUse: command-allowlist.sh, block-no-verify.sh, block-add-all.sh, block-dangerous-git.sh, prevent-secret-commit.sh
Every git commit (by any user or agent) Git pre-commit: diff content scan for secret patterns
Security-critical files permissions.deny + sandbox denyWrite globs
Secret file reads permissions.deny + sandbox denyRead globs
Observability PostToolUse + PermissionDenied β†’ docs/logs/audit/YYYY-MM-DD.jsonl

CI Workflows

  • hook-tests.yml β€” Runs bats tests/hooks/ on PRs that touch hooks, settings, or tests.
  • claude-code-review.yml β€” Automated code review on every PR using Claude Code.
  • claude.yml β€” Claude Code agent that responds to @claude mentions in issues and PRs.

License

MIT

About

My harness for Claude Code

Resources

License

Stars

19 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages