Skip to content

dev → main: v0.1.0 governance hardening, Phase 2 daemon, e2e showcase, dependabot bumps#17

Open
gnanirahulnutakki wants to merge 351 commits into
mainfrom
dev
Open

dev → main: v0.1.0 governance hardening, Phase 2 daemon, e2e showcase, dependabot bumps#17
gnanirahulnutakki wants to merge 351 commits into
mainfrom
dev

Conversation

@gnanirahulnutakki

@gnanirahulnutakki gnanirahulnutakki commented May 26, 2026

Copy link
Copy Markdown
Member

Summary

Promotes dev to main with 81 commits. This is the full v0.1.0 hardening cycle that brings all governance features from development into the release branch.

Governance & Policy Engine

  • MIC-State / MIC-Evidence conformance — manifest digests, envelope signatures, visibility checks, hidden-hop detection
  • Multi-backend composition — native, Cedar DSL, forbid_rules with deny-wins semantics
  • Declared telemetry (B.2 fail-closed) — missing fields → INSUFFICIENT_EVIDENCE
  • Delegation replay hardening
  • Biscuit auth + bearer token enforcement

Proxy Surface

  • TLS support, kill switch, rate limiting
  • Prometheus metrics/metrics endpoint
  • Health + JWKS endpoints

Phase 2 Daemon

  • Unix socket server with accept loop
  • Peer credential retrieval + handshake contract
  • Launch-wrapper session proof seam
  • eBPF process exec/exit capture MVP
  • Cgroup allowlist filter + daemon custody scaffold

Claude Code & Gemini Integration

  • Claude Code hook plugin (PreToolUse/PostToolUse with chained receipts)
  • Gemini CLI hook with telemetry
  • Posture detector (read-only Claude Code posture)

Testing

  • E2E showcase — 28 tests across 7 layers using real Ollama
  • Phase 1 + 2 adversarial test suites
  • RWT harness gate — real-world testing harness
  • Coverage tests for log_rotation, backed_policy_store

