Commit graph

15 commits

Author SHA1 Message Date
argenis de la rosa
dbf02291b4 fix: escape AppleScript target parameter in iMessage channel
- Add escape_applescript() function to prevent injection attacks
- Add is_valid_imessage_target() validation for phone/email patterns
- Update send() method to escape both message AND target parameters
- Add 40 comprehensive tests covering injection edge cases
- Addresses CWE-78 (OS Command Injection) vulnerability

Fixes #29
2026-02-14 13:38:13 -05:00
argenis de la rosa
ef4444ba43 fix: resolve build errors and add comprehensive symlink tests
- Fixed E0425 error in src/skills/mod.rs by moving println! inside #[cfg(unix)] block where 'dest' variable is in scope
- Added missing 'identity' field to Config struct initializations in src/onboard/wizard.rs
- Fixed import paths for AIEOS identity functions in src/channels/mod.rs
- Added comprehensive symlink edge case tests in src/skills/symlink_tests.rs
- All 840 tests passing, 0 clippy warnings

Resolves issue #28: skills symlink functionality now works correctly on Unix platforms with proper error handling on non-Unix platforms
2026-02-14 13:37:27 -05:00
argenis de la rosa
76074cb789 fix: run Docker container as non-root user (closes #34)
- Switch to gcr.io/distroless/cc-debian12:nonroot
- Add explicit USER 65534:65534 directive
- Add Docker security CI job verifying non-root UID, :nonroot base, and USER directive
- Document CIS Docker Benchmark compliance in SECURITY.md
- Add tests and edge cases for container security
2026-02-14 13:16:33 -05:00
argenis de la rosa
cc08f4bfff feat: Add full WhatsApp Business Cloud API integration
- Add WhatsApp channel module with Cloud API v18.0 support
- Implement webhook-based message reception and API sending
- Add allowlist for phone numbers (E.164 format or wildcard)
- Add WhatsApp webhook endpoints to gateway (/whatsapp GET/POST)
- Add WhatsApp config schema with TOML support
- Wire WhatsApp into channel factory, CLI, and doctor commands
- Add WhatsApp to setup wizard with connection testing
- Add comprehensive test coverage (47 channel tests + 9 URL decoding tests)
- Update README with detailed WhatsApp setup instructions
- Support text messages only, skip media/status updates
- Normalize phone numbers with + prefix
- Handle webhook verification with Meta challenge-response

All 756 tests pass. Ready for production use.
2026-02-14 13:10:16 -05:00
argenis de la rosa
ec2d5cc93d feat: enhance agent personality, tool guidance, and memory hygiene
- Expand communication style presets (professional, expressive, custom)
- Enrich SOUL.md with human-like tone and emoji-awareness guidance
- Add crash recovery and sub-task scoping guidance to AGENTS.md scaffold
- Add 'Use when / Don't use when' guidance to TOOLS.md and runtime prompts
- Implement memory hygiene system with configurable archiving and retention
- Add MemoryConfig options: hygiene_enabled, archive_after_days, purge_after_days, conversation_retention_days
- Archive old daily memory and session files to archive subdirectories
- Purge old archives and prune stale SQLite conversation rows
- Add comprehensive tests for new features
2026-02-14 11:28:39 -05:00
argenis de la rosa
1fd51f1984 fix: resolve all clippy --all-targets warnings across 15 files
- gateway/mod.rs: move send_json before test module (items_after_test_module)
- memory/vector.rs: fix float_cmp, cast_precision_loss, approx_constant
- memory/chunker.rs: fix format_collect, format_push_string, write_with_newline
- memory/sqlite.rs: fix useless_vec
- heartbeat/engine.rs: fix format_collect, write_with_newline
- config/schema.rs: fix needless_raw_string_hashes
- tools/composio.rs: fix needless_raw_string_hashes
- integrations/registry.rs: fix uninlined_format_args, unused import
- tunnel/mod.rs: fix doc_markdown
- skills/mod.rs: allow similar_names in test module
- channels/cli.rs: fix unreadable_literal
- observability/mod.rs: fix manual_string_new
- runtime/mod.rs: fix manual_string_new
- examples/custom_memory.rs: add Default impl (new_without_default)
- examples/custom_channel.rs: fix needless_borrows_for_generic_args
2026-02-14 03:52:57 -05:00
argenis de la rosa
976c5bbf3c hardening: fix 7 production weaknesses found in codebase scan
Scan findings and fixes:

1. Gateway buffer overflow (8KB → 64KB)
   - Fixed: Increased request buffer from 8,192 to 65,536 bytes
   - Large POST bodies (long prompts) were silently truncated

2. Gateway slow-loris attack (no read timeout → 30s)
   - Fixed: tokio::time::timeout(30s) on stream.read()
   - Malicious clients could hold connections indefinitely

3. Webhook secret timing attack (== → constant_time_eq)
   - Fixed: Now uses constant_time_eq() for secret comparison
   - Prevents timing side-channel on webhook authentication

4. Pairing brute force (no limit → 5 attempts + 5min lockout)
   - Fixed: PairingGuard tracks failed attempts with lockout
   - Returns 429 Too Many Requests with retry_after seconds

5. Shell tool hang (no timeout → 60s kill)
   - Fixed: tokio::time::timeout(60s) on Command::output()
   - Commands that hang are killed and return error

6. Shell tool OOM (unbounded output → 1MB cap)
   - Fixed: stdout/stderr truncated at 1MB with warning
   - Prevents memory exhaustion from verbose commands

7. Provider HTTP timeout (none → 120s request + 10s connect)
   - Fixed: All 5 providers (OpenRouter, Anthropic, OpenAI,
     Ollama, Compatible) now have reqwest timeouts
   - Ollama gets 300s (local models are slower)

949 tests passing, 0 clippy warnings, cargo fmt clean
2026-02-14 01:47:08 -05:00
argenis de la rosa
c8d4ceee71 feat: add port 0 (random port) support for gateway security
When --port 0 is passed, the OS assigns a random available ephemeral
port (typically 49152-65535). The actual port is resolved after binding
and used for all log output and tunnel forwarding.

This prevents port-scanning attacks against a known fixed port.

Changes:
  src/gateway/mod.rs — bind first, extract actual_port from listener,
    use actual_port for addr formatting and tunnel.start()
  src/main.rs — update CLI help text, conditional log for port=0

8 new edge case tests:
  - port_zero_binds_to_random_port
  - port_zero_assigns_different_ports
  - port_zero_assigns_high_port
  - specific_port_binds_exactly
  - actual_port_matches_addr_format
  - port_zero_listener_accepts_connections
  - duplicate_specific_port_fails
  - tunnel_gets_actual_port_not_zero

943 tests passing, 0 clippy warnings, cargo fmt clean
2026-02-14 01:21:55 -05:00
argenis de la rosa
b2aff60722 security: pass all 4 checklist items — gateway not public, pairing required, filesystem scoped, tunnel access
Security checklist from @anshnanda / @ledger_eth:
   Gateway not public — default bind 127.0.0.1, refuses 0.0.0.0 without
     tunnel or explicit allow_public_bind=true in config
   Pairing required — one-time 6-digit code printed on startup, exchanged
     for bearer token via POST /pair, enforced on all /webhook requests
   Filesystem scoped (no /) — workspace_only=true by default, null byte
     injection blocked, 14 system dirs + 4 sensitive dotfiles in forbidden
     list, is_resolved_path_allowed() for symlink escape prevention
   Access via Tailscale/SSH tunnel — tunnel system integrated, gateway
     refuses public bind without active tunnel

New files:
  src/security/pairing.rs — PairingGuard with OTP generation, constant-time
    code comparison, bearer token issuance, token persistence

Changed files:
  src/config/schema.rs — GatewayConfig (require_pairing, allow_public_bind,
    paired_tokens), expanded AutonomyConfig forbidden_paths
  src/config/mod.rs — export GatewayConfig
  src/gateway/mod.rs — public bind guard, pairing enforcement on /webhook,
    /pair endpoint, /health no longer leaks version/memory info
  src/security/policy.rs — null byte blocking, is_resolved_path_allowed(),
    expanded forbidden_paths (14 system dirs + 4 dotfiles)
  src/security/mod.rs — export pairing module
  src/onboard/wizard.rs — wire gateway config

935 tests passing (up from 905), 0 clippy warnings, cargo fmt clean
2026-02-14 00:39:51 -05:00
argenis de la rosa
0e7f501fd6 feat: full-stack search engine — FTS5, vector search, hybrid merge, embedding cache, chunker
The Full Stack (All Custom):
- Vector DB: embeddings stored as BLOB, cosine similarity in pure Rust
- Keyword Search: FTS5 virtual tables with BM25 scoring + auto-sync triggers
- Hybrid Merge: weighted fusion of vector + keyword results (configurable weights)
- Embeddings: provider abstraction (OpenAI, custom URL, noop fallback)
- Chunking: line-based markdown chunker with heading preservation
- Caching: embedding_cache table with LRU eviction
- Safe Reindex: rebuild FTS5 + re-embed missing vectors

New modules:
- src/memory/embeddings.rs — EmbeddingProvider trait + OpenAI + Noop + factory
- src/memory/vector.rs — cosine similarity, vec↔bytes, ScoredResult, hybrid_merge
- src/memory/chunker.rs — markdown-aware document splitting

Upgraded:
- src/memory/sqlite.rs — FTS5 schema, embedding column, hybrid recall, cache, reindex
- src/config/schema.rs — MemoryConfig expanded with embedding/search settings
- All callers updated to pass api_key for embedding provider

739 tests passing, 0 clippy warnings (Rust 1.93.1), cargo-deny clean
2026-02-14 00:00:23 -05:00
argenis de la rosa
390cbc0a6c feat: agnostic tunnel system — bring your own tunnel provider
New Tunnel trait + 5 implementations:
- NoneTunnel: local-only, no external exposure (default)
- CloudflareTunnel: wraps cloudflared binary, extracts public URL
- TailscaleTunnel: tailscale serve (tailnet) or funnel (public)
- NgrokTunnel: wraps ngrok binary, supports custom domains
- CustomTunnel: user-provided command with {port}/{host} placeholders

Config schema:
- [tunnel] section with provider selector
- Provider-specific sub-configs: cloudflare, tailscale, ngrok, custom
- Backward compatible (serde default = "none")

Gateway integration:
- Tunnel starts automatically on 'zeroclaw gateway'
- Prints public URL on success, falls back to local on failure

20 new tests (factory, constructors, NoneTunnel async start/health)
649 tests passing, 0 clippy warnings, cargo fmt clean
2026-02-13 16:25:01 -05:00
argenis de la rosa
bc31e4389b style: cargo fmt — fix all formatting for CI
Ran cargo fmt across entire codebase to pass CI's cargo fmt --check.
No logic changes, only whitespace/formatting.
2026-02-13 16:03:50 -05:00
argenis de la rosa
a5887ad2dc docs+tests: architecture diagram, security docs, 75 new edge-case tests
README:
- Add ASCII architecture flow diagram showing all layers
- Add Security Architecture section (Layer 1: Channel Auth,
  Layer 2: Rate Limiting, Layer 3: Tool Sandbox)
- Update test count to 629

New edge-case tests (75 new):
- SecurityPolicy: command injection (semicolon, backtick, dollar-paren,
  env prefix, newline), path traversal (encoded dots, double-dot in
  filename, null byte, symlink, tilde-ssh, /var/run), rate limiter
  boundaries (exactly-at, zero, high), autonomy+command combos,
  from_config fresh tracker
- Discord: exact match not substring, empty user ID, wildcard+specific,
  case sensitivity, base64 edge cases
- Slack: exact match, empty user ID, case sensitivity, wildcard combo
- Telegram: exact match, empty string, case sensitivity, wildcard combo
- Gateway: first-match-wins, empty value, colon in value, different
  headers, empty request, newline-only request
- Config schema: backward compat (Discord/Slack without allowed_users),
  TOML roundtrip, webhook secret presence/absence

629 tests passing, 0 clippy warnings
2026-02-13 16:00:15 -05:00
argenis de la rosa
542bb80743 security: harden architecture against Moltbot security model
- Discord: add allowed_users field + sender validation in listen()
- Slack: add allowed_users field + sender validation in listen()
- Webhook: add X-Webhook-Secret header auth (401 on mismatch)
- SecurityPolicy: add ActionTracker with sliding-window rate limiting
  - record_action() enforces max_actions_per_hour
  - is_rate_limited() checks without recording
- Gateway: print auth status on startup (ENABLED/DISABLED)
- 22 new tests (Discord/Slack allowlists, gateway header extraction,
  rate limiter: starts at zero, records, allows within limit,
  blocks over limit, clone independence)
- 554 tests passing, 0 clippy warnings
2026-02-13 15:31:21 -05:00
argenis de la rosa
05cb353f7f feat: initial release — ZeroClaw v0.1.0
- 22 AI providers (OpenRouter, Anthropic, OpenAI, Mistral, etc.)
- 7 channels (CLI, Telegram, Discord, Slack, iMessage, Matrix, Webhook)
- 5-step onboarding wizard with Project Context personalization
- OpenClaw-aligned system prompt (SOUL.md, IDENTITY.md, USER.md, AGENTS.md, etc.)
- SQLite memory backend with auto-save
- Skills system with on-demand loading
- Security: autonomy levels, command allowlists, cost limits
- 532 tests passing, 0 clippy warnings
2026-02-13 12:19:14 -05:00