Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
f37df5e
bootstrap: init Go module, project structure, default policy
pietroperona Apr 9, 2026
7ca13ca
chore: add .gitignore, remove binary and DS_Store from tracking
pietroperona Apr 9, 2026
3d53bf6
feat(policy): YAML loader and rule engine with glob/regex matching
pietroperona Apr 9, 2026
6a1e3a8
feat(interception): command normalizer with shell/git/file classifica…
pietroperona Apr 9, 2026
babb72e
feat(audit): JSONL event logger with filter support
pietroperona Apr 9, 2026
bfd4057
feat(daemon): Unix socket server with policy evaluation and audit log…
pietroperona Apr 9, 2026
9a47d2d
feat(shell): zshrc hook injector with idempotent inject/remove
pietroperona Apr 9, 2026
e40b2c6
feat(cli): add init, start, logs, doctor commands
pietroperona Apr 9, 2026
2633ac9
feat(daemon): log each evaluated command to stdout
pietroperona Apr 9, 2026
f1f1181
feat(intercept): DYLD_INSERT_LIBRARIES injection with execve/posix_sp…
pietroperona Apr 9, 2026
4b83dba
feat(shim): PATH shims per interception agnostica dagli agenti
pietroperona Apr 9, 2026
9ece971
feat(launchagent): avvio automatico daemon al login macOS
pietroperona Apr 10, 2026
b670b66
feat(prompt): dialog interattivo ask con sessione/sempre per agente
pietroperona Apr 10, 2026
295f40d
feat(wizard): configurazione policy interattiva durante guardian init
pietroperona Apr 10, 2026
433aade
feat(wizard): UI con ASCII art, colori ANSI e progress bar
pietroperona Apr 10, 2026
f7c831c
feat(policy): comando policy edit con list/toggle/add/remove
pietroperona Apr 10, 2026
0e5422e
docs: README e comando help con UI colorata
pietroperona Apr 10, 2026
9e9c661
release: Cycle 1 MVP
pietroperona Apr 10, 2026
7531024
feat(sandbox): ciclo 2 — Docker sandbox integration
pietroperona Apr 11, 2026
884d56a
Merge branch 'feature/sandbox-cycle2'
pietroperona Apr 11, 2026
a418558
feat(sandbox): profili per progetto e comando reset
pietroperona Apr 11, 2026
14d1446
chore: rinomina progetto in Night Agent
pietroperona Apr 11, 2026
0e24a82
chore: aggiorna stringhe terminale in Night Agent
pietroperona Apr 11, 2026
28f87f3
chore: rinomina directory di sistema ~/.guardian → ~/.night-agent
pietroperona Apr 11, 2026
00108b8
feat(brew): aggiungi formula Homebrew e istruzioni installazione via tap
pietroperona Apr 11, 2026
8e61606
fix(wizard): aggiorna logo e testo con Night Agent
pietroperona Apr 11, 2026
c9c3fa4
fix(brew): rimuovi placeholder bottle — build da sorgente
pietroperona Apr 11, 2026
45c930b
fix(wizard): sostituisci logo con design compatto e leggibile
pietroperona Apr 11, 2026
04be255
fix(wizard): logo stacked NIGHT/AGENT — stessa larghezza di FORTIFY
pietroperona Apr 11, 2026
056aa97
refactor: rinomina binario CLI da night-agent/guardian a nightagent
pietroperona Apr 11, 2026
d27ff55
feat(cycle3): risk scoring euristico, anomaly detection, policy sugge…
pietroperona Apr 12, 2026
e2f3861
fix(ui): aggiungi divisore tra logo e subtitle nel terminale
pietroperona Apr 12, 2026
683702e
fix(ui): correggi logo help — era FORTIFY, ora NIGHT AGENT
pietroperona Apr 12, 2026
3286c5c
docs: documenta --json risk fields e test manuale scorer
pietroperona Apr 12, 2026
3d4aa5a
docs: rimuovi roadmap, elimina riferimenti a cicli numerati
pietroperona Apr 12, 2026
a219642
feat: signed audit trail + MCP hook per Claude Code
pietroperona Apr 13, 2026
8832823
feat: catena hash blockchain-like su audit trail + docs MCP e signed …
pietroperona Apr 13, 2026
15c3858
docs: aggiorna MVP plan — cicli 1-4 completati, ciclo 5 (dashboard) e…
pietroperona Apr 13, 2026
0bfe2be
feat(cloud): sync agent locale + CLI cloud connect/status/disconnect
pietroperona Apr 13, 2026
77be334
test(cloudconfig): aggiunge 8 test TDD per Load/Save/Connect/Disconne…
pietroperona Apr 13, 2026
c5135f7
fix(mcp-hook): legge tool_name e tool_input da stdin — Claude Code no…
pietroperona Apr 13, 2026
553bef1
feat(init): configura hook Claude Code automaticamente se Claude Code…
pietroperona Apr 13, 2026
e416075
feat(cloud): endpoint iniettato a compile time via ldflags
pietroperona Apr 14, 2026
96dc8fe
fix(audit): action_type e agent_name sempre popolati negli eventi
pietroperona Apr 14, 2026
24d269b
feat(daemon): sync cloud automatico ogni 30s + fix audit + sandbox /tmp
pietroperona Apr 14, 2026
b79a3b1
feat(configdir): config per directory + policy cloud + flag --global
pietroperona Apr 14, 2026
54790a3
docs: aggiunge sezione configurazione per progetto
pietroperona Apr 14, 2026
82d4c33
fix(start): valida policy cloud prima di scriverla, fallback se non v…
pietroperona Apr 14, 2026
7ce1416
feat(policy): hot-reload + priorità cloud/locale/globale + --local-po…
pietroperona Apr 14, 2026
2df4ced
docs: aggiunge hot-reload, priorità policy e --local-policy-only
pietroperona Apr 14, 2026
5dc4051
fix(run): tutti i comandi usano resolveConfigDir() — no più path hard…
pietroperona Apr 14, 2026
1edcae9
feat(sync): includi policy_yaml nel payload ingest quando sorgente lo…
pietroperona Apr 14, 2026
2b78d99
feat(policy): polling cloud ogni 60s in Watch per aggiornamenti polic…
pietroperona Apr 15, 2026
46c7f59
Policy YAML docs
pietroperona Apr 15, 2026
0e25946
feat(security): policy tamper protection — daemon-owned writes
pietroperona Apr 16, 2026
56e3760
feat(security): chflags uchg lock su policy file
pietroperona Apr 16, 2026
7c3f55b
feat(security): lock workdir policy file al momento della creazione
pietroperona Apr 16, 2026
2e26ccd
feat(dist): curl install script + GitHub Actions release workflow
pietroperona Apr 24, 2026
9bc5157
feat(dist): migrazione org night-agent-cli — aggiorna tutti i riferim…
pietroperona Apr 25, 2026
c9ed6cf
docs: riscrittura README — struttura utente-first, fix binary name, r…
pietroperona Apr 30, 2026
e11fa3b
Change project title and update platform support details
pietroperona Apr 30, 2026
e49ac7b
Fix formatting in README description
pietroperona Apr 30, 2026
c714e58
fix(security): mcp-hook fail-closed quando daemon non risponde
pietroperona Apr 30, 2026
1308986
fix(security): mcp-hook fail-closed quando daemon non risponde
pietroperona Apr 30, 2026
36e8041
feat(audit): remote signing con fallback locale
pietroperona Apr 30, 2026
85f0b4e
feat(audit): remote signing — chiave HMAC server-side per eventi audit
pietroperona Apr 30, 2026
2af0fb3
fix(config): endpoint dal YAML se presente, altrimenti compilato; fix…
pietroperona Apr 30, 2026
455fefb
tested on windows and linux
anywayzz Apr 30, 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
54 changes: 54 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Release

