mirror of
https://github.com/we-promise/sure.git
synced 2026-04-19 03:54:08 +00:00
Add Pipelock operational templates, docs, and config hardening (#1102)
* feat(helm): add Pipelock ConfigMap, scanning config, and consolidate compose - Add ConfigMap template rendering DLP, response scanning, MCP input/tool scanning, and forward proxy settings from values - Mount ConfigMap as /etc/pipelock/pipelock.yaml volume in deployment - Add checksum/config annotation for automatic pod restart on config change - Gate HTTPS_PROXY/HTTP_PROXY env injection on forwardProxy.enabled (skip in MCP-only mode) - Use hasKey for all boolean values to prevent Helm default swallowing false - Single source of truth for ports (forwardProxy.port/mcpProxy.port) - Pipelock-specific imagePullSecrets with fallback to app secrets - Merge standalone compose.example.pipelock.yml into compose.example.ai.yml - Add pipelock.example.yaml for Docker Compose users - Add exclude-paths to CI workflow for locale file false positives * Add external assistant support (OpenAI-compatible SSE proxy) Allow self-hosted instances to delegate chat to an external AI agent via an OpenAI-compatible streaming endpoint. Configurable per-family through Settings UI or ASSISTANT_TYPE env override. - Assistant::External::Client: SSE streaming HTTP client (no new gems) - Settings UI with type selector, env lock indicator, config status - Helm chart and Docker Compose env var support - 45 tests covering client, config, routing, controller, integration * Add session key routing, email allowlist, and config plumbing Route to the actual OpenClaw session via x-openclaw-session-key header instead of creating isolated sessions. Gate external assistant access behind an email allowlist (EXTERNAL_ASSISTANT_ALLOWED_EMAILS env var). Plumb session_key and allowedEmails through Helm chart, compose, and env template. * Add HTTPS_PROXY support to External::Client for Pipelock integration Net::HTTP does not auto-read HTTPS_PROXY/HTTP_PROXY env vars (unlike Faraday). Explicitly resolve proxy from environment in build_http so outbound traffic to the external assistant routes through Pipelock's forward proxy when enabled. Respects NO_PROXY for internal hosts. * Add UI fields for external assistant config (Setting-backed with env fallback) Follow the same pattern as OpenAI settings: database-backed Setting fields with env var defaults. Self-hosters can now configure the external assistant URL, token, and agent ID from the browser (Settings > Self-Hosting > AI Assistant) instead of requiring env vars. Fields disable when the corresponding env var is set. * Improve external assistant UI labels and add help text Change placeholder to generic OpenAI-compatible URL pattern. Add help text under each field explaining where the values come from: URL from agent provider, token for authentication, agent ID for multi-agent routing. * Add external assistant docs and fix URL help text Add External AI Assistant section to docs/hosting/ai.md covering setup (UI and env vars), how it works, Pipelock security scanning, access control, and Docker Compose example. Drop "chat completions" jargon from URL help text. * Harden external assistant: retry logic, disconnect UI, error handling, and test coverage - Add retry with backoff for transient network errors (no retry after streaming starts) - Add disconnect button with confirmation modal in self-hosting settings - Narrow rescue scope with fallback logging for unexpected errors - Safe cleanup of partial responses on stream interruption - Gate ai_available? on family assistant_type instead of OR-ing all providers - Truncate conversation history to last 20 messages - Proxy-aware HTTP client with NO_PROXY support - Sanitize protocol to use generic headers (X-Agent-Id, X-Session-Key) - Full test coverage for streaming, retries, proxy routing, config, and disconnect * Exclude external assistant client from Pipelock scan-diff False positive: `@token` instance variable flagged as "Credential in URL". Temporary workaround until Pipelock supports inline suppression. * Address review feedback: NO_PROXY boundary fix, SSE done flag, design tokens - Fix NO_PROXY matching to require domain boundary (exact match or .suffix), case-insensitive. Prevents badexample.com matching example.com. - Add done flag to SSE streaming so read_body stops after [DONE] - Move MAX_CONVERSATION_MESSAGES to class level - Use bg-success/bg-destructive design tokens for status indicators - Add rationale comment for pipelock scan exclusion - Update docs last-updated date * Address second round of review feedback - Allowlist email comparison is now case-insensitive and nil-safe - Cap SSE buffer at 1 MB to prevent memory blowup from malformed streams - Don't expose upstream HTTP response body in user-facing errors (log it instead) - Fix frozen string warning on buffer initialization - Fix "builtin" typo in docs (should be "built-in") * Protect completed responses from cleanup, sanitize error messages - Don't destroy a fully streamed assistant message if post-stream metadata update fails (only cleanup partial responses) - Log raw connection/HTTP errors internally, show generic messages to users to avoid leaking network/proxy details - Update test assertions for new error message wording * Fix SSE content guard and NO_PROXY test correctness Use nil check instead of present? for SSE delta content to preserve whitespace-only chunks (newlines, spaces) that can occur in code output. Fix NO_PROXY test to use HTTP_PROXY matching the http:// client URL so the proxy resolution and NO_PROXY bypass logic are actually exercised. * Forward proxy credentials to Net::HTTP Pass proxy_uri.user and proxy_uri.password to Net::HTTP.new so authenticated proxies (http://user:pass@host:port) work correctly. Without this, credentials parsed from the proxy URL were silently dropped. Nil values are safe as positional args when no creds exist. * Update pipelock integration to v0.3.1 with full scanning config Bump Helm image tag from 0.2.7 to 0.3.1. Add missing security sections to both the Helm ConfigMap and compose example config: mcp_tool_policy, mcp_session_binding, and tool_chain_detection. These protect the /mcp endpoint against tool injection, session hijacking, and multi-step exfiltration chains. Add version and mode fields to config files. Enable include_defaults for DLP and response scanning to merge user patterns with the 35 built-in patterns. Remove redundant --mode CLI flag from the Helm deployment template since mode is now in the config file. * Pipelock Helm hardening + docs for external assistant and pipelock Helm templates: - ServiceMonitor for Prometheus scraping on /metrics (proxy port) - Ingress template for MCP reverse proxy (external AI agent access) - PodDisruptionBudget with minAvailable/maxUnavailable mutual exclusion - topologySpreadConstraints on Deployment - Structured logging config (format, output, include_allowed/blocked) - extraConfig escape hatch for additional pipelock.yaml sections - requireForExternalAssistant guard (fails when assistant enabled without pipelock) - Component label on Service metadata for ServiceMonitor targeting - NOTES.txt pipelock section with health, access, security, metrics info - Bump pipelock image tag 0.3.1 -> 0.3.2 - Fix: rename _asserts.tpl -> asserts.tpl (Helm skipped _ prefixed file) Documentation: - Helm chart README: full Pipelock section - docs/hosting/pipelock.md: dedicated hosting guide (Docker + Kubernetes) - docs/hosting/docker.md: AI features section (external assistant, pipelock) - .env.example: external assistant and MCP env vars Infra: - Chart.lock pinning dependency versions - .gitignore for vendored subchart tarballs * Fix bot comments: quote ingress host, fix sidecar wording, add code block lang * Fail fast when pipelock ingress enabled with empty hosts * Fail fast when pipelock ingress host has empty paths * Messed up the conflict merge --------- Signed-off-by: Juan José Mata <juanjo.mata@gmail.com> Co-authored-by: Juan José Mata <juanjo.mata@gmail.com> Co-authored-by: Juan José Mata <jjmata@jjmata.com>
This commit is contained in:
@@ -152,6 +152,62 @@ Your app is now set up. You can visit it at `http://localhost:3000` in your brow
|
||||
|
||||
If you find bugs or have a feature request, be sure to read through our [contributing guide here](https://github.com/we-promise/sure/wiki/How-to-Contribute-Effectively-to-Sure).
|
||||
|
||||
## AI features, external assistant, and Pipelock
|
||||
|
||||
Sure ships with a separate compose file for AI-related features: `compose.example.ai.yml`. It adds:
|
||||
|
||||
- **Pipelock** (always on): AI agent security proxy that scans outbound LLM calls and inbound MCP traffic
|
||||
- **Ollama + Open WebUI** (optional `--profile ai`): local LLM inference
|
||||
|
||||
### Using the AI compose file
|
||||
|
||||
```bash
|
||||
# Download both compose files
|
||||
curl -o compose.yml https://raw.githubusercontent.com/we-promise/sure/main/compose.example.yml
|
||||
curl -o compose.ai.yml https://raw.githubusercontent.com/we-promise/sure/main/compose.example.ai.yml
|
||||
curl -o pipelock.example.yaml https://raw.githubusercontent.com/we-promise/sure/main/pipelock.example.yaml
|
||||
|
||||
# Run with Pipelock (no local LLM)
|
||||
docker compose -f compose.ai.yml up -d
|
||||
|
||||
# Run with Pipelock + Ollama
|
||||
docker compose -f compose.ai.yml --profile ai up -d
|
||||
```
|
||||
|
||||
### Setting up the external AI assistant
|
||||
|
||||
The external assistant delegates chat to a remote AI agent instead of calling LLMs directly. The agent calls back to Sure's `/mcp` endpoint for financial data (accounts, transactions, balance sheet).
|
||||
|
||||
1. Set the MCP endpoint credentials in your `.env`:
|
||||
```bash
|
||||
MCP_API_TOKEN=generate-a-random-token-here
|
||||
MCP_USER_EMAIL=your@email.com # must match an existing Sure user
|
||||
```
|
||||
|
||||
2. Set the external assistant connection:
|
||||
```bash
|
||||
EXTERNAL_ASSISTANT_URL=https://your-agent/v1/chat/completions
|
||||
EXTERNAL_ASSISTANT_TOKEN=your-agent-api-token
|
||||
```
|
||||
|
||||
3. Choose how to activate:
|
||||
- **Per-family (UI):** Go to Settings > Self-Hosting > AI Assistant, select "External"
|
||||
- **Global (env):** Set `ASSISTANT_TYPE=external` to force all families to use external
|
||||
|
||||
See [docs/hosting/ai.md](ai.md) for full configuration details including agent ID, session keys, and email allowlisting.
|
||||
|
||||
### Pipelock security proxy
|
||||
|
||||
Pipelock sits between Sure and external services, scanning AI traffic for:
|
||||
|
||||
- **Secret exfiltration** (DLP): catches API keys, tokens, or personal data leaking in prompts
|
||||
- **Prompt injection**: detects attempts to override system instructions
|
||||
- **Tool poisoning**: validates MCP tool calls against known-safe patterns
|
||||
|
||||
When using `compose.example.ai.yml`, Pipelock is always running. External AI agents should connect to port 8889 (MCP reverse proxy) instead of directly to Sure's `/mcp` on port 3000.
|
||||
|
||||
For full Pipelock configuration, see [docs/hosting/pipelock.md](pipelock.md).
|
||||
|
||||
## How to update your app
|
||||
|
||||
The mechanism that updates your self-hosted Sure app is the GHCR (Github Container Registry) Docker image that you see in the `compose.yml` file:
|
||||
|
||||
Reference in New Issue
Block a user