From bd6e6f69e99b56a7d4c0419b32241c6146069d92 Mon Sep 17 00:00:00 2001 From: Luca Muscariello Date: Wed, 11 Mar 2026 00:30:12 +0100 Subject: [PATCH] docs: overhaul navigation and docs experience Signed-off-by: Luca Muscariello --- Justfile | 5 + README.md | 26 +++++- docs/api_integration.md | 32 +++---- docs/architecture.md | 92 ++++++++++++++++-- docs/assets/img/logo-dark.svg | 3 + docs/assets/img/logo-light.svg | 3 + docs/cli.md | 26 +++--- docs/demo.md | 65 +++++++++++-- docs/getting_started.md | 130 ++++++++++++++++++++++++++ docs/index.md | 100 ++++++++++++++------ docs/operations.md | 98 ++++++++++++++++++++ docs/sandbox.md | 10 ++ docs/secops_agent.md | 105 ++++++++++++++++++++- docs/stylesheets/custom.css | 149 ++++++++++++++++++++++++++++++ mkdocs.yml | 73 ++++++++++++--- overrides/partials/copyright.html | 3 + overrides/partials/logo.html | 2 + tools/prepare_skill_scan.py | 84 +++++++++++++++++ 18 files changed, 910 insertions(+), 96 deletions(-) create mode 100644 docs/assets/img/logo-dark.svg create mode 100644 docs/assets/img/logo-light.svg create mode 100644 docs/getting_started.md create mode 100644 docs/operations.md create mode 100644 docs/stylesheets/custom.css create mode 100644 overrides/partials/copyright.html create mode 100644 overrides/partials/logo.html create mode 100644 tools/prepare_skill_scan.py diff --git a/Justfile b/Justfile index f5be64b..e39e940 100644 --- a/Justfile +++ b/Justfile @@ -97,6 +97,11 @@ secops-approve-prs: secops-test-python: uv run --with pytest pytest agents/secops/tests/test_skills.py +secops-skill-scan: + rm -rf .tmp/skill-scanner/secops + uv run --no-project --python .venv/bin/python tools/prepare_skill_scan.py --source agents/secops --dest .tmp/skill-scanner/secops + uvx --from cisco-ai-skill-scanner skill-scanner scan .tmp/skill-scanner/secops --format summary --format markdown --detailed --output-markdown .tmp/skill-scanner/secops-scan.md + secops-a2a: uv run --no-project --python .venv/bin/python agents/secops/a2a_server.py diff --git a/README.md b/README.md index a1af67b..90995fc 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,14 @@ SHADI is designed for environments where agents are long-lived, hold real creden - SQLCipher-backed encrypted local memory (`shadi_memory`). - Python bindings (`shadi_py`) for secrets, memory, and sandboxed execution. - SLIM transport integration for secure agent-to-agent messaging. -- A practical SecOps agent demo and launch scripts. +- Example agents and demos, including a practical SecOps workflow and launch scripts. + +Recent updates in this branch of the project: + +- SecOps now treats container CVEs as rebuild or base-image refresh work instead of mutating Dockerfiles with ad-hoc package upgrade lines. +- Dockerfile resolution for container findings is workflow-first, using `.github/workflows/*` metadata before repo-wide scanning. +- Demo launchers are hardened for the optional 1Password backend by reading required secrets before entering the sandbox. +- Avatar surfaces clearer SLIM handshake errors when the SecOps A2A side is unavailable or misconfigured. ## Repository layout @@ -22,7 +29,7 @@ SHADI is designed for environments where agents are long-lived, hold real creden - `crates/shadi_memory`: SQLCipher memory library and CLI (`shadi-memory`). - `crates/shadi_py`: Python extension module `shadi`. - `crates/agent_transport_slim` + `crates/slim_mas`: secure transport and moderation helpers. -- `agents/secops`: SecOps agent, A2A server, and skill implementation. +- `agents/secops`: example SecOps workload, A2A server, and skill implementation. - `docs`: architecture, security, CLI, demos, and integration docs. - `scripts`: local launch helpers for SLIM + agent demos. @@ -141,7 +148,7 @@ The module exposes bindings for: ## SecOps demo and launch scripts -The repo includes runnable examples under `agents/secops` and helper scripts in `scripts/`. +The repo includes runnable demo workloads under `agents/secops` and helper scripts in `scripts/`. Common local flow: @@ -152,6 +159,18 @@ Common local flow: ./scripts/launch_avatar.sh ``` +Focused Python tests for the SecOps skill: + +```bash +just secops-test-python +``` + +Security scan for the SecOps skill package: + +```bash +just secops-skill-scan +``` + See `scripts/README.md` and `docs/demo.md` for full setup details. ## Documentation @@ -164,6 +183,7 @@ Primary docs live in `docs/`: - `docs/cli.md`: complete CLI reference - `docs/sandbox.md`: policy model and profile behavior - `docs/demo.md`: demo walkthrough +- `docs/secops_agent.md`: SecOps demo workload and remediation behavior Build/serve docs locally: diff --git a/docs/api_integration.md b/docs/api_integration.md index 9b2093d..d2b3429 100644 --- a/docs/api_integration.md +++ b/docs/api_integration.md @@ -32,7 +32,7 @@ To list secrets stored for an app or agent, use `shadictl`: ```bash cargo run -p shadictl -- --list-keychain --list-prefix agents/ -cargo run -p shadictl -- --list-keychain --list-prefix secops/ +cargo run -p shadictl -- --list-keychain --list-prefix apps/ ``` Avoid printing secret values. Pass key names to helpers that resolve secrets @@ -45,14 +45,14 @@ To list or search long-term memory in the encrypted SQLCipher store, use the cargo run -p shadictl -- -- memory list \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - --scope secops --limit 50 + --scope app --limit 50 ``` ```bash cargo run -p shadictl -- -- memory search \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - --scope secops --query dependabot --limit 10 + --scope app --query policy --limit 10 ``` ## Integration overview @@ -103,8 +103,8 @@ fn main() -> Result<(), SecretError> { let mut session = SessionContext::new("agent-1", "session-1"); session.verified = true; - access.put_for_session(&session, "secops/token", b"secret", SecretPolicy::default())?; - let secret = access.get_for_session(&session, "secops/token")?; + access.put_for_session(&session, "app/config", b"secret", SecretPolicy::default())?; + let secret = access.get_for_session(&session, "app/config")?; let value = secret.expose(|bytes| bytes.to_vec()); println!("secret len: {}", value.len()); @@ -157,9 +157,9 @@ store.set_verifier(lambda agent_id, session_id, presentation, claims: True) session = PySessionContext("agent-1", "session-1") store.verify_session(session, b"didvc-presentation") -store.put(session, "secops/token", b"secret") -print(store.get(session, "secops/token")) -store.delete(session, "secops/token") +store.put(session, "app/config", b"secret") +print(store.get(session, "app/config")) +store.delete(session, "app/config") ``` ### Example: integrate with an app session @@ -196,12 +196,12 @@ store.put(session, "app/config", b"value") from shadi import SqlCipherMemoryStore store = SqlCipherMemoryStore( - db_path="./.tmp/shadi-secops/secops_memory.db", - key_name="secops/memory_key", + db_path="./.tmp/shadi-app/app_memory.db", + key_name="app/memory_key", ) -store.put("secops", "security_report", "{\"status\":\"ok\"}") -latest = store.get_latest("secops", "security_report") +store.put("app", "latest_state", "{\"status\":\"ok\"}") +latest = store.get_latest("app", "latest_state") print(latest.payload if latest else "no entry") ``` @@ -286,7 +286,7 @@ access to the agent sessions. ## Secret store naming in Rust vs Python Rust and Python use the same underlying SHADI secret store. The "name" you see -in examples is just the secret key string (for example, `secops/token` or +in examples is just the secret key string (for example, `app/config` or `agents/agent-a/did`). There is no separate store per language. If you see different names between Rust and Python examples, it is only a @@ -313,8 +313,8 @@ For Python agents, you can run under the sandbox using the JSON policy runner: ```bash ./.venv/bin/python tools/run_sandboxed_agent.py \ - --policy policies/demo/secops-a.json \ - -- ./.venv/bin/python agents/secops/a2a_server.py + --policy ./sandbox.json \ + -- ./.venv/bin/python ./your_agent.py ``` `net_allow` in the policy file is enforced by the Python runner using a @@ -325,7 +325,7 @@ sandbox and inject it as an environment variable: ```bash cargo run -p shadictl -- \ - --inject-keychain secops/token=GITHUB_TOKEN \ + --inject-keychain app/config=APP_CONFIG \ -- \ ./your-agent ``` diff --git a/docs/architecture.md b/docs/architecture.md index dee6007..4b68d58 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -56,9 +56,11 @@ actions and prevent unauthorized data access or exfiltration. ### 2) Sandbox layer - **macOS**: Seatbelt profile enforcement for filesystem and network policies. - **Windows**: AppContainer + ACL allowlists + Job Objects (kill-on-close). -- **CLI**: `shadi` provides command blocklists and a JSON policy format. +- **CLI**: `shadi` provides JSON policy loading, profile defaults, optional command blocklists, and brokered secret injection. - **Portable launcher model**: `shadi` supports built-in profiles (`strict`, `balanced`, `connected`) for portable secure launch defaults. +- **Launch-time enforcement**: Policy is resolved before the agent process starts, so the sandbox is not a prompt-level suggestion that the agent can rewrite from inside the session. +- **Operational hardening**: macOS launcher support now resolves relative paths before emitting Seatbelt rules and accounts for required local IPC paths such as 1Password and SLIM runtime state. #### Key modules - `crates/shadi_sandbox/src/policy.rs`: policy model and helpers. @@ -68,14 +70,14 @@ actions and prevent unauthorized data access or exfiltration. ### 3) Memory layer - **Local encrypted store**: SQLCipher-backed SQLite for portable, on-device memory. - **Key management**: Encryption keys live in SHADI secrets (keychain backed). -- **Agent usage**: SecOps writes summaries to the encrypted store; ADK memory remains in-process unless configured for persistent backends. +- **Agent usage**: workloads running on SHADI can persist local state in the encrypted store; the SecOps demo writes summaries there, while ADK memory remains in-process unless configured for persistent backends. #### Key modules - `crates/shadi_memory/src/lib.rs`: SQLCipher store and query helpers. - `crates/shadi_memory/src/main.rs`: shadi-memory CLI. - `crates/shadictl/src/main.rs`: `shadictl memory` helper. - `crates/shadi_py/src/lib.rs`: SQLCipher bindings. -- `agents/secops/skills.py`: SecOps summary persistence. +- `agents/secops/skills.py`: example summary persistence used by the SecOps demo. ### 4) Transport layer - **SLIM/A2A**: MLS provides confidentiality and integrity between agents. @@ -87,6 +89,9 @@ actions and prevent unauthorized data access or exfiltration. ### 5) Brokered secret injection (optional) - If sandbox rules prevent keystore access, secrets can be brokered outside the sandbox and injected as environment variables into the agent process. +- This is also the fallback path used by the demo launchers when the optional + 1Password backend is enabled: required items are read in the foreground and + exported into the sandboxed process environment. #### Key modules - `crates/shadictl/src/main.rs`: `--inject-keychain` and policy enforcement. @@ -114,9 +119,10 @@ The CLI combines profile defaults, policy file settings, and explicit flags: - CLI flags override or extend resulting policy. - The effective policy can be printed with `--print-policy`. -## SecOps agent architecture -The SecOps agent runs locally under SHADI and uses the Python bindings for secrets -plus GitHub APIs for security signals. +## Demo workload: SecOps agent +The SecOps agent is an example workload that runs on top of SHADI. It uses the +Python bindings for secrets plus GitHub APIs for security signals, but it is +not part of the core runtime itself. #### Key modules - `agents/secops/skills.py`: skills to collect alerts and issues. @@ -128,7 +134,71 @@ plus GitHub APIs for security signals. 1. Read config from secops.toml. 2. Fetch GitHub token and workspace path from SHADI. 3. Collect Dependabot alerts and security-labeled issues. -4. Write `secops_security_report.json` to the workspace. +4. Collect code-scanning alerts for container findings via GitHub code scanning. +5. For dependency alerts, patch supported manifests and stage repo-relative changes. +6. For container CVEs, locate the authoritative Dockerfile from GitHub workflow metadata when possible and recommend image rebuilds or base-image refreshes instead of ad-hoc package-install edits. +7. Create remediation issues and optional PRs, then write `secops_security_report.json` to the workspace. + +## Updated system view + +```mermaid +flowchart TB + subgraph Operator[Operator and Control Plane] + Human[Human operator] + Config[secops.toml and policy JSON] + Launchers[Launch scripts and shadictl] + end + + subgraph Trust[Identity and Secret Plane] + Verify[PySessionContext and verifier] + Secrets[ShadiStore] + Keychain[OS keychain or 1Password backend] + MemoryKey[SQLCipher memory key] + end + + subgraph Runtime[Sandboxed Runtime Plane] + Sandbox[shadi_sandbox policy enforcement] + Avatar[Avatar ADK agent] + SecOps[SecOps agent or A2A server] + Memory[SqlCipherMemoryStore] + end + + subgraph External[External Services] + GitHub[GitHub APIs and gh CLI] + Models[LLM provider endpoints] + SLIM[SLIM or A2A transport] + end + + Human --> Launchers + Config --> Launchers + Launchers --> Sandbox + Human --> Verify + Verify --> Secrets + Secrets --> Keychain + Secrets --> MemoryKey + Sandbox --> Avatar + Sandbox --> SecOps + Avatar --> SLIM + SecOps --> SLIM + SecOps --> GitHub + SecOps --> Models + SecOps --> Memory + MemoryKey --> Memory + Avatar -. verified secret reads .-> Secrets + SecOps -. verified secret reads .-> Secrets +``` + +The main architecture update is that SHADI now has a clearer split between: +- control-plane launch logic that resolves policy and optional secret brokerage before process start, +- runtime enforcement that the agent cannot weaken by rewriting a local denylist path string, +- and application-layer behavior implemented by example workloads such as SecOps remediation planning and Avatar-to-SecOps orchestration. + +## Demo workload behavior: SecOps remediation model + +- Dependency remediation still edits supported manifests directly and can open PRs. +- Container CVEs are handled as rebuild guidance, not by mutating Dockerfiles with ad-hoc OS package commands. +- Dockerfile discovery prefers `.github/workflows/*` as the authoritative source of build definitions, then falls back to portable filesystem scanning. +- If only guidance is needed, SecOps opens a remediation issue so the repo owner can refresh the base image or rebuild the container in the right place. ## Data flow (high level) 1. Human identity material is ingested (OpenPGP or seed bytes). @@ -210,8 +280,9 @@ flowchart LR - **Stopped**: Message tampering; MLS provides integrity/authentication. ### Privilege escalation -- **Stopped**: Running blocked commands via CLI blocklist. -- **Mitigated**: Kernel-level constraints remain even if the agent tries to evade. +- **Mitigated**: Prompt-level or path-level agent reasoning by applying sandbox policy before launch. +- **Mitigated**: Running blocked commands via CLI blocklist when that feature is used. +- **Mitigated**: Kernel-level constraints remain even if the agent tries to evade application-layer logic. ## Threat-to-control mapping @@ -221,7 +292,7 @@ flowchart LR | Secret theft at rest | OS keystore storage | Blocked | | Secret exfiltration in sandbox | OS sandbox + net block | Blocked | | Unauthorized file access | Seatbelt/AppContainer allowlists | Blocked | -| Destructive commands | CLI blocklist | Blocked | +| Destructive commands | CLI blocklist | Mitigated | | Message interception | MLS in SLIM | Blocked | | Message tampering | MLS integrity | Blocked | | Agent identity substitution | HKDF derivation + verify-agent-identity | Blocked (with verification) | @@ -231,6 +302,7 @@ flowchart LR - Host OS compromise or kernel-level malware can bypass sandbox controls. - Metadata leakage (timing, sizes, endpoints) is not fully addressed in v1. - ACL changes on Windows could be interrupted before rollback in a crash. +- Application-level path deny rules are weaker than OS-enforced sandbox restrictions; do not rely on path matching alone for high-assurance policy. ## Deployment guidance - Prefer running agents under the sandbox with a JSON policy file. diff --git a/docs/assets/img/logo-dark.svg b/docs/assets/img/logo-dark.svg new file mode 100644 index 0000000..a7784b8 --- /dev/null +++ b/docs/assets/img/logo-dark.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/assets/img/logo-light.svg b/docs/assets/img/logo-light.svg new file mode 100644 index 0000000..393dd5f --- /dev/null +++ b/docs/assets/img/logo-light.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/cli.md b/docs/cli.md index 6edf4ba..2996142 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -67,7 +67,7 @@ Inject a secret into the command environment (brokered secrets): ```bash cargo run -p shadictl -- \ - --inject-keychain secops/token=GITHUB_TOKEN \ + --inject-keychain app/config=APP_CONFIG \ -- \ ./your-agent ``` @@ -227,14 +227,14 @@ Put a memory entry from inline payload or file: cargo run -p shadictl -- -- memory put \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - --scope secops --entry-key report --payload '{"status":"ok"}' + --scope app --entry-key state --payload '{"status":"ok"}' ``` ```bash cargo run -p shadictl -- -- memory put \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - --scope secops --entry-key report --payload-file ./report.json + --scope app --entry-key state --payload-file ./state.json ``` Get the latest entry: @@ -243,7 +243,7 @@ Get the latest entry: cargo run -p shadictl -- -- memory get \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - --scope secops --entry-key report + --scope app --entry-key state ``` Search entries: @@ -252,7 +252,7 @@ Search entries: cargo run -p shadictl -- -- memory search \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - --scope secops --query dependabot --limit 10 + --scope app --query policy --limit 10 ``` List entries: @@ -261,7 +261,7 @@ List entries: cargo run -p shadictl -- -- memory list \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - --scope secops --limit 50 + --scope app --limit 50 ``` Delete an entry: @@ -270,7 +270,7 @@ Delete an entry: cargo run -p shadictl -- -- memory delete \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - --scope secops --entry-key report + --scope app --entry-key state ``` ## shadi-memory (`shadi-memory`) @@ -302,14 +302,14 @@ Put a memory entry from inline payload or file: cargo run -p shadi_memory -- \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - put --scope secops --entry-key report --payload '{"status":"ok"}' + put --scope app --entry-key state --payload '{"status":"ok"}' ``` ```bash cargo run -p shadi_memory -- \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - put --scope secops --entry-key report --payload-file ./report.json + put --scope app --entry-key state --payload-file ./state.json ``` Get the latest entry: @@ -318,7 +318,7 @@ Get the latest entry: cargo run -p shadi_memory -- \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - get --scope secops --entry-key report + get --scope app --entry-key state ``` Search entries: @@ -327,7 +327,7 @@ Search entries: cargo run -p shadi_memory -- \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - search --scope secops --query dependabot --limit 10 + search --scope app --query policy --limit 10 ``` List entries: @@ -336,7 +336,7 @@ List entries: cargo run -p shadi_memory -- \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - list --scope secops --limit 50 + list --scope app --limit 50 ``` Delete an entry: @@ -345,7 +345,7 @@ Delete an entry: cargo run -p shadi_memory -- \ --db "${SHADI_TMP_DIR:-./.tmp}/shadi-memory.db" \ --key-name shadi/memory/sqlcipher_key \ - delete --scope secops --entry-key report + delete --scope app --entry-key state ``` ## slim-mas (`slim-mas`) diff --git a/docs/demo.md b/docs/demo.md index 4374366..27bee1c 100644 --- a/docs/demo.md +++ b/docs/demo.md @@ -1,7 +1,32 @@ -# Demo walkthrough +# Demo Walkthrough -This walkthrough shows a real, end-to-end SLIM A2A demo: two SecOps agents and -one human (Avatar) in the same group channel, backed by a local SLIM node. +This page documents an example multi-agent scenario built on top of SHADI. It +is useful for validating the runtime end to end, but it is not the default +operating model for every SHADI deployment. + +The example scenario uses two SecOps agents and one human-facing Avatar agent +in the same SLIM group channel, backed by a local SLIM node. + +!!! note + + Use this walkthrough when you want to exercise SHADI with a realistic + multi-agent workflow. For the core runtime model, start with + [Getting Started](getting_started.md), [Operations](operations.md), and + [Architecture](architecture.md). + +## Scenario Overview + +In this example, SHADI is responsible for: + +- storing shared secrets and identity material +- applying sandbox policy before each agent starts +- brokering the local runtime environment for the demo agents + +The workload-specific behavior comes from the demo agents themselves: + +- Avatar acts as the human-facing entry point +- the SecOps agents perform scanning and remediation planning +- SLIM provides the transport between participants ## 1) Start a local SLIM node @@ -35,6 +60,12 @@ just launch-secops-a2a-example To start a second agent, set `SHADI_AGENT_ID=secops-b` and point `SHADI_SECOPS_CONFIG` to `./.tmp/secops-b.toml` before running the launcher. +If you want the SecOps side to open PRs, also set: + +```bash +export SHADI_HUMAN_GITHUB="your-github-handle" +``` + ## 4) Connect as a human using the Avatar ADK agent ```bash @@ -48,6 +79,14 @@ scan dependabot for the allowlist report ``` +For remediation flows, ask for something like: + +```text +scan dependabot for the allowlist and remediate actionable findings +``` + +Container findings now come back as rebuild or base-image refresh guidance rather than Dockerfile package-layer edits. + ## 5) Key and DID utilities SHADI can ingest OpenPGP keys without shelling out to `gpg`. Store a human @@ -76,7 +115,7 @@ Notes: - Keys and DIDs are stored in the SHADI secret store. - OpenPGP parsing uses `sequoia-openpgp`, not the OS `gpg` binary. -## Notes +## Scenario Notes - The SecOps A2A servers and Avatar agent share the same SLIM endpoint and shared secret in SHADI. - Adjust `secops.toml` or the per-agent configs if you want different identities @@ -84,8 +123,8 @@ Notes: ## Using 1Password instead of the OS keychain -All demo steps work with 1Password as the secret backend. Export the following -before running the walkthrough: +All steps in this example scenario work with 1Password as the secret backend. +Export the following before running the walkthrough: ```bash export SHADI_SECRET_BACKEND=onepassword @@ -94,6 +133,14 @@ export SHADI_OP_VAULT=shadi # optional, default: shadi The `op` CLI (1Password CLI v2) must be installed and authenticated (or set `OP_SERVICE_ACCOUNT_TOKEN` for headless/CI use). Then run every step above -exactly as written — `just import-secops-secrets`, the A2A launchers, and the -Avatar agent will all store and retrieve secrets from the 1Password vault -instead of the OS keychain. +exactly as written. The bootstrap and launch helpers will store and retrieve +secrets from the 1Password vault instead of the OS keychain. + +The launchers pre-read the required 1Password items before entering the sandbox. +This avoids the common failure mode where the `op` background prompt or daemon +startup is blocked by sandbox policy. + +## Troubleshooting + +- If `launch_secops_a2a.sh` fails under the 1Password backend, confirm that the `op` CLI is authenticated for the selected account and vault. +- If Avatar reports a SLIM session handshake failure, verify that the SecOps A2A server is already running and that both terminals use the same shared secret, identity, endpoint, and TLS files. diff --git a/docs/getting_started.md b/docs/getting_started.md new file mode 100644 index 0000000..8ae67fd --- /dev/null +++ b/docs/getting_started.md @@ -0,0 +1,130 @@ +# Getting Started + +This guide is the fastest path from a fresh checkout to a working SHADI run. +It focuses on one outcome: confirm that the workspace builds, the sandbox +launcher works, and the runtime is ready for a real agent workflow. + +## Overview + +By the end of this guide, you will have: + +- built the workspace +- inspected the effective sandbox policy +- run a command through `shadictl` +- prepared the identity and secret flow used by the rest of the docs + +## Before You Begin + +Install the local tooling SHADI expects: + +- Rust stable with Cargo +- Python 3.12 +- `uv` for Python workflows +- `just` for the common repo tasks +- `mkdocs` if you want to preview the docs site locally + +!!! note + + If you only want to validate the launcher and CLI path, you do not need to + configure the full SecOps demo yet. That comes later in [Operations](operations.md). + +## Build the Workspace + +Build the workspace with either Cargo directly or the repo task runner. + +=== "Cargo" + + ```bash + cargo build --workspace + ``` + +=== "Just" + + ```bash + just build + ``` + +## Inspect the Launcher Policy + +SHADI resolves sandbox policy before process start. That is the key runtime +property to keep in mind while reading the rest of the documentation. + +```bash +cargo run -p shadictl -- --profile balanced --print-policy +``` + +Use these defaults as your baseline: + +- `strict`: local workspace only, network blocked +- `balanced`: workspace plus common system reads, network blocked +- `connected`: balanced plus network access + +!!! info + + For the full policy model, profile merge rules, and platform-specific + behavior, continue to [Sandbox and Policies](sandbox.md). + +## Run Your First Sandboxed Command + +Launch a trivial command with explicit local access: + +```bash +cargo run -p shadictl -- \ + --allow . \ + --read / \ + --net-block \ + -- \ + /usr/bin/env echo "hello from shadi" +``` + +This confirms three things: + +- the CLI is resolving policy correctly +- the sandbox launcher is functional on your host +- the runtime path is ready for a real agent command + +## Prepare Identity and Secrets + +SHADI is most useful when the runtime can derive agent identity and gate secret +access on verified sessions. + +=== "Store Human Identity Material" + + ```bash + cargo run -p shadictl -- \ + put-key --key human/gpg --in /path/to/human-secret.asc + ``` + +=== "Derive an Agent Identity" + + ```bash + cargo run -p shadictl -- \ + derive-agent-identity \ + --source gpg \ + --human-secret human/gpg \ + --name agent-a \ + --prefix agents + ``` + +!!! note + + If you need the full identity lifecycle, DID verification flow, or Python + integration surface, continue to [API Guide](api_integration.md). + +## Next Steps + +After the first successful sandboxed command, choose the track that matches your goal. + +- Run the end-to-end local demo: [Operations](operations.md) +- Integrate SHADI into an agent or app: [API Guide](api_integration.md) +- Review the system model before deploying: [Architecture](architecture.md) + +## Recommended Reading Order + +If you want a practical progression through the docs, use this sequence: + +1. [Getting Started](getting_started.md) +2. [Sandbox and Policies](sandbox.md) +3. [Operations](operations.md) +4. [Security Notes](security.md) +5. [CLI Reference](cli.md) \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index ef7664c..dc4bf1f 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,30 +1,74 @@ # SHADI -Secure Host Agentic AI Dynamic Instantiation (SHADI) is a host runtime designed -for autonomous, multi-agent systems running on end devices. It is critical in -this setting because agents are long-lived, operate with real credentials, and -run on machines that can access sensitive local data. SHADI reduces the blast -radius of mistakes or compromise by enforcing identity checks, secrets access -gating, and OS-level restrictions. - -### Why it matters on end devices - -- **Least-privilege execution**: sandbox policies limit filesystem and network access. -- **Verified identity**: agents must pass DID/VC checks before touching secrets. -- **Local secrets hygiene**: secrets live in OS keystores and are zeroized in memory. -- **Secure agent-to-agent transport**: MLS-backed messaging protects content in transit. -- **Durable local memory**: SQLCipher-backed storage keeps contexts and long-term memory secure at rest. - -### What SHADI provides - -- Secure secrets storage for agents across platforms. -- OpenPGP key ingestion and DID derivation via `shadictl` (no OS `gpg` dependency). -- Deterministic human->agent identity derivation (HKDF-SHA256) with verifiable provenance. -- MLS-backed secure agent messaging via SLIM/A2A integration. -- Kernel-enforced sandboxing for agent processes. -- Portable profile-based secure launcher defaults (`strict`, `balanced`, `connected`). -- Encrypted local memory via SQLCipher. -- Python bindings for secrets, SQLCipher memory, and sandbox execution. -- A SecOps agent for security monitoring and reporting. - -Use the navigation to find setup, security, CLI, and integration details. +SHADI is a secure host runtime for agents that run close to real credentials, +local data, and developer tooling. It combines verified identity, gated secret +access, OS-enforced sandboxing, encrypted local memory, and secure transport so +agent execution is constrained by launch-time policy instead of prompt-time +intent alone. + +## Start Here + +Use the docs by task, not by file name: + +- If you are new to SHADI, start with [Getting Started](getting_started.md). +- If you are running or debugging real agent workflows, start with [Operations](operations.md). +- If you need the system model, start with [Architecture](architecture.md) and [Security Notes](security.md). +- If you are integrating an agent or app, start with [API Guide](api_integration.md), then the relevant integration page. +- If you need commands and flags, use [CLI Reference](cli.md). + +## What SHADI Gives You + +- Verified secret access backed by platform keystores and optional 1Password integration. +- Deterministic human-to-agent identity derivation with provenance checks. +- Kernel-enforced sandbox execution with portable profiles and JSON policy support. +- Encrypted on-device memory through SQLCipher. +- Python bindings for secrets, memory, and sandboxed execution. +- Secure agent-to-agent messaging through SLIM and A2A. +- Example agents and demos, including a SecOps workflow that exercises the runtime against real GitHub signals. + +## Read By Role + +### Operator + +You are trying to run agents safely on a workstation or end device. + +- Read [Getting Started](getting_started.md) for the shortest path from clone to first sandboxed command. +- Read [Operations](operations.md) for runtime checks, demo flows, and troubleshooting. +- Read [Security Notes](security.md) for the threat model and deployment caveats. + +### Agent or Platform Engineer + +You are integrating SHADI into an agent runtime, toolchain, or application. + +- Read [Architecture](architecture.md) for the runtime split between launch, trust, sandbox, memory, and transport. +- Read [API Guide](api_integration.md) for Rust and Python integration patterns. +- Read [SLIM and A2A](slim_a2a.md) or [Google ADK](adk_integration.md) for runtime-specific paths. + +### Security Engineering + +You are evaluating controls, provenance, and remediation behavior. + +- Read [Security Notes](security.md) for the control model. +- Read [SecOps Demo](secops_agent.md) for the security-demo workload, remediation boundaries, and operator workflows. +- Read [Design Overview](design.md) for implementation direction and current constraints. + +## Documentation Map + +The site is organized into four sections: + +- `Introduction`: project framing, architecture, security, and design intent. +- `Guides`: onboarding and operational flows for setup, sandboxing, and demo workloads. +- `Integrations`: API usage plus transport and agent-framework integration notes. +- `Reference`: command and flag documentation for `shadictl`. + +## Core Runtime Model + +SHADI is built around a small set of enforcement layers: + +- Identity verification determines whether an agent session is trusted. +- Secret access is gated on that verified session. +- Sandbox policy is resolved before process start and enforced by the OS. +- Local memory stays encrypted at rest. +- Inter-agent transport is protected by MLS-backed messaging. + +For a system-level view of how those layers fit together, continue to [Architecture](architecture.md). diff --git a/docs/operations.md b/docs/operations.md new file mode 100644 index 0000000..08e592a --- /dev/null +++ b/docs/operations.md @@ -0,0 +1,98 @@ +# Operations + +This guide is for running SHADI as an actual agent host instead of treating the +repository as a CLI demo. It pulls together the pages you need for execution, +troubleshooting, and the example workloads shipped with the repository. + +## Overview + +Use this page as the operator entry point. It does not replace the detailed +guides. It tells you which page to open next and in what order. + +## Operating Model + +In a normal SHADI run, the operator does four things: + +1. Resolve a sandbox policy and choose the right launcher profile. +2. Ensure secrets and identity material are available before launch. +3. Start the runtime components in the correct order. +4. Verify outputs, reports, and runtime health when an agent action fails. + +The detailed references still live in the underlying pages; this guide is the +entry point that tells you where to go and in what order. + +!!! note + + If you are completely new to the project, start with [Getting Started](getting_started.md) + first and come back here once the local launcher path is working. + +## Choose a Workflow + +=== "Sandboxed Execution" + + Use [Sandbox and Policies](sandbox.md) when you need to: + + - choose between `strict`, `balanced`, and `connected` + - combine JSON policy with CLI overrides + - broker secrets into the process environment before sandboxing + - reason about the enforcement boundary on macOS and Windows + +=== "Local Demo" + + Use [Demo Walkthrough](demo.md) when you want to run the local multi-agent demo. + That page covers: + + - starting the local SLIM node + - seeding shared secrets into SHADI + - launching SecOps A2A servers + - launching Avatar and sending operator requests + - using the optional 1Password backend safely + +=== "Demo Runbooks" + + Use [SecOps Demo](secops_agent.md) when you need a concrete example of a + SHADI-hosted workload with GitHub, SLIM/A2A, and remediation logic. + + - configure the GitHub allowlist and required SHADI keys + - run scans and remediation mode + - understand the difference between dependency edits and container guidance + - inspect memory, reports, and pending PR artifacts + - run the focused Python test suite and skill scan + +## Suggested Operator Flow + +For the current demo workflows, this is the practical order: + +1. Review [Sandbox and Policies](sandbox.md) and print the resolved policy you intend to run. +2. Load secrets and identity material required by the chosen agent. +3. Start transport dependencies from [Demo Walkthrough](demo.md). +4. Launch the sandboxed agent process. +5. Inspect outputs such as policy, report files, memory state, and queued PR artifacts. + +!!! info + + The most common operator failure mode is not a code bug. It is a mismatch + between policy, secret availability, launch order, or shared transport configuration. + +## Troubleshooting Map + +Start from the symptom, then jump to the right page: + +- Sandbox launch or path access issue: [Sandbox and Policies](sandbox.md) +- Avatar or SLIM handshake issue: [Demo Walkthrough](demo.md) +- Demo workload or remediation behavior issue: [SecOps Demo](secops_agent.md) +- Identity, DID, or secret access issue: [API Guide](api_integration.md) and [CLI Reference](cli.md) + +## Operational References + +Keep these pages close when running the system: + +- [CLI Reference](cli.md) for `shadictl` flags and memory commands +- [Security Notes](security.md) for threat-model boundaries and backend caveats +- [Architecture](architecture.md) for the control-plane versus runtime split + +## Scope of This Page + +This page does not repeat every command from the detailed guides. It exists so +operators have a stable route through the docs instead of jumping between long, +flat pages with no execution order. \ No newline at end of file diff --git a/docs/sandbox.md b/docs/sandbox.md index fc1dec7..15760a6 100644 --- a/docs/sandbox.md +++ b/docs/sandbox.md @@ -115,10 +115,20 @@ cargo run -p shadictl -- \ - This is an MVP and uses a conservative Seatbelt profile. System paths required to execute processes are allowed for read access. - Command blocking is enforced before launch in the CLI. +- On macOS, policy paths are resolved to absolute paths before Seatbelt rules are emitted; relative subpaths are not reliable enforcement inputs. +- The demo launchers can broker secrets outside the sandbox and inject them into the agent environment before execution. - Windows: ACL allowlists are applied to the specified paths for the AppContainer SID and automatically reverted when the sandboxed process exits. Network access is controlled by AppContainer capabilities. +### Sandbox boundary guidance + +Use the sandbox as the security boundary, not application-level path deny rules. +Path-matching controls are useful for operator ergonomics, but they are weaker +than OS-enforced policy because the agent can reason about alternate paths and +wrappers. SHADI resolves and applies the effective sandbox policy before launch, +which is the property you should rely on for enforcement. + ## Windows integration test The Windows AppContainer sandbox has an opt-in integration test. Run it on diff --git a/docs/secops_agent.md b/docs/secops_agent.md index be506eb..1211d91 100644 --- a/docs/secops_agent.md +++ b/docs/secops_agent.md @@ -1,8 +1,18 @@ # SecOps Agent -The SecOps agent runs locally under SHADI sandbox constraints and monitors -GitHub security signals for an allowlist of repositories. It writes a report -and can be extended to open remediation PRs. +The SecOps agent is a demo workload built on top of SHADI. It is useful for +exercising the runtime against a realistic GitHub- and SLIM-backed workflow, +but it is not a core component of the SHADI platform itself. + +It runs locally under SHADI sandbox constraints, monitors GitHub security +signals for an allowlist of repositories, writes a report, and can open +remediation issues or PRs depending on what the finding supports. + +!!! note + + Use this page as a workload-specific runbook. For the core runtime surface, + start with [Architecture](architecture.md), [Sandbox and Policies](sandbox.md), + and [API Guide](api_integration.md). ## Prerequisites - SHADI Python extension installed in your `uv` environment. @@ -16,6 +26,12 @@ Configuration lives in secops.toml at the repo root: - `secops.workspace_key` - `github.api_base` +For PR creation and signed commits, SecOps can also use: +- `secops.human_github` +- `secops.git_name` +- `secops.git_email` +- `secops.git_signing_key` + ## Load secrets ```bash source ~/.env-phoenix @@ -32,9 +48,57 @@ SHADI so it never leaves the secret store. SHADI_OPERATOR_PRESENTATION="local-operator" uv run agents/secops/secops.py ``` +Select a provider explicitly: + +```bash +just secops-run PROVIDER="google" +just secops-run PROVIDER="azure" +just secops-run PROVIDER="anthropic" +``` + +Run remediation mode: + +```bash +just secops-run PROVIDER="google" REMEDIATE="true" +``` + The report is written to: - `${SHADI_TMP_DIR:-./.tmp}/shadi-secops/secops_security_report.md` +Pending PR requests are written to: +- `${workspace_dir}/secops_pending_prs.json` + +Approve queued PR creations later: + +```bash +just secops-approve-prs +``` + +## What SecOps remediates today + +SecOps consumes three classes of GitHub signal: +- Dependabot alerts +- Security-labeled issues +- Code-scanning alerts such as Trivy container findings + +The remediation behavior is intentionally different by finding type: + +- Dependency alerts: update supported manifests in-place, commit repo-relative changes, and optionally open a PR. +- Container CVEs: inspect the alert, map it to the container build definition, and recommend a rebuild or base-image refresh. + +Container remediation no longer injects ad-hoc package installation or upgrade lines into Dockerfiles. If the scan points at the base image lineage, the expected fix is to refresh the `FROM` image or rebuild the image so the next container scan picks up the upstream fix. + +## Dockerfile discovery + +For container findings, SecOps resolves the target Dockerfile in this order: + +1. Direct Dockerfile path in the alert, if present. +2. `.github/workflows/*.yml` and `.github/workflows/*.yaml` as the authoritative source of build definitions. +3. Portable Python filesystem traversal of the cloned repository. +4. Single-Dockerfile fallback if the repository has only one candidate. + +Workflow metadata is preferred because `docker/build-push-action` already carries the real `dockerfile:` and `context:` paths used in CI. + ## Long-running operation For continuous monitoring, run on a schedule and manage memory: @@ -61,6 +125,9 @@ while True: Ensure the sandbox policy allows workspace read/write and network access to GitHub and the ADK model endpoint. +For A2A deployments, Avatar and SecOps must also agree on the SLIM endpoint, +shared secret, identity values, and TLS configuration. + To use persistent ADK memory (Vertex AI Memory Bank), run the ADK agent with a memory service URI: @@ -104,6 +171,33 @@ Local-only run with in-memory ADK memory service: uv run agents/secops/adk_agent/run_local.py ``` +## Test the Python remediation logic + +Run the focused unit suite with `uv`: + +```bash +just secops-test-python +``` + +This covers remediation behavior such as: +- workflow-first Dockerfile resolution, +- repo-relative staging for dependency updates, +- and container CVE guidance that prefers rebuilds or base-image refreshes. + +## Scan the skill package + +Run Cisco's Skill Scanner against a sanitized copy of the SecOps skill package: + +```bash +just secops-skill-scan +``` + +This target excludes local development artifacts such as `.venv`, `__pycache__`, +`.pytest_cache`, `tests`, and `evals` before scanning, then writes a Markdown +report to: + +- `${PWD}/.tmp/skill-scanner/secops-scan.md` + ## Encrypted local memory (SQLCipher) The SecOps agent uses the Python bindings (`SqlCipherMemoryStore`) for the encrypted store. Use the helper below to inspect or seed entries without @@ -146,3 +240,8 @@ cargo run -p shadictl -- -- memory list --db "$SHADI_SECOPS_MEMORY_DB" \ --key-name secops/memory_key \ --scope secops ``` + +## Operational notes + +- When `SHADI_SECRET_BACKEND=onepassword`, the launch scripts pre-read required secrets before entering the sandbox because the sandbox may block the `op` CLI biometric/background flow. +- If Avatar reports a SLIM session handshake failure, check that the SecOps A2A server is running and that both sides share the same endpoint, shared secret, identity, and TLS settings. diff --git a/docs/stylesheets/custom.css b/docs/stylesheets/custom.css new file mode 100644 index 0000000..bd5da88 --- /dev/null +++ b/docs/stylesheets/custom.css @@ -0,0 +1,149 @@ +[data-md-color-scheme="default"] { + --md-primary-fg-color: rgb(243, 246, 253); + --md-primary-bg-color: rgb(2, 81, 175); + --md-primary-fg-color--dark: rgb(243, 246, 253); + + --md-accent-fg-color: rgb(2, 81, 175); + + --md-default-fg-color: rgb(28, 30, 33); + --md-default-fg-color--light: rgb(28, 30, 33); + --md-default-fg-color--lighter: #00000052; + --md-default-fg-color--lightest: #00000012; + + --md-default-bg-color: rgb(239, 243, 252); + --md-default-bg-color--light: #e8eefb; + --md-default-bg-color--lighter: #eff3fc; + --md-default-bg-color--lightest: #f5f8fd; + + --md-footer-fg-color: rgb(2, 81, 175); + --md-footer-fg-color--light: rgb(28, 30, 33); + --md-footer-fg-color--lighter: rgb(28, 30, 33); + --md-footer-bg-color: rgb(232, 238, 251); + --md-footer-bg-color--dark: #00000052; + --md-typeset-a-color: rgb(2, 81, 175); + + --md-typeset-table-color--light: #e8eefb; +} + +[data-md-color-scheme="slate"] { + --md-primary-fg-color: rgb(3, 20, 43); + --md-primary-bg-color: rgb(251, 175, 70); + + --md-accent-fg-color: rgb(251, 175, 70); + + --md-default-fg-color: rgb(227, 227, 227); + --md-default-fg-color--light: rgb(227, 227, 227); + --md-default-fg-color--lighter: rgb(237, 237, 237); + --md-default-fg-color--lightest: rgb(3, 20, 43); + + --md-default-bg-color: rgb(3, 20, 43); + --md-code-bg-color: rgb(0, 42, 77); + --md-typeset-color: rgb(227, 227, 227); + + --md-footer-fg-color: rgb(251, 175, 70); + --md-footer-fg-color--light: rgb(227, 227, 227); + --md-footer-fg-color--lighter: rgb(227, 227, 227); + --md-footer-bg-color: rgb(3, 20, 43); + --md-footer-bg-color--dark: #00000052; + --md-typeset-a-color: rgb(251, 175, 70) !important; + --md-typeset-a-color--hover: rgb(251, 175, 70) !important; + + --md-footer-meta-bg-color: rgb(232, 238, 251); + --md-typeset-table-color--light: rgb(0, 42, 77); + --md-code-fg-color: rgb(248, 248, 242); +} + +[data-md-color-primary="black"] .md-header { + background-color: var(--md-primary-fg-color) !important; +} + +[data-md-color-scheme="default"] .md-search__form { + background-color: rgb(236, 237, 240); + color: var(--md-primary-bg-color); +} + +[data-md-color-scheme="default"] .md-search__form:hover { + background-color: rgb(236, 237, 240); +} + +[data-md-color-scheme="slate"] .md-search__form { + background-color: rgb(0, 42, 77); + color: var(--md-primary-bg-color) !important; +} + +[data-md-color-scheme="slate"] .md-search__form:hover { + background-color: rgb(0, 42, 77); +} + +[data-md-color-scheme="default"] .md-search__input::placeholder { + color: #9ea2a8; +} + +[data-md-color-scheme="slate"] .md-search__input::placeholder { + color: #59616b; +} + +.md-footer { + box-shadow: 0 0 0.2rem #0000001a, 0 0.2rem 0.4rem #0003; + background-color: var(--md-footer-bg-color); + color: var(--md-default-fg-color); +} + +.md-footer-meta { + background-color: var(--md-footer-bg-color); +} + +.md-footer__link { + color: var(--md-default-fg-color); +} + +.md-footer__link:hover { + color: var(--md-typeset-a-color); +} + +html [data-md-color-primary="black"] .md-nav--primary .md-nav__title[for="__drawer"] { + background-color: var(--md-default-bg-color); +} + +[data-md-color-scheme="default"] .logo-dark { + display: none !important; +} + +[data-md-color-scheme="slate"] .logo-light { + display: none !important; +} + +.md-sidebar--primary .md-nav__link--active { + font-weight: 700; + border-radius: 0.25rem; +} + +.md-sidebar--primary .md-nav__link { + padding-top: 5px; + padding-bottom: 5px; + padding-left: 10px; +} + +[data-md-color-scheme="default"] .md-sidebar--primary .md-nav__link--active { + background-color: rgb(220, 226, 238); +} + +[data-md-color-scheme="slate"] .md-sidebar--primary .md-nav__link--active { + background-color: rgb(12, 31, 54); +} + +.md-nav__title { + font-size: 0 !important; +} + +.md-nav__title img { + font-size: initial !important; +} + +.md-header__ellipsis > :first-child { + display: none !important; +} + +[data-md-color-scheme="default"] code { + background-color: rgb(246, 248, 250) !important; +} \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index ca515ee..5cd7fe8 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -4,38 +4,83 @@ site_url: https://example.com/shadi repo_url: https://github.com/your-org/shadi repo_name: shadi +extra: + copyright: > + Copyright SHADI Contributors. + +extra_css: + - stylesheets/custom.css + theme: name: material + custom_dir: overrides + font: + text: Roboto + code: Roboto Mono palette: - - scheme: default + - media: "(prefers-color-scheme)" toggle: - icon: material/weather-night + icon: material/link + name: Switch to light mode + - media: "(prefers-color-scheme: light)" + scheme: default + primary: indigo + accent: indigo + toggle: + icon: material/toggle-switch name: Switch to dark mode - - scheme: slate + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: black + accent: indigo toggle: - icon: material/weather-sunny - name: Switch to light mode + icon: material/toggle-switch-off + name: Switch to system preference + logo_light: assets/img/logo-light.svg + logo_dark: assets/img/logo-dark.svg features: - navigation.tabs + - navigation.sections + - navigation.expand + - navigation.footer - navigation.top + - navigation.tracking - content.code.copy + - content.tabs.link + - search.highlight + - search.share + - search.suggest + - toc.follow nav: - - Overview: index.md - - CLI Reference: cli.md - - API & Integration: api_integration.md - - Architecture: architecture.md - - Demo: demo.md - - SecOps Agent: secops_agent.md - - Security: security.md - - Design: design.md - - Sandbox: sandbox.md + - Introduction: + - Overview: index.md + - Architecture: architecture.md + - Security Notes: security.md + - Design Overview: design.md + - Guides: + - Getting Started: getting_started.md + - Operations: operations.md + - Sandbox and Policies: sandbox.md + - Demo Walkthrough: demo.md + - SecOps Demo: secops_agent.md + - Integrations: + - API Guide: api_integration.md + - SLIM and A2A: slim_a2a.md + - Google ADK: adk_integration.md + - Mobile: mobile_integration.md + - Reference: + - CLI Reference: cli.md exclude_docs: | README.md markdown_extensions: - admonition + - md_in_html + - pymdownx.details + - pymdownx.tabbed: + alternate_style: true - pymdownx.superfences: custom_fences: - name: mermaid diff --git a/overrides/partials/copyright.html b/overrides/partials/copyright.html new file mode 100644 index 0000000..19a3cdd --- /dev/null +++ b/overrides/partials/copyright.html @@ -0,0 +1,3 @@ +
+ {{ config.extra.copyright }} +
\ No newline at end of file diff --git a/overrides/partials/logo.html b/overrides/partials/logo.html new file mode 100644 index 0000000..ce50213 --- /dev/null +++ b/overrides/partials/logo.html @@ -0,0 +1,2 @@ +logo +logo \ No newline at end of file diff --git a/tools/prepare_skill_scan.py b/tools/prepare_skill_scan.py new file mode 100644 index 0000000..53e3614 --- /dev/null +++ b/tools/prepare_skill_scan.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +import shutil +from pathlib import Path + + +EXCLUDED_DIRS = { + ".git", + ".pytest_cache", + ".venv", + "__pycache__", + "evals", + "tests", +} + +EXCLUDED_FILES = { + ".DS_Store", +} + + +def should_skip(path: Path, source_root: Path) -> bool: + relative = path.relative_to(source_root) + for part in relative.parts: + if part in EXCLUDED_DIRS: + return True + return path.name in EXCLUDED_FILES + + +def copy_skill_tree(source_root: Path, dest_root: Path) -> tuple[int, int]: + copied_files = 0 + copied_dirs = 0 + + if dest_root.exists(): + shutil.rmtree(dest_root) + dest_root.mkdir(parents=True, exist_ok=True) + + for path in sorted(source_root.rglob("*")): + if should_skip(path, source_root): + continue + + relative = path.relative_to(source_root) + destination = dest_root / relative + if path.is_dir(): + destination.mkdir(parents=True, exist_ok=True) + copied_dirs += 1 + continue + + destination.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(path, destination) + copied_files += 1 + + return copied_dirs, copied_files + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Prepare a sanitized skill directory for external scanners." + ) + parser.add_argument("--source", required=True, help="Source skill directory") + parser.add_argument("--dest", required=True, help="Destination directory") + return parser.parse_args() + + +def main() -> int: + args = parse_args() + source_root = Path(args.source).resolve() + dest_root = Path(args.dest).resolve() + + if not source_root.exists() or not source_root.is_dir(): + raise SystemExit(f"Source skill directory not found: {source_root}") + + copied_dirs, copied_files = copy_skill_tree(source_root, dest_root) + print( + f"Prepared sanitized skill tree at {dest_root} " + f"({copied_dirs} directories, {copied_files} files)." + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) \ No newline at end of file