on:
push:
tags:
- 'v*'

permissions:
contents: write

jobs:
release:
runs-on: macos-latest # arm64 (Apple Silicon)
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true

- name: Build
run: make all

- name: Package
run: |
VERSION="${GITHUB_REF_NAME}"
ARCHIVE="night-agent-${VERSION}-darwin-arm64.tar.gz"

mkdir -p dist
cp nightagent guardian-shim guardian-intercept.dylib dist/
cp -r configs dist/

tar -czf "${ARCHIVE}" -C dist .
shasum -a 256 "${ARCHIVE}" | awk '{print $1}' > "${ARCHIVE}.sha256"

echo "ARCHIVE=${ARCHIVE}" >> "$GITHUB_ENV"
echo "VERSION=${VERSION}" >> "$GITHUB_ENV"

- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
if gh release view "${VERSION}" &>/dev/null; then
gh release upload "${VERSION}" "${ARCHIVE}" "${ARCHIVE}.sha256" --clobber
else
gh release create "${VERSION}" \
--title "Night Agent ${VERSION}" \
--generate-notes \
"${ARCHIVE}" \
"${ARCHIVE}.sha256"
fi
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Binaries (solo root, non directory col nome)
/nightagent
/night-agent
/guardian
/guardian-shim
/guardian-intercept.dylib