Dependabot bumps

  • Go: cilium/ebpf, k8s.io/*, controller-runtime, cedar-go
  • Docker: python 3.13→3.14, spire-agent
  • CI: setup-go, setup-python, checkout, cache, codeql-action

Test plan

  • Python: 659 passed, 21 skipped
  • Go: all tests pass
  • E2E showcase: 28/28 passing

🤖 Generated with Claude Code

Comment thread python/tests/test_e2e_showcase.py Fixed
Comment thread python/tests/test_e2e_showcase.py Fixed
Comment thread python/tests/test_e2e_showcase.py Fixed
Comment thread python/tests/test_e2e_showcase.py Fixed
Comment thread python/tests/test_e2e_showcase.py Fixed
Comment thread python/tests/test_e2e_showcase.py Fixed
Comment thread python/tests/test_e2e_showcase.py Fixed
Comment thread python/tests/test_e2e_showcase.py Fixed
Comment thread python/tests/test_e2e_showcase.py Fixed
gnanirahulnutakki added a commit that referenced this pull request May 26, 2026
…o/sigs.k8s.io/controller-runtime-0.24.0

deps(go)(deps): bump sigs.k8s.io/controller-runtime from 0.23.3 to 0.24.0 in /go
@gnanirahulnutakki gnanirahulnutakki changed the title dev → main: e2e showcase, dependabot bumps, controller-runtime update dev → main: v0.1.0 governance hardening, Phase 2 daemon, e2e showcase, dependabot bumps May 26, 2026
Comment thread python/vibap/gemini_cli_hook.py Fixed
Comment thread python/vibap/codex_app_server_fixture.py Fixed
Comment thread python/vibap/proxy.py Fixed
Comment thread python/vibap/gemini_cli_hook.py Fixed
Comment thread python/vibap/codex_app_server_fixture.py Fixed
Comment thread python/tests/test_gemini_cli_hook.py Fixed
Comment thread python/tests/test_examples_governance_integration.py Fixed
Comment thread python/tests/test_examples_governance_integration.py Fixed
Comment thread python/tests/test_examples_governance_integration.py Fixed
Comment thread python/tests/test_examples_governance_integration.py Fixed
Comment thread python/vibap/proxy.py Fixed
Comment thread python/vibap/mcp_gateway.py Fixed
Comment thread python/vibap/mcp_gateway.py Fixed
Comment thread python/vibap/proxy.py Fixed
Comment thread python/vibap/claude_code_hook.py Fixed
Comment thread python/tests/test_mcp_gateway.py Fixed
Comment thread python/tests/test_mcp_gateway.py Fixed
Comment thread python/tests/test_mcp_gateway.py Fixed
Comment thread python/tests/test_content_safety.py Fixed
Comment thread python/tests/test_content_safety.py Fixed
Comment thread scripts/generate_adversarial_scoreboard.py Fixed
Comment thread python/vibap/gemini_cli_hook.py Fixed
Comment thread python/vibap/passport.py Fixed
Comment thread python/vibap/proxy.py Fixed
Comment thread python/vibap/proxy.py Fixed
Comment thread go/pkg/kernelcapture/daemon_session_status_evidence_log_entry.go Fixed
gnanirahulnutakki and others added 19 commits July 3, 2026 09:31
…dation

Document the empty, whitespace-only, and traversal-escaping path
rejection behavior landed at commit 500bd5a. Update both
docs/reference/cli.md and the Hugo source mirror to reflect the
current CLI contract: JSON error shape, detail field, human output,
and explicit non-claims.
… suggestion

ardur profile init --path /dev/null (or any existing non-regular file:
device files, FIFOs, sockets) previously returned a misleading
profile_exists condition with a destructive --force suggestion.

Add a non-regular-file check between the directory check and
FileExistsError in write_profile_template() so these paths are rejected
with profile_path_invalid instead. Regular-file profile_exists behavior
and --force semantics are unchanged.

Two regression tests added: library-level InvalidProfilePathError for
FIFOs and CLI JSON response contract for non-regular files.
Design deep-dive on the auto-detection plan's §4.1 seam: which mission
governs an agent nobody launched under 'ardur run'. Proposes the AG-0..AG-4
governance posture ladder (observe-first, identity-bound, operator-promoted),
synthesized shadow baselines structurally barred from enforcing, the operator
agent-binding registry with load-time dry-run lowering validation, two-claim
verifier semantics (mission vs class-policy compliance), and the composition
contract with lower_to_bpf_policy_plan/apply_policy. Web-verified survey of
EDR / zero-trust / allowlisting precedent for policy on unmanaged workloads.
Research document only; no code changed.
…wdStrike tax) (#117)

Net-new Epic B research lane: the cost and reliability budget of always-on
host-wide agent detection. Covers (1) eBPF exec-tracing overhead on every
host exec with web-verified incumbent numbers (Tetragon 1.68%/2.46% worst
case, Falco 2-5% / 431-millicore baseline, CrowdStrike <=1% claim); (2) the
FP/FN budget with the McAfee 2010 and CrowdStrike 2024 enforce-on-error
outages as the FP-cost anchor and Phantom Attack (CVE-2021-33505) as the FN
anchor; (3) fail-safe posture (observe, never enforce, on uncertainty); and
(4) eight concrete SLOs the Epic B slices (B1/B2/B5/B8) are held to.

Does not duplicate the detection/fingerprinting/policy lanes in the roadmap
plan (PR #114) -- it supplies the numeric budget those docs defer to.
Mirror the three Epic B docs merged in #114/#116/#117 (docs/roadmap +
docs/research) into site/content/source and refresh source_routes.json, so the
Validate-and-build-Hugo-site source-sync check passes on dev. Mechanical
regeneration via site/scripts/sync_source_docs.py; no content changes.
…#108/#109/#110) (#115)

* fix(enforce): close the enforcement-surface authz + stale-policy findings

Closes the three vulns filed against the merged BPF-LSM enforcement surface.

#108 (missing authorization / IDOR):
- apply_policy and set_kill_switch now receive the peer handshake.
- apply_policy resolves the session via the new
  DaemonSessionRegistry.ActiveSessionForPeer, which requires the caller to OWN
  the session (same UID/GID/PID/start-time/cred-source recorded at register) —
  the same gate end_session/session_status already enforced.
- set_kill_switch (global, fail-open) is gated to a uid-0 admin peer, not any
  allowlisted UID, so a sandboxed workload can't disable enforcement host-wide.
- register_session now verifies the client-supplied root_pid is a descendant of
  the registering peer (namespace-robust /proc ancestry), so a peer can only
  register process trees it spawned — it cannot bind a session to another
  workload's cgroup. A literal /proc/<peer>/cgroup inode match is intentionally
  not used: the launcher adopts the agent child into the cgroup (it isn't in it
  itself) and cgroup namespaces make the inode unresolvable across the daemon
  boundary — that check would reject the verified `ardur run` flow.

#109 (stale policy state):
- ApplyPolicyMaps clears the inactive double-buffer op slot before writing, so
  a rule from two generations ago can't survive the flip.
- New DeleteAllowlistEntries; the daemon tracks applied path/net allowlist
  entries per session and revokes the dropped ones on re-apply and releases all
  on session end / expiry (the allowlist maps are not double-buffered).

#110 (double-buffer race):
- daemon-wide applyMu serializes ApplyPolicyMaps / RemovePolicyMaps /
  SetKillSwitch (applyMu acquired outside mu; no lock-order inversion).

Tests: foreign-peer apply_policy rejected; set_kill_switch admin-gated;
inactive-slot cleared; allowlist revoked on re-apply + session end;
concurrent applies serialized (‑race); Linux /proc ancestry check. Verified
on a real BPF-LSM kernel that `ardur run --enforce` still blocks (EPERM) +
attests + verifies offline, and that a foreign peer's apply_policy is rejected
at the socket. Refs #63.

* fix(enforce): inject the register cgroup verifier so daemon-flow tests can stub it

The Linux register-time ancestry check rejected existing daemon tests that
register synthetic root_pids (which aren't real /proc descendants) — darwin's
stub masked it. Make the verifier an injected daemon field: production wires
verifyRegisterSessionCgroup, newTestDaemon substitutes a no-op. The real check
stays covered directly by daemon_cgroup_verify_linux_test.go.

* fix(enforce): skip register ancestry check for root peers

A root (uid 0) peer is already fully privileged (it can move processes between
cgroups directly), so the register-time root_pid-ancestry check adds nothing
against it — its purpose is constraining NON-root allowed peers (the sandboxed-
workload spoofing threat). Skipping root also unblocks tiers that register a
placeholder root_pid: the seccomp tier enforces per-shim'd-process (not by
cgroup) and its smoke registers root_pid=1, which a root daemon+client must be
able to register. Per-session ownership on apply_policy still applies to every
peer regardless of uid.
developers.redhat.com and medium.com return 403 Forbidden to the
lychee link checker. Both URLs are legitimate research citations in
the Epic B docs. Excluding the domains rather than removing the
references.
developers.redhat.com, medium.com, and answers.uillinois.edu return
403 Forbidden to the lychee link checker. All URLs are legitimate
research citations in the Epic B docs. Excluding the domains rather
than removing the references. Also regenerates the Hugo source mirror.
developers.redhat.com, medium.com, answers.uillinois.edu, and
theregister.com return 403 Forbidden to the lychee link checker from
GitHub Actions IPs. All URLs are legitimate research citations in
the Epic B docs. Excluding the domains rather than removing the
references. Also regenerates the Hugo source mirror.
Update docs/TESTING.md and Hugo source mirror to accurately describe
all five link-check exclude patterns: one unauthenticated-404 pattern
(security/advisories/new) and four bot-blocking-403 domains added in
e351209 (developers.redhat.com, medium.com, answers.uillinois.edu,
theregister.com). The previous prose said 'one URL pattern' which
was stale after the lychee 403 fix landed.
…efault fallback

The cmd_kill_switch() proxy URL resolution used an 'or' fallback chain
that treated an explicitly-passed empty string ('') as falsy, silently
substituting the default https://127.0.0.1:8443 and reaching the network
layer with a raw urllib error instead of returning structured
proxy_url_invalid recovery guidance.

Replace the fallback chain with an explicit 'args.proxy_url is None'
check so an empty string reaches the validator and returns
proxy_url_invalid, matching every other invalid URL variant.

Adds test_kill_switch_empty_proxy_url_returns_invalid regression guard.
…eneration

Empty or whitespace-only --agent-id and --mission values were silently
accepted by 'ardur issue', producing a Mission Passport with sub='' or
mission='' and creating signing keys. Add fail-closed validation in
cmd_issue that rejects these inputs before generate_keypair, returning
structured JSON (issue_agent_id_invalid / issue_mission_invalid) with
placeholder-only next_steps and exit 1. No keys are created on rejection.

Refs: t_266acd61, t_56ba844b
CodeQL alert #236: Import of 'MissionPassport' is not used.
The TYPE_CHECKING block imported MissionPassport for a type annotation
that is already a string-literal forward reference at line 493. The
runtime import at line 591 handles actual usage. Behavior-preserving.
Protect claude-code used type=Path for --scope, and Path("") normalizes
to Path(".") which silently resolved empty/whitespace scope values to
the current working directory. This let --scope "" or --scope "   "
succeed with exit 0 and create real signing keys plus an active mission
instead of failing closed.

Change --scope from type=Path to type=str and add an explicit
empty/whitespace guard before home.mkdir/generate_keypair, returning
structured JSON (protect_scope_invalid) with placeholder-only
next_steps. Explicit --scope . continues to work as before.
Python argparse type=Path converts --keys-dir "" to Path("") which
normalizes to Path(".") (cwd), silently writing signing keys and state
to an unexpected directory. Change type=Path to type=str for path flags
on start/issue/verify/attest so empty strings survive argparse, then
reject them with a structured path_arg_invalid error before any key
generation, state creation, or directory resolution.

Valid --keys-dir . (explicit cwd) is preserved. Omitted options (None)
pass through untouched. The existing protect_scope_invalid guard is
unchanged.
Document the path_arg_invalid structured error for start/issue/verify/attest
that rejects empty/whitespace-only path arguments before any key generation,
state creation, or directory resolution. Regenerate source-backed Hugo mirror.
Split _default_home_dir() into a pure path resolver and a deferred
_ensure_default_home_dir() side effect. Importing vibap modules no
longer creates .vibap/ on disk; the mkdir(0o700) happens on first
actual write (key generation, receipt write, etc).

VIBAP_HOME explicit dirs are not re-chmod'd (preserves legacy contract).
Adds 13 regression tests for import-side-effect-free module loading.
Comment thread python/tests/test_default_home_lazy_import.py Fixed
CodeQL note alert #239 flagged 'import stat' as unused. The test file
uses Path.stat() method calls (not the stat module), so the module-level
import is dead. Removing it clears the alert without behavior change.
setup_home_invalid (empty/whitespace --home) was implemented in 05ec053
but missing from the public CLI reference docs. Document the fail-closed
behavior for ardur setup and all Personal commands, matching the adjacent
path_not_directory and setup_port_invalid/setup_host_invalid contracts.

Files changed (2):
- docs/reference/cli.md: added 1 paragraph between path_not_directory
  and setup_port_invalid/setup_host_invalid sections
- site/content/source/docs/reference/cli.md: regenerated mirror
Empty or whitespace-only --agent-id and explicitly-provided whitespace-only
--mission previously flowed into Mission Passport JWT claims while generating
real signing keys, active_mission.jwt, and home artifacts. Reject them before
any key generation, JWT issuance, or plugin artifact creation with structured
JSON (protect_agent_id_invalid / protect_mission_invalid) and placeholder-only
next_steps, matching the established protect_scope_invalid shape.

--agent-id has an argparse default so only explicitly-passed empty strings
reach the guard. --mission defaults to None; an empty string is falsy and
falls through to the mode/profile default, which is acceptable. Only
whitespace-only strings (truthy but meaningless) are rejected.

Adds 8 regression tests covering empty, whitespace, and tab/newline variants
for both flags, plus the empty-string-mission fallback and valid-args success
path.
…ecovery

Align docs/reference/cli.md and the generated Hugo source mirror with the
landed protect claude-code --agent-id/--mission validation (commit 2010655).
Document the structured JSON error codes, placeholder-only next_steps, the
empty-string --mission fallback behavior, and the no-keys/no-JWT/no-home
guarantee on rejection.
empty/whitespace-only --mission values (e.g. '   ') were treated as
truthy by the run_governed_cli or-fallback and reached key generation,
creating a Mission Passport with a blank mission string before launching
the governed agent. Add an explicit .strip() validation gate that fails
closed with exit 2 and deterministic placeholder-only next_steps before
any keys, passports, or artifacts are created.
…mission

Empty or whitespace-only --mission on ardur start is a mission JSON file
path, not a directory. The generic path_arg_invalid hint suggested
--mission . which would fail with IsADirectoryError. Add
_start_mission_path_invalid_response() returning mission-file-specific
next_steps pointing at <mission.json> and never --mission . . Directory
args (--keys-dir, --state-dir, --log-path, --tls-cert, --tls-key) keep
the generic path_arg_invalid hint where '.' is valid.

Adds 3 parametrized regression tests covering empty, whitespace, and
tab/newline mission values, asserting no artifacts, no traceback, no
raw paths, and placeholder-only tokens. Documents the new recovery
contract in docs/reference/cli.md and regenerates the Hugo source mirror.
…tion

protect claude-code --home used type=Path, so argparse normalized empty
strings to PosixPath('.') (the CWD) at parse time and whitespace values
survived as literal directories. Both silently created signing keys and
active_mission.jwt in unintended locations before validation could run.

Switch --home to type=str so empty/whitespace values reach the handler
intact, then validate the stripped string before any mkdir/keygen/passport
write. Invalid values return the structured protect_home_invalid response
with placeholder-only next_steps and no artifacts. Explicit --home . and
omitted --home are preserved.

Mirrors the established protect_scope_invalid / setup_home_invalid shape.
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.

2 participants