From cc5f3141230ef760df211525dbb97153fc5d46c7 Mon Sep 17 00:00:00 2001 From: David Abutbul Date: Wed, 22 Jul 2026 20:25:30 +0300 Subject: [PATCH 1/3] fix(nanoclaw): mark legacy adapter v1-only --- skills/clawsec-nanoclaw/CHANGELOG.md | 8 + skills/clawsec-nanoclaw/INSTALL.md | 36 ++-- skills/clawsec-nanoclaw/README.md | 76 +++------ skills/clawsec-nanoclaw/SKILL.md | 74 ++++---- skills/clawsec-nanoclaw/docs/INTEGRITY.md | 14 +- skills/clawsec-nanoclaw/docs/SKILL_SIGNING.md | 159 +++++------------- .../host-services/skill-signature-handler.ts | 3 +- .../mcp-tools/advisory-tools.ts | 2 +- .../mcp-tools/signature-verification.ts | 5 +- skills/clawsec-nanoclaw/skill.json | 12 +- .../test/nanoclaw-v1-compatibility.test.mjs | 114 +++++++++++++ 11 files changed, 266 insertions(+), 237 deletions(-) create mode 100644 skills/clawsec-nanoclaw/test/nanoclaw-v1-compatibility.test.mjs diff --git a/skills/clawsec-nanoclaw/CHANGELOG.md b/skills/clawsec-nanoclaw/CHANGELOG.md index c09d023f..d4e5d5c3 100644 --- a/skills/clawsec-nanoclaw/CHANGELOG.md +++ b/skills/clawsec-nanoclaw/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.0.11] - 2026-07-22 + +### Changed + +- Bounded this legacy adapter to NanoClaw `>=0.1.0 <2.0.0` and marked NanoClaw v2 as incompatible. +- Removed or explicitly scoped obsolete v2-facing installation, scheduler, IPC-layout, and key-management claims to the pre-v2 adapter. +- Added a compatibility regression test while preserving the frozen v1 runtime behavior as migration evidence. + ## [0.0.10] - 2026-06-23 ### Changed diff --git a/skills/clawsec-nanoclaw/INSTALL.md b/skills/clawsec-nanoclaw/INSTALL.md index 056f5112..89046dd7 100644 --- a/skills/clawsec-nanoclaw/INSTALL.md +++ b/skills/clawsec-nanoclaw/INSTALL.md @@ -1,24 +1,28 @@ -# ClawSec for NanoClaw - Installation Guide +# ClawSec Legacy NanoClaw v1 Integration Guide -This guide shows how to add ClawSec security monitoring to your NanoClaw deployment. +> **Compatibility boundary:** This entire guide applies only to NanoClaw `>=0.1.0 <2.0.0`. NanoClaw v2 (`>=2.0.0`) is incompatible. Do not copy these files, use these IPC paths, or run these restart steps on v2. NanoClaw v2 requires a separate adapter for its current SQLite-backed and host/container extension model. + +This guide records the manual integration for compatible pre-v2 NanoClaw deployments. ## Overview -ClawSec provides security advisory monitoring for NanoClaw through: +The legacy v1 adapter provides security advisory monitoring through: - **MCP Tools**: Agents can check for vulnerabilities via `clawsec_check_advisories` -- **Advisory Feed**: Automatic monitoring of https://clawsec.prompt.security/advisories/feed.json +- **Advisory Feed**: Host-wired monitoring of https://clawsec.prompt.security/advisories/feed.json - **Signature Verification**: Ed25519-signed feeds ensure integrity - **Exploitability Context**: Advisories include exploitability score and rationale for triage ## Prerequisites -- NanoClaw >= 0.1.0 +- NanoClaw >= 0.1.0 and < 2.0.0 - Node.js >= 18.0.0 - Write access to NanoClaw installation directory -## Installation Steps +## Legacy v1 Integration Steps + +Every path and code fragment below is a NanoClaw v1 layout assumption. Stop if the target version is unknown or is NanoClaw v2. -### 1. Copy Skill Files +### 1. Copy Skill Files into a Confirmed v1 Checkout Copy the `clawsec-nanoclaw` skill directory to your NanoClaw installation: @@ -27,7 +31,7 @@ Copy the `clawsec-nanoclaw` skill directory to your NanoClaw installation: cp -r skills/clawsec-nanoclaw /path/to/your/nanoclaw/skills/ ``` -### 2. Integrate MCP Tools +### 2. Integrate v1 MCP Tools Add the ClawSec MCP tools to your NanoClaw container agent runner. @@ -53,7 +57,7 @@ Each file calls `server.tool()` directly to register its tools. The `server`, the scope where these files are imported (they are declared as ambient globals in each tool file). -### 3. Integrate IPC Handlers +### 3. Integrate v1 IPC Handlers Add the host-side IPC handlers for ClawSec operations. @@ -84,7 +88,7 @@ default: } ``` -### 4. Start Advisory Cache Service +### 4. Start the v1 Host Advisory Cache Service Add the advisory cache manager to your host services. @@ -112,7 +116,7 @@ async function main() { } ``` -### 5. Restart NanoClaw +### 5. Restart the Legacy v1 Docker Compose Deployment Restart your NanoClaw instance to load the new MCP tools and services: @@ -124,7 +128,7 @@ docker-compose down docker-compose up -d ``` -## Verification +## Legacy v1 Verification Test that ClawSec is working: @@ -219,7 +223,7 @@ To change, pass a different data directory path to `new AdvisoryCacheManager(dat ### Refresh Interval -Default: 6 hours +Example v1 host cadence: 6 hours after explicit operator wiring. The skill does not install a scheduler. To change, update the `setInterval(...)` duration (in milliseconds) in host startup. @@ -244,12 +248,12 @@ Platform metadata is preserved in advisory records and can be filtered by your p ### Signature Verification -All advisory feeds are Ed25519 signed. The public key is pinned in: +The v1 advisory cache verifies Ed25519-signed feeds with the public key embedded at: ``` skills/clawsec-nanoclaw/advisories/feed-signing-public.pem ``` -Feeds failing signature verification are rejected. +Feeds failing signature verification are rejected. The v1 package-verifier handler also reads this embedded feed-verification key by default. This is not a NanoClaw v2 installer/trust contract, and it is distinct from the ClawSec GitHub Release manifest key downloaded and fingerprint-checked in `SKILL.md`. ### Cache Integrity @@ -301,7 +305,7 @@ Never manually edit the cache file - it will break signature verification. 3. Ensure host process is running 4. Check host logs for handler errors -## Uninstallation +## Legacy v1 Uninstallation To remove ClawSec from NanoClaw: diff --git a/skills/clawsec-nanoclaw/README.md b/skills/clawsec-nanoclaw/README.md index 4c9401cd..c7f462dc 100644 --- a/skills/clawsec-nanoclaw/README.md +++ b/skills/clawsec-nanoclaw/README.md @@ -1,14 +1,15 @@ -# ClawSec for NanoClaw +# ClawSec for NanoClaw v1 (Legacy Adapter) -ClawSec now supports NanoClaw, a containerized WhatsApp bot powered by Claude agents. +This package preserves the original ClawSec integration for pre-v2 NanoClaw deployments. -## Vercel Skills Installation +## Compatibility -Install with the Vercel Skills CLI for this harness: +- Supported NanoClaw range: `>=0.1.0 <2.0.0`. +- NanoClaw v2 (`>=2.0.0`): **incompatible; do not install or activate this adapter**. +- The bundled IPC, cache, scheduler, and integrity examples describe the v1 layout only. +- NanoClaw v2 needs a separate adapter for its current host, container, SQLite IPC, and extension surfaces. -```bash -npx skills add prompt-security/clawsec --skill clawsec-nanoclaw -a openclaw -y -``` +This package remains available for legacy users and migration evidence. It is not a NanoClaw v2 installation path. ## What Changed @@ -45,9 +46,9 @@ Advisories now support optional `platforms` field: - `["openclaw", "nanoclaw"]` - Affects both platforms - (empty/missing) - Applies to all platforms (backward compatible) -## ClawSec NanoClaw Skill +## Legacy ClawSec NanoClaw Skill -ClawSec provides a complete security skill for NanoClaw deployments: +ClawSec provides a legacy adapter for compatible pre-v2 NanoClaw deployments: **Location**: `skills/clawsec-nanoclaw/` @@ -69,18 +70,11 @@ ClawSec provides a complete security skill for NanoClaw deployments: - **Exploitability Context**: Surfaces `exploitability_score` and rationale to reduce alert fatigue - **IPC Communication**: Container-safe host communication -### Installation - -1. Copy the skill to your NanoClaw deployment: - ```bash - cp -r skills/clawsec-nanoclaw /path/to/nanoclaw/skills/ - ``` - -2. Follow the detailed guide at `skills/clawsec-nanoclaw/INSTALL.md` +### Legacy v1 Integration Map -### Quick Integration +Only operators who have confirmed a target version in `>=0.1.0 <2.0.0` should use the detailed [legacy installation guide](./INSTALL.md). Do not raw-copy or import these files into NanoClaw v2. -The skill integrates into three places: +The v1 adapter historically integrates into three v1 locations: **1. MCP Tools** (container): ```typescript @@ -107,49 +101,17 @@ NanoClaw consumes the same feed as OpenClaw: https://clawsec.prompt.security/advisories/feed.json ``` -The feed is Ed25519 signed and automatically fetched by the cache service. - -## Team Credits - -This integration was developed by a team of 8 specialized agents coordinated to adapt ClawSec for NanoClaw: - -- **pioneer-repo-scout** - ClawSec architecture analysis -- **pioneer-nanoclaw-scout** - NanoClaw architecture analysis -- **architect** - Integration design and coordination -- **advisory-specialist** - Advisory feed integration -- **integrity-specialist** - File integrity design -- **installer-specialist** - Signature verification implementation -- **tester** - Test infrastructure and validation -- **documenter** - Documentation - -Total contribution: 3000+ lines of code and comprehensive design documents. - -## What's Included - -The `clawsec-nanoclaw` skill provides: - -- **1,730 lines** of production-ready TypeScript code -- **MCP Tools** (350 lines): Agent-facing vulnerability checking -- **Advisory Cache** (492 lines): Automatic feed fetching and caching -- **Signature Verification** (387 lines): Ed25519 signature validation -- **Advisory Matching** (289 lines): Skill-to-vulnerability correlation -- **IPC Handlers** (212 lines): Container-to-host communication -- **Complete Documentation**: Installation guide, usage examples, troubleshooting +The feed is Ed25519 signed. A v1 operator must explicitly wire and start the cache service; this package does not install an automatic scheduler. -## Future Enhancements +## Legacy Implementation Status -Planned features for future releases: -- File integrity monitoring (soul-guardian adaptation for containers) -- Real-time advisory alerts via WebSocket -- WhatsApp-native security alert formatting -- Behavioral analysis and anomaly detection -- Custom/private advisory feed support +The MCP tools, host services, IPC handlers, and integrity code are frozen v1 implementation and migration evidence. They are not a starting point for claiming NanoClaw v2 support. A future v2 core, suite, and drift guardian must use the v2-native workflow and land in separate packages and PRs. ## Documentation -- [Skill Documentation](skills/clawsec-nanoclaw/SKILL.md) - Features and architecture -- [Installation Guide](skills/clawsec-nanoclaw/INSTALL.md) - Detailed setup instructions -- [ClawSec Main README](README.md) - Overall ClawSec documentation +- [Skill Documentation](./SKILL.md) - Legacy v1 behavior and compatibility boundary +- [Installation Guide](./INSTALL.md) - Legacy v1 integration instructions +- [ClawSec Main README](../../README.md) - Overall ClawSec documentation - [Security & Signing](../../wiki/security-signing-runbook.md) - Signature verification details ## Support diff --git a/skills/clawsec-nanoclaw/SKILL.md b/skills/clawsec-nanoclaw/SKILL.md index 63bf3a06..fd5b50ce 100644 --- a/skills/clawsec-nanoclaw/SKILL.md +++ b/skills/clawsec-nanoclaw/SKILL.md @@ -1,24 +1,25 @@ --- name: clawsec-nanoclaw -version: 0.0.10 -description: Use when checking for security vulnerabilities in NanoClaw skills, before installing new skills, or when asked about security advisories affecting the bot +version: 0.0.11 +description: Use only with legacy NanoClaw >=0.1.0 <2.0.0 to check ClawSec advisories, package signatures, and the bundled v1 integrity adapter; NanoClaw v2 is incompatible and requires a separate adapter --- -# ClawSec for NanoClaw +# ClawSec for NanoClaw v1 (Legacy) -Security advisory monitoring that protects your WhatsApp bot from known vulnerabilities in skills and dependencies. +Legacy advisory, package-signature, and integrity tooling for compatible pre-v2 NanoClaw deployments. -## Vercel Skills Installation +## Compatibility Gate -Install with the Vercel Skills CLI for this harness: +- Supported NanoClaw range: `>=0.1.0 <2.0.0`. +- NanoClaw v2 (`>=2.0.0`): **incompatible; do not install or activate this adapter**. +- NanoClaw v2 uses different host, container, SQLite IPC, and extension surfaces. It requires a separate ClawSec adapter. +- The v1 integration paths in this package are retained for legacy users and migration evidence only. They are not NanoClaw v2 instructions. -```bash -npx skills add prompt-security/clawsec --skill clawsec-nanoclaw -a openclaw -y -``` +Stop if the target version is unknown or is NanoClaw v2. Do not reinterpret the v1 IPC examples as a generic installation recipe. ## Overview -ClawSec provides MCP tools that check installed skills against a curated feed of security advisories. It prevents installation of vulnerable skills, includes exploitability context for triage, and alerts you to issues in existing ones. +The bundled v1 MCP tools check installed skills against a curated feed of security advisories, include exploitability context for triage, and report issues in existing packages. They return advisory decisions; they do not own or enforce the host installer. **Core principle:** Check before you install. Monitor what's running. @@ -95,7 +96,7 @@ const advisories = await tools.clawsec_list_advisories({ ## Common Patterns -### Pattern 1: Safe Skill Installation +### Pattern 1: Pre-Installation Advisory Review ```typescript // ALWAYS check before installing @@ -103,28 +104,25 @@ const safety = await tools.clawsec_check_skill_safety({ skillName: userRequestedSkill }); -if (safety.safe) { - // Proceed with installation - await installSkill(userRequestedSkill); -} else { - // Show user the risks and get confirmation +if (!safety.safe) { + // Return the advisory evidence to the host installer or operator. await showSecurityWarning(safety.advisories); - if (await getUserConfirmation()) { - await installSkill(userRequestedSkill); - } + return { recommendation: 'do-not-install', safety }; } + +// Advisory output is one input, not installation authorization. +return { + recommendation: 'continue-review', + safety, + requiresSignatureVerification: true, + requiresCodeReview: true, + requiresOperatorApproval: true +}; ``` -### Pattern 2: Periodic Security Check +### Pattern 2: Legacy v1 Host Scheduling -```typescript -// Add to scheduled tasks -schedule_task({ - prompt: "Check advisories using clawsec_check_advisories and alert when critical or high-exploitability matches appear", - schedule_type: "cron", - schedule_value: "0 9 * * *" // Daily at 9am -}); -``` +Scheduling is deployment-owned. This package does not register a NanoClaw v2 task or scheduler integration. A compatible v1 operator may wire an advisory check through the v1 host's reviewed scheduling surface after completing the manual integration in [INSTALL.md](./INSTALL.md). ### Pattern 3: User Security Query @@ -153,7 +151,13 @@ await installSkill('untrusted-skill'); const safety = await tools.clawsec_check_skill_safety({ skillName: 'untrusted-skill' }); -if (safety.safe) await installSkill('untrusted-skill'); +if (!safety.safe) return { recommendation: 'do-not-install', safety }; +return { + recommendation: 'continue-review', + requiresSignatureVerification: true, + requiresCodeReview: true, + requiresOperatorApproval: true +}; ``` ### ❌ Ignoring exploitability context @@ -193,21 +197,21 @@ if (advisory.exploitability_score === 'high' || advisory.severity === 'critical' This signed feed is consolidated. NanoClaw receives NVD CVEs, approved community advisories, and provisional GHSA-without-CVE advisories through the same default URL. -**Update Frequency**: Every 6 hours (automatic) +**Legacy v1 example cadence**: Every 6 hours after explicit host wiring; the skill does not install a scheduler. **Signature Verification**: Ed25519 signed feeds **Package Verification Policy**: pinned key only, bounded package/signature paths -**Cache Location**: `/workspace/project/data/clawsec-advisory-cache.json` +**Legacy v1 cache location**: `/workspace/project/data/clawsec-advisory-cache.json` See [INSTALL.md](./INSTALL.md) for setup and [docs/](./docs/) for advanced usage. ## Real-World Impact -- Prevents installation of skills with known RCE vulnerabilities +- Helps operators identify skills with known RCE vulnerabilities before installation - Alerts to supply chain attacks in dependencies - Provides actionable remediation steps -- Zero false positives (curated feed only) +- Uses a curated feed while preserving severity and exploitability context for operator review ## Release Artifact Verification @@ -217,7 +221,7 @@ For standalone installs, verify the signed release manifest before trusting `SKI set -euo pipefail SKILL_NAME="clawsec-nanoclaw" -VERSION="0.0.10" +VERSION="0.0.11" REPO="prompt-security/clawsec" TAG="${SKILL_NAME}-v${VERSION}" BASE="https://github.com/${REPO}/releases/download/${TAG}" @@ -225,6 +229,8 @@ ZIP_NAME="${SKILL_NAME}-v${VERSION}.zip" TMP_DIR="$(mktemp -d)" trap 'rm -rf "$TMP_DIR"' EXIT +# ClawSec GitHub Release signing trust anchor. This is not a NanoClaw v2 +# integration key and is distinct from the v1 embedded feed-verification path. RELEASE_PUBKEY_SHA256="711424e4535f84093fefb024cd1ca4ec87439e53907b305b79a631d5befba9c8" curl -fsSL "$BASE/checksums.json" -o "$TMP_DIR/checksums.json" diff --git a/skills/clawsec-nanoclaw/docs/INTEGRITY.md b/skills/clawsec-nanoclaw/docs/INTEGRITY.md index 780922e0..6fdf0cce 100644 --- a/skills/clawsec-nanoclaw/docs/INTEGRITY.md +++ b/skills/clawsec-nanoclaw/docs/INTEGRITY.md @@ -1,6 +1,8 @@ -# File Integrity Monitoring for NanoClaw +# File Integrity Monitoring for NanoClaw v1 (Legacy) -ClawSec's file integrity monitoring protects critical NanoClaw configuration files from unauthorized modification. +> **Compatibility boundary:** This document describes the bundled NanoClaw v1 adapter for `>=0.1.0 <2.0.0`. It is incompatible with NanoClaw v2. Paths such as `registered_groups.json`, `CLAUDE.md`, `/workspace/ipc`, and `/workspace/project/...`, plus the `schedule_task` examples, are v1 layout and scheduler assumptions—not NanoClaw v2 guidance. + +The legacy adapter monitors selected NanoClaw v1 configuration files for unauthorized modification. ## What It Does @@ -48,9 +50,9 @@ This creates: └── audit.jsonl # Event log ``` -### Step 3: Enable Scheduled Monitoring +### Step 3: Legacy NanoClaw v1 Scheduler Example -Add to main group's scheduled tasks: +Only a confirmed v1 deployment with a reviewed host scheduler may add this example to the main group's scheduled tasks. The skill does not install a scheduler: ```typescript schedule_task({ @@ -264,7 +266,7 @@ if (!verification.valid) { ## Workflow Examples -### Scenario 1: Scheduled Monitoring +### Scenario 1: Legacy NanoClaw v1 Scheduler Example **Setup:** ```typescript @@ -564,4 +566,4 @@ A: No, but it's hash-chained for tamper detection. Encryption can be added in Ph --- -**Ready to protect your NanoClaw deployment? Start with the [Quick Start](#quick-start) guide above.** +**For a confirmed compatible v1 deployment, start with the [Quick Start](#quick-start) guide above. Do not use it for NanoClaw v2.** diff --git a/skills/clawsec-nanoclaw/docs/SKILL_SIGNING.md b/skills/clawsec-nanoclaw/docs/SKILL_SIGNING.md index 5719dd49..2474b37f 100644 --- a/skills/clawsec-nanoclaw/docs/SKILL_SIGNING.md +++ b/skills/clawsec-nanoclaw/docs/SKILL_SIGNING.md @@ -1,14 +1,16 @@ -# Skill Package Signing and Verification +# Skill Package Signing and Verification for NanoClaw v1 (Legacy) -This document explains how ClawSec signs skill packages and how NanoClaw agents verify signatures before installation. +> **Compatibility boundary:** This document describes the bundled NanoClaw v1 adapter for `>=0.1.0 <2.0.0`. It is incompatible with NanoClaw v2 and is not a v2 installation, publisher, or key-management contract. + +The bundled v1 verifier checks one detached `.sig` file with its configured pinned ClawSec public key. It does not accept caller-selected publisher keys, unsigned packages, or a dual-signature rotation format. --- ## Table of Contents 1. [Overview](#overview) -2. [For Skill Publishers: How to Sign Packages](#for-skill-publishers-how-to-sign-packages) -3. [For NanoClaw Agents: How to Verify Signatures](#for-nanoclaw-agents-how-to-verify-signatures) +2. [Publisher Workflow Is Out of Scope](#publisher-workflow-is-out-of-scope) +3. [For Legacy NanoClaw v1 Agents](#for-legacy-nanoclaw-v1-agents) 4. [Security Properties](#security-properties) 5. [Key Management](#key-management) 6. [Troubleshooting](#troubleshooting) @@ -17,7 +19,7 @@ This document explains how ClawSec signs skill packages and how NanoClaw agents ## Overview -Skill signature verification prevents **supply chain attacks** by ensuring skill packages haven't been tampered with during distribution. ClawSec uses **Ed25519 digital signatures** to sign skill packages, and NanoClaw agents verify these signatures before installation. +The legacy verifier can detect whether a staged package matches a detached signature made by the pinned ClawSec key. Verification is one input to an operator decision; the tool does not install a package and does not make arbitrary third-party packages trusted. ### Why Signature Verification? @@ -27,82 +29,21 @@ Without signature verification, an attacker could: - **Distribute** trojan skills that appear legitimate but contain malware Signature verification ensures: -- ✅ **Authenticity**: Package comes from ClawSec (or trusted publisher) +- ✅ **Authenticity**: Signature matches the configured pinned ClawSec key - ✅ **Integrity**: Package hasn't been modified since signing - ✅ **Non-repudiation**: Signer can't deny signing the package --- -## For Skill Publishers: How to Sign Packages - -### Prerequisites - -- OpenSSL 1.1.1+ (for Ed25519 support) -- Private Ed25519 signing key (generate once, keep secure) -- Skill package ready for distribution - -### Step 1: Generate Ed25519 Keypair (One-Time Setup) - -```bash -# Generate private key (KEEP THIS SECRET!) -openssl genpkey -algorithm ED25519 -out clawsec-signing-private.pem - -# Extract public key (share this with users) -openssl pkey -in clawsec-signing-private.pem -pubout -out clawsec-signing-public.pem - -# Secure the private key -chmod 600 clawsec-signing-private.pem -``` - -**⚠️ CRITICAL**: Never commit the private key to version control! Store it securely: -- Local machine: `~/.ssh/clawsec-signing-private.pem` with `chmod 600` -- CI/CD: GitHub Secrets, AWS Secrets Manager, or similar -- Team: 1Password, Vault, or hardware security module (HSM) - -### Step 2: Package Your Skill - -```bash -# Create skill package (tarball or zip) -tar -czf my-skill-1.0.0.tar.gz -C skills/my-skill . - -# Or as a zip file -zip -r my-skill-1.0.0.zip skills/my-skill/ -``` - -### Step 3: Sign the Package - -```bash -# Create detached Ed25519 signature -openssl dgst -sha512 -sign clawsec-signing-private.pem \ - -out my-skill-1.0.0.tar.gz.sig \ - my-skill-1.0.0.tar.gz - -# Verify the signature was created -ls -lh my-skill-1.0.0.tar.gz.sig -# Should show a ~64-byte file -``` - -**Signature Format**: Detached Ed25519 signature, base64-encoded, stored in `.sig` file. - -### Step 4: Distribute Package + Signature - -Distribute **both** files together: -- `my-skill-1.0.0.tar.gz` (the skill package) -- `my-skill-1.0.0.tar.gz.sig` (the signature) - -Users will verify the signature against your public key before installation. +## Publisher Workflow Is Out of Scope -### Step 5: Publish Public Key +This legacy package does not define a supported publisher key-generation or arbitrary-package signing workflow. The bundled verifier accepts only the key configured by the v1 host service; callers cannot supply a different key or request unsigned acceptance. -Share your public key with users via: -- **Pinned in repository**: Commit `clawsec-signing-public.pem` to your repo -- **Website**: Host at `https://yoursite.com/clawsec-signing-public.pem` -- **DNS TXT record**: Publish as base64-encoded TXT record -- **Skill metadata**: Embed in `skill.json` +Use the ClawSec release pipeline and its signed release manifest for official ClawSec package publication. Do not generate a local key and expect this adapter to trust it. --- -## For NanoClaw Agents: How to Verify Signatures +## For Legacy NanoClaw v1 Agents ### Quick Start @@ -124,7 +65,7 @@ if (!result.valid) { console.log(`✓ Signature valid (signer: ${result.signer})`); console.log(`Package hash: ${result.packageInfo.sha256}`); -console.log('Safe to proceed with installation.'); +console.log('Signature matches the pinned key; continue required advisory review and operator approval.'); ``` ### MCP Tool: `clawsec_verify_skill_package` @@ -143,7 +84,7 @@ Path policy: { success: boolean, // Operation completed without errors valid: boolean, // Signature is cryptographically valid - recommendation: string, // "install" | "block" | "review" + recommendation: string, // "install" | "block" signer: string, // "clawsec" algorithm: "Ed25519", // Signature algorithm verifiedAt: string, // ISO timestamp @@ -157,27 +98,30 @@ Path policy: ### Usage Patterns -#### Pattern 1: Basic Pre-Installation Check +#### Pattern 1: Basic Signature Review ```typescript -async function installSkill(packagePath: string) { +async function reviewSkillSignature(packagePath: string) { // Verify signature first const verification = await tools.clawsec_verify_skill_package({ packagePath }); const result = JSON.parse(verification.content[0].text); - if (result.recommendation === 'block') { - throw new Error(`Cannot install: ${result.reason || result.error}`); + if (!result.success || !result.valid || result.recommendation === 'block') { + throw new Error(`Signature review failed: ${result.reason || result.error}`); } - // Signature valid - proceed with extraction - extractPackage(packagePath, '/workspace/project/skills/'); + return { + packagePath, + verification: result, + nextStep: 'Complete advisory and code review, then request operator approval.' + }; } ``` #### Pattern 2: Combined Security Checks ```typescript -async function installSkillSafely(packagePath: string, skillName: string) { +async function buildInstallReview(packagePath: string, skillName: string) { // Step 1: Verify signature const sigVerify = await tools.clawsec_verify_skill_package({ packagePath }); const sigResult = JSON.parse(sigVerify.content[0].text); @@ -194,16 +138,21 @@ async function installSkillSafely(packagePath: string, skillName: string) { throw new Error(`Known vulnerabilities: ${advResult.advisories.map(a => a.id).join(', ')}`); } - // Both checks passed - safe to install - extractPackage(packagePath, '/workspace/project/skills/'); - console.log(`✓ Installed ${skillName} (verified + no advisories)`); + // These checks produce evidence; they do not authorize or perform installation. + return { + packagePath, + signature: sigResult, + advisories: advResult, + requiresCodeReview: true, + requiresOperatorApproval: true + }; } ``` #### Pattern 3: Download and Verify Workflow ```typescript -async function downloadAndInstallSkill(url: string) { +async function downloadAndVerifySkill(url: string) { const packagePath = `/tmp/${Date.now()}-skill.tar.gz`; const signaturePath = `${packagePath}.sig`; @@ -231,12 +180,9 @@ async function downloadAndInstallSkill(url: string) { throw new Error('Signature verification failed'); } - // Install verified package - extractPackage(packagePath, '/workspace/project/skills/'); - - // Cleanup - fs.unlinkSync(packagePath); - fs.unlinkSync(signaturePath); + // Preserve the staged files for advisory/code review and operator approval. + // The host installer must separately enforce the final decision. + return { packagePath, signaturePath, verification: result }; } ``` @@ -263,13 +209,10 @@ if (!result.valid) { // Finally check recommendation switch (result.recommendation) { case 'install': - console.log('✓ Safe to install'); + console.log('✓ Signature recommendation permits continued review; operator approval is still required'); break; case 'block': - console.error('⛔ Installation blocked'); - break; - case 'review': - console.warn('⚠️ Manual review recommended'); + console.error('⛔ Signature recommendation is block; the host installer or operator must enforce it'); break; } ``` @@ -278,9 +221,9 @@ switch (result.recommendation) { ## Security Properties -### What Signature Verification Prevents +### What Signature Verification Detects -✅ **Prevents:** +✅ **Detects:** - **Tampering**: Detecting if package contents were modified after signing - **MITM attacks**: Detecting if package was swapped during download - **Malicious mirrors**: Ensuring package comes from trusted source @@ -312,7 +255,7 @@ Signature verification relies on **trust in the public key**: │ ↓ │ │ You verify signature with ClawSec's public key │ │ ↓ │ -│ Signature valid → Package is authentic │ +│ Signature valid → Bytes match the pinned key │ └─────────────────────────────────────────────────┘ ``` @@ -330,7 +273,7 @@ Signature verification relies on **trust in the public key**: **Location**: `/workspace/project/skills/clawsec-nanoclaw/advisories/feed-signing-public.pem` -This is the **same key** used for advisory feed verification, providing a single trust anchor for all ClawSec security operations. +The legacy v1 package-verifier handler reads the embedded advisory feed-verification key by default. That coupling is limited to this frozen adapter. It is not the ClawSec GitHub Release manifest trust anchor and is not a NanoClaw v2 trust contract. **Key Fingerprint** (for manual verification): ```bash @@ -347,19 +290,7 @@ Runtime public-key overrides are intentionally not supported. ### Key Rotation -If ClawSec's signing key is compromised or needs rotation: - -1. **Generate new keypair** (keep private key secure) -2. **Sign all packages** with new key -3. **Publish new public key** to all distribution channels -4. **Update pinned key** in `/workspace/project/skills/clawsec-nanoclaw/advisories/` -5. **Deprecate old key** after transition period (e.g., 90 days) - -During transition, support **dual signatures**: -- `package.tar.gz.sig` (old key) -- `package.tar.gz.sig2` (new key) - -Agents can verify with either key during the overlap period. +The bundled v1 verifier has no dual-key or dual-signature rotation protocol. It accepts one configured public key and one `.sig` path. A key change requires a reviewed package update and explicit operator migration; do not invent a `.sig2` fallback or accept caller-selected keys. --- @@ -483,6 +414,6 @@ MEQCIDxyz...ABC123== --- -**Document Version**: 1.0.0 -**Last Updated**: 2026-02-25 +**Document Version**: 0.0.11 legacy adapter +**Last Updated**: 2026-07-22 **Maintainer**: ClawSec Security Team diff --git a/skills/clawsec-nanoclaw/host-services/skill-signature-handler.ts b/skills/clawsec-nanoclaw/host-services/skill-signature-handler.ts index 4c5b6480..ebe9a8f7 100644 --- a/skills/clawsec-nanoclaw/host-services/skill-signature-handler.ts +++ b/skills/clawsec-nanoclaw/host-services/skill-signature-handler.ts @@ -1,7 +1,8 @@ /** * Skill Signature Verification Handler for NanoClaw * - * Verifies Ed25519 signatures on skill packages to prevent supply chain attacks. + * Verifies Ed25519 signatures on staged skill packages so callers can detect + * tampering before an operator or host installer decides whether to proceed. * Uses the same pinned public key as advisory feed verification. */ diff --git a/skills/clawsec-nanoclaw/mcp-tools/advisory-tools.ts b/skills/clawsec-nanoclaw/mcp-tools/advisory-tools.ts index c705785d..ccc38f14 100644 --- a/skills/clawsec-nanoclaw/mcp-tools/advisory-tools.ts +++ b/skills/clawsec-nanoclaw/mcp-tools/advisory-tools.ts @@ -182,7 +182,7 @@ server.tool( server.tool( 'clawsec_check_skill_safety', - 'Check if a specific skill is safe to install based on ClawSec advisory feed. Returns safety recommendation (install/block/review) with reasons. Use this as a pre-install gate before installing any skill.', + 'Check a skill and optional version against the cached ClawSec advisory feed. Returns an install/block/review recommendation with reasons; the host installer or operator must enforce it and complete other required review.', { skillName: z.string().describe('Name of skill to check'), skillVersion: z.string().optional().describe('Version of skill (optional, for version-specific checks)'), diff --git a/skills/clawsec-nanoclaw/mcp-tools/signature-verification.ts b/skills/clawsec-nanoclaw/mcp-tools/signature-verification.ts index 216e8181..b3f9576b 100644 --- a/skills/clawsec-nanoclaw/mcp-tools/signature-verification.ts +++ b/skills/clawsec-nanoclaw/mcp-tools/signature-verification.ts @@ -3,7 +3,8 @@ * * Add this tool to /workspace/project/container/agent-runner/src/ipc-mcp-stdio.ts * - * This tool verifies Ed25519 signatures on skill packages to prevent supply chain attacks. + * This tool reports Ed25519 signature verification results for operator or + * host-installer review. It does not install packages or enforce the result. */ /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -91,7 +92,7 @@ async function waitForResult(requestId: string, timeoutMs: number = 5000): Promi server.tool( 'clawsec_verify_skill_package', - 'Verify Ed25519 signature of a skill package before installation. Prevents installation of tampered or malicious skill packages by checking ClawSec signatures.', + 'Verify the Ed25519 signature of a staged skill package and return an install/block recommendation. The host installer or operator must enforce the result and complete advisory and code review.', { packagePath: z.string().describe('Absolute path to skill package (.tar.gz or .zip)'), signaturePath: z.string().optional().describe('Path to signature file. If omitted, auto-detects .sig'), diff --git a/skills/clawsec-nanoclaw/skill.json b/skills/clawsec-nanoclaw/skill.json index 22e21a5b..3e52dc94 100644 --- a/skills/clawsec-nanoclaw/skill.json +++ b/skills/clawsec-nanoclaw/skill.json @@ -1,7 +1,7 @@ { "name": "clawsec-nanoclaw", - "version": "0.0.10", - "description": "ClawSec security suite for NanoClaw - Advisory feed monitoring, MCP tools for vulnerability checking, and Ed25519 signature verification for containerized WhatsApp bot agents", + "version": "0.0.11", + "description": "Legacy ClawSec adapter for pre-v2 NanoClaw deployments; supports NanoClaw >=0.1.0 <2.0.0 and is incompatible with NanoClaw v2", "author": "prompt-security", "license": "AGPL-3.0-or-later", "homepage": "https://clawsec.prompt.security/", @@ -35,7 +35,7 @@ { "path": "INSTALL.md", "required": true, - "description": "Installation guide for NanoClaw deployments" + "description": "Legacy integration guide for NanoClaw >=0.1.0 <2.0.0" }, { "path": "mcp-tools/advisory-tools.ts", @@ -128,10 +128,10 @@ "Advisory feed monitoring from clawsec.prompt.security", "MCP tools for agent-initiated vulnerability scans", "Exploitability-aware advisory prioritization for agent environments", - "Pre-installation skill safety checks", + "Pre-installation advisory checks for operator decisions", "Ed25519 signature verification for advisory feeds", "Platform metadata preserved in advisory records for downstream filtering", - "Containerized agent support with IPC communication" + "Legacy NanoClaw v1 container support with v1 IPC communication" ], "nanoclaw": { "mcp_tools": [ @@ -147,7 +147,7 @@ ], "requires": { "node": ">=18.0.0", - "nanoclaw": ">=0.1.0" + "nanoclaw": ">=0.1.0 <2.0.0" }, "integration": { "mcp_tools_file": "container/agent-runner/src/ipc-mcp-stdio.ts", diff --git a/skills/clawsec-nanoclaw/test/nanoclaw-v1-compatibility.test.mjs b/skills/clawsec-nanoclaw/test/nanoclaw-v1-compatibility.test.mjs new file mode 100644 index 00000000..d6e54cf2 --- /dev/null +++ b/skills/clawsec-nanoclaw/test/nanoclaw-v1-compatibility.test.mjs @@ -0,0 +1,114 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const testDir = path.dirname(fileURLToPath(import.meta.url)); +const skillRoot = path.resolve(testDir, '..'); + +function read(relativePath) { + return fs.readFileSync(path.join(skillRoot, relativePath), 'utf8'); +} + +function frontmatterValue(markdown, key) { + const match = markdown.match(new RegExp(`^${key}:\\s*(.+)$`, 'm')); + assert.ok(match, `SKILL.md frontmatter must define ${key}`); + return match[1].trim(); +} + +const skillJson = JSON.parse(read('skill.json')); +const skill = read('SKILL.md'); +const readme = read('README.md'); +const install = read('INSTALL.md'); +const signing = read('docs/SKILL_SIGNING.md'); +const integrity = read('docs/INTEGRITY.md'); +const changelog = read('CHANGELOG.md'); +const signatureTool = read('mcp-tools/signature-verification.ts'); +const advisoryTool = read('mcp-tools/advisory-tools.ts'); + +assert.equal(skillJson.version, '0.0.11', 'skill.json must carry the truthfulness release version'); +assert.equal(frontmatterValue(skill, 'version'), '0.0.11', 'SKILL.md must match skill.json version'); +assert.equal( + skillJson.nanoclaw?.requires?.nanoclaw, + '>=0.1.0 <2.0.0', + 'legacy package metadata must exclude NanoClaw v2', +); + +const compatibilityDocuments = new Map([ + ['skill.json description', skillJson.description], + ['SKILL.md', skill], + ['README.md', readme], + ['INSTALL.md', install], + ['docs/SKILL_SIGNING.md', signing], + ['docs/INTEGRITY.md', integrity], +]); + +for (const [label, text] of compatibilityDocuments) { + assert.match(text, /(?:NanoClaw v1|pre-v2)/i, `${label} must identify the legacy v1/pre-v2 scope`); + assert.match(text, /NanoClaw v2[\s\S]{0,100}incompatible|incompatible[\s\S]{0,100}NanoClaw v2/i, + `${label} must state NanoClaw v2 incompatibility`); +} + +for (const [label, text] of [['SKILL.md', skill], ['README.md', readme]]) { + assert.doesNotMatch( + text, + /npx\s+skills\s+add[\s\S]{0,160}(?:-a|--agent)\s+openclaw/i, + `${label} must not present an OpenClaw-targeted installer command for NanoClaw`, + ); +} + +for (const [label, text] of [['SKILL.md', skill], ['README.md', readme], ['INSTALL.md', install]]) { + assert.doesNotMatch(text, /Every 6 hours \(automatic\)/i, `${label} must not claim automatic scheduling`); +} + +assert.doesNotMatch(skill, /prevents installation of vulnerable skills/i, + 'the advisory tool must not claim ownership of the host installer'); +assert.doesNotMatch(readme, /ClawSec now supports NanoClaw/i, + 'the legacy README must not make an unqualified current-support claim'); +assert.doesNotMatch(signatureTool, /prevents installation/i, + 'the signature tool must not claim ownership of the host installer'); +assert.match(signatureTool, /host installer or operator must enforce/i, + 'the signature tool must identify who enforces its recommendation'); +assert.doesNotMatch(signatureTool, /install\/block\/review/i, + 'the signature tool must not advertise an unreachable review recommendation'); +assert.doesNotMatch(advisoryTool, /safe to install based on/i, + 'the advisory tool must not present its feed result as complete installation safety'); +assert.match(advisoryTool, /host installer or operator must enforce/i, + 'the advisory tool must identify who enforces its recommendation'); + +for (const [label, text] of compatibilityDocuments) { + let offset = 0; + while ((offset = text.indexOf('schedule_task(', offset)) !== -1) { + const context = text.slice(Math.max(0, offset - 320), offset); + assert.match( + context, + /Legacy NanoClaw v1 Scheduler Example|Compatibility boundary/i, + `${label} must scope every retained schedule_task example to legacy NanoClaw v1`, + ); + offset += 'schedule_task('.length; + } +} + +assert.match(signing, /Publisher Workflow Is Out of Scope/, + 'legacy signing documentation must reject an invented publisher workflow'); +assert.match(signing, /does not accept caller-selected publisher keys/i, + 'legacy signing documentation must describe pinned-key behavior'); +assert.match(signing, /has no dual-key or dual-signature rotation protocol/i, + 'legacy signing documentation must describe the actual single-key verifier'); +assert.doesNotMatch(signing, /comes from ClawSec \(or trusted publisher\)/i, + 'legacy signing documentation must not claim arbitrary publisher trust'); +assert.doesNotMatch(signing, /During transition, support \*\*dual signatures\*\*/i, + 'legacy signing documentation must not claim unsupported dual-signature rotation'); +assert.doesNotMatch(signing, /Agents can verify with either key during the overlap period/i, + 'legacy signing documentation must not claim unsupported multi-key verification'); +assert.doesNotMatch(signing, /Safe to install|Installation blocked|proceed with extraction|extractPackage\(/i, + 'legacy signing examples must not treat verification as installation authority'); +assert.match(signing, /requiresOperatorApproval|operator approval is still required/i, + 'legacy signing examples must preserve explicit operator approval'); +assert.doesNotMatch(signing, /"install"\s*\|\s*"block"\s*\|\s*"review"|case 'review'/i, + 'legacy signing documentation must list only implemented recommendation outcomes'); +assert.doesNotMatch(skill, /if\s*\(safety\.safe\)\s*await installSkill|Proceed with installation/i, + 'the skill must not treat advisory output as installation authorization'); + +assert.match(changelog, /^## \[0\.0\.11\] - 2026-07-22$/m, + 'CHANGELOG.md must record the truthfulness release'); From 09b72d3e76e32ec684b1cfb6228528895ffa66ee Mon Sep 17 00:00:00 2001 From: David Abutbul Date: Thu, 23 Jul 2026 00:23:29 +0300 Subject: [PATCH 2/3] fix(nanoclaw): make legacy package non-installable --- skills/clawsec-nanoclaw/CHANGELOG.md | 8 +- skills/clawsec-nanoclaw/INSTALL.md | 367 ++--------- skills/clawsec-nanoclaw/README.md | 133 ++-- skills/clawsec-nanoclaw/SKILL.md | 322 ++-------- skills/clawsec-nanoclaw/docs/INTEGRITY.md | 591 ++---------------- skills/clawsec-nanoclaw/docs/SKILL_SIGNING.md | 439 ++----------- skills/clawsec-nanoclaw/skill.json | 126 +--- .../test/nanoclaw-legacy-status.test.mjs | 151 +++++ .../test/nanoclaw-v1-compatibility.test.mjs | 114 ---- .../test/security-hardening.test.mjs | 2 + 10 files changed, 422 insertions(+), 1831 deletions(-) create mode 100644 skills/clawsec-nanoclaw/test/nanoclaw-legacy-status.test.mjs delete mode 100644 skills/clawsec-nanoclaw/test/nanoclaw-v1-compatibility.test.mjs diff --git a/skills/clawsec-nanoclaw/CHANGELOG.md b/skills/clawsec-nanoclaw/CHANGELOG.md index d4e5d5c3..8366a2d1 100644 --- a/skills/clawsec-nanoclaw/CHANGELOG.md +++ b/skills/clawsec-nanoclaw/CHANGELOG.md @@ -4,9 +4,11 @@ ### Changed -- Bounded this legacy adapter to NanoClaw `>=0.1.0 <2.0.0` and marked NanoClaw v2 as incompatible. -- Removed or explicitly scoped obsolete v2-facing installation, scheduler, IPC-layout, and key-management claims to the pre-v2 adapter. -- Added a compatibility regression test while preserving the frozen v1 runtime behavior as migration evidence. +- Reclassified the package as a deprecated, runtime-unverified NanoClaw v1-era integration prototype with no asserted support range. +- Removed actionable setup, restart, scheduling, integrity, and signing instructions from the packaged user-facing Markdown where they were not proven against an official NanoClaw runtime. +- Marked NanoClaw v2 as incompatible and documented its additive skill and two-database host/container boundaries. +- Excluded runtime-unverified TypeScript, policy JSON, and PEM artifacts from the release SBOM while retaining the frozen source in the repository as migration evidence. +- Added a static legacy-status contract test for the non-installable, documentation-only release boundary. ## [0.0.10] - 2026-06-23 diff --git a/skills/clawsec-nanoclaw/INSTALL.md b/skills/clawsec-nanoclaw/INSTALL.md index 89046dd7..de3dd02e 100644 --- a/skills/clawsec-nanoclaw/INSTALL.md +++ b/skills/clawsec-nanoclaw/INSTALL.md @@ -1,331 +1,92 @@ -# ClawSec Legacy NanoClaw v1 Integration Guide +# Historical NanoClaw Integration Record -> **Compatibility boundary:** This entire guide applies only to NanoClaw `>=0.1.0 <2.0.0`. NanoClaw v2 (`>=2.0.0`) is incompatible. Do not copy these files, use these IPC paths, or run these restart steps on v2. NanoClaw v2 requires a separate adapter for its current SQLite-backed and host/container extension model. +> **Do not install this package.** This file preserves the failed assumptions of an earlier NanoClaw v1-era integration template. It is not an installation guide. -This guide records the manual integration for compatible pre-v2 NanoClaw deployments. +## Classification -## Overview +- Package: `clawsec-nanoclaw` +- Version: `0.0.11` +- Status: historical and unverified +- Supported NanoClaw versions: none asserted +- NanoClaw v2: incompatible +- Runtime activation: prohibited until a separate implementation passes its own acceptance suite -The legacy v1 adapter provides security advisory monitoring through: -- **MCP Tools**: Agents can check for vulnerabilities via `clawsec_check_advisories` -- **Advisory Feed**: Host-wired monitoring of https://clawsec.prompt.security/advisories/feed.json -- **Signature Verification**: Ed25519-signed feeds ensure integrity -- **Exploitability Context**: Advisories include exploitability score and rationale for triage +NanoClaw has no reviewed direct Agent Skills CLI target; do not substitute an OpenClaw or another unrelated target. -## Prerequisites +## Why the Former Procedure Was Withdrawn -- NanoClaw >= 0.1.0 and < 2.0.0 -- Node.js >= 18.0.0 -- Write access to NanoClaw installation directory +The previous procedure instructed operators to copy modules into a NanoClaw checkout and import them from the agent runner. That does not establish a working module boundary. -## Legacy v1 Integration Steps +The files under `mcp-tools/` declare these identifiers without importing or receiving them: -Every path and code fragment below is a NanoClaw v1 layout assumption. Stop if the target version is unknown or is NanoClaw v2. +- `server` +- `writeIpcFile` +- `TASKS_DIR` +- `groupFolder` -### 1. Copy Skill Files into a Confirmed v1 Checkout +TypeScript `declare` statements emit no JavaScript. ES modules also do not inherit lexical variables from their importers. Importing these files therefore cannot bind the identifiers that their top-level registration and handlers use. -Copy the `clawsec-nanoclaw` skill directory to your NanoClaw installation: +Additional retained assumptions were not qualified against an upstream runtime: -```bash -# From the ClawSec repository -cp -r skills/clawsec-nanoclaw /path/to/your/nanoclaw/skills/ -``` +- `guardian/integrity-monitor.ts` declares a `glob` namespace but imports or receives no runtime implementation, so `glob.sync` is unbound. +- `host-services/ipc-handlers.ts` declares `writeResponse` but imports or implements no such function. +- `host-services/skill-signature-handler.ts` uses CommonJS `__dirname` in an ES module without defining an equivalent ESM path. +- Docker Compose restart commands did not match the reviewed v1 service model. +- Some host services hard-code paths that belong to the container view. +- Group, task, cache, result, and integrity paths are not bound to one verified NanoClaw layout. +- The host IPC wrapper is incomplete and has no end-to-end response-path test. +- No apply, update, removal, interruption-recovery, or rollback transaction was tested. -### 2. Integrate v1 MCP Tools +The old commands and code snippets were removed so an agent cannot mistake them for a supported installation path. -Add the ClawSec MCP tools to your NanoClaw container agent runner. +## NanoClaw v2 Boundary -**File**: `container/agent-runner/src/ipc-mcp-stdio.ts` +NanoClaw v2 is a ground-up rewrite. Current official documentation describes: -```typescript -// Add these imports at the top to register all ClawSec MCP tools: +- A Node.js host and one container per active session. +- Per-session `inbound.db` and `outbound.db` files with opposite writer ownership. +- Additive code-carrying skills executed by a coding harness. +- Skills that copy reviewed files, append explicit registration imports, pin dependencies, run integration tests, and provide `REMOVE.md` when state is left behind. +- Scheduled tasks managed by current host surfaces rather than the retired v1 `schedule_task` MCP example. -// Advisory tools: clawsec_check_advisories, clawsec_check_skill_safety, -// clawsec_list_advisories, clawsec_refresh_cache -import '../../../skills/clawsec-nanoclaw/mcp-tools/advisory-tools.js'; +These upstream facts were observed on 2026-07-22. Reverify the current official documentation and source revision before relying on them for a migration decision. -// Signature verification: clawsec_verify_skill_package -import '../../../skills/clawsec-nanoclaw/mcp-tools/signature-verification.js'; +This package instead preserves v1-era message-file IPC, runner reach-ins, and path assumptions. Do not translate them by changing path strings. -// Integrity monitoring: clawsec_check_integrity, clawsec_approve_change, -// clawsec_integrity_status, clawsec_verify_audit -import '../../../skills/clawsec-nanoclaw/mcp-tools/integrity-tools.js'; -``` +## Existing Fork Assessment -Each file calls `server.tool()` directly to register its tools. The `server`, -`writeIpcFile`, `TASKS_DIR`, and `groupFolder` variables must be available in -the scope where these files are imported (they are declared as ambient globals -in each tool file). +If an operator already has a historical customization, perform a read-only assessment: -### 3. Integrate v1 IPC Handlers +1. Record the exact NanoClaw commit and local modifications. +2. Locate every ClawSec file, import, service, task, cache, baseline, and result path. +3. Determine whether any process actually loads the modules and capture its logs without restarting it. +4. Record file digests, ownership, permissions, host/container location, and dependencies. +5. Identify how to disable the customization without deleting state. +6. Prepare rollback and migration steps for operator review. -Add the host-side IPC handlers for ClawSec operations. +If current authorization does not permit access to live logs, record runtime execution evidence as unknown. Do not infer that the customization works or is inactive. -**File**: `src/ipc.ts` +Do not run the historical setup or removal instructions from an older release. Do not mutate the deployment merely to test whether the integration works. -```typescript -// Add these imports at the top -import { handleAdvisoryIpc } from '../skills/clawsec-nanoclaw/host-services/ipc-handlers.js'; -import { AdvisoryCacheManager } from '../skills/clawsec-nanoclaw/host-services/advisory-cache.js'; -import { SkillSignatureVerifier } from '../skills/clawsec-nanoclaw/host-services/skill-signature-handler.js'; +## Qualification Required for Any Replacement -// Initialize these once in host startup and pass through deps -const advisoryCacheManager = new AdvisoryCacheManager('/workspace/project/data', logger); -const signatureVerifier = new SkillSignatureVerifier(); +A new NanoClaw package must be developed separately and must provide: -// In processTaskIpc switch: -case 'refresh_advisory_cache': -case 'verify_skill_signature': - await handleAdvisoryIpc( - data, - { advisoryCacheManager, signatureVerifier }, - logger, - sourceGroup - ); - break; -default: - // existing task handling -} -``` +- A declared, pinned NanoClaw v2 support range. +- A complete additive apply plan with exact preimages and postimages. +- An explicit registration boundary; no ambient globals. +- Integration tests that fail when required wiring is absent. +- Correct host/container path ownership and database-writer invariants. +- Idempotent apply, update, resume, remove, and rollback behavior. +- `REMOVE.md` for every persistent change. +- Remote harness acceptance using the exact copied candidate bytes. +- Signed qualification and installation receipts before stable release. -### 4. Start the v1 Host Advisory Cache Service +Treat a successor as available only when the current published release and its acceptance evidence prove that status. A roadmap entry, source directory, branch, pull request, or version-shaped label is not availability evidence. -Add the advisory cache manager to your host services. +## Official References -**File**: `src/index.ts` (or your main entry point) - -```typescript -import { AdvisoryCacheManager } from '../skills/clawsec-nanoclaw/host-services/advisory-cache.js'; - -// Start the service when your host process starts -async function main() { - // ... your existing initialization ... - - // Initialize cache manager and prime it at startup - const advisoryCacheManager = new AdvisoryCacheManager('/workspace/project/data', logger); - await advisoryCacheManager.initialize(); - - // Recommended refresh cadence (6h) - setInterval(() => { - advisoryCacheManager.refresh().catch((error) => { - logger.error({ error }, 'Periodic advisory cache refresh failed'); - }); - }, 6 * 60 * 60 * 1000); - - // ... rest of your startup ... -} -``` - -### 5. Restart the Legacy v1 Docker Compose Deployment - -Restart your NanoClaw instance to load the new MCP tools and services: - -```bash -# Stop NanoClaw -docker-compose down - -# Start with new configuration -docker-compose up -d -``` - -## Legacy v1 Verification - -Test that ClawSec is working: - -### 1. Check MCP Tools Available - -From within a NanoClaw agent session, the following tools should be available: - -**Advisory Tools** (mcp-tools/advisory-tools.ts): -- `clawsec_check_advisories` - Scan installed skills for vulnerabilities -- `clawsec_check_skill_safety` - Pre-installation safety check -- `clawsec_list_advisories` - List all advisories with filtering -- `clawsec_refresh_cache` - Request immediate advisory cache refresh - -**Signature Verification** (mcp-tools/signature-verification.ts): -- `clawsec_verify_skill_package` - Verify Ed25519 signature on skill packages - - Uses pinned ClawSec public key (no runtime key override) - - Accepts staged package/signature paths only under `/tmp`, `/var/tmp`, `/workspace/ipc`, `/workspace/project/data`, `/workspace/project/tmp`, `/workspace/project/downloads` - -**Integrity Monitoring** (mcp-tools/integrity-tools.ts): -- `clawsec_check_integrity` - Check protected files for unauthorized changes -- `clawsec_approve_change` - Approve intentional file modification as new baseline -- `clawsec_integrity_status` - View current baseline status -- `clawsec_verify_audit` - Verify audit log hash chain integrity - -### 2. Test Advisory Checking - -Ask your NanoClaw agent: -``` -Check if any of my installed skills have security advisories -``` - -The agent should use the `clawsec_check_advisories` tool and report results. - -### 3. Check Advisory Cache - -Verify the cache file was created: -```bash -cat /workspace/project/data/clawsec-advisory-cache.json -``` - -You should see: -- `feed`: Array of advisories -- `fetchedAt`: Timestamp of last update -- `verified`: Should be `true` -- `publicKeyFingerprint`: SHA-256 fingerprint of the pinned signing key - -## Usage Examples - -### Agent Commands - -Once installed, your NanoClaw agents can: - -**Check for vulnerabilities:** -``` -Scan my installed skills for security issues -``` - -**Pre-installation check:** -``` -Is it safe to install skill-name@1.0.0? -``` - -**List all advisories:** -``` -Show me all ClawSec security advisories -``` - -### Manual Tool Invocation - -You can also call the MCP tools directly from agent code: - -```typescript -// Check all installed skills -const result = await tools.clawsec_check_advisories({ - installRoot: '/home/node/.claude/skills' -}); - -// Check specific skill before installation -const safetyCheck = await tools.clawsec_check_skill_safety({ - skillName: 'risky-skill', - skillVersion: '1.0.0' -}); -``` - -## Configuration - -### Cache Location - -Default: `/workspace/project/data/clawsec-advisory-cache.json` - -To change, pass a different data directory path to `new AdvisoryCacheManager(dataDir, logger)`. - -### Refresh Interval - -Example v1 host cadence: 6 hours after explicit operator wiring. The skill does not install a scheduler. - -To change, update the `setInterval(...)` duration (in milliseconds) in host startup. - -### Feed URL - -Default: `https://clawsec.prompt.security/advisories/feed.json` - -To use a mirror or custom feed, update `FEED_URL` in `skills/clawsec-nanoclaw/host-services/advisory-cache.ts`. - -## Platform-Specific Advisories - -ClawSec advisories can target specific platforms: - -- **`platforms: ["nanoclaw"]`**: Only affects NanoClaw -- **`platforms: ["openclaw"]`**: Only affects OpenClaw/MoltBot -- **`platforms: ["openclaw", "nanoclaw"]`**: Affects both -- **No `platforms` field**: Applies to all platforms - -Platform metadata is preserved in advisory records and can be filtered by your policy layer. - -## Security - -### Signature Verification - -The v1 advisory cache verifies Ed25519-signed feeds with the public key embedded at: -``` -skills/clawsec-nanoclaw/advisories/feed-signing-public.pem -``` - -Feeds failing signature verification are rejected. The v1 package-verifier handler also reads this embedded feed-verification key by default. This is not a NanoClaw v2 installer/trust contract, and it is distinct from the ClawSec GitHub Release manifest key downloaded and fingerprint-checked in `SKILL.md`. - -### Cache Integrity - -The advisory cache includes: -- Cryptographic signature of feed contents -- Verification status -- Timestamp of last successful fetch - -Never manually edit the cache file - it will break signature verification. - -## Troubleshooting - -### Tools Not Appearing - -**Problem**: MCP tools not showing up in agent - -**Solution**: -1. Check that you added the import and registration in `ipc-mcp-stdio.ts` -2. Restart the container -3. Check container logs for import errors - -### Cache Not Updating - -**Problem**: Advisory cache is empty or stale - -**Solution**: -1. Check that `AdvisoryCacheManager.initialize()` is called in your host entry point -2. Verify network access to `clawsec.prompt.security` -3. Check host logs for fetch errors -4. Manually trigger: `curl https://clawsec.prompt.security/advisories/feed.json` - -### Signature Verification Failing - -**Problem**: Cache shows `"verified": false` - -**Solution**: -1. Ensure public key file exists at correct path -2. Check file permissions (should be readable) -3. Verify feed URL is correct (not using HTTP instead of HTTPS) -4. Check for corrupted downloads (try clearing cache and refetching) - -### IPC Communication Issues - -**Problem**: Tools return errors about IPC - -**Solution**: -1. Verify IPC handlers are registered in `src/ipc.ts` -2. Check that IPC directory exists and is writable -3. Ensure host process is running -4. Check host logs for handler errors - -## Legacy v1 Uninstallation - -To remove ClawSec from NanoClaw: - -1. Remove MCP tool registration from `ipc-mcp-stdio.ts` -2. Remove IPC handler registration from `src/ipc.ts` -3. Remove `AdvisoryCacheManager` initialization from host entry point -4. Delete the skill directory: `rm -rf skills/clawsec-nanoclaw` -5. Delete the cache file: `rm /workspace/project/data/clawsec-advisory-cache.json` -6. Restart NanoClaw - -## Support - -- **Documentation**: https://clawsec.prompt.security/ -- **Issues**: https://github.com/prompt-security/clawsec/issues -- **Security**: security@prompt.security - -## License - -AGPL-3.0-or-later - ---- - -**Questions?** Open an issue or check the main ClawSec documentation. +- [NanoClaw architecture](https://docs.nanoclaw.dev/concepts/architecture) +- [NanoClaw v2 skills](https://docs.nanoclaw.dev/extend/overview) +- [Writing NanoClaw skills](https://docs.nanoclaw.dev/extend/writing-skills) +- [Migrate from NanoClaw v1](https://docs.nanoclaw.dev/migrate-from-v1) diff --git a/skills/clawsec-nanoclaw/README.md b/skills/clawsec-nanoclaw/README.md index c7f462dc..08c2837d 100644 --- a/skills/clawsec-nanoclaw/README.md +++ b/skills/clawsec-nanoclaw/README.md @@ -1,121 +1,58 @@ -# ClawSec for NanoClaw v1 (Legacy Adapter) +# ClawSec NanoClaw v1-Era Template -This package preserves the original ClawSec integration for pre-v2 NanoClaw deployments. +> **Status:** Deprecated, historical, and runtime-unverified. This package is retained as migration evidence. It is not a supported NanoClaw adapter and must not be installed into NanoClaw v2. ## Compatibility -- Supported NanoClaw range: `>=0.1.0 <2.0.0`. -- NanoClaw v2 (`>=2.0.0`): **incompatible; do not install or activate this adapter**. -- The bundled IPC, cache, scheduler, and integrity examples describe the v1 layout only. -- NanoClaw v2 needs a separate adapter for its current host, container, SQLite IPC, and extension surfaces. +- No NanoClaw runtime version is advertised as supported. The package has not passed an end-to-end harness test against a pinned upstream release. +- NanoClaw v2 is incompatible with this template. +- NanoClaw v2 uses a Node.js host, per-session `inbound.db` and `outbound.db` transport, additive code-carrying skills, and current host registration surfaces. +- This template assumes retired v1-era message-file IPC, paths, scheduling, and source reach-ins. -This package remains available for legacy users and migration evidence. It is not a NanoClaw v2 installation path. +NanoClaw has no reviewed direct Agent Skills CLI target; do not substitute `--agent openclaw` or another unrelated target. -## What Changed +Read the [historical integration record](./INSTALL.md) for the known limitations. It is not an installation procedure. -### Advisory Feed Monitoring -- **NVD CVE Pipeline**: Now monitors for NanoClaw-specific keywords - - "NanoClaw", "WhatsApp-bot", "baileys" (WhatsApp library) - - Container-related vulnerabilities -- **Platform Targeting**: Advisories can specify `platforms: ["nanoclaw"]` for NanoClaw-specific issues +## Why It Is Unverified -### Keywords Added -The CVE monitoring now includes: -- `NanoClaw` - Direct product name -- `WhatsApp-bot` - Core functionality -- `baileys` - WhatsApp client library dependency +The bundled MCP modules declare `server`, `writeIpcFile`, `TASKS_DIR`, and `groupFolder` as ambient identifiers. Importing an ES module does not make module-local variables from the importer visible to the imported module. The historical instructions therefore do not provide a working registration boundary. -## Advisory Schema +Other retained assumptions also differ from the official v1 and v2 trees: -Advisories now support optional `platforms` field: +- The old restart instructions referenced Docker Compose even though the reviewed v1 trees use host services and a separate container build step. +- Several host services use container-side paths. +- The historical group, task, and message-file paths do not represent NanoClaw v2's database model. +- The package has no tested apply, update, remove, rollback, or recovery transaction. -```json -{ - "id": "CVE-2026-XXXXX", - "platforms": ["openclaw", "nanoclaw"], - "severity": "critical", - "type": "prompt_injection", - "affected": ["skill-name@1.0.0"], - "action": "Update to version 1.0.1" -} -``` +Unit tests cover isolated ClawSec helper invariants. They do not prove that NanoClaw loads or executes this package. -**Platform values:** -- `"openclaw"` - Affects OpenClaw/ClawdBot/MoltBot only -- `"nanoclaw"` - Affects NanoClaw only -- `["openclaw", "nanoclaw"]` - Affects both platforms -- (empty/missing) - Applies to all platforms (backward compatible) +## Preserved Evidence -## Legacy ClawSec NanoClaw Skill +The source remains available for migration analysis and future test fixtures: -ClawSec provides a legacy adapter for compatible pre-v2 NanoClaw deployments: +- Advisory matching and feed-signature helpers. +- Historical MCP declarations and message-file handlers. +- Historical package-signature and integrity components. +- v1-era path and policy assumptions that future migration checks must detect. -**Location**: `skills/clawsec-nanoclaw/` +Do not interpret preserved source as an available protection or installation path. -### Features +## Replacement Direction -- **9 MCP Tools** for agents to manage security: - - `clawsec_check_advisories` - Scan installed skills for vulnerabilities - - `clawsec_check_skill_safety` - Pre-installation safety checks - - `clawsec_list_advisories` - Browse advisory feed with filtering - - `clawsec_refresh_cache` - Request immediate advisory cache refresh - - `clawsec_verify_skill_package` - Verify Ed25519 signatures on skill packages - - `clawsec_check_integrity` - Check protected files for unauthorized changes - - `clawsec_approve_change` - Approve intentional file modifications - - `clawsec_integrity_status` - View file baseline status - - `clawsec_verify_audit` - Verify audit log hash chain +Current NanoClaw support will be implemented as separate v2-native packages: -- **Advisory Cache Service**: Host-managed feed fetching with signature validation -- **Signature Verification**: Ed25519-signed feeds ensure integrity -- **Exploitability Context**: Surfaces `exploitability_score` and rationale to reduce alert fatigue -- **IPC Communication**: Container-safe host communication +- `clawsec-core-nanoclaw` +- `clawsec-suite-nanoclaw` +- `clawsec-drift-guardian-nanoclaw` -### Legacy v1 Integration Map +None is available merely because its name appears here. Each package must use NanoClaw v2's additive skill workflow, include complete apply and removal behavior, and pass remote harness acceptance before it can claim support. -Only operators who have confirmed a target version in `>=0.1.0 <2.0.0` should use the detailed [legacy installation guide](./INSTALL.md). Do not raw-copy or import these files into NanoClaw v2. +## Official NanoClaw References -The v1 adapter historically integrates into three v1 locations: +- [NanoClaw architecture](https://docs.nanoclaw.dev/concepts/architecture) +- [NanoClaw v2 skills](https://docs.nanoclaw.dev/extend/overview) +- [Migrate from NanoClaw v1](https://docs.nanoclaw.dev/migrate-from-v1) -**1. MCP Tools** (container): -```typescript -// container/agent-runner/src/ipc-mcp-stdio.ts -import '../../../skills/clawsec-nanoclaw/mcp-tools/advisory-tools.js'; -``` +## Security Reporting -**2. IPC Handlers** (host): -```typescript -// src/ipc.ts -import { handleAdvisoryIpc } from '../skills/clawsec-nanoclaw/host-services/ipc-handlers.js'; -``` - -**3. Cache Service** (host): -```typescript -// src/index.ts -import { AdvisoryCacheManager } from '../skills/clawsec-nanoclaw/host-services/advisory-cache.js'; -``` - -### Advisory Feed - -NanoClaw consumes the same feed as OpenClaw: -``` -https://clawsec.prompt.security/advisories/feed.json -``` - -The feed is Ed25519 signed. A v1 operator must explicitly wire and start the cache service; this package does not install an automatic scheduler. - -## Legacy Implementation Status - -The MCP tools, host services, IPC handlers, and integrity code are frozen v1 implementation and migration evidence. They are not a starting point for claiming NanoClaw v2 support. A future v2 core, suite, and drift guardian must use the v2-native workflow and land in separate packages and PRs. - -## Documentation - -- [Skill Documentation](./SKILL.md) - Legacy v1 behavior and compatibility boundary -- [Installation Guide](./INSTALL.md) - Legacy v1 integration instructions -- [ClawSec Main README](../../README.md) - Overall ClawSec documentation -- [Security & Signing](../../wiki/security-signing-runbook.md) - Signature verification details - -## Support - -- **Issues**: https://github.com/prompt-security/clawsec/issues -- **Security**: security@prompt.security -- NanoClaw Repository: https://github.com/qwibitai/nanoclaw +Report ClawSec issues through the repository's security policy. For NanoClaw behavior, verify findings against a pinned upstream source revision and the current official documentation. diff --git a/skills/clawsec-nanoclaw/SKILL.md b/skills/clawsec-nanoclaw/SKILL.md index fd5b50ce..a79de631 100644 --- a/skills/clawsec-nanoclaw/SKILL.md +++ b/skills/clawsec-nanoclaw/SKILL.md @@ -1,295 +1,91 @@ --- name: clawsec-nanoclaw version: 0.0.11 -description: Use only with legacy NanoClaw >=0.1.0 <2.0.0 to check ClawSec advisories, package signatures, and the bundled v1 integrity adapter; NanoClaw v2 is incompatible and requires a separate adapter +description: Use when auditing or migrating historical ClawSec artifacts from a NanoClaw v1-era fork; this package is an unverified template with no supported runtime range, must not be installed, and is incompatible with NanoClaw v2 --- -# ClawSec for NanoClaw v1 (Legacy) +# Audit the Historical ClawSec NanoClaw Template -Legacy advisory, package-signature, and integrity tooling for compatible pre-v2 NanoClaw deployments. +Treat this package as migration evidence only. -## Compatibility Gate +## Stop Gate -- Supported NanoClaw range: `>=0.1.0 <2.0.0`. -- NanoClaw v2 (`>=2.0.0`): **incompatible; do not install or activate this adapter**. -- NanoClaw v2 uses different host, container, SQLite IPC, and extension surfaces. It requires a separate ClawSec adapter. -- The v1 integration paths in this package are retained for legacy users and migration evidence only. They are not NanoClaw v2 instructions. +- Do not install, import, or activate the bundled TypeScript. +- Do not claim that any NanoClaw version is supported by this package. +- Do not use the package as evidence of NanoClaw v2 support. +- Do not copy v1-era paths, message-file handlers, scheduler examples, or service commands into v2. +- Do not treat isolated unit tests as a harness acceptance result. -Stop if the target version is unknown or is NanoClaw v2. Do not reinterpret the v1 IPC examples as a generic installation recipe. +NanoClaw has no reviewed direct Agent Skills CLI target; do not substitute `--agent openclaw` or another unrelated target. -## Overview +Read the [historical integration record](./INSTALL.md) before assessing an existing deployment. It documents why the former integration procedure is not runnable as written. -The bundled v1 MCP tools check installed skills against a curated feed of security advisories, include exploitability context for triage, and report issues in existing packages. They return advisory decisions; they do not own or enforce the host installer. +## Compatibility Result -**Core principle:** Check before you install. Monitor what's running. +Return these conclusions when asked whether this package can be installed: -## When to Use +- Status: historical, unverified v1-era template. +- Supported NanoClaw range: none asserted. +- NanoClaw v2: incompatible. +- Installation recommendation: do not install. +- Successor status: prove availability from the current published release and its acceptance evidence; do not infer it from a roadmap, directory, branch, pull request, or version label. -Use ClawSec tools when: -- Installing a new skill (check safety first) -- User asks "are my skills secure?" -- Investigating suspicious behavior -- Regular security audits -- After receiving security notifications +## Why the Runtime Is Not Qualified -Do NOT use for: -- Code review (use other tools) -- Performance issues (different concern) -- General debugging +The MCP modules use ambient declarations for `server`, `writeIpcFile`, `TASKS_DIR`, and `groupFolder`. Those declarations satisfy TypeScript but create no runtime binding. Importing the modules cannot access module-local identifiers from NanoClaw's runner. -## MCP Tools Available +The remaining source also leaves `glob` and `writeResponse` without runtime implementations and uses CommonJS `__dirname` in an ES module. It preserves unqualified assumptions about host/container paths, message-file IPC, group state, scheduling, restart behavior, and writable state. No pinned NanoClaw checkout has passed a complete apply, run, remove, and rollback test for this package. -### Pre-Installation Check +## Allowed Uses -```typescript -// Before installing any skill -const safety = await tools.clawsec_check_skill_safety({ - skillName: 'new-skill', - skillVersion: '1.0.0' // optional -}); +Use the package only to: -if (!safety.safe) { - // Show user the risks before proceeding - console.warn(`Security issues: ${safety.advisories.map(a => a.id)}`); -} -``` +- Identify historical ClawSec files in a customized NanoClaw v1-era checkout. +- Compare those files with the operator's actual fork and service configuration. +- Produce a read-only migration inventory. +- Preserve source as test-vector input for future migration tooling. +- Explain why the old integration must not be copied into NanoClaw v2. -### Security Audit +Do not modify or remove an operator's existing deployment without an explicit reviewed plan and rollback path. -```typescript -// Check all installed skills (defaults to ~/.claude/skills in the container) -const result = await tools.clawsec_check_advisories({ - installRoot: '/home/node/.claude/skills' // optional -}); +## Migration Inventory -if (result.matches.some((m) => - m.advisory.severity === 'critical' || m.advisory.exploitability_score === 'high' -)) { - // Alert user immediately - console.error('Urgent advisories found!'); -} -``` +Record evidence without executing the package: -### Browse Advisories +1. Pin the exact NanoClaw source commit and record its reported version. +2. Locate every copied ClawSec file and every source reach-in. +3. Locate service, task, hook, database, cache, and integrity state owned by the old customization. +4. Record file digests, permissions, ownership, and whether each path is host-side or container-side. +5. Record any active process or scheduler that imports or invokes the historical code. +6. Identify conflicts with NanoClaw v2's additive skill workflow and two-database host/container boundary. +7. Propose disable, migration, and rollback steps without executing them. -```typescript -// List advisories with filters -const advisories = await tools.clawsec_list_advisories({ - severity: 'high', // optional - exploitabilityScore: 'high' // optional -}); -``` +If current authorization does not permit access to live logs, record runtime execution evidence as unknown. Do not infer success or inactivity from missing evidence. -## Quick Reference +## Preserved Source Boundaries -| Task | Tool | Key Parameter | -|------|------|---------------| -| Pre-install check | `clawsec_check_skill_safety` | `skillName` | -| Audit all skills | `clawsec_check_advisories` | `installRoot` (optional) | -| Browse feed | `clawsec_list_advisories` | `severity`, `type`, `exploitabilityScore` (optional) | -| Verify package signature | `clawsec_verify_skill_package` | `packagePath` | -| Refresh advisory cache | `clawsec_refresh_cache` | (none) | -| Check file integrity | `clawsec_check_integrity` | `mode`, `autoRestore` (optional) | -| Approve file change | `clawsec_approve_change` | `path` | -| View baseline status | `clawsec_integrity_status` | `path` (optional) | -| Verify audit log | `clawsec_verify_audit` | (none) | +- `mcp-tools/` contains historical declarations, not a supported registration API. +- `host-services/` contains unqualified v1-era host integration attempts. +- `guardian/` contains a historical integrity implementation, not the future NanoClaw drift guardian. +- `lib/` contains isolated helpers that may inform common contracts only after independent review. +- `advisories/feed-signing-public.pem` is a feed-verification key and is not release-installation authority. -## Common Patterns +## Future v2 Requirements -### Pattern 1: Pre-Installation Advisory Review +A supported NanoClaw package must be implemented separately. Require it to: -```typescript -// ALWAYS check before installing -const safety = await tools.clawsec_check_skill_safety({ - skillName: userRequestedSkill -}); +- Target a pinned NanoClaw v2 range and current official architecture. +- Use an explicit registration API or reviewed additive reach-in with a failing-when-removed integration test. +- Keep authoritative trust and receipts on the host, outside agent-controlled state. +- Provide idempotent apply, update, removal, resume, and rollback behavior. +- Ship `REMOVE.md` whenever apply leaves state. +- Run NanoClaw host build/tests and Bun tests for any agent-runner change. +- Pass the remote lab and release lifecycle before any support claim. -if (!safety.safe) { - // Return the advisory evidence to the host installer or operator. - await showSecurityWarning(safety.advisories); - return { recommendation: 'do-not-install', safety }; -} +The v2 architecture statements above reflect official upstream material observed on 2026-07-22. Reverify the current documentation and source revision before making a migration or support decision. -// Advisory output is one input, not installation authorization. -return { - recommendation: 'continue-review', - safety, - requiresSignatureVerification: true, - requiresCodeReview: true, - requiresOperatorApproval: true -}; -``` +## References -### Pattern 2: Legacy v1 Host Scheduling - -Scheduling is deployment-owned. This package does not register a NanoClaw v2 task or scheduler integration. A compatible v1 operator may wire an advisory check through the v1 host's reviewed scheduling surface after completing the manual integration in [INSTALL.md](./INSTALL.md). - -### Pattern 3: User Security Query - -``` -User: "Are my skills secure?" - -You: I'll check installed skills for known vulnerabilities. -[Use clawsec_check_advisories] - -Response: -✅ No urgent issues found. -- 2 low-severity/low-exploitability advisories -- All skills up to date -``` - -## Common Mistakes - -### ❌ Installing without checking -```typescript -// DON'T -await installSkill('untrusted-skill'); -``` - -```typescript -// DO -const safety = await tools.clawsec_check_skill_safety({ - skillName: 'untrusted-skill' -}); -if (!safety.safe) return { recommendation: 'do-not-install', safety }; -return { - recommendation: 'continue-review', - requiresSignatureVerification: true, - requiresCodeReview: true, - requiresOperatorApproval: true -}; -``` - -### ❌ Ignoring exploitability context -```typescript -// DON'T: Use severity only -if (advisory.severity === 'high') { - notifyNow(advisory); -} -``` - -```typescript -// DO: Use exploitability + severity -if ( - advisory.exploitability_score === 'high' || - advisory.severity === 'critical' -) { - notifyNow(advisory); -} -``` - -### ❌ Skipping critical severity -```typescript -// DON'T: Ignore high exploitability in medium severity advisories -if (advisory.severity === 'critical') alert(); -``` - -```typescript -// DO: Prioritize exploitability and severity together -if (advisory.exploitability_score === 'high' || advisory.severity === 'critical') { - // Alert immediately -} -``` - -## Implementation Details - -**Feed Source**: https://clawsec.prompt.security/advisories/feed.json - -This signed feed is consolidated. NanoClaw receives NVD CVEs, approved community advisories, and provisional GHSA-without-CVE advisories through the same default URL. - -**Legacy v1 example cadence**: Every 6 hours after explicit host wiring; the skill does not install a scheduler. - -**Signature Verification**: Ed25519 signed feeds -**Package Verification Policy**: pinned key only, bounded package/signature paths - -**Legacy v1 cache location**: `/workspace/project/data/clawsec-advisory-cache.json` - -See [INSTALL.md](./INSTALL.md) for setup and [docs/](./docs/) for advanced usage. - -## Real-World Impact - -- Helps operators identify skills with known RCE vulnerabilities before installation -- Alerts to supply chain attacks in dependencies -- Provides actionable remediation steps -- Uses a curated feed while preserving severity and exploitability context for operator review - -## Release Artifact Verification - -For standalone installs, verify the signed release manifest before trusting `SKILL.md`, `skill.json`, or the archive. The `skill.json` file is the package metadata/SBOM source, and the release pipeline signs `checksums.json` with the ClawSec release key. - -```bash -set -euo pipefail - -SKILL_NAME="clawsec-nanoclaw" -VERSION="0.0.11" -REPO="prompt-security/clawsec" -TAG="${SKILL_NAME}-v${VERSION}" -BASE="https://github.com/${REPO}/releases/download/${TAG}" -ZIP_NAME="${SKILL_NAME}-v${VERSION}.zip" -TMP_DIR="$(mktemp -d)" -trap 'rm -rf "$TMP_DIR"' EXIT - -# ClawSec GitHub Release signing trust anchor. This is not a NanoClaw v2 -# integration key and is distinct from the v1 embedded feed-verification path. -RELEASE_PUBKEY_SHA256="711424e4535f84093fefb024cd1ca4ec87439e53907b305b79a631d5befba9c8" - -curl -fsSL "$BASE/checksums.json" -o "$TMP_DIR/checksums.json" -curl -fsSL "$BASE/checksums.sig" -o "$TMP_DIR/checksums.sig" -curl -fsSL "$BASE/signing-public.pem" -o "$TMP_DIR/signing-public.pem" -curl -fsSL "$BASE/$ZIP_NAME" -o "$TMP_DIR/$ZIP_NAME" -curl -fsSL "$BASE/SKILL.md" -o "$TMP_DIR/SKILL.md" -curl -fsSL "$BASE/skill.json" -o "$TMP_DIR/skill.json" - -ACTUAL_PUBKEY_SHA256="$(openssl pkey -pubin -in "$TMP_DIR/signing-public.pem" -outform DER | shasum -a 256 | awk '{print $1}')" -if [ "$ACTUAL_PUBKEY_SHA256" != "$RELEASE_PUBKEY_SHA256" ]; then - echo "ERROR: signing-public.pem fingerprint mismatch" >&2 - exit 1 -fi - -openssl base64 -d -A -in "$TMP_DIR/checksums.sig" -out "$TMP_DIR/checksums.sig.bin" -openssl pkeyutl -verify -rawin -pubin \ - -inkey "$TMP_DIR/signing-public.pem" \ - -sigfile "$TMP_DIR/checksums.sig.bin" \ - -in "$TMP_DIR/checksums.json" >/dev/null - -hash_file() { - if command -v shasum >/dev/null 2>&1; then - shasum -a 256 "$1" | awk '{print $1}' - else - sha256sum "$1" | awk '{print $1}' - fi -} - -verify_manifest_file() { - asset="$1" - path="$2" - expected="$(jq -r --arg asset "$asset" '.files[$asset].sha256 // empty' "$TMP_DIR/checksums.json")" - if [ -z "$expected" ]; then - echo "ERROR: checksums.json missing $asset" >&2 - exit 1 - fi - actual="$(hash_file "$path")" - if [ "$actual" != "$expected" ]; then - echo "ERROR: checksum mismatch for $asset" >&2 - exit 1 - fi -} - -expected_archive="$(jq -r '.archive.sha256 // empty' "$TMP_DIR/checksums.json")" -if [ -z "$expected_archive" ]; then - echo "ERROR: checksums.json missing archive.sha256" >&2 - exit 1 -fi -actual_archive="$(hash_file "$TMP_DIR/$ZIP_NAME")" -if [ "$actual_archive" != "$expected_archive" ]; then - echo "ERROR: archive checksum mismatch" >&2 - exit 1 -fi - -verify_manifest_file "SKILL.md" "$TMP_DIR/SKILL.md" -verify_manifest_file "skill.json" "$TMP_DIR/skill.json" - -echo "Signed release manifest, archive, SKILL.md, and skill.json verified." -``` - -Only install or extract the archive after this verification succeeds. +- [NanoClaw architecture](https://docs.nanoclaw.dev/concepts/architecture) +- [NanoClaw v2 skills](https://docs.nanoclaw.dev/extend/overview) +- [Migrate from NanoClaw v1](https://docs.nanoclaw.dev/migrate-from-v1) diff --git a/skills/clawsec-nanoclaw/docs/INTEGRITY.md b/skills/clawsec-nanoclaw/docs/INTEGRITY.md index 6fdf0cce..9632067b 100644 --- a/skills/clawsec-nanoclaw/docs/INTEGRITY.md +++ b/skills/clawsec-nanoclaw/docs/INTEGRITY.md @@ -1,569 +1,56 @@ -# File Integrity Monitoring for NanoClaw v1 (Legacy) +# Historical NanoClaw Integrity Component Record -> **Compatibility boundary:** This document describes the bundled NanoClaw v1 adapter for `>=0.1.0 <2.0.0`. It is incompatible with NanoClaw v2. Paths such as `registered_groups.json`, `CLAUDE.md`, `/workspace/ipc`, and `/workspace/project/...`, plus the `schedule_task` examples, are v1 layout and scheduler assumptions—not NanoClaw v2 guidance. +> **Status:** Deprecated and runtime-unverified. This v1-era source is migration evidence, not an active integrity guardian. It is incompatible with NanoClaw v2. -The legacy adapter monitors selected NanoClaw v1 configuration files for unauthorized modification. +## Do Not Activate -## What It Does +Do not copy the files under `guardian/` or `host-services/` into a NanoClaw deployment. Do not enable automatic restoration from this package. It has no supported NanoClaw runtime range and has not passed a pinned harness acceptance test. -**Protects Critical Files:** -- `registered_groups.json` - Prevents unauthorized group access -- `CLAUDE.md` files - Protects agent instructions -- Container/host code - Alerts on unexpected changes +## Why the Old Policy Is Not a Valid Posture Model -**How It Works:** -1. **Baseline**: Stores SHA-256 hashes of approved file states -2. **Monitoring**: Periodically checks files for changes (drift) -3. **Restore**: Automatically reverts critical files to approved versions -4. **Audit**: Maintains tamper-evident log of all operations +The retained policy and documentation mix host and container namespaces and include obsolete or nonexistent paths: -## Quick Start +- `/workspace/project/data/registered_groups.json` is not the active v1 group database. +- `/workspace/project/host/**/*.ts` does not map to the official v1 host source tree. +- `/workspace/group/CLAUDE.md` is a container-side path presented to a host monitor. +- `/workspace/project/data/soul-guardian` is another container-side path used as host state. +- `/workspace/ipc` represents the retired v1 message-file transport, not NanoClaw v2's two-database session boundary. -### Step 1: Verify Installation +Because the monitored objects are not derived from a verified checkout and scope, a successful local hash comparison would not prove NanoClaw posture integrity. -Check that integrity monitoring is available: +## Security Limits -```bash -# From container -ls /workspace/project/skills/clawsec-nanoclaw/guardian/ -# Should show: policy.json, integrity-monitor.ts -``` +- A hash chain can detect internal sequence changes relative to its chosen first record; it does not independently authenticate that first record. +- A locally generated baseline is not trustworthy merely because later hashes match it. +- Automatic restoration can destroy legitimate changes and must remain off unless a future guardian authenticates its baseline and obtains explicit operator approval. +- The historical code has no verified registration, scheduler, service, disable, removal, or rollback path. +- ClawSec installs no schedule. Any refresh or integrity cadence in a v1-era fork is an operator-owned customization. -### Step 2: Initialize Baselines +## Preserved Files -The first time integrity monitoring runs, it creates baselines automatically: +- `guardian/integrity-monitor.ts` — historical implementation input for future tests. +- `guardian/policy.json` — inventory of obsolete path assumptions that migration tooling should detect. +- `host-services/integrity-handler.ts` — historical message-file handler. +- `mcp-tools/integrity-tools.ts` — historical ambient-global MCP declarations. -```typescript -// Agent calls this (happens automatically on first integrity check) -await tools.clawsec_check_integrity(); -``` +Their presence is not capability evidence. -This creates: -``` -/workspace/project/data/soul-guardian/ -├── baselines.json # SHA-256 hashes -├── approved/ # File snapshots -│ ├── registered_groups.json -│ └── CLAUDE.md -├── patches/ # Diffs (empty initially) -├── quarantine/ # Tampered files (empty initially) -└── audit.jsonl # Event log -``` +## Future Drift Guardian Requirements -### Step 3: Legacy NanoClaw v1 Scheduler Example +Implement `clawsec-drift-guardian-nanoclaw` as a separate NanoClaw v2-native package. Require it to: -Only a confirmed v1 deployment with a reviewed host scheduler may add this example to the main group's scheduled tasks. The skill does not install a scheduler: +- Derive posture from a pinned, supported v2 checkout and explicit host scope. +- Keep authoritative baselines and receipts outside agent-controlled paths. +- Authenticate the baseline before comparing drift. +- Default to read-only detection. +- Disclose every persistent path and keep restoration opt-in. +- Provide idempotent apply, disable, remove, resume, and rollback behavior. +- Ship `REMOVE.md` whenever it leaves state. +- Test every host registration reach-in and database ownership boundary. +- Pass remote harness acceptance before claiming availability. -```typescript -schedule_task({ - prompt: ` - Check file integrity with clawsec_check_integrity. - If drift detected and files restored, send WhatsApp message: - "⚠️ SECURITY ALERT +## References - Unauthorized changes detected and automatically reverted: - [list files that were restored] - - Review details: /workspace/project/data/soul-guardian/patches/" - `, - schedule_type: 'cron', - schedule_value: '*/30 * * * *', // Every 30 minutes - context_mode: 'isolated' -}); -``` - -That's it! Integrity monitoring is now active. - -## MCP Tools Reference - -### 1. `clawsec_check_integrity` - -Check all protected files for unauthorized changes. - -**Parameters:** -- `mode` (optional): `'check'` (default) or `'status'` - - `check`: Detect drift and auto-restore - - `status`: View baselines only (no drift detection) -- `autoRestore` (optional): `true` (default) or `false` - - If `false`, drift is detected but not auto-fixed - -**Output:** -```json -{ - "success": true, - "timestamp": "2026-02-25T12:00:00Z", - "drift_detected": false, - "files": [ - { - "path": "/workspace/project/data/registered_groups.json", - "status": "ok", - "mode": "restore", - "expected_sha": "abc123...", - "found_sha": "abc123..." - } - ], - "summary": { - "total": 3, - "ok": 3, - "drifted": 0, - "restored": 0, - "alerted": 0, - "errors": 0 - } -} -``` - -**Example:** -```typescript -const result = await tools.clawsec_check_integrity(); - -if (result.drift_detected) { - console.log('⚠️ Drift detected!'); - for (const file of result.files) { - if (file.status === 'restored') { - console.log(`✅ Restored: ${file.path}`); - console.log(` Diff: ${file.patch_path}`); - } else if (file.status === 'drifted') { - console.log(`⚠️ Changed: ${file.path} (alert only)`); - } - } -} -``` - -### 2. `clawsec_approve_change` - -Approve an intentional file modification as the new baseline. - -**When to use:** -- After legitimately updating CLAUDE.md -- After adding/removing groups in registered_groups.json -- After any intentional change to protected files - -**Parameters:** -- `path` (required): Absolute path to file -- `note` (optional): Explanation for audit log - -**Output:** -```json -{ - "success": true, - "path": "/workspace/group/CLAUDE.md", - "approved_at": "2026-02-25T12:00:00Z", - "approved_by": "agent", - "note": "Added new skill instructions" -} -``` - -**Example:** -```typescript -// After editing CLAUDE.md -await tools.clawsec_approve_change({ - path: '/workspace/group/CLAUDE.md', - note: 'Updated agent instructions for new skill' -}); - -console.log('✅ Change approved - new baseline created'); -``` - -### 3. `clawsec_integrity_status` - -View current baseline status without checking for drift. - -**Parameters:** -- `path` (optional): Specific file, or all if omitted - -**Output:** -```json -{ - "success": true, - "baseline_age": "2026-02-25T10:00:00Z", - "files": [ - { - "path": "/workspace/project/data/registered_groups.json", - "mode": "restore", - "priority": "critical", - "has_baseline": true, - "baseline_sha": "abc123...", - "approved_at": "2026-02-25T10:00:00Z", - "snapshot_exists": true - } - ] -} -``` - -**Example:** -```typescript -const status = await tools.clawsec_integrity_status(); - -console.log('Protected files:'); -for (const file of status.files) { - console.log(`- ${file.path} (${file.mode}, ${file.priority})`); - console.log(` Last approved: ${file.approved_at}`); -} -``` - -### 4. `clawsec_verify_audit` - -Verify audit log hash chain integrity. - -**No parameters.** - -**Output:** -```json -{ - "success": true, - "valid": true, - "entries": 42, - "errors": [] -} -``` - -**Example:** -```typescript -const verification = await tools.clawsec_verify_audit(); - -if (!verification.valid) { - console.log('🚨 CRITICAL: Audit log has been tampered with!'); - console.log('Errors:', verification.errors); -} else { - console.log(`✅ Audit log verified (${verification.entries} entries)`); -} -``` - -## Protected Files Policy - -### Critical Priority (Auto-Restore) - -**`/workspace/project/data/registered_groups.json`** -- **Risk**: Tampering grants unauthorized group access -- **Action**: Immediate auto-restore + alert - -**`/workspace/group/CLAUDE.md`** -- **Risk**: Modifies agent behavior -- **Action**: Immediate auto-restore + alert - -**`/workspace/project/groups/global/CLAUDE.md`** -- **Risk**: Affects all groups -- **Action**: Immediate auto-restore + alert - -### Medium Priority (Alert Only) - -**Container code** (`/workspace/project/container/**/*.ts`) -- **Risk**: Unexpected code changes -- **Action**: Alert for review (no auto-restore) - -**Host code** (`/workspace/project/host/**/*.ts`) -- **Risk**: Unexpected code changes -- **Action**: Alert for review (no auto-restore) - -### Ignored - -**IPC files** (`/workspace/ipc/**/*`) -- Changes are expected and frequent - -**Conversations** (`/workspace/group/conversations/**/*`) -- Changes are expected and frequent - -## Workflow Examples - -### Scenario 1: Legacy NanoClaw v1 Scheduler Example - -**Setup:** -```typescript -schedule_task({ - prompt: 'Run clawsec_check_integrity and alert on drift', - schedule_type: 'cron', - schedule_value: '*/30 * * * *' -}); -``` - -**What happens:** -1. Every 30 minutes, agent checks integrity -2. If drift detected in critical files: - - Files auto-restored to baseline - - Tampered versions quarantined - - Diff patch generated - - User alerted via WhatsApp -3. If drift in non-critical files: - - Alert only, no auto-restore - -### Scenario 2: Updating Agent Instructions - -**Workflow:** -```typescript -// 1. Edit CLAUDE.md -fs.writeFileSync('/workspace/group/CLAUDE.md', newInstructions); - -// 2. Test changes -// ... verify agent behaves correctly ... - -// 3. Approve changes -await tools.clawsec_approve_change({ - path: '/workspace/group/CLAUDE.md', - note: 'Added instructions for new weather skill' -}); - -// 4. Future integrity checks will use this new baseline -``` - -### Scenario 3: Adding a New Group - -**Workflow:** -```typescript -// 1. Add group to registered_groups.json -const groups = JSON.parse(fs.readFileSync('/workspace/project/data/registered_groups.json')); -groups['new-jid'] = { name: 'Family', folder: 'family', trigger: '@Andy' }; -fs.writeFileSync('/workspace/project/data/registered_groups.json', JSON.stringify(groups, null, 2)); - -// 2. Approve the change -await tools.clawsec_approve_change({ - path: '/workspace/project/data/registered_groups.json', - note: 'Added family group' -}); -``` - -### Scenario 4: Investigating Drift - -**When drift is detected:** -```typescript -const result = await tools.clawsec_check_integrity(); - -if (result.drift_detected) { - for (const file of result.files) { - if (file.status === 'restored') { - // Critical file was auto-restored - console.log(`🔧 Auto-restored: ${file.path}`); - console.log(`📄 Diff: ${file.patch_path}`); - console.log(`📦 Quarantine: ${file.quarantine_path}`); - - // Review the diff - const diff = fs.readFileSync(file.patch_path, 'utf-8'); - console.log('Changes that were reverted:'); - console.log(diff); - } - } -} -``` - -## Security Model - -### Threat Model - -**Protects Against:** -- Unauthorized file modifications -- Group hijacking (via registered_groups.json tampering) -- Agent instruction poisoning (via CLAUDE.md changes) -- Accidental file corruption - -**Does NOT Protect Against:** -- Attacker with full host access (can modify baselines) -- Simultaneous baseline + file modification -- Malicious scheduled tasks that approve their own changes - -### Baseline Storage - -**Location:** `/workspace/project/data/soul-guardian/` - -**Access Control:** -- Baselines written only by host process -- Containers access via IPC only -- No container can modify its own baselines - -**Integrity:** -- SHA-256 hashes (industry standard) -- Hash-chained audit log (tamper-evident) -- Atomic file operations (safe restores) - -### Audit Log - -**Format:** JSONL with hash chaining - -**Each entry includes:** -```json -{ - "ts": "2026-02-25T12:00:00Z", - "event": "drift", - "actor": "agent", - "path": "/workspace/group/CLAUDE.md", - "expected_sha": "abc123...", - "found_sha": "def456...", - "chain": { - "prev": "previous_entry_hash", - "hash": "this_entry_hash" - } -} -``` - -**Chain calculation:** -``` -hash = SHA-256(prev_hash + '\n' + canonical_json(entry_without_chain)) -``` - -This makes tampering detectable: changing any entry breaks the chain. - -## Troubleshooting - -### Integrity Check Fails - -**Symptom:** `clawsec_check_integrity` returns `success: false` - -**Causes:** -1. IntegrityService not initialized -2. Policy file missing -3. Baselines corrupted - -**Solution:** -```bash -# Check service status -ls /workspace/project/data/soul-guardian/ - -# If missing, reinitialize -rm -rf /workspace/project/data/soul-guardian/ -# Next integrity check will recreate baselines -``` - -### False Positives (Legitimate Changes Flagged) - -**Symptom:** File keeps getting restored even though changes are legitimate - -**Cause:** Baseline not updated after intentional changes - -**Solution:** -```typescript -await tools.clawsec_approve_change({ - path: '/path/to/file', - note: 'Legitimate change' -}); -``` - -### Audit Chain Broken - -**Symptom:** `clawsec_verify_audit` returns `valid: false` - -**Causes:** -1. Audit log manually edited -2. Filesystem corruption -3. Security breach - -**Solution:** -```typescript -const verification = await tools.clawsec_verify_audit(); -console.log('Errors:', verification.errors); - -// If corruption, backup and reset -cp /workspace/project/data/soul-guardian/audit.jsonl /tmp/audit-backup.jsonl -rm /workspace/project/data/soul-guardian/audit.jsonl -// Audit log will restart on next operation -``` - -### High Disk Usage - -**Symptom:** `/workspace/project/data/soul-guardian/` grows large - -**Causes:** -- Many drift events generate patches -- Quarantine files accumulate - -**Solution:** -```bash -# Clean old patches (older than 30 days) -find /workspace/project/data/soul-guardian/patches/ -mtime +30 -delete - -# Clean quarantine (after review) -rm /workspace/project/data/soul-guardian/quarantine/* -``` - -## Performance - -**Overhead:** -- Baseline check: ~10ms per file -- SHA-256 computation: ~1ms per KB -- Restore operation: ~20ms per file - -**Typical deployment:** -- 3-5 protected files -- 30-minute check interval -- < 0.1% CPU usage -- < 5MB disk usage - -## Advanced Topics - -### Custom Policy - -While the default policy is pinned by the skill, you can fork it: - -```bash -cp /workspace/project/skills/clawsec-nanoclaw/guardian/policy.json /workspace/project/data/custom-policy.json -``` - -Edit and reinitialize: -```typescript -// Update IntegrityMonitor initialization -new IntegrityMonitor({ - policyPath: '/workspace/project/data/custom-policy.json', - stateDir: '/workspace/project/data/soul-guardian' -}); -``` - -### Manual Baseline Export - -```bash -# Export current baselines -cp /workspace/project/data/soul-guardian/baselines.json /tmp/baselines-backup.json - -# Export approved snapshots -tar -czf /tmp/approved-snapshots.tar.gz /workspace/project/data/soul-guardian/approved/ -``` - -### Baseline Import (Disaster Recovery) - -```bash -# Restore baselines -cp /tmp/baselines-backup.json /workspace/project/data/soul-guardian/baselines.json - -# Restore snapshots -tar -xzf /tmp/approved-snapshots.tar.gz -C /workspace/project/data/soul-guardian/ -``` - -## FAQ - -**Q: Can I disable auto-restore for testing?** - -A: Yes, use `autoRestore: false`: -```typescript -await tools.clawsec_check_integrity({ autoRestore: false }); -``` - -**Q: How do I protect additional files?** - -A: Edit `policy.json` and add targets: -```json -{ - "path": "/workspace/group/my-config.json", - "mode": "restore", - "priority": "high", - "description": "My custom config" -} -``` - -**Q: What happens if both baseline and file are modified?** - -A: The most recent baseline wins. Always approve legitimate changes immediately. - -**Q: Can I run integrity checks on-demand?** - -A: Yes, just call `clawsec_check_integrity` from any agent. - -**Q: Is the audit log encrypted?** - -A: No, but it's hash-chained for tamper detection. Encryption can be added in Phase 3. - -## Support - -- **Documentation**: https://clawsec.prompt.security/ -- **Issues**: https://github.com/prompt-security/clawsec/issues -- **Security Reports**: security@prompt.security - ---- - -**For a confirmed compatible v1 deployment, start with the [Quick Start](#quick-start) guide above. Do not use it for NanoClaw v2.** +- [NanoClaw architecture](https://docs.nanoclaw.dev/concepts/architecture) +- [NanoClaw security model](https://docs.nanoclaw.dev/concepts/security) +- [Migrate from NanoClaw v1](https://docs.nanoclaw.dev/migrate-from-v1) diff --git a/skills/clawsec-nanoclaw/docs/SKILL_SIGNING.md b/skills/clawsec-nanoclaw/docs/SKILL_SIGNING.md index 2474b37f..8065246a 100644 --- a/skills/clawsec-nanoclaw/docs/SKILL_SIGNING.md +++ b/skills/clawsec-nanoclaw/docs/SKILL_SIGNING.md @@ -1,419 +1,72 @@ -# Skill Package Signing and Verification for NanoClaw v1 (Legacy) +# Historical NanoClaw Signature Component Record -> **Compatibility boundary:** This document describes the bundled NanoClaw v1 adapter for `>=0.1.0 <2.0.0`. It is incompatible with NanoClaw v2 and is not a v2 installation, publisher, or key-management contract. +> **Status:** Deprecated and runtime-unverified. This v1-era source is migration evidence, not a supported package-verification workflow. It is incompatible with NanoClaw v2. -The bundled v1 verifier checks one detached `.sig` file with its configured pinned ClawSec public key. It does not accept caller-selected publisher keys, unsigned packages, or a dual-signature rotation format. +## Do Not Use It to Authorize Installation ---- +Do not copy or activate the historical verifier. A valid signature proves only that bytes match the selected key and signed input. It does not prove code safety, current catalog authorization, advisory clearance, or operator approval. -## Table of Contents +The bundled MCP and host integration has not passed an end-to-end NanoClaw test. Its machine-readable `install` recommendation must not be treated as installation authority. -1. [Overview](#overview) -2. [Publisher Workflow Is Out of Scope](#publisher-workflow-is-out-of-scope) -3. [For Legacy NanoClaw v1 Agents](#for-legacy-nanoclaw-v1-agents) -4. [Security Properties](#security-properties) -5. [Key Management](#key-management) -6. [Troubleshooting](#troubleshooting) +## Trust-Domain Mismatch ---- +The historical handler expects a detached `.sig` and defaults to the embedded advisory-feed public key. That is not the current ClawSec release contract. -## Overview +ClawSec release artifacts use a signed `checksums.json` manifest whose authenticated archive digest binds the release ZIP. Release verification also requires a pinned release trust root, exact package identity and version, safe archive validation, and an installation receipt. The advisory-feed key and release-manifest trust domain must not be treated as interchangeable. -The legacy verifier can detect whether a staged package matches a detached signature made by the pinned ClawSec key. Verification is one input to an operator decision; the tool does not install a package and does not make arbitrary third-party packages trusted. +No supported ClawSec publisher flow creates the detached archive signatures expected by this legacy handler. -### Why Signature Verification? +## Runtime Limitations -Without signature verification, an attacker could: -- **Replace** a legitimate skill package with a malicious one during download -- **Modify** package contents to inject backdoors or steal data -- **Distribute** trojan skills that appear legitimate but contain malware +- The MCP module depends on ambient identifiers that imports do not bind at runtime. +- The host verifier uses unqualified v1-era path assumptions. +- The historical host response path is incomplete. +- The ESM integration and key-path resolution were never proven in a composed upstream build. +- No pinned NanoClaw checkout passed request, response, rejection, cleanup, or removal tests. +- The documentation defines no supported key-rotation or multi-key transition protocol. -Signature verification ensures: -- ✅ **Authenticity**: Signature matches the configured pinned ClawSec key -- ✅ **Integrity**: Package hasn't been modified since signing -- ✅ **Non-repudiation**: Signer can't deny signing the package +## Isolated Invariants Preserved in Source ---- +The retained code and unit tests still provide review input for narrow properties: -## Publisher Workflow Is Out of Scope +- Reject caller-supplied public-key overrides. +- Reject unsigned bypass requests. +- Bound package and signature paths before reading them. +- Verify an Ed25519 signature with a configured key. +- Return evidence to a caller rather than extracting a package. -This legacy package does not define a supported publisher key-generation or arbitrary-package signing workflow. The bundled verifier accepts only the key configured by the v1 host service; callers cannot supply a different key or request unsigned acceptance. +These isolated properties do not make the NanoClaw integration operational. -Use the ClawSec release pipeline and its signed release manifest for official ClawSec package publication. Do not generate a local key and expect this adapter to trust it. +## Publisher Workflow ---- +This package defines no publisher key-generation, signing, distribution, or rotation workflow. Do not generate a local key, sign an arbitrary archive, and expect ClawSec or NanoClaw to authorize it. -## For Legacy NanoClaw v1 Agents +Use the ClawSec release pipeline only after the relevant package has passed the private lifecycle and promotion gates. Production release keys must never be copied to a harness lab or agent-controlled path. -### Quick Start +## Future Ownership -```typescript -// Verify a downloaded skill package before installation -const verification = await tools.clawsec_verify_skill_package({ - packagePath: '/tmp/my-skill-1.0.0.tar.gz' - // signaturePath auto-detected as /tmp/my-skill-1.0.0.tar.gz.sig -}); +The future `clawsec-core-nanoclaw` package, not a guardian or suite, must own deterministic release verification. Require it to: -const result = JSON.parse(verification.content[0].text); +- Authenticate pinned root metadata and the exact release manifest. +- Verify the canonical archive digest and package identity. +- Reject unsafe archive entries before writing. +- Install the exact verified bytes through a NanoClaw v2-native transaction. +- Record scope, origin, preimages, postimages, signer, and result in a receipt. +- Keep trust roots and authoritative receipts on the host. +- Separate advisory-feed verification from release-installation authorization. +- Fail closed on unknown keys, identities, versions, paths, or partial state. -if (!result.valid) { - console.log('⚠️ SIGNATURE VERIFICATION FAILED!'); - console.log(`Reason: ${result.reason || result.error}`); - console.log('DO NOT install this package.'); - return; -} +## Preserved Files -console.log(`✓ Signature valid (signer: ${result.signer})`); -console.log(`Package hash: ${result.packageInfo.sha256}`); -console.log('Signature matches the pinned key; continue required advisory review and operator approval.'); -``` +- `mcp-tools/signature-verification.ts` +- `host-services/skill-signature-handler.ts` +- `lib/signatures.ts` +- `advisories/feed-signing-public.pem` -### MCP Tool: `clawsec_verify_skill_package` - -**Parameters:** -- `packagePath` (required): Absolute path to skill package (`.tar.gz`, `.tar`, `.tgz`, or `.zip`) -- `signaturePath` (optional): Path to signature file (auto-detects `.sig` if omitted) - -Path policy: -- Files must be under one of: `/tmp`, `/var/tmp`, `/workspace/ipc`, `/workspace/project/data`, `/workspace/project/tmp`, `/workspace/project/downloads` -- Symlinks are rejected -- Signatures must use `.sig` - -**Returns:** -```typescript -{ - success: boolean, // Operation completed without errors - valid: boolean, // Signature is cryptographically valid - recommendation: string, // "install" | "block" - signer: string, // "clawsec" - algorithm: "Ed25519", // Signature algorithm - verifiedAt: string, // ISO timestamp - packageInfo: { - size: number, // Package file size in bytes - sha256: string // SHA-256 hash of package - }, - error?: string // Error message if failed -} -``` - -### Usage Patterns - -#### Pattern 1: Basic Signature Review - -```typescript -async function reviewSkillSignature(packagePath: string) { - // Verify signature first - const verification = await tools.clawsec_verify_skill_package({ packagePath }); - const result = JSON.parse(verification.content[0].text); - - if (!result.success || !result.valid || result.recommendation === 'block') { - throw new Error(`Signature review failed: ${result.reason || result.error}`); - } - - return { - packagePath, - verification: result, - nextStep: 'Complete advisory and code review, then request operator approval.' - }; -} -``` - -#### Pattern 2: Combined Security Checks - -```typescript -async function buildInstallReview(packagePath: string, skillName: string) { - // Step 1: Verify signature - const sigVerify = await tools.clawsec_verify_skill_package({ packagePath }); - const sigResult = JSON.parse(sigVerify.content[0].text); - - if (!sigResult.valid) { - throw new Error(`Signature invalid: ${sigResult.reason}`); - } - - // Step 2: Check advisories - const advisory = await tools.clawsec_check_skill_safety({ skillName }); - const advResult = JSON.parse(advisory.content[0].text); - - if (!advResult.safe) { - throw new Error(`Known vulnerabilities: ${advResult.advisories.map(a => a.id).join(', ')}`); - } - - // These checks produce evidence; they do not authorize or perform installation. - return { - packagePath, - signature: sigResult, - advisories: advResult, - requiresCodeReview: true, - requiresOperatorApproval: true - }; -} -``` - -#### Pattern 3: Download and Verify Workflow - -```typescript -async function downloadAndVerifySkill(url: string) { - const packagePath = `/tmp/${Date.now()}-skill.tar.gz`; - const signaturePath = `${packagePath}.sig`; - - // Download package - await fetch(url).then(r => r.arrayBuffer()).then(buf => { - fs.writeFileSync(packagePath, Buffer.from(buf)); - }); - - // Download signature - await fetch(`${url}.sig`).then(r => r.text()).then(sig => { - fs.writeFileSync(signaturePath, sig); - }); - - // Verify before installation - const verification = await tools.clawsec_verify_skill_package({ - packagePath, - signaturePath - }); - - const result = JSON.parse(verification.content[0].text); - - if (!result.valid) { - fs.unlinkSync(packagePath); // Delete tampered file - fs.unlinkSync(signaturePath); - throw new Error('Signature verification failed'); - } - - // Preserve the staged files for advisory/code review and operator approval. - // The host installer must separately enforce the final decision. - return { packagePath, signaturePath, verification: result }; -} -``` - -### Error Handling - -```typescript -const verification = await tools.clawsec_verify_skill_package({ packagePath }); -const result = JSON.parse(verification.content[0].text); - -// Check result.success first (operation completed) -if (!result.success) { - console.error('Verification operation failed:', result.error); - // Reasons: file not found, service unavailable, timeout - return; -} - -// Then check result.valid (signature cryptographically valid) -if (!result.valid) { - console.error('Invalid signature:', result.reason); - // Reasons: signature mismatch, tampered package, invalid format - return; -} - -// Finally check recommendation -switch (result.recommendation) { - case 'install': - console.log('✓ Signature recommendation permits continued review; operator approval is still required'); - break; - case 'block': - console.error('⛔ Signature recommendation is block; the host installer or operator must enforce it'); - break; -} -``` - ---- - -## Security Properties - -### What Signature Verification Detects - -✅ **Detects:** -- **Tampering**: Detecting if package contents were modified after signing -- **MITM attacks**: Detecting if package was swapped during download -- **Malicious mirrors**: Ensuring package comes from trusted source -- **Accidental corruption**: Detecting file corruption during transfer - -### What Signature Verification Does NOT Prevent - -❌ **Does Not Prevent:** -- **Malicious signed packages**: If the publisher's key is compromised -- **Zero-day vulnerabilities**: Bugs unknown to the publisher -- **Social engineering**: Convincing users to trust malicious publishers -- **Time-of-check-to-time-of-use**: Package modified after verification - -**Defense in Depth**: Combine signature verification with: -1. **Advisory checking** (`clawsec_check_skill_safety`) -2. **Code review** (manual inspection of skill code) -3. **Sandboxing** (run skills in isolated containers) -4. **Monitoring** (detect suspicious behavior at runtime) - -### Trust Model - -Signature verification relies on **trust in the public key**: - -``` -┌─────────────────────────────────────────────────┐ -│ You trust ClawSec's public key │ -│ ↓ │ -│ ClawSec signs package with private key │ -│ ↓ │ -│ You verify signature with ClawSec's public key │ -│ ↓ │ -│ Signature valid → Bytes match the pinned key │ -└─────────────────────────────────────────────────┘ -``` - -**Key Question**: How do you establish trust in the public key? -- **Pinned in repository**: Public key committed to ClawSec repo (trust GitHub) -- **HTTPS website**: Download from `https://clawsec.prompt.security/` (trust TLS/CA) -- **Out-of-band verification**: Compare key fingerprint via phone, Signal, etc. -- **Web of Trust**: Multiple trusted sources publish the same key - ---- - -## Key Management - -### ClawSec's Pinned Public Key - -**Location**: `/workspace/project/skills/clawsec-nanoclaw/advisories/feed-signing-public.pem` - -The legacy v1 package-verifier handler reads the embedded advisory feed-verification key by default. That coupling is limited to this frozen adapter. It is not the ClawSec GitHub Release manifest trust anchor and is not a NanoClaw v2 trust contract. - -**Key Fingerprint** (for manual verification): -```bash -# Compute fingerprint of pinned key -openssl pkey -pubin -in feed-signing-public.pem -outform DER | \ - openssl dgst -sha256 -binary | base64 -# Expected: -``` - -### Public Key Policy - -The verifier always uses the pinned ClawSec public key from this skill package. -Runtime public-key overrides are intentionally not supported. - -### Key Rotation - -The bundled v1 verifier has no dual-key or dual-signature rotation protocol. It accepts one configured public key and one `.sig` path. A key change requires a reviewed package update and explicit operator migration; do not invent a `.sig2` fallback or accept caller-selected keys. - ---- - -## Troubleshooting - -### Error: "Signature file not found" - -**Cause**: Missing `.sig` file or incorrect path. - -**Solution**: -```bash -# Check if signature exists -ls -l /tmp/skill.tar.gz.sig - -# If missing, download signature -curl -o /tmp/skill.tar.gz.sig https://example.com/skill.tar.gz.sig - -# Or specify explicit path -clawsec_verify_skill_package({ - packagePath: '/tmp/skill.tar.gz', - signaturePath: '/tmp/custom-signature.sig' -}) -``` - -### Error: "Signature verification failed" - -**Cause**: Package was tampered with, or signature doesn't match package. - -**Solution**: -```bash -# Re-download package and signature -curl -o /tmp/skill.tar.gz https://example.com/skill.tar.gz -curl -o /tmp/skill.tar.gz.sig https://example.com/skill.tar.gz.sig - -# Verify manually with OpenSSL -openssl dgst -sha512 -verify clawsec-signing-public.pem \ - -signature /tmp/skill.tar.gz.sig /tmp/skill.tar.gz -# Should output: "Verified OK" -``` - -### Error: "Invalid PEM format" - -**Cause**: Public key file is corrupted or not in PEM format. - -**Solution**: -```bash -# Check public key format -head -1 /path/to/public-key.pem -# Should output: "-----BEGIN PUBLIC KEY-----" - -# Re-download public key -curl -o clawsec-signing-public.pem \ - https://clawsec.prompt.security/clawsec-signing-public.pem -``` - -### Error: "Package file not found" - -**Cause**: Incorrect path or file doesn't exist. - -**Solution**: -```bash -# Use absolute paths (required) -clawsec_verify_skill_package({ - packagePath: '/tmp/skill.tar.gz' // ✓ Absolute - // packagePath: './skill.tar.gz' // ✗ Relative (won't work) -}) - -# Verify file exists -stat /tmp/skill.tar.gz -``` - -### Verification Times Out (>5s) - -**Cause**: Large package (>50MB) or slow disk I/O. - -**Solution**: -```bash -# Check package size -ls -lh /tmp/skill.tar.gz - -# For very large packages, verification can take time -# Consider splitting into smaller skill modules -``` - ---- - -## Appendix: Signature File Format - -ClawSec uses **Ed25519 detached signatures** in raw binary format, base64-encoded. - -**File Structure**: -``` -my-skill-1.0.0.tar.gz.sig: - Line 1: base64-encoded signature (88 characters) -``` - -**Example**: -``` -MEQCIDxyz...ABC123== -``` - -**Properties**: -- Algorithm: Ed25519 (EdDSA with Curve25519) -- Signature size: 64 bytes (88 characters base64) -- Hash function: SHA-512 (internal to Ed25519) -- Format: Raw binary, base64-encoded - -**Verification Algorithm**: -1. Decode base64 signature → 64-byte binary -2. Hash package with SHA-512 -3. Verify Ed25519 signature(hash, publicKey) → boolean - ---- +Treat them as historical/test-vector input only. ## References -- [Ed25519 Specification (RFC 8032)](https://tools.ietf.org/html/rfc8032) -- [OpenSSL Ed25519 Documentation](https://www.openssl.org/docs/man3.0/man7/Ed25519.html) -- [ClawSec Security Architecture](https://clawsec.prompt.security/docs/architecture) -- [Supply Chain Attack Prevention](https://owasp.org/www-community/attacks/Supply_Chain_Attack) - ---- - -**Document Version**: 0.0.11 legacy adapter -**Last Updated**: 2026-07-22 -**Maintainer**: ClawSec Security Team +- [NanoClaw architecture](https://docs.nanoclaw.dev/concepts/architecture) +- [NanoClaw v2 skills](https://docs.nanoclaw.dev/extend/overview) +- [ClawSec security and signing runbook](../../../wiki/security-signing-runbook.md) diff --git a/skills/clawsec-nanoclaw/skill.json b/skills/clawsec-nanoclaw/skill.json index 3e52dc94..622625c5 100644 --- a/skills/clawsec-nanoclaw/skill.json +++ b/skills/clawsec-nanoclaw/skill.json @@ -1,23 +1,19 @@ { "name": "clawsec-nanoclaw", "version": "0.0.11", - "description": "Legacy ClawSec adapter for pre-v2 NanoClaw deployments; supports NanoClaw >=0.1.0 <2.0.0 and is incompatible with NanoClaw v2", + "description": "Deprecated, runtime-unverified NanoClaw v1-era integration prototype retained only as migration and test-vector evidence; incompatible with NanoClaw v2", "author": "prompt-security", "license": "AGPL-3.0-or-later", "homepage": "https://clawsec.prompt.security/", + "installable": false, "keywords": [ "security", "nanoclaw", - "whatsapp-bot", - "mcp-tools", - "advisory", - "feed", - "threat-intel", - "containers", - "signature-verification", - "vulnerability-scanning", - "agents", - "ai" + "legacy", + "deprecated", + "migration", + "historical", + "test-vectors" ], "platform": "nanoclaw", "sbom": { @@ -25,7 +21,7 @@ { "path": "SKILL.md", "required": true, - "description": "NanoClaw skill documentation" + "description": "Historical-template status and migration guidance" }, { "path": "CHANGELOG.md", @@ -35,106 +31,30 @@ { "path": "INSTALL.md", "required": true, - "description": "Legacy integration guide for NanoClaw >=0.1.0 <2.0.0" - }, - { - "path": "mcp-tools/advisory-tools.ts", - "required": true, - "description": "MCP tools for advisory checking in container context" - }, - { - "path": "host-services/advisory-cache.ts", - "required": true, - "description": "Host-side advisory cache manager with periodic feed fetching" - }, - { - "path": "host-services/ipc-handlers.ts", - "required": true, - "description": "IPC handlers for MCP tool requests" - }, - { - "path": "lib/signatures.ts", - "required": true, - "description": "Ed25519 signature verification utilities" - }, - { - "path": "lib/local_file_io.ts", - "required": true, - "description": "Local file access helpers used by signature verification routines" - }, - { - "path": "lib/advisories.ts", - "required": true, - "description": "Advisory matching and vulnerability detection" - }, - { - "path": "lib/types.ts", - "required": true, - "description": "TypeScript type definitions" - }, - { - "path": "lib/risk.ts", - "required": true, - "description": "Shared advisory risk evaluation logic for host and MCP tools" - }, - { - "path": "advisories/feed-signing-public.pem", - "required": true, - "description": "Pinned Ed25519 public key for feed signature verification" - }, - { - "path": "mcp-tools/signature-verification.ts", - "required": true, - "description": "Phase 1: MCP tool for skill package signature verification" - }, - { - "path": "host-services/skill-signature-handler.ts", - "required": true, - "description": "Phase 1: Host-side signature verification service" + "description": "Historical integration record; explicitly not an installation guide" }, { "path": "docs/SKILL_SIGNING.md", "required": true, - "description": "Phase 1: Documentation for skill signing and verification" - }, - { - "path": "mcp-tools/integrity-tools.ts", - "required": true, - "description": "Phase 2: MCP tools for file integrity monitoring" - }, - { - "path": "host-services/integrity-handler.ts", - "required": true, - "description": "Phase 2: Host-side integrity monitoring service" - }, - { - "path": "guardian/integrity-monitor.ts", - "required": true, - "description": "Phase 2: Core file integrity monitoring engine" - }, - { - "path": "guardian/policy.json", - "required": true, - "description": "Phase 2: NanoClaw-specific file protection policy" + "description": "Historical signature component record" }, { "path": "docs/INTEGRITY.md", "required": true, - "description": "Phase 2: Documentation for file integrity monitoring" + "description": "Historical integrity component record" } ] }, - "capabilities": [ - "Advisory feed monitoring from clawsec.prompt.security", - "MCP tools for agent-initiated vulnerability scans", - "Exploitability-aware advisory prioritization for agent environments", - "Pre-installation advisory checks for operator decisions", - "Ed25519 signature verification for advisory feeds", - "Platform metadata preserved in advisory records for downstream filtering", - "Legacy NanoClaw v1 container support with v1 IPC communication" - ], + "capabilities": [], "nanoclaw": { - "mcp_tools": [ + "status": "deprecated-runtime-unverified", + "lineage": "v1-era", + "runtime_verified": false, + "supported_versions": [], + "incompatible_generations": [ + "v2" + ], + "historical_mcp_tool_names": [ "clawsec_check_advisories", "clawsec_check_skill_safety", "clawsec_list_advisories", @@ -145,11 +65,7 @@ "clawsec_integrity_status", "clawsec_verify_audit" ], - "requires": { - "node": ">=18.0.0", - "nanoclaw": ">=0.1.0 <2.0.0" - }, - "integration": { + "historical_integration_assumptions": { "mcp_tools_file": "container/agent-runner/src/ipc-mcp-stdio.ts", "ipc_handlers_file": "src/ipc.ts", "cache_location": "/workspace/project/data/clawsec-advisory-cache.json" diff --git a/skills/clawsec-nanoclaw/test/nanoclaw-legacy-status.test.mjs b/skills/clawsec-nanoclaw/test/nanoclaw-legacy-status.test.mjs new file mode 100644 index 00000000..f5c89ee7 --- /dev/null +++ b/skills/clawsec-nanoclaw/test/nanoclaw-legacy-status.test.mjs @@ -0,0 +1,151 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const testDir = path.dirname(fileURLToPath(import.meta.url)); +const skillRoot = path.resolve(testDir, '..'); + +function read(relativePath) { + return fs.readFileSync(path.join(skillRoot, relativePath), 'utf8'); +} + +function frontmatterValue(markdown, key) { + const match = markdown.match(new RegExp(`^${key}:\\s*(.+)$`, 'm')); + assert.ok(match, `SKILL.md frontmatter must define ${key}`); + return match[1].trim(); +} + +const skillJson = JSON.parse(read('skill.json')); +const skill = read('SKILL.md'); +const readme = read('README.md'); +const install = read('INSTALL.md'); +const signing = read('docs/SKILL_SIGNING.md'); +const integrity = read('docs/INTEGRITY.md'); +const changelog = read('CHANGELOG.md'); +const signatureTool = read('mcp-tools/signature-verification.ts'); +const advisoryTool = read('mcp-tools/advisory-tools.ts'); + +assert.equal(skillJson.version, '0.0.11', 'skill.json must carry the truthfulness release version'); +assert.equal(frontmatterValue(skill, 'version'), '0.0.11', 'SKILL.md must match skill.json version'); +assert.match(skillJson.description, /deprecated[\s\S]*runtime-unverified/i); +assert.equal(skillJson.installable, false, 'a deprecated unverified template must be non-installable'); +assert.deepEqual(skillJson.capabilities, [], 'an unverified template must not advertise active capabilities'); +assert.equal(skillJson.nanoclaw?.status, 'deprecated-runtime-unverified'); +assert.equal(skillJson.nanoclaw?.lineage, 'v1-era'); +assert.equal(skillJson.nanoclaw?.runtime_verified, false); +assert.deepEqual(skillJson.nanoclaw?.supported_versions, []); +assert.deepEqual(skillJson.nanoclaw?.incompatible_generations, ['v2']); +assert.equal(skillJson.nanoclaw?.requires, undefined, 'unverified metadata must not advertise runtime requirements'); +assert.equal(skillJson.nanoclaw?.integration, undefined, 'historical paths must not be presented as an active integration'); + +const statusDocuments = new Map([ + ['skill.json description', skillJson.description], + ['SKILL.md', skill], + ['README.md', readme], + ['INSTALL.md', install], + ['docs/SKILL_SIGNING.md', signing], + ['docs/INTEGRITY.md', integrity], +]); + +for (const [label, text] of statusDocuments) { + assert.match(text, /(?:v1-era|NanoClaw v1)/i, `${label} must identify the historical v1-era lineage`); + assert.match(text, /(?:runtime-unverified|runtime unverified|unverified)/i, + `${label} must state that runtime support is unverified`); + assert.match(text, /NanoClaw v2[\s\S]{0,120}incompatible|incompatible[\s\S]{0,120}NanoClaw v2/i, + `${label} must state NanoClaw v2 incompatibility`); +} + +for (const [label, text] of [['SKILL.md', skill], ['README.md', readme]]) { + assert.match(text, /NanoClaw has no reviewed direct Agent Skills CLI target/i, + `${label} must state that NanoClaw has no reviewed direct target`); + assert.match(text, /\[[^\]]*(?:install|integration)[^\]]*\]\(\.\/INSTALL\.md\)/i, + `${label} must link the packaged historical integration record`); + assert.doesNotMatch(text, /npx\s+skills\s+add/i, + `${label} must not present a Skills CLI install command`); +} + +for (const [label, text] of statusDocuments) { + assert.doesNotMatch(text, />=\s*0\.1\.0\s*<\s*2\.0\.0/i, + `${label} must not advertise the invented legacy support range`); + assert.doesNotMatch(text, /Supported NanoClaw range:\s*`?[^\n]*\d+\.\d+/i, + `${label} must not advertise a numeric support range`); + assert.doesNotMatch(text, /SQLite IPC/i, + `${label} must use the explicit two-database boundary terminology`); +} + +assert.match(install, /not an installation guide/i); +assert.match(install, /declare[\s\S]*emit no JavaScript/i, + 'the historical record must explain the ambient-declaration runtime failure'); +assert.match(install, /ES modules[\s\S]*do not inherit lexical variables/i, + 'the historical record must explain the module-scope failure'); +assert.match(install, /glob[\s\S]{0,180}(?:no runtime implementation|unbound)/i, + 'the historical record must identify the unbound glob implementation'); +assert.match(install, /writeResponse[\s\S]{0,180}(?:imports or implements no|no implementation)/i, + 'the historical record must identify the missing writeResponse implementation'); +assert.match(install, /__dirname[\s\S]{0,180}ES module/i, + 'the historical record must identify the CommonJS __dirname use in ESM'); +assert.doesNotMatch(install, /docker-compose\s+(?:down|up)|docker\s+compose\s+(?:down|up)/i, + 'the withdrawn record must not retain false service commands'); +assert.doesNotMatch(install, /\bcp\s+-r\b|\bimport\s+['"][.]{1,2}\//i, + 'the withdrawn record must not contain actionable legacy copy/import steps'); + +assert.match(integrity, /not an active integrity guardian/i); +assert.match(integrity, /Automatic restoration[\s\S]*must remain off/i); +assert.doesNotMatch(integrity, /schedule_task\s*\(/i, + 'historical integrity documentation must not include an activation example'); + +assert.match(signing, /not a supported package-verification workflow/i); +assert.match(signing, /signed `checksums\.json` manifest/i); +assert.match(signing, /machine-readable `install` recommendation must not be treated as installation authority/i); +assert.doesNotMatch(signing, /Safe to install|proceed with extraction|extractPackage\(/i, + 'historical signing documentation must not authorize installation'); + +assert.doesNotMatch(skill, /prevents installation of vulnerable skills/i, + 'the skill must not claim ownership of a host installer'); +assert.doesNotMatch(readme, /ClawSec now supports NanoClaw/i, + 'the README must not make an unqualified support claim'); +assert.doesNotMatch(signatureTool, /prevents installation/i, + 'the signature tool description must not claim ownership of a host installer'); +assert.match(signatureTool, /host installer or operator must enforce/i, + 'the historical signature source must still identify who would enforce a result'); +assert.doesNotMatch(advisoryTool, /safe to install based on/i, + 'the advisory source must not present a feed result as complete installation safety'); +assert.match(advisoryTool, /host installer or operator must enforce/i, + 'the historical advisory source must still identify who would enforce a result'); + +const packagedPaths = skillJson.sbom?.files?.map((entry) => entry.path) ?? []; +const expectedPackagedPaths = [ + 'CHANGELOG.md', + 'INSTALL.md', + 'SKILL.md', + 'docs/INTEGRITY.md', + 'docs/SKILL_SIGNING.md', +]; +assert.deepEqual([...packagedPaths].sort(), expectedPackagedPaths, + 'the release SBOM must contain only essential migration and status documentation'); +for (const packagedPath of packagedPaths) { + assert.doesNotMatch(packagedPath, /\.ts$/i, + 'the release SBOM must not ship runtime-unverified TypeScript'); + assert.doesNotMatch(packagedPath, /(?:^|\/)policy\.json$/i, + 'the release SBOM must not ship the historical policy JSON'); + assert.doesNotMatch(packagedPath, /\.pem$/i, + 'the release SBOM must not ship historical PEM material'); +} +assert.match(skill, /successor[\s\S]{0,180}current published release[\s\S]{0,180}acceptance evidence/i, + 'successor availability must require current release and acceptance evidence'); +assert.match(skill, /live logs[\s\S]{0,180}runtime execution evidence as unknown/i, + 'missing live-log access must leave runtime evidence unknown'); +assert.match(skill, /upstream material observed on 2026-07-22[\s\S]{0,180}Reverify/i, + 'observed upstream facts must carry a revalidation requirement'); +assert.match(changelog, /^## \[0\.0\.11\] - 2026-07-22$/m, + 'CHANGELOG.md must record the truthfulness release'); +assert.match(changelog, /runtime-unverified NanoClaw v1-era integration prototype/i); +assert.match(changelog, /packaged user-facing Markdown/i, + 'the changelog must scope instruction removal to the packaged Markdown'); +assert.match(changelog, /Excluded runtime-unverified TypeScript, policy JSON, and PEM artifacts from the release SBOM/i, + 'the changelog must record the documentation-only release boundary'); + +assert.ok(skill.split('\n').length < 500, 'SKILL.md must remain concise enough for skill context'); + +console.log('NanoClaw legacy status contract tests passed.'); diff --git a/skills/clawsec-nanoclaw/test/nanoclaw-v1-compatibility.test.mjs b/skills/clawsec-nanoclaw/test/nanoclaw-v1-compatibility.test.mjs deleted file mode 100644 index d6e54cf2..00000000 --- a/skills/clawsec-nanoclaw/test/nanoclaw-v1-compatibility.test.mjs +++ /dev/null @@ -1,114 +0,0 @@ -import assert from 'node:assert/strict'; -import fs from 'node:fs'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const testDir = path.dirname(fileURLToPath(import.meta.url)); -const skillRoot = path.resolve(testDir, '..'); - -function read(relativePath) { - return fs.readFileSync(path.join(skillRoot, relativePath), 'utf8'); -} - -function frontmatterValue(markdown, key) { - const match = markdown.match(new RegExp(`^${key}:\\s*(.+)$`, 'm')); - assert.ok(match, `SKILL.md frontmatter must define ${key}`); - return match[1].trim(); -} - -const skillJson = JSON.parse(read('skill.json')); -const skill = read('SKILL.md'); -const readme = read('README.md'); -const install = read('INSTALL.md'); -const signing = read('docs/SKILL_SIGNING.md'); -const integrity = read('docs/INTEGRITY.md'); -const changelog = read('CHANGELOG.md'); -const signatureTool = read('mcp-tools/signature-verification.ts'); -const advisoryTool = read('mcp-tools/advisory-tools.ts'); - -assert.equal(skillJson.version, '0.0.11', 'skill.json must carry the truthfulness release version'); -assert.equal(frontmatterValue(skill, 'version'), '0.0.11', 'SKILL.md must match skill.json version'); -assert.equal( - skillJson.nanoclaw?.requires?.nanoclaw, - '>=0.1.0 <2.0.0', - 'legacy package metadata must exclude NanoClaw v2', -); - -const compatibilityDocuments = new Map([ - ['skill.json description', skillJson.description], - ['SKILL.md', skill], - ['README.md', readme], - ['INSTALL.md', install], - ['docs/SKILL_SIGNING.md', signing], - ['docs/INTEGRITY.md', integrity], -]); - -for (const [label, text] of compatibilityDocuments) { - assert.match(text, /(?:NanoClaw v1|pre-v2)/i, `${label} must identify the legacy v1/pre-v2 scope`); - assert.match(text, /NanoClaw v2[\s\S]{0,100}incompatible|incompatible[\s\S]{0,100}NanoClaw v2/i, - `${label} must state NanoClaw v2 incompatibility`); -} - -for (const [label, text] of [['SKILL.md', skill], ['README.md', readme]]) { - assert.doesNotMatch( - text, - /npx\s+skills\s+add[\s\S]{0,160}(?:-a|--agent)\s+openclaw/i, - `${label} must not present an OpenClaw-targeted installer command for NanoClaw`, - ); -} - -for (const [label, text] of [['SKILL.md', skill], ['README.md', readme], ['INSTALL.md', install]]) { - assert.doesNotMatch(text, /Every 6 hours \(automatic\)/i, `${label} must not claim automatic scheduling`); -} - -assert.doesNotMatch(skill, /prevents installation of vulnerable skills/i, - 'the advisory tool must not claim ownership of the host installer'); -assert.doesNotMatch(readme, /ClawSec now supports NanoClaw/i, - 'the legacy README must not make an unqualified current-support claim'); -assert.doesNotMatch(signatureTool, /prevents installation/i, - 'the signature tool must not claim ownership of the host installer'); -assert.match(signatureTool, /host installer or operator must enforce/i, - 'the signature tool must identify who enforces its recommendation'); -assert.doesNotMatch(signatureTool, /install\/block\/review/i, - 'the signature tool must not advertise an unreachable review recommendation'); -assert.doesNotMatch(advisoryTool, /safe to install based on/i, - 'the advisory tool must not present its feed result as complete installation safety'); -assert.match(advisoryTool, /host installer or operator must enforce/i, - 'the advisory tool must identify who enforces its recommendation'); - -for (const [label, text] of compatibilityDocuments) { - let offset = 0; - while ((offset = text.indexOf('schedule_task(', offset)) !== -1) { - const context = text.slice(Math.max(0, offset - 320), offset); - assert.match( - context, - /Legacy NanoClaw v1 Scheduler Example|Compatibility boundary/i, - `${label} must scope every retained schedule_task example to legacy NanoClaw v1`, - ); - offset += 'schedule_task('.length; - } -} - -assert.match(signing, /Publisher Workflow Is Out of Scope/, - 'legacy signing documentation must reject an invented publisher workflow'); -assert.match(signing, /does not accept caller-selected publisher keys/i, - 'legacy signing documentation must describe pinned-key behavior'); -assert.match(signing, /has no dual-key or dual-signature rotation protocol/i, - 'legacy signing documentation must describe the actual single-key verifier'); -assert.doesNotMatch(signing, /comes from ClawSec \(or trusted publisher\)/i, - 'legacy signing documentation must not claim arbitrary publisher trust'); -assert.doesNotMatch(signing, /During transition, support \*\*dual signatures\*\*/i, - 'legacy signing documentation must not claim unsupported dual-signature rotation'); -assert.doesNotMatch(signing, /Agents can verify with either key during the overlap period/i, - 'legacy signing documentation must not claim unsupported multi-key verification'); -assert.doesNotMatch(signing, /Safe to install|Installation blocked|proceed with extraction|extractPackage\(/i, - 'legacy signing examples must not treat verification as installation authority'); -assert.match(signing, /requiresOperatorApproval|operator approval is still required/i, - 'legacy signing examples must preserve explicit operator approval'); -assert.doesNotMatch(signing, /"install"\s*\|\s*"block"\s*\|\s*"review"|case 'review'/i, - 'legacy signing documentation must list only implemented recommendation outcomes'); -assert.doesNotMatch(skill, /if\s*\(safety\.safe\)\s*await installSkill|Proceed with installation/i, - 'the skill must not treat advisory output as installation authorization'); - -assert.match(changelog, /^## \[0\.0\.11\] - 2026-07-22$/m, - 'CHANGELOG.md must record the truthfulness release'); diff --git a/skills/clawsec-nanoclaw/test/security-hardening.test.mjs b/skills/clawsec-nanoclaw/test/security-hardening.test.mjs index 494aeffb..39cccd92 100644 --- a/skills/clawsec-nanoclaw/test/security-hardening.test.mjs +++ b/skills/clawsec-nanoclaw/test/security-hardening.test.mjs @@ -6,6 +6,8 @@ import test from 'node:test'; import vm from 'node:vm'; import { fileURLToPath } from 'node:url'; +import './nanoclaw-legacy-status.test.mjs'; + const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const SKILL_ROOT = path.resolve(__dirname, '..'); From ffe94d3b1e5f596d8dc1ce8c72ce49ebdca70775 Mon Sep 17 00:00:00 2001 From: David Abutbul Date: Thu, 23 Jul 2026 00:37:17 +0300 Subject: [PATCH 3/3] refactor(nanoclaw): keep legacy runtime source frozen --- .../host-services/skill-signature-handler.ts | 3 +-- skills/clawsec-nanoclaw/mcp-tools/advisory-tools.ts | 2 +- .../mcp-tools/signature-verification.ts | 5 ++--- .../test/nanoclaw-legacy-status.test.mjs | 11 ----------- 4 files changed, 4 insertions(+), 17 deletions(-) diff --git a/skills/clawsec-nanoclaw/host-services/skill-signature-handler.ts b/skills/clawsec-nanoclaw/host-services/skill-signature-handler.ts index ebe9a8f7..4c5b6480 100644 --- a/skills/clawsec-nanoclaw/host-services/skill-signature-handler.ts +++ b/skills/clawsec-nanoclaw/host-services/skill-signature-handler.ts @@ -1,8 +1,7 @@ /** * Skill Signature Verification Handler for NanoClaw * - * Verifies Ed25519 signatures on staged skill packages so callers can detect - * tampering before an operator or host installer decides whether to proceed. + * Verifies Ed25519 signatures on skill packages to prevent supply chain attacks. * Uses the same pinned public key as advisory feed verification. */ diff --git a/skills/clawsec-nanoclaw/mcp-tools/advisory-tools.ts b/skills/clawsec-nanoclaw/mcp-tools/advisory-tools.ts index ccc38f14..c705785d 100644 --- a/skills/clawsec-nanoclaw/mcp-tools/advisory-tools.ts +++ b/skills/clawsec-nanoclaw/mcp-tools/advisory-tools.ts @@ -182,7 +182,7 @@ server.tool( server.tool( 'clawsec_check_skill_safety', - 'Check a skill and optional version against the cached ClawSec advisory feed. Returns an install/block/review recommendation with reasons; the host installer or operator must enforce it and complete other required review.', + 'Check if a specific skill is safe to install based on ClawSec advisory feed. Returns safety recommendation (install/block/review) with reasons. Use this as a pre-install gate before installing any skill.', { skillName: z.string().describe('Name of skill to check'), skillVersion: z.string().optional().describe('Version of skill (optional, for version-specific checks)'), diff --git a/skills/clawsec-nanoclaw/mcp-tools/signature-verification.ts b/skills/clawsec-nanoclaw/mcp-tools/signature-verification.ts index b3f9576b..216e8181 100644 --- a/skills/clawsec-nanoclaw/mcp-tools/signature-verification.ts +++ b/skills/clawsec-nanoclaw/mcp-tools/signature-verification.ts @@ -3,8 +3,7 @@ * * Add this tool to /workspace/project/container/agent-runner/src/ipc-mcp-stdio.ts * - * This tool reports Ed25519 signature verification results for operator or - * host-installer review. It does not install packages or enforce the result. + * This tool verifies Ed25519 signatures on skill packages to prevent supply chain attacks. */ /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -92,7 +91,7 @@ async function waitForResult(requestId: string, timeoutMs: number = 5000): Promi server.tool( 'clawsec_verify_skill_package', - 'Verify the Ed25519 signature of a staged skill package and return an install/block recommendation. The host installer or operator must enforce the result and complete advisory and code review.', + 'Verify Ed25519 signature of a skill package before installation. Prevents installation of tampered or malicious skill packages by checking ClawSec signatures.', { packagePath: z.string().describe('Absolute path to skill package (.tar.gz or .zip)'), signaturePath: z.string().optional().describe('Path to signature file. If omitted, auto-detects .sig'), diff --git a/skills/clawsec-nanoclaw/test/nanoclaw-legacy-status.test.mjs b/skills/clawsec-nanoclaw/test/nanoclaw-legacy-status.test.mjs index f5c89ee7..73e3d0db 100644 --- a/skills/clawsec-nanoclaw/test/nanoclaw-legacy-status.test.mjs +++ b/skills/clawsec-nanoclaw/test/nanoclaw-legacy-status.test.mjs @@ -23,8 +23,6 @@ const install = read('INSTALL.md'); const signing = read('docs/SKILL_SIGNING.md'); const integrity = read('docs/INTEGRITY.md'); const changelog = read('CHANGELOG.md'); -const signatureTool = read('mcp-tools/signature-verification.ts'); -const advisoryTool = read('mcp-tools/advisory-tools.ts'); assert.equal(skillJson.version, '0.0.11', 'skill.json must carry the truthfulness release version'); assert.equal(frontmatterValue(skill, 'version'), '0.0.11', 'SKILL.md must match skill.json version'); @@ -105,15 +103,6 @@ assert.doesNotMatch(skill, /prevents installation of vulnerable skills/i, 'the skill must not claim ownership of a host installer'); assert.doesNotMatch(readme, /ClawSec now supports NanoClaw/i, 'the README must not make an unqualified support claim'); -assert.doesNotMatch(signatureTool, /prevents installation/i, - 'the signature tool description must not claim ownership of a host installer'); -assert.match(signatureTool, /host installer or operator must enforce/i, - 'the historical signature source must still identify who would enforce a result'); -assert.doesNotMatch(advisoryTool, /safe to install based on/i, - 'the advisory source must not present a feed result as complete installation safety'); -assert.match(advisoryTool, /host installer or operator must enforce/i, - 'the historical advisory source must still identify who would enforce a result'); - const packagedPaths = skillJson.sbom?.files?.map((entry) => entry.path) ?? []; const expectedPackagedPaths = [ 'CHANGELOG.md',