# macOS
.DS_Store

# Go
*.test
*.out
/vendor/

# Night Agent config locale
.nightagent/

# Documenti privati (non versionati)
docs/private/
135 changes: 86 additions & 49 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,106 +4,143 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project Overview

**AI Guardian** è un CLI tool per macOS che funge da runtime security layer per agenti AI (Claude Code, Codex, ecc.). Intercetta e governa le azioni degli agenti prima che vengano eseguite. Il progetto è attualmente in fase di pianificazione/design — il codice è ancora da scrivere.
**Night Agent** è un CLI tool per macOS che funge da runtime security layer per agenti AI (Claude Code, Codex, ecc.). Intercetta e governa le azioni degli agenti prima che vengano eseguite.

Documento di specifica completo: [docs/ai-agent-guardian-mvp-plan.md](docs/ai-agent-guardian-mvp-plan.md)
Documento di specifica completo: [docs/ai-night-agent-mvp-plan.md](docs/ai-night-agent-mvp-plan.md)

## Tech Stack Pianificato
**Stato attuale: Cycle 1 ✅ + Cycle 2 ✅ + Cycle 3 ✅**

- **Linguaggio**: Go (single binary, process handling, cross-platform)
## Tech Stack

- **Linguaggio**: Go (single binary) + C (shim + dylib)
- **Config**: YAML
- **Logging**: SQLite o JSONL
- **Packaging**: Homebrew tap
- **Sandbox (Cycle 2)**: Docker Desktop
- **Logging**: JSONL
- **Sandbox**: Docker Desktop (Cycle 2)
- **Packaging**: Homebrew tap (futuro)

## Struttura del Progetto

```
cmd/guardian/ CLI principale (Cobra) — init, run, start, logs, policy, doctor, sandbox, uninstall
internal/
policy/ Policy engine — load/evaluate YAML, glob/regex matching, SandboxConfig
audit/ Audit logger — JSONL append-only, filtri decision/action_type, campi sandbox + risk
daemon/ Unix socket server — valuta policy, gestisce sandbox Docker, routing decisioni
sandbox/ Sandbox manager — docker run wrapper, resolveDockerBinary, BuildDockerArgs
scorer/ Risk scorer — heuristics pesate, anomaly burst detection (Cycle 3)
suggestions/ Policy suggestion engine — hints contestuali su path, override, anomalie (Cycle 3)
shim/ PATH shim — CreateSymlinks, ShimmedCommands (include python/python3)
intercept/ DYLD injection — per agenti senza Hardened Runtime
interception/ Normalizer — classifica comandi in shell/git/file
shell/ Hook injector — preexec in .zshrc, gestisce block + sandbox response
wizard/ Setup wizard — UI ASCII art + progress bar
policyeditor/ Policy CRUD — toggle/add/remove rules
launchagent/ LaunchAgent macOS — autostart al login
configs/
default_policy.yaml Policy di default con regole Cycle 1 + Cycle 2 (sandbox)
```

## Architettura — 5 Layer Logici

```
Agente AI
[Interception Layer] ← cattura shell commands, file ops, git ops, processi
[Interception Layer] ← PATH shims + DYLD injection + shell hook preexec
[Policy Engine] ← valuta regole YAML → decisione: allow / block / ask / sandbox
[Policy Engine] ← valuta regole YAML → allow / block / ask / sandbox
[Execution Layer] ← esegue azioni approvate (locale o isolato)
[Execution Layer] ← locale (allow) · bloccato (block) · Docker isolato (sandbox)
[Audit Layer] ← log con timestamp, decisione, motivo, contesto
[Audit Layer] ← JSONL con campi sandbox (sandboxed, sandbox_image, sandbox_exit_code)
[Config & UX Layer] ← CLI per init, logs, policy edit, approve
[Config & UX Layer] ← CLI completo
```

## CLI Commands Pianificati
## CLI Commands Implementati

```bash
guardian init # Inizializza progetto con policy di default
guardian run # Esegue agente con protezione attiva
guardian logs # Visualizza audit trail
guardian policy edit # Modifica regole di policy
guardian doctor # Diagnostica e verifica setup
guardian sandbox run # Esegue in container isolato (Cycle 2)
nightagent init [--yes] # Setup + wizard policy
nightagent start # Avvia daemon (Unix socket)
nightagent run <agente> # Avvia agente con interception attiva
nightagent sandbox run <cmd> # Esegui comando in Docker sandbox (Cycle 2)
--image <img> # Immagine Docker (default: alpine:3.20)
--network <net> # Rete: none (default) o bridge
nightagent logs [--decision] [--type] [--limit] [--json]
nightagent policy list|toggle|add|remove
nightagent doctor # Check installazione + Docker status
nightagent uninstall
nightagent help
```

## Policy Model

```yaml
version: 1
rules:
- id: block_sudo
when: {action_type: shell, command_matches: ["sudo *"]}
match_type: glob
decision: block
reason: "sudo disabled"

- id: ask_git_push_main
when: {action_type: git, command_matches: ["git push origin main"]}
decision: ask
reason: "push to protected branch"
reason: "sudo disabilitato"

- id: sandbox_python_scripts
when: {action_type: shell, command_matches: ["python3 *.py"]}
match_type: glob
decision: sandbox
sandbox:
image: "python:3.12-alpine"
network: "none"
reason: "script Python in ambiente isolato"
```

Decisioni possibili: `allow`, `block`, `ask`, `sandbox`
Decisioni: `allow`, `block`, `ask` (= block a runtime), `sandbox`

## Comportamento Sandbox (Cycle 2)

Quando il policy engine restituisce `sandbox`:

1. Il daemon verifica che Docker sia disponibile (`resolveDockerBinary` — cerca anche in path fissi macOS)
2. Avvia `docker run --rm --network <net> -v <workdir>:/workspace:rw -w /workspace <image> sh -c <cmd>`
3. I path host nel comando vengono riscritti (`workdir` → `/workspace`)
4. Cattura stdout/stderr/exit code
5. Restituisce risposta `{"decision":"sandbox","exit_code":N,"output":"..."}` al shim
6. Il shim stampa `[⬡ sandbox] <cmd> — <reason>` su stderr e propaga l'exit code
7. L'evento viene loggato con `sandboxed: true`, `sandbox_image`, `sandbox_exit_code`

Fail-safe: se Docker non è disponibile → blocca con messaggio esplicito.

## Roadmap

- **Cycle 1 (MVP)**: Policy engine rule-based, intercettazione shell + git, audit log
- **Cycle 2**: Docker sandbox integration, network isolation
- **Cycle 3**: Risk scoring, anomaly detection, policy suggestions
- **Cycle 1** ✅ — Policy engine, PATH shims, DYLD, shell hook, audit log, LaunchAgent
- **Cycle 2** ✅ — Docker sandbox, `nightagent sandbox run`, routing automatico, path rewriting
- **Cycle 3** ✅ — Risk scorer (heuristics), anomaly detection, policy suggestions, risk score in logs

## Repository & Git Workflow

- **Remote**: [github.com/pietroperona/agent-guardian](https://github.com/pietroperona/agent-guardian)
- **Branch principali**:
- `main` — produzione, solo merge da feature branch o staging
- `develop` — sviluppo locale
- `staging` — ambiente di staging (futuro)
- **Feature branch**: ogni funzione specifica ha il suo branch (`feature/nome`), poi merge su `main`
- **Remote**: [github.com/night-agent-cli/night-agent](https://github.com/night-agent-cli/night-agent)
- **Branch principali**: `main` (produzione), `develop`
- **Commit**: non citare mai il nome di strumenti AI nei messaggi di commit

## Approccio di Sviluppo — TDD

Tutto lo sviluppo segue **Test-Driven Development**:

1. Scrivi il test che descrive il comportamento atteso (red)
1. Scrivi il test (red)
2. Scrivi il codice minimo per farlo passare (green)
3. Refactoring se necessario (refactor)

In Go, ogni package ha il suo file `_test.go`. Eseguire i test con:
3. Refactoring se necessario

```bash
go test ./... # tutti i test
go test ./internal/policy # test di un package specifico
go test ./... # tutti i test
go test ./internal/sandbox/... # solo sandbox
go test -run TestNomeFunzione ./... # singolo test
make # build completo (dylib + shim + nightagent)
```

## Principi di Design Fondamentali

1. Controlla **azioni**, non intenzioni
2. **Determinismo** prima di intelligenza — no ML per decisioni hard
3. **Explainability** — l'utente deve sempre capire perché qualcosa è bloccato
4. **Safe failure mode** — in caso di errore del guardian, blocca (non permette)
4. **Safe failure mode** — in caso di errore, blocca (non permette)
5. Security by default, friction minimale
6. Framework-agnostic — funziona con qualsiasi agente AI

## Superfici da Proteggere (Scope MVP)

- Shell commands pericolosi (`rm -rf`, `curl | bash`, `chmod 777`, ecc.)
- File operations su path sensibili (`~/.ssh`, `~/.aws`, `.env`)
- Git operations (`git push --force`, push su main/master)
- Installazione package/processi non autorizzati
76 changes: 76 additions & 0 deletions Formula/night-agent.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
class NightAgent < Formula
desc "Runtime security layer for AI agents on macOS"
homepage "https://github.com/night-agent-cli/night-agent"
url "https://github.com/night-agent-cli/night-agent/archive/refs/tags/v0.2.2.tar.gz"
sha256 "0019dfc4b32d63c1392aa264aed2253c1e0c2fb09216f8e2cc269bbfb8bb49b5"
license "MIT"
head "https://github.com/night-agent-cli/night-agent.git", branch: "main"

depends_on "go" => :build
depends_on :macos

def install
# Compila il binario principale Go
system "go", "build", "-o", bin/"nightagent", "./cmd/guardian"

# Compila lo shim C (intercettazione comandi via PATH)
system "clang", "-o", libexec/"guardian-shim",
"internal/shim/csrc/guardian_shim.c",
"-Wall", "-Wextra", "-Wno-unused-parameter"

# Compila la dylib DYLD_INSERT_LIBRARIES (opzionale, per intercettazione avanzata)
system "clang", "-dynamiclib",
"-o", lib/"guardian-intercept.dylib",
"internal/intercept/csrc/guardian_intercept.c",
"-Wall", "-Wextra", "-Wno-unused-parameter",
"-current_version", "1.0",
"-compatibility_version", "1.0"

# Installa la policy di default
pkgshare.install "configs"

# Crea symlink per lo shim nella libexec
(libexec/"shims").mkpath
end

def post_install
# Copia la policy di default se non esiste già
guardian_dir = Pathname.new(ENV["HOME"]) / ".night-agent"
policy_dest = guardian_dir / "policy.yaml"
policy_src = pkgshare / "configs" / "default_policy.yaml"

unless policy_dest.exist?
guardian_dir.mkpath
FileUtils.cp policy_src, policy_dest
policy_dest.chmod(0600)
end
end

def caveats
<<~EOS
Night Agent è stato installato. Per completare la configurazione:

1. Inizializza Night Agent:
nightagent init

2. Per le funzionalità sandbox, installa Docker Desktop:
https://www.docker.com/products/docker-desktop/
Avvialo almeno una volta manualmente dopo l'installazione.

3. Riavvia il terminale o esegui:
source ~/.zshrc

Per verificare che tutto funzioni:
nightagent doctor
EOS
end

test do
# Test che il binario risponde correttamente
output = shell_output("#{bin}/nightagent --help")
assert_match "nightagent", output

# Test che la policy di default è accessibile
assert_predicate pkgshare / "configs" / "default_policy.yaml", :exist?
end
end
Loading