# Get Results Source: https://docs.rafter.so/api-reference/endpoint/static/get Retrieve scan results and check scan status ## GET /api/static/scan Check the status of a scan and retrieve results once completed. ### Request **Headers:** * `x-api-key` (required): Your Rafter API key **Query Parameters:** * `scan_id` (required): The scan request ID to check * `format` (optional): Output format - `json` (default) or `md` ### Example Requests **Check status (JSON format):** ```bash theme={null} curl -H "x-api-key: RFabc-your-api-key-here" \ "https://rafter.so/api/static/scan?scan_id=b1b2c3d4-e5f6-7890-abcd-ef1234567890" ``` **Get results in Markdown format (format=md):** ```bash theme={null} curl -H "x-api-key: RFabc-your-api-key-here" \ "https://rafter.so/api/static/scan?scan_id=b1b2c3d4-e5f6-7890-abcd-ef1234567890&format=md" ``` ### Response #### Scan Pending/Processing **Status: pending, queued, or processing** ```json theme={null} { "status": "pending" } ``` #### Scan Completed (JSON Format) **Status: completed** ```json theme={null} { "status": "completed", "repository_name": "myorg/myrepo", "branch_name": "prod", "scan_date": "2025-07-24T00:00:00.000+00:00", "scan_id": "abcdabcd-abcd-abcd-abcd-abcdabcd", "scan_mode": "fast", "vulnerabilities": [ { "rule_id": "SEC001", "level": "error", "file": "src/auth.js", "line": 42, "column": 15, "message": "Hardcoded API key detected", "description": "API keys should be stored in environment variables", "suggestion": "Move the API key to an environment variable" }, { "rule_id": "SEC002", "level": "warning", "file": "src/database.js", "line": 78, "column": 8, "message": "SQL injection vulnerability", "description": "User input is directly concatenated into SQL query", "suggestion": "Use parameterized queries or prepared statements" } ] } ``` #### Scan Completed (Markdown Format - format=md) **Status: completed with format=md** When `format=md` is specified, the response includes a `markdown` field containing a structured security report designed for LLM-assisted remediation. The report uses role-priming, step-by-step instructions, and per-issue detail to produce high-quality analysis. ```json theme={null} { "status": "completed", "repository_name": "myorg/myrepo", "branch_name": "prod", "scan_date": "2025-07-24T00:00:00.000+00:00", "scan_id": "abcdabcd-abcd-abcd-abcd-abcdabcd", "scan_mode": "fast", "markdown": "You are a senior application-security, web-application, and cloud-reliability engineer. Implement production-grade solutions that scale. Never mock data, suppress linter security rules, or shortcut the fix. Think step-by-step.\n\n# Security Issues and Vulnerabilities\n\n**Total Issues:** 2\n\nThis report contains 2 security issues found in the repository. Each issue requires attention and remediation. Proceed one-by-one, thinking step-by-step to understand and remediate each.\n\n## Issues Summary\n\n### Issue 1\n**Rule ID:** a1b2c3d4\n**File:** src/auth.js\n**Line:** 42\n**Description:** Hardcoded API key detected\n\n### Issue 2\n**Rule ID:** e5f6a7b8\n**File:** src/database.js\n**Line:** 78\n**Description:** User input is directly concatenated into SQL query\n\nPlease analyze these 2 security vulnerabilities and provide:\n1. A comprehensive analysis of the security risks\n2. Prioritized remediation steps\n3. Code examples for fixes\n4. Prevention strategies for future development" } ``` Rule IDs in the markdown report are hashed for consistency. The report format is optimized for feeding into LLMs—it includes a security-engineer role prompt, structured issue metadata, and a trailing analysis request. #### Scan Failed **Status: failed** ```json theme={null} { "status": "failed", "error": "Repository access denied or not found" } ``` #### No Vulnerabilities Found **Status: completed with no issues** ```json theme={null} { "status": "completed", "repository_name": "myorg/myrepo", "branch_name": "prod", "scan_date": "2025-07-24T00:00:00.000+00:00", "scan_id": "abcdabcd-abcd-abcd-abcd-abcdabcd", "scan_mode": "fast", "vulnerabilities": [] } ``` ### Error Responses **Error (400 Bad Request):** ```json theme={null} { "error": "Missing required parameter: scan_id" } ``` **Error (401 Unauthorized):** ```json theme={null} { "error": "Invalid or inactive API key." } ``` **Error (404 Not Found):** ```json theme={null} { "error": "Scan not found." } ``` **Error (500 Internal Server Error):** ```json theme={null} { "error": "An unexpected error occurred." } ``` ### Response Fields #### Common Fields | Field | Type | Description | | -------- | ------ | --------------------------------------------------------------------- | | `status` | string | Scan status: `pending`, `queued`, `processing`, `completed`, `failed` | #### Completed Scan Fields (JSON) | Field | Type | Description | | ----------------- | ------ | ---------------------------------------- | | `repository_name` | string | Repository name in format "org/repo" | | `branch_name` | string | Branch name that was scanned | | `scan_date` | string | ISO 8601 timestamp when scan was created | | `scan_mode` | string | Scan mode used: `"fast"` or `"plus"` | | `vulnerabilities` | array | Array of vulnerability objects | #### Vulnerability Object Fields | Field | Type | Description | | ------------- | ------- | ------------------------------------------ | | `rule_id` | string | Unique identifier for the security rule | | `level` | string | Severity level: `error`, `warning`, `note` | | `file` | string | File path where vulnerability was found | | `line` | integer | Line number in the file | | `column` | integer | Column number in the line | | `message` | string | Short description of the issue | | `description` | string | Detailed explanation of the vulnerability | | `suggestion` | string | Recommended fix or mitigation | ## Rate Limiting The API implements rate limiting to ensure fair usage: * **Rate Limit**: 100 requests per minute per IP address * **Quota**: Based on your subscription plan ### Examples #### JavaScript ```javascript theme={null} async function getScanResults(scanId, format = 'json') { const response = await fetch( `https://rafter.so/api/static/scan?scan_id=${scanId}&format=${format}`, { headers: { 'x-api-key': 'RFabc-your-api-key-here' } } ); const data = await response.json(); if (data.status === 'completed') { if (format === 'json') { console.log(`Found ${data.vulnerabilities.length} vulnerabilities`); } else { console.log('Markdown report generated'); } } else { console.log(`Scan status: ${data.status}`); } return data; } ``` #### Python ```python theme={null} import requests import time def wait_for_scan_completion(scan_id, api_key, max_wait=300): start_time = time.time() while time.time() - start_time < max_wait: response = requests.get( f'https://rafter.so/api/static/scan?scan_id={scan_id}', headers={'x-api-key': api_key} ) data = response.json() if data['status'] == 'completed': return data elif data['status'] == 'failed': raise Exception(f"Scan failed: {data.get('error', 'Unknown error')}") print(f"Scan status: {data['status']}") time.sleep(10) raise Exception("Scan timed out") # Enhanced polling strategy with failure handling in Bash #!/bin/bash SCAN_ID="b1b2c3d4-e5f6-7890-abcd-ef1234567890" API_KEY="RFabc-your-api-key-here" MAX_ATTEMPTS=15 for i in $(seq 1 $MAX_ATTEMPTS); do RESPONSE=$(curl -fsS -H "x-api-key: $API_KEY" \ "https://rafter.so/api/static/scan?scan_id=$SCAN_ID") STATUS=$(echo $RESPONSE | jq -r '.status') if [ "$STATUS" = "completed" ]; then echo "Scan completed!" echo $RESPONSE | jq '.vulnerabilities | length' | xargs echo "Found vulnerabilities:" break elif [ "$STATUS" = "failed" ]; then echo "Scan failed!" echo $RESPONSE | jq -r '.error' exit 1 else echo "Attempt $i/$MAX_ATTEMPTS: Status is $STATUS" sleep 10 fi done ``` # Trigger Scan Source: https://docs.rafter.so/api-reference/endpoint/static/scan Start a new security scan for your repository ## POST /api/static/scan Trigger a new security scan for a specific repository and branch. ### Request **Headers:** * `x-api-key` (required): Your Rafter security API key * `Content-Type: application/json` **Body:** ```json theme={null} { "repository_name": "myorg/myrepo", "branch_name": "main", "scan_mode": "fast", "github_token": "github_pat_..." } ``` The `github_token` field is optional. When omitted, the scan uses the OAuth credentials linked to your Rafter account. Use this field for scanning private repositories without OAuth — the token only needs `Contents:Read` permission. **Fields:** | Field | Type | Required | Description | | ----------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `repository_name` | string | Yes | Repository name in format `org/repo` | | `branch_name` | string | Yes | Branch name to scan | | `scan_mode` | string | No | Scan mode: `"fast"` (default) or `"plus"`. Fast uses industry-standard tooling and Rafter's proprietary analysis for SAST, secret detection, and dependency checks. Plus runs the full fast pipeline plus additional agent-driven analysis passes for deeper coverage. | | `github_token` | string | No | Fine-grained GitHub PAT for scanning private repositories. Only needs `Contents:Read` permission. Can also be set via `RAFTER_GITHUB_TOKEN` environment variable when using the CLI. | ### Example Request ```bash theme={null} curl -X POST \ -H "Content-Type: application/json" \ -H "x-api-key: RFabc-your-api-key-here" \ -d '{ "repository_name": "myorg/myrepo", "branch_name": "main", "scan_mode": "fast" }' \ https://rafter.so/api/static/scan ``` ### Response **Success (200 OK):** ```json theme={null} { "success": true, "scan_id": "b1b2c3d4-e5f6-7890-abcd-ef1234567890" } ``` **Error (400 Bad Request):** ```json theme={null} { "error": "Missing required field: repository_name" } ``` **Error (401 Unauthorized):** ```json theme={null} { "error": "Invalid or inactive API key." } ``` **Error (403 Forbidden — scan limit reached):** ```json theme={null} { "error": "You have reached your Plus scan limit for this billing period.", "scan_mode": "plus", "used": 1, "limit": 1 } ``` **Error (403 Forbidden — insufficient scope):** ```json theme={null} { "error": "API key does not have scan scope." } ``` **Error (429 Too Many Requests):** ```json theme={null} { "error": "Rate limit exceeded. Please try again later." } ``` The CLI maps this to exit code 3 (quota exhausted). **Error (404 Not Found):** ```json theme={null} { "error": "Repository not found or access denied." } ``` **Error (500 Internal Server Error):** ```json theme={null} { "error": "An unexpected error occurred." } ``` ### Response Fields | Field | Type | Description | | --------- | ------- | ------------------------------------------- | | `success` | boolean | Whether the scan was successfully triggered | | `scan_id` | string | Unique identifier for the scan request | ## Rate Limiting The API implements rate limiting to ensure fair usage: * **Rate Limit**: 100 requests per minute per IP address * **Quota**: Based on your subscription plan ### Examples #### JavaScript ```javascript theme={null} const response = await fetch('https://rafter.so/api/static/scan', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'RFabc-your-api-key-here' }, body: JSON.stringify({ repository_name: 'myorg/myrepo', branch_name: 'main', scan_mode: 'fast' }) }); const data = await response.json(); console.log(`Scan ID: ${data.scan_id}`); ``` #### Python ```python theme={null} import requests response = requests.post( 'https://rafter.so/api/static/scan', headers={ 'Content-Type': 'application/json', 'x-api-key': 'RFabc-your-api-key-here' }, json={ 'repository_name': 'myorg/myrepo', 'branch_name': 'main', 'scan_mode': 'fast' } ) data = response.json() print(f"Scan ID: {data['scan_id']}") ``` ### Next Steps After triggering a scan, you can: 1. **Check scan status** using the `scan_id` with the [Get Results endpoint](/api-reference/endpoint/static/get) 2. **Wait for completion** by polling the status endpoint 3. **Retrieve results** once the scan is complete ### Workflow Example ```bash theme={null} # 1. Trigger scan SCAN_ID=$(curl -X POST \ -H "Content-Type: application/json" \ -H "x-api-key: RFabc-your-api-key-here" \ -d '{"repository_name": "myorg/myrepo", "branch_name": "main", "scan_mode": "fast"}' \ https://rafter.so/api/static/scan | jq -r '.scan_id') # 2. Wait for completion (polling) MAX_ATTEMPTS=15 for i in $(seq 1 $MAX_ATTEMPTS); do RESPONSE=$(curl -fsS -H "x-api-key: $API_KEY" \ "https://rafter.so/api/static/scan?scan_id=$SCAN_ID") STATUS=$(echo $RESPONSE | jq -r '.status') if [ "$STATUS" = "completed" ]; then echo "Scan completed!" echo $RESPONSE | jq '.vulnerabilities | length' | xargs echo "Found vulnerabilities:" break elif [ "$STATUS" = "failed" ]; then echo "Scan failed!" echo $RESPONSE | jq -r '.error' exit 1 else echo "Attempt $i/$MAX_ATTEMPTS: Status is $STATUS" sleep 10 fi done # 3. Get results curl -H "x-api-key: RFabc-your-api-key-here" \ "https://rafter.so/api/static/scan?scan_id=$SCAN_ID" ``` # Create Site Source: https://docs.rafter.so/api-reference/endpoint/static/sites/create Register a site for live-application security monitoring and kick off its first scan ## POST /api/static/sites Register a new [Site](/guides/sites) for live-application monitoring and trigger its first scan. Sites are distinct from repository scans (`/api/static/scan`) — instead of scanning source code, Sites continuously monitor a live domain for exposed backends, DNS misconfiguration, SEO issues, and accessibility problems. Requires an API key with the `read-and-scan` scope. ### Request **Headers:** * `x-api-key` (required): Your Rafter security API key, scope `read-and-scan` * `Content-Type: application/json` **Body:** ```json theme={null} { "url": "https://example.com" } ``` **Fields:** | Field | Type | Required | Description | | ----- | ------ | -------- | ------------------------------ | | `url` | string | Yes | The URL of the site to monitor | ### Example Request ```bash theme={null} curl -X POST \ -H "Content-Type: application/json" \ -H "x-api-key: RFabc-your-api-key-here" \ -d '{"url": "https://example.com"}' \ https://rafter.so/api/static/sites ``` ### Response **Success (200 OK — new site):** ```json theme={null} { "site": { "id": "b1b2c3d4-e5f6-7890-abcd-ef1234567890", "user_id": "u_abc123", "registrable_domain": "example.com", "preferred_base_url": "https://example.com", "scope_type": "domain", "scope_value": "example.com", "is_archived": false, "github_repos": [], "created_at": "2026-07-24T00:00:00.000+00:00", "updated_at": "2026-07-24T00:00:00.000+00:00" }, "run": { "id": "r_1a2b3c4d", "project_id": "b1b2c3d4-e5f6-7890-abcd-ef1234567890", "user_id": "u_abc123", "status": "running", "started_at": "2026-07-24T00:00:00.000+00:00", "finished_at": null, "progress_total": 0, "progress_done": 0, "created_at": "2026-07-24T00:00:00.000+00:00", "updated_at": "2026-07-24T00:00:00.000+00:00" }, "created": true } ``` If the site was created but its initial scan failed to start, the response includes a `scan_error` string alongside `"created": true` and `"run": null`. **Success (200 OK — site already existed):** ```json theme={null} { "site": { "id": "b1b2c3d4-e5f6-7890-abcd-ef1234567890", "is_archived": false }, "run": null, "created": false } ``` **Error (400 Bad Request — missing, invalid, or blocked URL):** ```json theme={null} { "error": "Invalid or blocked URL." } ``` **Error (401 Unauthorized):** ```json theme={null} { "error": "Invalid or inactive API key." } ``` **Error (403 Forbidden — wrong scope):** ```json theme={null} { "error": "API key does not have read-and-scan scope." } ``` **Error (403 Forbidden — plan or site limit reached):** ```json theme={null} { "error": "You have reached your site limit for this billing period." } ``` **Error (429 Too Many Requests):** ```json theme={null} { "error": "Rate limit exceeded", "message": "Too many requests. Please try again later.", "retryAfter": 30 } ``` **Error (500 Internal Server Error):** ```json theme={null} { "error": "An unexpected error occurred." } ``` ### Response Fields | Field | Type | Description | | ------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `site.id` | string | Unique identifier for the site (project id) | | `site.user_id` | string | Owning user's id (omitted when `created` is `false`) | | `site.registrable_domain` | string | The site's registrable domain | | `site.preferred_base_url` | string | The canonical base URL used for scanning | | `site.scope_type` | string | How the site's scan scope is defined | | `site.scope_value` | string | The value for `scope_type` | | `site.is_archived` | boolean | Whether the site has been archived | | `site.github_repos` | array | Linked GitHub repos for this site (empty until configured) | | `site.created_at` | string | ISO 8601 timestamp when the site was created | | `site.updated_at` | string | ISO 8601 timestamp when the site was last updated | | `run` | object \| null | The first scan run that was kicked off, or `null` if the site already existed or the scan failed to start | | `run.status` | string | The run's status. The initial run created here starts as `running` (its steps are enqueued synchronously); it can also be `queued`, `succeeded`, or `failed` at other points in its lifecycle | | `run.updated_at` | string | ISO 8601 timestamp when the run was last updated | | `created` | boolean | `true` if this call created a new site, `false` if the site already existed | | `scan_error` | string | Present only when `created` is `true` but the initial scan failed to start | ## Rate Limiting The API implements rate limiting to ensure fair usage: * **Rate Limit**: 100 requests per minute per IP address * **Quota**: Based on your subscription plan ### Examples #### JavaScript ```javascript theme={null} const response = await fetch('https://rafter.so/api/static/sites', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'RFabc-your-api-key-here' }, body: JSON.stringify({ url: 'https://example.com' }) }); const data = await response.json(); console.log(`Site ID: ${data.site.id}`); ``` #### Python ```python theme={null} import requests response = requests.post( 'https://rafter.so/api/static/sites', headers={ 'Content-Type': 'application/json', 'x-api-key': 'RFabc-your-api-key-here' }, json={'url': 'https://example.com'} ) data = response.json() print(f"Site ID: {data['site']['id']}") ``` ### Next Steps After creating a site, you can: 1. **Check status and findings** using the site id with the [Get Site endpoint](/api-reference/endpoint/static/sites/get) 2. **Trigger a re-scan** later with the [Scan Site endpoint](/api-reference/endpoint/static/sites/scan) 3. **List all your sites** with the [List Sites endpoint](/api-reference/endpoint/static/sites/list) # Get Site Source: https://docs.rafter.so/api-reference/endpoint/static/sites/get Check a site's status, latest run, and findings summary ## GET /api/static/sites/:id Retrieve a single [Site's](/guides/sites) status, its latest scan run, and a summary of current security findings. Requires an API key with the `read` scope (a `read-and-scan` key also works, since `read-and-scan` implies `read`). ### Request **Headers:** * `x-api-key` (required): Your Rafter security API key, scope `read` or `read-and-scan` **Path Parameters:** | Parameter | Type | Required | Description | | --------- | ------ | -------- | -------------------------- | | `id` | string | Yes | The site's id (project id) | ### Example Request ```bash theme={null} curl -H "x-api-key: RFabc-your-api-key-here" \ https://rafter.so/api/static/sites/b1b2c3d4-e5f6-7890-abcd-ef1234567890 ``` ### Response **Success (200 OK):** ```json theme={null} { "site": { "id": "b1b2c3d4-e5f6-7890-abcd-ef1234567890", "registrable_domain": "example.com", "preferred_base_url": "https://example.com", "scope_type": "domain", "scope_value": "example.com", "is_archived": false, "created_at": "2026-07-24T00:00:00.000+00:00" }, "latest_run": { "id": "r_1a2b3c4d", "status": "failed", "progress_total": 12, "progress_done": 12, "started_at": "2026-07-24T00:01:00.000+00:00", "finished_at": "2026-07-24T00:04:30.000+00:00", "created_at": "2026-07-24T00:00:00.000+00:00", "step_counts": { "queued": 0, "running": 0, "succeeded": 11, "failed": 1 }, "progress_percent": 100 }, "security": { "critical": 1, "warn": 3, "info": 5, "total": 9 } } ``` **No runs yet (`latest_run` is `null`):** ```json theme={null} { "site": { "id": "b1b2c3d4-e5f6-7890-abcd-ef1234567890", "registrable_domain": "example.com", "preferred_base_url": "https://example.com", "scope_type": "domain", "scope_value": "example.com", "is_archived": false, "created_at": "2026-07-24T00:00:00.000+00:00" }, "latest_run": null, "security": { "critical": 0, "warn": 0, "info": 0, "total": 0 } } ``` **Error (401 Unauthorized):** ```json theme={null} { "error": "Invalid or inactive API key." } ``` **Error (404 Not Found — not owned or doesn't exist):** ```json theme={null} { "error": "Site not found." } ``` **Error (429 Too Many Requests):** ```json theme={null} { "error": "Rate limit exceeded", "message": "Too many requests. Please try again later.", "retryAfter": 30 } ``` **Error (500 Internal Server Error):** ```json theme={null} { "error": "An unexpected error occurred." } ``` ### Response Fields | Field | Type | Description | | ----------------------------- | -------------- | ------------------------------------------------------------------------ | | `site.id` | string | Unique identifier for the site | | `site.registrable_domain` | string | The site's registrable domain | | `site.preferred_base_url` | string | The canonical base URL used for scanning | | `site.scope_type` | string | How the site's scan scope is defined | | `site.scope_value` | string | The value for `scope_type` | | `site.is_archived` | boolean | Whether the site has been archived | | `site.created_at` | string | ISO 8601 timestamp when the site was created | | `latest_run` | object \| null | The most recent scan run, or `null` if the site has never been scanned | | `latest_run.id` | string | Unique identifier for the run | | `latest_run.status` | string | Run status | | `latest_run.progress_total` | integer | Total number of steps in the run | | `latest_run.progress_done` | integer | Number of steps completed so far | | `latest_run.started_at` | string \| null | ISO 8601 timestamp when the run started | | `latest_run.finished_at` | string \| null | ISO 8601 timestamp when the run finished | | `latest_run.created_at` | string | ISO 8601 timestamp when the run was created | | `latest_run.step_counts` | object | Count of steps in each state: `queued`, `running`, `succeeded`, `failed` | | `latest_run.progress_percent` | integer | Overall run progress, `0`–`100` | | `security.critical` | integer | Number of critical findings | | `security.warn` | integer | Number of warning-level findings | | `security.info` | integer | Number of informational findings | | `security.total` | integer | Total findings across all severities | ## Rate Limiting The API implements rate limiting to ensure fair usage: * **Rate Limit**: 100 requests per minute per IP address * **Quota**: Based on your subscription plan ### Examples #### JavaScript ```javascript theme={null} const response = await fetch( 'https://rafter.so/api/static/sites/b1b2c3d4-e5f6-7890-abcd-ef1234567890', { headers: { 'x-api-key': 'RFabc-your-api-key-here' } } ); const data = await response.json(); console.log(`Status: ${data.latest_run?.status ?? 'no runs yet'}`); console.log(`Critical findings: ${data.security.critical}`); ``` #### Python ```python theme={null} import requests response = requests.get( 'https://rafter.so/api/static/sites/b1b2c3d4-e5f6-7890-abcd-ef1234567890', headers={'x-api-key': 'RFabc-your-api-key-here'} ) data = response.json() status = data['latest_run']['status'] if data['latest_run'] else 'no runs yet' print(f"Status: {status}") print(f"Critical findings: {data['security']['critical']}") ``` # List Sites Source: https://docs.rafter.so/api-reference/endpoint/static/sites/list List your sites, paginated ## GET /api/static/sites List the [Sites](/guides/sites) you own, paginated. Requires an API key with the `read` scope (a `read-and-scan` key also works, since `read-and-scan` implies `read`). ### Request **Headers:** * `x-api-key` (required): Your Rafter security API key, scope `read` or `read-and-scan` **Query Parameters:** | Parameter | Type | Required | Description | | ------------------ | ------- | -------- | ----------------------------------------------------------------- | | `limit` | integer | No | Number of sites to return. Range `1`–`100`, default `25`. | | `offset` | integer | No | Number of sites to skip. Default `0`. | | `include_archived` | string | No | Set to `"true"` to include archived sites. Default excludes them. | ### Example Requests ```bash theme={null} curl -H "x-api-key: RFabc-your-api-key-here" \ "https://rafter.so/api/static/sites?limit=25&offset=0" ``` ```bash theme={null} # Include archived sites curl -H "x-api-key: RFabc-your-api-key-here" \ "https://rafter.so/api/static/sites?include_archived=true" ``` ### Response **Success (200 OK):** ```json theme={null} { "sites": [ { "id": "b1b2c3d4-e5f6-7890-abcd-ef1234567890", "registrable_domain": "example.com", "preferred_base_url": "https://example.com", "scope_type": "domain", "scope_value": "example.com", "is_archived": false, "created_at": "2026-07-24T00:00:00.000+00:00" } ], "limit": 25, "offset": 0, "has_more": false } ``` **Error (401 Unauthorized):** ```json theme={null} { "error": "Invalid or inactive API key." } ``` **Error (429 Too Many Requests):** ```json theme={null} { "error": "Rate limit exceeded", "message": "Too many requests. Please try again later.", "retryAfter": 30 } ``` **Error (500 Internal Server Error):** ```json theme={null} { "error": "An unexpected error occurred." } ``` ### Response Fields | Field | Type | Description | | ---------------------------- | ------- | -------------------------------------------- | | `sites` | array | Array of site objects (no `user_id`) | | `sites[].id` | string | Unique identifier for the site | | `sites[].registrable_domain` | string | The site's registrable domain | | `sites[].preferred_base_url` | string | The canonical base URL used for scanning | | `sites[].scope_type` | string | How the site's scan scope is defined | | `sites[].scope_value` | string | The value for `scope_type` | | `sites[].is_archived` | boolean | Whether the site has been archived | | `sites[].created_at` | string | ISO 8601 timestamp when the site was created | | `limit` | integer | The `limit` used for this page | | `offset` | integer | The `offset` used for this page | | `has_more` | boolean | Whether more sites exist beyond this page | ## Rate Limiting The API implements rate limiting to ensure fair usage: * **Rate Limit**: 100 requests per minute per IP address * **Quota**: Based on your subscription plan ### Examples #### JavaScript ```javascript theme={null} const response = await fetch('https://rafter.so/api/static/sites?limit=25&offset=0', { headers: { 'x-api-key': 'RFabc-your-api-key-here' } }); const data = await response.json(); console.log(`Found ${data.sites.length} sites, more: ${data.has_more}`); ``` #### Python ```python theme={null} import requests response = requests.get( 'https://rafter.so/api/static/sites', headers={'x-api-key': 'RFabc-your-api-key-here'}, params={'limit': 25, 'offset': 0} ) data = response.json() print(f"Found {len(data['sites'])} sites, more: {data['has_more']}") ``` ### Next Steps Use each site's `id` with the [Get Site endpoint](/api-reference/endpoint/static/sites/get) to check status and findings, or with [Scan Site](/api-reference/endpoint/static/sites/scan) to trigger a re-scan. # Scan Site Source: https://docs.rafter.so/api-reference/endpoint/static/sites/scan Trigger a re-scan of a site you already own ## POST /api/static/sites/scan Trigger a new scan run for a [Site](/guides/sites) you already own. Use this to re-check a site after remediation or on a schedule. Requires an API key with the `read-and-scan` scope. ### Request **Headers:** * `x-api-key` (required): Your Rafter security API key, scope `read-and-scan` * `Content-Type: application/json` **Body:** Provide exactly one of `projectId` or `url` to identify the site. Optionally restrict the scan to specific sections. ```json theme={null} { "projectId": "b1b2c3d4-e5f6-7890-abcd-ef1234567890" } ``` ```json theme={null} { "url": "https://example.com" } ``` **Fields:** | Field | Type | Required | Description | | ----------- | ---------------- | ------------------------ | -------------------------------------------------------------------------------------------------------- | | `projectId` | string | One of `projectId`/`url` | The site's id | | `url` | string | One of `projectId`/`url` | The site's URL (used to look up the site) | | `sections` | array of strings | No | Restrict the scan to a subset of sections: `"flight"`, `"security"`, `"dns"`. Omit to scan all sections. | ### Example Request ```bash theme={null} curl -X POST \ -H "Content-Type: application/json" \ -H "x-api-key: RFabc-your-api-key-here" \ -d '{ "projectId": "b1b2c3d4-e5f6-7890-abcd-ef1234567890", "sections": ["security", "dns"] }' \ https://rafter.so/api/static/sites/scan ``` ### Response **Success (200 OK):** ```json theme={null} { "run": { "id": "r_1a2b3c4d", "project_id": "b1b2c3d4-e5f6-7890-abcd-ef1234567890", "user_id": "u_abc123", "status": "running", "started_at": "2026-07-24T00:00:00.000+00:00", "finished_at": null, "progress_total": 0, "progress_done": 0, "created_at": "2026-07-24T00:00:00.000+00:00", "updated_at": "2026-07-24T00:00:00.000+00:00" } } ``` **Error (400 Bad Request — missing or ambiguous identifier):** ```json theme={null} { "error": "Provide exactly one of projectId or url." } ``` **Error (401 Unauthorized):** ```json theme={null} { "error": "Invalid or inactive API key." } ``` **Error (403 Forbidden — wrong scope):** ```json theme={null} { "error": "API key does not have read-and-scan scope." } ``` **Error (403 Forbidden — run limit reached):** ```json theme={null} { "error": "You have reached your scan run limit for this billing period." } ``` **Error (404 Not Found — not owned or doesn't exist):** ```json theme={null} { "error": "Site not found." } ``` The 404 response is deliberately identical whether the site doesn't exist or simply isn't owned by your account — this avoids leaking which domains other accounts monitor. **Error (429 Too Many Requests):** ```json theme={null} { "error": "Rate limit exceeded", "message": "Too many requests. Please try again later.", "retryAfter": 30 } ``` **Error (500 Internal Server Error):** ```json theme={null} { "error": "An unexpected error occurred." } ``` ### Response Fields | Field | Type | Description | | -------------------- | -------------- | ------------------------------------------------ | | `run.id` | string | Unique identifier for the scan run | | `run.project_id` | string | The site's id | | `run.user_id` | string | Owning user's id | | `run.status` | string | Run status | | `run.started_at` | string \| null | ISO 8601 timestamp when the run started | | `run.finished_at` | string \| null | ISO 8601 timestamp when the run finished | | `run.progress_total` | integer | Total number of steps in the run | | `run.progress_done` | integer | Number of steps completed so far | | `run.created_at` | string | ISO 8601 timestamp when the run was created | | `run.updated_at` | string | ISO 8601 timestamp when the run was last updated | ## Rate Limiting The API implements rate limiting to ensure fair usage: * **Rate Limit**: 100 requests per minute per IP address * **Quota**: Based on your subscription plan ### Examples #### JavaScript ```javascript theme={null} const response = await fetch('https://rafter.so/api/static/sites/scan', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': 'RFabc-your-api-key-here' }, body: JSON.stringify({ projectId: 'b1b2c3d4-e5f6-7890-abcd-ef1234567890' }) }); const data = await response.json(); console.log(`Run ID: ${data.run.id}`); ``` #### Python ```python theme={null} import requests response = requests.post( 'https://rafter.so/api/static/sites/scan', headers={ 'Content-Type': 'application/json', 'x-api-key': 'RFabc-your-api-key-here' }, json={'projectId': 'b1b2c3d4-e5f6-7890-abcd-ef1234567890'} ) data = response.json() print(f"Run ID: {data['run']['id']}") ``` ### Next Steps Poll the [Get Site endpoint](/api-reference/endpoint/static/sites/get) with the site's id to watch the run's status and see the resulting findings summary once it completes. # Check Usage Source: https://docs.rafter.so/api-reference/endpoint/usage Check your API quota and remaining scans ## GET /api/static/usage Check your current API quota and usage information, broken down by scan mode. ### Request **Headers:** * `x-api-key` (required): Your Rafter API key **Example:** ```bash theme={null} curl -H "x-api-key: RFabc-your-api-key-here" \ https://rafter.so/api/static/usage ``` ### Response **Success (200 OK):** ```json theme={null} { "quota": { "fast": { "used": 3, "limit": 15, "remaining": 12 }, "plus": { "used": 1, "limit": 1, "remaining": 0 }, "quota_reset_date": "2026-04-12T00:00:00Z" } } ``` **Error (401 Unauthorized):** ```json theme={null} { "error": "Invalid or inactive API key." } ``` **Error (400 Bad Request):** ```json theme={null} { "error": "Missing API key." } ``` ### Response Fields | Field | Type | Description | | ------------------------ | ------- | ---------------------------------- | | `quota.fast.used` | integer | Fast scans used in current period | | `quota.fast.limit` | integer | Fast scan limit for current period | | `quota.fast.remaining` | integer | Fast scans remaining | | `quota.plus.used` | integer | Plus scans used in current period | | `quota.plus.limit` | integer | Plus scan limit for current period | | `quota.plus.remaining` | integer | Plus scans remaining | | `quota.quota_reset_date` | string | ISO 8601 date when quota resets | ### Plan Limits Fast and Plus scans draw from separate quota pools — using one does not affect the other. See [rafter.so/pricing](https://rafter.so/pricing) for current plan limits. ### Common Scenarios #### Quota Available ```json theme={null} { "quota": { "fast": { "used": 3, "limit": 15, "remaining": 12 }, "plus": { "used": 0, "limit": 1, "remaining": 1 }, "quota_reset_date": "2026-04-12T00:00:00Z" } } ``` #### Fast Quota Exhausted (Plus Still Available) ```json theme={null} { "quota": { "fast": { "used": 15, "limit": 15, "remaining": 0 }, "plus": { "used": 0, "limit": 1, "remaining": 1 }, "quota_reset_date": "2026-04-12T00:00:00Z" } } ``` ## Rate Limiting The API implements rate limiting to ensure fair usage: * **Rate Limit**: 100 requests per minute per IP address * **Quota**: Based on your subscription plan ### Examples #### JavaScript ```javascript theme={null} const response = await fetch('https://rafter.so/api/static/usage', { headers: { 'x-api-key': 'RFabc-your-api-key-here' } }); const data = await response.json(); const { fast, plus } = data.quota; console.log(`Fast scans: ${fast.remaining}/${fast.limit} remaining`); console.log(`Plus scans: ${plus.remaining}/${plus.limit} remaining`); ``` #### Python ```python theme={null} import requests response = requests.get( 'https://rafter.so/api/static/usage', headers={'x-api-key': 'RFabc-your-api-key-here'} ) data = response.json() fast = data['quota']['fast'] plus = data['quota']['plus'] print(f"Fast scans: {fast['remaining']}/{fast['limit']} remaining") print(f"Plus scans: {plus['remaining']}/{plus['limit']} remaining") ``` #### Shell ```bash theme={null} #!/bin/bash API_KEY="RFabc-your-api-key-here" RESPONSE=$(curl -s -H "x-api-key: $API_KEY" \ https://rafter.so/api/static/usage) echo "Fast remaining: $(echo $RESPONSE | jq '.quota.fast.remaining')" echo "Plus remaining: $(echo $RESPONSE | jq '.quota.plus.remaining')" ``` # Reference Source: https://docs.rafter.so/api-reference/introduction Complete API reference for Rafter's public scanning API ## Welcome to the Rafter API The Rafter API provides programmatic access to our security scanning capabilities. Use this API to integrate security scanning into your applications, automation workflows, and CI/CD pipelines. ## Base URL ``` https://rafter.so ``` ## API Endpoints | Method | Endpoint | Description | | ------ | ------------------- | ------------------------------------------------------------------------------- | | GET | `/api/static/usage` | Check your API quota and remaining scans | | POST | `/api/static/scan` | Trigger a new security scan for a repository (supports `fast` and `plus` modes) | | GET | `/api/static/scan` | Check scan status and retrieve results | ## Authentication All API requests require authentication using an API key. Include your API key in the `x-api-key` header with every request. ```bash theme={null} curl -H "x-api-key: RFabc-your-api-key-here" \ https://rafter.so/api/static/usage ``` Your API key starts with `RF` and should be kept secure. Never commit it to version control. Use environment variables or secure secret management systems. ## Rate Limiting The API implements rate limiting to ensure fair usage: * **Rate Limit**: 100 requests per minute per IP address * **Quota**: Based on your subscription plan ## Response Formats The API supports multiple response formats: ### JSON (Default) All endpoints return JSON responses by default: ```json theme={null} { "status": "completed", "vulnerabilities": [ { "rule_id": "SEC001", "level": "error", "file": "src/auth.js", "line": 42, "message": "Hardcoded API key detected" } ] } ``` ### Markdown (format=md) Some endpoints support Markdown format for human-readable reports: ```bash theme={null} curl -H "x-api-key: RFabc-your-key" \ "https://rafter.so/api/static/scan?scan_id=123&format=md" ``` ## Error Handling The API uses standard HTTP status codes: | Status Code | Description | | ----------- | --------------------------------------- | | 200 | Success | | 400 | Bad Request - Missing required fields | | 401 | Unauthorized - Invalid API key | | 403 | Forbidden - Quota exceeded | | 404 | Not Found - Resource not found | | 429 | Too Many Requests - Rate limit exceeded | | 500 | Internal Server Error - Server error | Error responses include a descriptive message: ```json theme={null} { "error": "Invalid or inactive API key." } ``` ## Getting Started Check your API quota and remaining scans. Start a new security scan for your repository. Retrieve scan results and vulnerability reports. ## CLI While you can use the API directly with HTTP requests, we also provide powerful [CLI tools](/guides/basics). ## Support * **Documentation**: This API reference * **Support**: Visit our [support page](https://rafter.so/help) # Advanced Source: https://docs.rafter.so/guides/advanced Discover advanced CLI features, automation techniques, and integration patterns for Rafter security. ## Advanced CLI Usage Once you're comfortable with the basics, explore these advanced features to enhance your security scanning workflows. ## Advanced Command Options ### `rafter run` - Scanning Options ```bash theme={null} # Specify custom repository and branch rafter run --repo myorg/myrepo --branch feature/new-feature # Use custom API key (overrides environment variable) rafter run --api-key "RFabc-custom-key" # Output in specific format rafter run --format md # Choose scan mode (fast or plus) rafter run --mode plus --format md rafter run -m plus --format md # Non-interactive mode for automation, no status updates rafter run --quiet # Combine multiple options for versatile automation rafter run --repo myorg/myrepo --branch main --format md --mode plus --quiet -k "RFabc-custom-key" ``` ### `rafter get` - Retrieval Options ```bash theme={null} # Wait for scan completion with polling rafter get --interactive # Get results in specific format rafter get --format md # Suppress status messages rafter get --quiet # Use custom API key rafter get --api-key "RFabc-custom-key" ``` ## Common Use Cases ### Local Development ```bash theme={null} # Quick scan during development rafter run --format md # Save results to a file rafter run --format md > security-report-$(date +%Y-%m-%d-%H-%M-%S).md ``` ### Feature Branch Workflow ```bash theme={null} # Scan your feature branch rafter run --branch feature/new-feature # Get results in Markdown (with prompting for your favorite AI) rafter run --branch feature/new-feature --format md > rafter-report-$(date +%Y-%m-%d-%H-%M-%S).md ``` ### CI/CD Integration ```bash theme={null} # Check results in scripts if rafter run --quiet | jq -e '.vulnerabilities | length > 0'; then echo "Security issues found!" exit 1 fi ``` See more on our [CD/CI page](/guides/ci-cd). ## Automation Techniques ### Shell Scripting Create reusable scripts for common workflows: ```bash theme={null} #!/bin/bash # scan-and-report.sh # Run scan and capture results RESULTS=$(rafter run --quiet --format json) # Check for critical vulnerabilities (or any other severity) CRITICAL_COUNT=$(RESULTS | jq '.vulnerabilities | map(select(.level=="error")) | length') if [ $CRITICAL_COUNT -gt 0 ]; then echo "❌ Found $CRITICAL_COUNT critical vulnerabilities!" exit 1 else echo "✅ No critical vulnerabilities found" fi ``` ### Pipeline Integration Integrate with your existing development pipelines: ```bash theme={null} # Pre-commit hook example #!/bin/bash # .git/hooks/pre-commit # Only scan if we have API key if [ -z "$RAFTER_API_KEY" ]; then echo "Skipping security scan - no API key set" exit 0 fi # Run scan and capture results RESULTS=$(rafter run --quiet --format json) # Check for error-level issues HIGH_ISSUES=$(rafter get $SCAN_ID --format json | jq '.vulnerabilities | map(select(.level=="error")) | length') if [ $HIGH_ISSUES -gt 0 ]; then echo "❌ Security scan found $HIGH_ISSUES critical issues" echo "Run 'rafter get $SCAN_ID' for details" exit 1 fi echo "✅ Security scan passed" ``` ## Output Processing Rafter defaults to reporting results in JSON format following our [API Schema](/api-reference/endpoint/static/get#scan-completed-json-format), which makes it easy to process with `jq`. At the top level is various details about the scan, including a vulnerabilities object in [SARIF](https://sarifweb.azurewebsites.net/) format, an industry-standard format for security scanning results. ### Setup for JSON Processing First, set up your results object either from a scan run or by getting existing results. ```bash theme={null} # Option 1: Run a new scan and capture results RESULTS=$(rafter run --quiet) # Option 2: Get results from an existing scan RESULTS=$(rafter get ) ``` Next, we'll demonstrate many common use cases for processing the results object. ### Basic Analysis ```bash theme={null} # Extract all vulnerability levels echo "$RESULTS" | jq -r '.vulnerabilities[].level' | sort | uniq -c # Find files with most vulnerabilities echo "$RESULTS" | jq -r '.vulnerabilities[].file' | sort | uniq -c | sort -nr # Count total vulnerabilities echo "$RESULTS" | jq '.vulnerabilities | length' ``` ### Summary Reports ```bash theme={null} # Create comprehensive summary echo "$RESULTS" | jq '{ scan_id: .scan_id, total_vulnerabilities: (.vulnerabilities | length), error: (.vulnerabilities | map(select(.level=="error")) | length), warning: (.vulnerabilities | map(select(.level=="warning")) | length), note: (.vulnerabilities | map(select(.level=="note")) | length) }' # Filter by severity level echo "$RESULTS" | jq '.vulnerabilities[] | select(.level=="error" or .level=="warning")' ``` ### Data Extraction ```bash theme={null} # Extract specific fields to CSV format echo "$RESULTS" | jq -r '.vulnerabilities[] | [.level, .rule_id, .file, .line, .message] | @csv' # Get all file paths with vulnerabilities echo "$RESULTS" | jq -r '.vulnerabilities[].file' | sort | uniq # Extract rule IDs and their counts echo "$RESULTS" | jq -r '.vulnerabilities[].ruleId' | sort | uniq -c ``` ### Complete Analysis Processing Script Below is a complete script that runs a Rafter security scan and processes the JSON results. ```bash expandable theme={null} #!/bin/bash # Rafter Security Scan Analysis Script # Analyzes Rafter output for security vulnerabilities and provides actionable insights echo "Rafter Security Scan Analysis" echo "=============================" echo "" # Run Rafter scan and capture results echo "Running Rafter security scan..." RESULTS=$(rafter run --quiet --format json) if [ $? -ne 0 ]; then echo "Error running Rafter scan" exit 1 fi # Check if we got results if [ -z "$RESULTS" ]; then echo "No results returned from Rafter scan" exit 0 fi echo "Scan completed successfully" echo "" # Parse the custom Rafter JSON format and extract key metrics echo "Security Scan Summary" echo "--------------------" # Extract scan metadata REPO_NAME=$(echo "$RESULTS" | jq -r '.repository_name // "unknown"') BRANCH_NAME=$(echo "$RESULTS" | jq -r '.branch_name // "unknown"') SCAN_DATE=$(echo "$RESULTS" | jq -r '.scan_date // "unknown"') STATUS=$(echo "$RESULTS" | jq -r '.status // "unknown"') echo "Repository: $REPO_NAME" echo "Branch: $BRANCH_NAME" echo "Scan Date: $SCAN_DATE" echo "Status: $STATUS" echo "" # Count total vulnerabilities TOTAL_VULNS=$(echo "$RESULTS" | jq -r '.vulnerabilities | length // 0') echo "Total Vulnerabilities: $TOTAL_VULNS" if [ "$TOTAL_VULNS" -eq 0 ]; then echo "No security issues found! Your codebase appears secure." exit 0 fi # Count by severity level CRITICAL=$(echo "$RESULTS" | jq -r '.vulnerabilities[] | select(.level == "error") | .ruleId' | wc -l) HIGH=$(echo "$RESULTS" | jq -r '.vulnerabilities[] | select(.level == "warning") | .ruleId' | wc -l) MEDIUM=$(echo "$RESULTS" | jq -r '.vulnerabilities[] | select(.level == "note") | .ruleId' | wc -l) LOW=$(echo "$RESULTS" | jq -r '.vulnerabilities[] | select(.level == "none") | .ruleId' | wc -l) echo "Critical: $CRITICAL" echo "Warning: $HIGH" echo "Note: $MEDIUM" echo "Uncategorized: $LOW" echo "" # Show top rule violations echo "Top Security Rule Violations" echo "---------------------------" echo "$RESULTS" | jq -r '.vulnerabilities[] | .ruleId' | sort | uniq -c | sort -nr | head -10 | while read count rule; do echo "$count violations: $rule" done echo "" # Show critical and high severity findings echo "Critical & High Severity Findings" echo "--------------------------------" echo "$RESULTS" | jq -r '.vulnerabilities[] | select(.level == "error" or .level == "warning") | "\(.level | ascii_upcase): \(.ruleId) - \(.message)"' | head -20 if [ $((CRITICAL + HIGH)) -gt 20 ]; then echo "... and $((CRITICAL + HIGH - 20)) more critical/high findings" fi echo "" # Show specific vulnerability types with better categorization echo "Vulnerability Categories" echo "-----------------------" echo "$RESULTS" | jq -r '.vulnerabilities[] | .ruleId' | grep -E "(sql|injection|xss|csrf|auth|secret|key|weak|crypto|mocked|problematic)" | sort | uniq -c | sort -nr | head -10 | while read count vuln; do echo "$count: $vuln" done echo "" # Show code locations for critical issues echo "Critical Issue by File" echo "-----------------------" echo "$RESULTS" | jq -r '.vulnerabilities[] | select(.level == "error") | "\(.file)\nLine: \(.line)\nRule: \(.ruleId)\nMessage: \(.message)\n---"' | head -10 echo "" # Show high severity issues with locations echo "Warning by File" echo "-------------------" echo "$RESULTS" | jq -r '.vulnerabilities[] | select(.level == "warning") | "\(.file):\(.line) - \(.ruleId): \(.message)"' | head -10 echo "" # Show Note severity issues with locations echo "Note by File" echo "-------------------" echo "$RESULTS" | jq -r '.vulnerabilities[] | select(.level == "note") | "\(.file):\(.line) - \(.ruleId): \(.message)"' | head -10 echo "" echo "" echo "Analysis complete. Review findings and prioritize fixes based on severity." echo "" echo "Scan Summary: $TOTAL_VULNS total issues found in $REPO_NAME ($BRANCH_NAME)" ``` ### Markdown Processing Process Markdown output for documentation: ```bash theme={null} # Generate report for GitHub rafter get --format md > SECURITY_SCAN.md # Add to pull request echo "## Security Scan Results" >> PR_DESCRIPTION.md rafter get --format md >> PR_DESCRIPTION.md ``` ## Next Steps Learn the fundamentals of using the Rafter CLI. Master advanced CLI features and automation. Build custom integrations with the REST API. Set up automated scanning in your pipelines. # Audit Log Source: https://docs.rafter.so/guides/agent-security/audit-log Stable JSONL schema for the Rafter security audit log # Audit Log Rafter writes a security audit log to `~/.rafter/audit.jsonl` in [JSONL](https://jsonl.org/) format (newline-delimited JSON). Every security-relevant action — policy enforcement decisions, secret detections, overrides — is recorded as a single JSON object per line. Both the Node and Python CLIs write to the same file using the same schema. The Node CLI is the reference implementation; the Python CLI currently emits `command_intercepted` and `secret_detected` events only. ## File Location ``` ~/.rafter/audit.jsonl ``` The directory `~/.rafter/` is created automatically on first use. *** ## Schema Every audit log entry contains these fields: ### Base Fields | Field | Type | Required | Description | | ----------- | ------ | -------- | --------------------------------------------------------- | | `timestamp` | string | yes | ISO 8601 UTC timestamp (e.g., `2026-02-20T10:30:45.123Z`) | | `sessionId` | string | yes | Unique per CLI invocation. Format: `{epoch_ms}-{random}` | | `eventType` | string | yes | Event type identifier (see [Event Types](#event-types)) | | `agentType` | string | no | AI agent platform: `"openclaw"` or `"claude-code"` | ### `action` Object Present on most events. Contains context about what triggered the event. | Field | Type | Required | Description | | ----------- | ------ | -------- | ---------------------------------------------- | | `command` | string | no | Shell command string | | `tool` | string | no | Tool name (e.g., `Write`, `Bash`) | | `riskLevel` | string | no | `"low"`, `"medium"`, `"high"`, or `"critical"` | ### `securityCheck` Object Always present. Records the outcome of the security evaluation. | Field | Type | Required | Description | | --------- | ------- | -------- | ------------------------------------ | | `passed` | boolean | yes | Whether the security check passed | | `reason` | string | no | Human-readable explanation | | `details` | object | no | Structured metadata (event-specific) | ### `resolution` Object Always present. Records what action was taken. | Field | Type | Required | Description | | ---------------- | ------ | -------- | --------------------------------------------------------- | | `actionTaken` | string | yes | `"blocked"`, `"allowed"`, `"overridden"`, or `"redacted"` | | `overrideReason` | string | no | User-provided justification (only on `policy_override`) | *** ## Event Types ### `command_intercepted` Emitted when a shell command is evaluated against the security policy. | Field | Value | | ------------------------ | ------------------------------------------------------------ | | `action.command` | The shell command string | | `action.riskLevel` | Dynamically assessed: `low`, `medium`, `high`, or `critical` | | `securityCheck.passed` | `true` if allowed, `false` if blocked | | `securityCheck.reason` | Why the command was blocked/flagged | | `resolution.actionTaken` | `"allowed"`, `"blocked"`, or `"overridden"` | **Example:** ```json theme={null} { "timestamp": "2026-02-20T10:30:45.123Z", "sessionId": "1740047445123-k8f2m", "eventType": "command_intercepted", "agentType": "claude-code", "action": { "command": "git push --force", "riskLevel": "high" }, "securityCheck": { "passed": false, "reason": "High-risk command requires approval" }, "resolution": { "actionTaken": "blocked" } } ``` ### `secret_detected` Emitted when a secret is found in files, staged content, or tool output. | Field | Value | | ------------------------ | ---------------------------------------- | | `action.riskLevel` | Always `"critical"` | | `securityCheck.passed` | Always `false` | | `securityCheck.reason` | `"{secret_type} detected in {location}"` | | `resolution.actionTaken` | `"blocked"` or `"allowed"` | The audit log **never contains the raw secret value**—only the type (e.g., "AWS Access Key") and location (e.g., "staged files", "config.js"). **Example:** ```json theme={null} { "timestamp": "2026-02-20T10:25:12.456Z", "sessionId": "1740047445123-k8f2m", "eventType": "secret_detected", "agentType": "openclaw", "action": { "riskLevel": "critical" }, "securityCheck": { "passed": false, "reason": "AWS Access Key detected in config.js" }, "resolution": { "actionTaken": "blocked" } } ``` ### `content_sanitized` Emitted when sensitive patterns are redacted from output. | Field | Value | | ------------------------ | ------------------------------------------------ | | `securityCheck.passed` | Always `false` | | `securityCheck.reason` | `"{n} sensitive patterns detected"` | | `securityCheck.details` | `{ "contentType": "...", "patternsMatched": n }` | | `resolution.actionTaken` | Always `"redacted"` | **Example:** ```json theme={null} { "timestamp": "2026-02-20T11:00:00.000Z", "sessionId": "1740047445123-k8f2m", "eventType": "content_sanitized", "securityCheck": { "passed": false, "reason": "3 sensitive patterns detected", "details": { "contentType": "shell_output", "patternsMatched": 3 } }, "resolution": { "actionTaken": "redacted" } } ``` ### `policy_override` Emitted when a user explicitly overrides a security policy (e.g., `--force` flag). | Field | Value | | --------------------------- | -------------------------------------- | | `action.command` | The overridden command (optional) | | `action.riskLevel` | Always `"high"` | | `securityCheck.passed` | Always `false` | | `securityCheck.reason` | `"Security policy overridden by user"` | | `resolution.actionTaken` | Always `"overridden"` | | `resolution.overrideReason` | User-provided reason string | ### `scan_executed` Reserved for future use. Will be emitted when file scans are performed. ### `config_changed` Reserved for future use. Will be emitted when security configuration is modified. *** ## Redaction Behavior The audit log is designed to be safe to retain and share: * **Secret values are never logged.** `secret_detected` events record the secret type and file location, not the secret itself. * **Content is not stored.** `content_sanitized` events record pattern counts and content types, not the raw content. * **Commands are logged verbatim.** `command_intercepted` (policy enforcement) events include the full command string. If commands contain sensitive arguments, they appear in the log. *** ## Size and Rotation * **No automatic rotation.** The log file grows unbounded until cleanup runs. * **Time-based retention:** Entries older than `retentionDays` are purged when `cleanup()` is called. * **No automatic scheduling.** Cleanup must be triggered manually or via the API. * **Default retention:** 30 days. *** ## Configuration Configure audit logging in `~/.rafter/config.json` under `agent.audit`, or in `.rafter.yml` under `audit`: | Key | Type | Default | Description | | --------------- | ------- | -------- | ------------------------------------------------------ | | `logAllActions` | boolean | `true` | Master switch. If `false`, no events are written. | | `retentionDays` | number | `30` | Days to retain entries before cleanup purges them. | | `logLevel` | string | `"info"` | Stored in config but not currently used for filtering. | **Config file example:** ```json theme={null} { "agent": { "audit": { "logAllActions": true, "retentionDays": 90, "logLevel": "info" } } } ``` **Policy file example (`.rafter.yml`):** ```yaml theme={null} audit: retention_days: 90 log_level: info ``` *** ## Webhook Notifications When configured, the audit logger sends a POST request to a webhook URL for events at or above a minimum risk level. Works with Slack incoming webhooks, Discord webhooks, and generic HTTP endpoints. ### Configuration | Key | Type | Default | Description | | ---------------------------------- | ------ | -------- | --------------------------------------------------------------------- | | `agent.notifications.webhook` | string | — | Webhook URL to POST notifications to | | `agent.notifications.minRiskLevel` | string | `"high"` | Minimum risk level to trigger notification (`"high"` or `"critical"`) | ### Webhook Payload ```json theme={null} { "event": "command_intercepted", "risk": "high", "command": "git push --force", "timestamp": "2026-02-21T10:30:45.123Z", "agent": "claude-code", "text": "[rafter] high-risk event: command_intercepted — git push --force", "content": "[rafter] high-risk event: command_intercepted — git push --force" } ``` The `text` field provides Slack compatibility. The `content` field provides Discord compatibility. Both contain a human-readable summary. Webhook delivery is fire-and-forget with a 5-second timeout. Failures are silently ignored to avoid disrupting audit logging. ### Setup ```bash theme={null} # Configure webhook URL rafter agent config set agent.notifications.webhook https://hooks.slack.com/services/T.../B.../xxx # Only notify on critical events rafter agent config set agent.notifications.minRiskLevel critical # Disable notifications rafter agent config set agent.notifications.webhook "" ``` *** ## Querying the Audit Log Use `rafter agent audit` to view and filter entries: ```bash theme={null} # Show last 10 entries (default) rafter agent audit # Show last 50 entries rafter agent audit --last 50 # Filter by event type rafter agent audit --event secret_detected # Filter by agent rafter agent audit --agent claude-code # Entries since a specific date rafter agent audit --since 2026-02-01 # Combine filters rafter agent audit --event command_intercepted --agent openclaw --last 100 ``` Or query the JSONL file directly with standard tools: ```bash theme={null} # Count blocked commands grep '"actionTaken":"blocked"' ~/.rafter/audit.jsonl | wc -l # Find all secret detections with jq jq 'select(.eventType == "secret_detected")' ~/.rafter/audit.jsonl # Events from the last 24 hours jq --arg cutoff "$(date -u -v-1d +%Y-%m-%dT%H:%M:%S)" \ 'select(.timestamp > $cutoff)' ~/.rafter/audit.jsonl ``` *** ## MCP Access The `read_audit_log` MCP tool exposes audit log entries to MCP clients: ```json theme={null} { "tool": "read_audit_log", "arguments": { "event_type": "secret_detected", "limit": 20 } } ``` See [MCP Integration](/guides/agent-security/mcp-integration) for setup. # Claude Code Integration Source: https://docs.rafter.so/guides/agent-security/claude-code-integration Set up Rafter security for Claude Code # Claude Code Integration Rafter provides two skills for [Claude Code](https://claude.ai/code) that separate remote code analysis from local security operations. ## Why Two Skills? **Auto-invocable** - Claude can proactively suggest scans * API-based SAST/SCA scanning * Read-only operations * Safe for Claude to auto-invoke * `rafter run` / `rafter scan` / `rafter get` / `rafter usage` **User-only** - Requires explicit invocation * Local secret scanning * Policy enforcement * Extension auditing * Side effects require permission This architecture separates read-only remote analysis from local security operations that have side effects. ## Setup ### 1. Install Rafter CLI Install globally: ```bash npm theme={null} npm install -g @rafter-security/cli ``` ```bash pnpm theme={null} pnpm add -g @rafter-security/cli ``` ### 2. Initialize Local Security Run initialization with Claude Code integration: ```bash theme={null} rafter agent init --with-claude-code ``` Or install all detected integrations at once: ```bash theme={null} rafter agent init --all ``` If Claude Code is detected (checks for `~/.claude/` directory), Rafter will: * Install Remote Code Analysis skill to `~/.claude/skills/rafter/SKILL.md` * Install Local Security skill to `~/.claude/skills/rafter-agent-security/SKILL.md` * Install a first-class **`rafter` sub-agent** to `~/.claude/agents/rafter.md` (v0.7.9+, rf-q7j) — the calling agent can invoke it as `Agent(subagent_type="rafter")`. Sub-agents appear in the main agent's tool list (skills only surface in the activation prompt), making delegation the natural motion for "is this safe / secure / production worthy?" questions. Hard-restricted to `Bash`, `Read`, `Grep`. * Enable agent integration in config Use `rafter agent init --with-claude-code --dry-run` (v0.8.0+) to see every file path that would be created or modified before running the install for real. ### 3. Restart Claude Code Restart your Claude Code session to load the skills: ```bash theme={null} # Kill existing session pkill -f claude # Start new session claude ``` ## Remote Code Analysis: Automated Scanning The remote analysis skill allows Claude to proactively suggest security scans. ### Commands Trigger a comprehensive security scan on your repository **Auto-detects:** Current repo and branch from git **Example:** ```bash theme={null} rafter run rafter scan --repo myorg/myrepo --branch feature-branch ``` `rafter scan` is an alias for `rafter run`. Retrieve results from a completed or in-progress scan **Example:** ```bash theme={null} rafter get scan_abc123xyz ``` View your API quota and usage statistics **Example:** ```bash theme={null} rafter usage ``` ### When Claude Uses It Claude will automatically invoke backend scanning when you: * Mention "security", "vulnerabilities", or "code analysis" * Start working on a new feature * Review a pull request * Update dependencies * Ask about security issues ### Example Interactions **You:** "I just updated all the npm packages" **Claude:** "Let me run a security scan to check for any new vulnerabilities in the updated dependencies." *\[Invokes: rafter run]* **Claude:** "Scan complete! Found 2 medium-severity issues in newly updated packages. Here's what needs attention..." **You:** "Can you review my changes before I create a PR?" **Claude:** "I'll run a security scan on your feature branch first." *\[Invokes: rafter run --branch feature-auth]* **Claude:** "Security scan passed with no issues. Your changes look good from a security perspective. Ready to create the PR?" **You:** "How many scans do I have left this month?" **Claude:** *\[Invokes: rafter usage]* **Claude:** "You've used 45 of 100 scans this month. 55 remaining. Your quota resets on March 1st." ## Local Security Skill The local security skill provides secret scanning, policy enforcement, and extension auditing. **You must explicitly invoke these commands.** ### Commands Scan files for secrets before commits **Example:** ``` /rafter-scan . /rafter-scan src/config.ts ``` **Detects:** AWS keys, GitHub tokens, Stripe keys, database credentials, private keys (21+ patterns) Execute commands with security validation **Example:** ``` /rafter-bash "git commit -m 'Add feature'" /rafter-bash "sudo systemctl restart nginx" ``` **Features:** * Blocks destructive commands (rm -rf /, fork bombs) * Requires approval for dangerous operations * Scans staged files before git commits * Logs all command attempts Comprehensive security audit of a Claude Code skill before installation **Example:** ``` /rafter-audit-skill ~/.claude/skills/untrusted-skill/SKILL.md ``` **Analyzes:** 12 security dimensions including network calls, command execution, file access, credential handling, input validation, and more View security event logs **Example:** ``` /rafter-audit /rafter-audit --last 20 ``` **Events:** Command attempts, secret detections, policy overrides, config changes ### Usage Examples **You:** `/rafter-scan .` **Output:** ``` 🔍 Scanning 47 files... ⚠️ Found 1 secret: File: src/config.ts:12 Type: AWS Access Key Value: AKIA...REDACTED...XYZ Severity: HIGH ❌ Secrets detected! Do not commit. ``` **You:** `/rafter-bash "git commit -m 'Add authentication'"` **Process:** 1. Rafter evaluates command risk level 2. Scans staged files for secrets (for git commands) 3. If clean: executes commit 4. If secrets found or command blocked: alerts user **Output:** ``` ✓ No secrets detected in staged files ✓ Command approved: git commit [main abc123d] Add authentication ``` **You:** `/rafter-audit-skill ~/.claude/skills/github-integration/SKILL.md` **Output:** ``` # Skill Audit Report **Skill**: github-integration **Risk Rating**: MEDIUM ## Findings ### Network Security: ⚠️ Warning - 3 external URLs found - https://api.github.com (HTTPS ✓) - http://internal-api.local (HTTP ⚠️) ### Command Execution: ✓ Pass - No dangerous commands detected ## Recommendation: ✓ YES (with modifications) Change http://internal-api.local to HTTPS before installing. ``` ## Configuration ### Risk Levels Choose based on your security requirements: Best for: Local development, prototyping ```bash theme={null} rafter agent config set agent.riskLevel minimal ``` * Allows most commands * Basic secret detection * Minimal workflow interruption Best for: General use, team environments ```bash theme={null} rafter agent config set agent.riskLevel moderate ``` * Blocks critical commands * Requires approval for high-risk operations * Secret scanning on all git operations * **Default setting** Best for: Sensitive environments, compliance requirements ```bash theme={null} rafter agent config set agent.riskLevel aggressive ``` * Maximum security checks * Requires approval for most operations * Comprehensive audit logging ### View Current Config ```bash theme={null} # View all settings rafter agent config show # Check specific setting rafter agent config get agent.riskLevel ``` ## Workflows ### Secure Development Cycle **You:** "Add user authentication" **Claude:** Writes code, then suggests: "Should I run a security scan?" *\[Invokes: rafter run]* **You:** `/rafter-scan .` Verify no secrets before committing **You:** `/rafter-bash "git commit -m 'Add auth'"` Rafter scans and executes if clean **You:** "Review my changes" **Claude:** *\[Invokes: rafter run --branch feature-auth]* "Security scan passed. Ready to create PR?" ### Installing Untrusted Skills Before installing skills from unknown sources: Save skill file to local directory **You:** `/rafter-audit-skill /path/to/skill.md` Review comprehensive 12-dimension security analysis Based on audit findings: * ✓ Install if LOW/MEDIUM risk * ⚠️ Modify if issues found * ❌ Don't install if HIGH/CRITICAL ## Monitoring ### View Agent Activity ```bash theme={null} # Recent command executions rafter agent audit --event command_intercepted # Secret detections rafter agent audit --event secret_detected # Last 50 events rafter agent audit --last 50 ``` ### Audit Reports Generate compliance reports: ```bash theme={null} # Export as JSON rafter agent audit --json > agent-audit.json # Filter by date rafter agent audit --since 2026-01-01 ``` ## Troubleshooting If Claude doesn't recognize Rafter skills: 1. **Verify skill files exist:** ```bash theme={null} ls ~/.claude/skills/rafter/SKILL.md ls ~/.claude/skills/rafter-agent-security/SKILL.md ``` 2. **Reinstall skills:** ```bash theme={null} rafter agent init ``` 3. **Restart Claude Code session** If Claude isn't suggesting scans automatically: 1. **Check skill is loaded:** Look for system reminders showing "rafter" skill 2. **Verify RAFTER\_API\_KEY is set:** ```bash theme={null} echo $RAFTER_API_KEY ``` 3. **Try explicit request:** "Can you run a Rafter security scan?" If backend scans fail: 1. **Set API key:** ```bash theme={null} export RAFTER_API_KEY="your-key-here" ``` 2. **Or use .env file:** ```bash theme={null} echo "RAFTER_API_KEY=your-key-here" >> .env ``` 3. **Get key from:** [rafter.so/dashboard](https://rafter.so/dashboard) If `/rafter-bash` isn't validating: 1. **Check config:** ```bash theme={null} rafter agent config get agent.environments.claudeCode.enabled # Should return: true ``` 2. **Enable if disabled:** ```bash theme={null} rafter agent config set agent.environments.claudeCode.enabled true ``` ## Best Practices 1. **Let Claude auto-scan**: Don't disable the backend skill - proactive scans catch issues early 2. **Scan before commits**: Always run `/rafter-scan` before committing 3. **Audit untrusted skills**: Use `/rafter-audit-skill` for skills from unknown sources 4. **Review audit logs**: Check `/rafter-audit` after suspicious activity 5. **Start with moderate**: Adjust risk level based on your needs 6. **Keep CLI updated**: `npm update -g @rafter-security/cli` ## Advanced Usage ### Pre-Commit Hooks Automate secret scanning for all commits: ```bash theme={null} # Install pre-commit hook rafter agent install-hook # Install globally (all repos) rafter agent install-hook --global ``` This automatically runs `/rafter-scan --staged` before every commit. ### Custom Blocked Patterns Add organization-specific command patterns: Edit `~/.rafter/config.json`: ```json theme={null} { "agent": { "commandPolicy": { "blockedPatterns": [ "kubectl delete namespace production", "terraform destroy", "rm -rf /important-data" ] } } } ``` ### Skill Auditing Framework The `/rafter-audit-skill` command analyzes 12 security dimensions: 1. **Trust & Attribution** - Source verification 2. **Network Security** - External API calls 3. **Command Execution** - Shell commands 4. **File System Access** - Read/write operations 5. **Credential Handling** - API keys, secrets 6. **Input Validation** - Injection risks 7. **Data Exfiltration** - Data leaving system 8. **Obfuscation** - Hidden behavior 9. **Scope Alignment** - Behavior vs purpose 10. **Error Handling** - Info leakage 11. **Dependencies** - Supply chain risks 12. **Environment Manipulation** - System modifications Each dimension gets a risk rating: ✓ Pass / ⚠️ Warning / ❌ Critical ## Comparison: OpenClaw vs Claude Code **OpenClaw:** Single skill with all features **Claude Code:** Two skills (remote analysis + local security) **Why different?** Claude Code's auto-invocation capability allows separating safe API calls from local operations **OpenClaw:** User or agent invokes all commands **Claude Code:** * Backend skill: Auto-invoked by Claude * Local security: User invokes via slash commands **OpenClaw:** `/rafter-scan`, `/rafter-bash`, etc. **Claude Code:** * Backend: `rafter run`, `rafter get`, `rafter usage` (auto) * Agent: `/rafter-scan`, `/rafter-bash`, etc. (manual) ## Support Complete guides and API reference Report bugs and request features Manage API keys and view scan history Learn more about Claude Code ## Next Steps Complete CLI command documentation Deep dive into secret detection Use Rafter in continuous integration Backend API documentation # Codex CLI Integration Source: https://docs.rafter.so/guides/agent-security/codex-integration Set up Rafter security for OpenAI Codex CLI # Codex CLI Integration Rafter provides two skills for [Codex CLI](https://github.com/openai/codex) that add remote code analysis and local security. ## Skills Architecture API-based security scanning * Trigger remote SAST/SCA scans * Retrieve scan results * Check usage quota * Read-only operations Local security operations * Secret scanning in files * Policy enforcement * Extension auditing * Audit logging ## Setup ### 1. Install Rafter CLI ```bash npm theme={null} npm install -g @rafter-security/cli ``` ```bash pnpm theme={null} pnpm add -g @rafter-security/cli ``` ```bash pip theme={null} pip install rafter-cli ``` ### 2. Initialize Local Security ```bash theme={null} rafter agent init --with-codex ``` Rafter detects Codex CLI via `~/.codex` and installs skills to `~/.agents/skills/rafter/`. To install all detected integrations at once: ```bash theme={null} rafter agent init --all ``` ### 3. Restart Codex CLI Restart Codex CLI to load the newly installed skills. ## Skill Location After initialization: ``` ~/.agents/skills/ ├── rafter/ │ └── SKILL.md # Remote code analysis skill └── rafter-agent-security/ └── SKILL.md # Local security skill ``` ## Usage ### Backend Scanning Trigger a security scan of your repository: ```bash theme={null} rafter run --format md ``` Or use the `rafter scan` alias: ```bash theme={null} rafter scan --repo myorg/myrepo --branch main ``` Backend scanning requires a [Rafter API key](https://rafter.so). Set it via `export RAFTER_API_KEY="your-key"` or pass `--api-key`. ### Local Security These commands work locally without an API key: ```bash theme={null} # Scan files for secrets rafter secrets . # Scan only staged files rafter secrets --staged # Execute a command with risk assessment rafter agent exec "git push --force" # Audit a third-party skill for malware rafter agent audit-skill path/to/untrusted-skill.md # View security event log rafter agent audit ``` > **Note:** `rafter agent scan` still works but is deprecated — it will be removed in a future major version. ### Skill Auditing **Treat third-party extension ecosystems as hostile by default.** There have been reports of malware distributed via skill marketplaces, using social-engineering instructions to run obfuscated shell commands. Before installing any third-party skill, audit it: ```bash theme={null} rafter agent audit-skill path/to/untrusted-skill.md ``` This analyzes 12 security dimensions: trust/attribution, network security, command execution, file system access, credential handling, input validation, data exfiltration, obfuscation, scope alignment, error handling, dependencies, and environment manipulation. ## Configuration ### Risk Levels ```bash theme={null} # Set during init rafter agent init --risk-level moderate # Change later rafter agent config set agent.riskLevel aggressive ``` | Level | Behavior | | ---------- | --------------------------------------------------------------------- | | Minimal | Basic guidance, most commands allowed | | Moderate | Approval for high-risk commands, secrets always blocked (**default**) | | Aggressive | Approval for most operations, maximum security | ### View Configuration ```bash theme={null} rafter agent config show ``` ## Monitoring ### View Agent Activity ```bash theme={null} # Recent events (last 10) rafter agent audit # Last 50 events rafter agent audit --last 50 # Filter by event type rafter agent audit --event secret_detected # Filter by agent platform rafter agent audit --agent claude-code ``` ## Troubleshooting 1. Verify skills are installed: `ls ~/.agents/skills/rafter/` 2. Re-run: `rafter agent init --with-codex` 3. Restart Codex CLI Ensure `~/.codex` exists, then run: `rafter agent init --with-codex` ## What's Next? 21+ secret patterns detected Risk-assessed command validation Full CLI reference # Safe Command Execution Source: https://docs.rafter.so/guides/agent-security/command-execution Execute shell commands with security validation and risk assessment # Safe Command Execution Rafter validates shell commands before execution to prevent dangerous operations. ## Quick Start Execute a command with security checks: ```bash theme={null} rafter agent exec "npm install" ``` ## How It Works When you run `rafter agent exec`, Rafter: 1. **Evaluates the command** against security policies 2. **Scans staged files** (for git commands) 3. **Assesses risk level** (low/medium/high/critical) 4. **Blocks or requires approval** based on risk 5. **Logs the execution** to audit log ## Risk Levels Commands that can cause catastrophic damage: * `rm -rf /` - Delete entire filesystem * `:(){ :|:& };:` - Fork bomb * `dd if=/dev/zero of=/dev/sda` - Wipe disk * `mkfs.*` - Format filesystems * `> /dev/sda` - Overwrite disk **These are always blocked**, even with `--force`. Commands with significant risk: * `rm -rf ` - Recursive deletion * `sudo rm` - Delete with elevated privileges * `chmod 777` - Insecure permissions * `curl ... | sh` - Pipe to shell * `git push --force` - Force push * `npm publish` - Publish packages * `docker system prune` - Delete Docker data **Requires user approval** unless `--force` flag is used. Commands that need elevated privileges: * `sudo` - Any sudo command * `chmod` - Change permissions * `kill -9` - Force kill processes * `systemctl` - System service management **Moderate risk level**: Requires approval, allowed in minimal mode. Standard commands with minimal risk: * `npm install` - Install packages * `git commit` - Commit changes * `ls`, `cat`, `grep` - Read operations * `echo`, `touch` - Basic file operations **Allowed immediately** across all risk levels. ## Usage Examples ### Safe Command Executes immediately: ```bash theme={null} rafter agent exec "npm install express" ``` ### Git Commit with Auto-Scan Scans staged files before committing: ```bash theme={null} rafter agent exec "git commit -m 'Add authentication'" ``` If secrets are detected in staged files, the commit is blocked: ``` ⚠️ Secrets detected in staged files! Found 2 secret(s) in 1 file(s) Run 'rafter secrets' for details. ``` > **Note:** `rafter agent scan` still works but is deprecated — it will be removed in a future major version. ### High-Risk Command Requires approval: ```bash theme={null} rafter agent exec "sudo rm /var/log/old-logs/*.log" ``` You'll see: ``` ⚠️ Command requires approval Risk Level: HIGH Command: sudo rm /var/log/old-logs/*.log Reason: Matches approval pattern: sudo rm Approve this command? (yes/no): ``` ### Force Execution Skip approval with `--force` (logged in audit): ```bash theme={null} rafter agent exec "sudo systemctl restart nginx" --force ``` The `--force` flag skips approval but is **logged in the audit trail**. Use responsibly. ### Skip File Scanning Skip pre-execution scanning for git commands: ```bash theme={null} rafter agent exec "git commit -m 'Fix typo'" --skip-scan ``` ## Command Policies Configure how Rafter handles commands: ### Policy Modes ```bash Approve Dangerous (Default) theme={null} # Requires approval for high/critical commands rafter agent config set agent.commandPolicy.mode approve-dangerous ``` ```bash Deny List theme={null} # Block specific patterns, allow everything else rafter agent config set agent.commandPolicy.mode deny-list ``` ```bash Allow All theme={null} # Allow all commands (not recommended) rafter agent config set agent.commandPolicy.mode allow-all ``` ### Custom Blocked Patterns Add patterns to always block: ```bash theme={null} # View current blocked patterns rafter agent config get agent.commandPolicy.blockedPatterns # Add custom pattern (requires manual config edit) # Edit ~/.rafter/config.json: { "agent": { "commandPolicy": { "blockedPatterns": [ "rm -rf /", "custom-dangerous-command" ] } } } ``` ### Custom Approval Patterns Patterns requiring approval: ```json theme={null} { "agent": { "commandPolicy": { "requireApproval": [ "rm -rf", "sudo rm", "git push --force", "npm publish" ] } } } ``` ## Audit Logging All command executions are logged: ```bash theme={null} # View command executions rafter agent audit --event command_intercepted # View blocked commands rafter agent audit --event command_intercepted | grep BLOCKED # View overrides rafter agent audit --event policy_override ``` Audit entries include: * Timestamp * Command executed * Risk level * Action taken (allowed/blocked/overridden) * User justification (for overrides) ## Integration with Agents ### OpenClaw When integrated with OpenClaw, commands are automatically routed through Rafter: ``` User: "Commit the changes" OpenClaw: rafter agent exec "git commit -m '...'" Rafter: Evaluates command risk → Scans staged files for secrets → Allows if clean ``` ### Claude Code Claude Code integration uses PreToolUse hooks to intercept commands before execution, plus MCP tools for agent-initiated scans. See [Claude Code Integration](/guides/agent-security/claude-code-integration) for setup, and [MCP Integration](/guides/agent-security/mcp-integration) for the MCP server. ## Exit Codes Rafter uses standard exit codes: * `0` - Success * `1` - Command blocked or execution failed Use in scripts: ```bash theme={null} if rafter agent exec "dangerous-command"; then echo "Command succeeded" else echo "Command blocked or failed" fi ``` ## Best Practices 1. **Always use for git commits**: Evaluates risk and scans staged files 2. **Never bypass with `--force` in production**: Use only when necessary 3. **Review audit logs**: Check `rafter agent audit` after suspicious activity 4. **Configure policies**: Adjust `commandPolicy.mode` for your environment 5. **Test in development**: Ensure policies work before deploying to agents ## Advanced Configuration ### Risk Level vs Policy Mode * **Risk Level** (`agent.riskLevel`): Controls overall security stance * **Policy Mode** (`agent.commandPolicy.mode`): Controls specific command handling Example: * `riskLevel: aggressive` + `mode: approve-dangerous` = Very secure * `riskLevel: minimal` + `mode: allow-all` = Permissive ### Custom Risk Assessment Future feature: Define custom risk patterns and severity levels. ## Troubleshooting ### Command Incorrectly Blocked If a safe command is blocked: 1. Check current policy: ```bash theme={null} rafter agent config get agent.commandPolicy ``` 2. Switch to a more permissive mode: ```bash theme={null} rafter agent config set agent.commandPolicy.mode allow-all ``` 3. Report false positive: [rafter-cli/issues](https://github.com/raftersecurity/rafter-cli/issues) ### Secrets Not Detected If secrets aren't caught during git commits: 1. Ensure scanning is enabled (default): ```bash theme={null} rafter agent exec "git commit -m 'message'" # (without --skip-scan) ``` 2. Test scanner separately: ```bash theme={null} rafter secrets ``` ## Next Steps Set up with OpenClaw agents Complete CLI command reference # Getting Started with Agent Security Source: https://docs.rafter.so/guides/agent-security/getting-started Set up Rafter — the security toolkit built for AI coding agents. One command, 9 platforms, free forever. # Getting Started Rafter is the way to **shift security left** — into your AI coding agent's feedback loop. It runs on your machine with zero setup — no API key, no account, no telemetry. Same tools, same output, same policies for every developer on every platform. Add an API key and your agent can also run the Code Security Engine (deep SAST/SCA) on demand. ## Why Install Rafter AI coding agents are powerful but they lack security judgment. They will run destructive commands, commit secrets, and install untrusted extensions without hesitation. Rafter sits inside the loop and gives them that judgment — before damage is done, not after. **Install it because:** * **Zero cost, zero risk.** Free, MIT-licensed, no telemetry, works offline. Nothing to evaluate — install it and see. * **One command, 9 platforms.** `rafter agent init --all` covers Claude Code, Codex CLI, Gemini CLI, Cursor, Windsurf, Continue.dev, Aider, and OpenClaw. No per-platform configuration. * **Complements sandboxing.** Sandboxes contain blast radius after something goes wrong. Rafter prevents the mistake in the first place — secrets never reach git, dangerous commands never execute. * **More than secret scanning.** Command interception, policy enforcement, extension auditing, custom rules, MCP server, pre-commit hooks, and full audit logging — all in one package. * **Stable output contract.** UNIX philosophy: scan results to stdout as JSON, status to stderr, exit codes are a versioned API. Deterministic for a given CLI version. Pipe to `jq`, feed to CI gates, hand to any automation that reads JSON. * **Not just for agents.** Every feature works in human workflows too — pre-commit hooks, CI/CD gates, manual scanning. Agent-first doesn't mean agent-only. ## What Does Rafter Do? Rafter provides six capabilities in one package: * 🔍 **Secret scanning** — 21+ built-in patterns, deterministic detection, optional Betterleaks (formerly Gitleaks) for deeper coverage * 🛡️ **Command interception** — Risk-tiered approval system that blocks destructive commands before agents execute them * 📋 **Policy enforcement** — Project-level `.rafter.yml` files define custom rules that travel with the repo * 🔌 **Extension auditing** — Evaluate third-party skills and MCP tools for embedded secrets, malicious URLs, and risky patterns * 📝 **Audit logging** — Stable JSONL schema recording every security event * ⚙️ **MCP server** — 4 tools exposed over stdio for native integration with any MCP-compatible client ## Installation Install the Rafter CLI globally: ```bash npm theme={null} npm install -g @rafter-security/cli ``` ```bash pnpm theme={null} pnpm add -g @rafter-security/cli ``` ```bash yarn theme={null} yarn global add @rafter-security/cli ``` ```bash pip theme={null} pip install rafter-cli ``` **Python 3.10+ required for pip installs.** Verify your version: ```bash theme={null} python3 --version # Must be 3.10 or higher ``` On Ubuntu/Debian, Python and pip may not be installed by default: ```bash theme={null} sudo apt update && sudo apt install -y python3 python3-pip python3-venv ``` On Fedora/RHEL: `sudo dnf install python3 python3-pip`. macOS: `brew install python`. Windows: install from [python.org](https://python.org) — pip is included. ## Quick Setup Initialize local security with one command: ```bash theme={null} rafter agent init ``` This will: 1. Create `~/.rafter/config.json` configuration 2. Initialize directory structure 3. Auto-detect installed agents (Claude Code, Codex CLI, OpenClaw, Gemini CLI, Cursor, Windsurf, Continue.dev, Aider) 4. Set up audit logging To install integrations, use `--with-*` flags, `--all`, or `--interactive`: ```bash theme={null} rafter agent init --all # install all detected integrations + Betterleaks rafter agent init --with-claude-code # install specific integration rafter agent init --interactive # guided setup — prompts for each detected platform ``` ### Project-Level Setup To generate instruction files that agents read at session start in a specific project: ```bash theme={null} rafter agent init-project # all platforms rafter agent init-project --only claude-code,cursor # specific platforms rafter agent init-project --list # preview without writing ``` This creates files like `.claude/CLAUDE.md`, `AGENTS.md`, `.windsurfrules`, etc. Commit them so every contributor's agent sees Rafter context automatically. ### Choose Your Risk Level During setup, choose from three risk levels: * Basic guidance only * Most commands allowed * Good for local development * Standard protections * Approval required for high-risk commands * Secrets always blocked * **Default setting** * Maximum security * Requires approval for most operations * Best for sensitive environments ```bash theme={null} # Set risk level during init rafter agent init --risk-level moderate # Install all integrations with aggressive security rafter agent init --all --risk-level aggressive # Or change risk level later rafter agent config set agent.riskLevel aggressive ``` ## Verify Installation Run the built-in health check to confirm everything is set up correctly: ```bash theme={null} rafter agent verify ``` This checks your config, Betterleaks binary, and all 8 supported agent integrations (Claude Code, Codex, OpenClaw, Gemini CLI, Cursor, Windsurf, Continue.dev, Aider). Pass `--json` for CI-consumable output, `--probe` to confirm Claude Code's `PreToolUse` hook actually fires (not just that the file is on disk). If any check fails, the output includes actionable fix instructions. You can also test individual components: ```bash theme={null} # Scan current directory for secrets rafter secrets . # View configuration rafter agent config show # Check audit logs rafter agent audit ``` > **Note:** `rafter agent scan` still works but is deprecated — it will be removed in a future major version. ## What's Next? Learn how to detect secrets in your code Safely execute shell commands with validation Set up Rafter with Claude Code Set up Rafter with OpenAI Codex CLI Set up Rafter with OpenClaw agents Use with Cursor, Windsurf, Claude Desktop, Cline Complete CLI command reference Fix common install and runtime issues ## Directory Structure After initialization, Rafter creates: ``` ~/.rafter/ ├── config.json # Configuration file ├── audit.jsonl # Security event log (JSON lines) ├── bin/betterleaks # Betterleaks binary (if installed; v0.8.0+) ├── patterns/ # Custom secret patterns (reserved) └── git-hooks/ # Global pre-commit hook (if --global) ``` ## Agent Auto-Detection `rafter agent init` detects all supported agents and installs the appropriate skills: | Agent | Detected via | Install flag | Skills installed to | | ------------ | --------------------- | -------------------- | -------------------------- | | Claude Code | `~/.claude` | `--with-claude-code` | `~/.claude/skills/rafter/` | | Codex CLI | `~/.codex` | `--with-codex` | `~/.agents/skills/rafter/` | | OpenClaw | `~/.openclaw` | `--with-openclaw` | `~/.openclaw/skills/` | | Gemini CLI | `~/.gemini` | `--with-gemini` | MCP server config | | Cursor | `.cursor/` | `--with-cursor` | MCP server config | | Windsurf | `~/.codeium/windsurf` | `--with-windsurf` | MCP server config | | Continue.dev | `~/.continue` | `--with-continue` | MCP server config | | Aider | `~/.aider.conf.yml` | `--with-aider` | MCP server config | Use `--all` to install all detected integrations at once, or individual `--with-*` flags for specific agents. Restart your agent after initialization to load the installed skills. ## Support * Documentation: [docs.rafter.so](https://docs.rafter.so) * GitHub Issues: [rafter-cli/issues](https://github.com/raftersecurity/rafter-cli/issues) * Support: [rafter.so/help](https://rafter.so/help) # MCP Integration Source: https://docs.rafter.so/guides/agent-security/mcp-integration Use Rafter security tools with any MCP-compatible agent platform # MCP Integration Rafter runs as a standard [MCP server](https://modelcontextprotocol.io/) over stdio, exposing security tools to **any MCP-compatible client**—Cursor, Windsurf, Claude Desktop, Cline, and others. No API key required. All tools run locally. ## Setup ### 1. Install Rafter CLI ```bash npm theme={null} npm install -g @rafter-security/cli ``` ```bash pnpm theme={null} pnpm add -g @rafter-security/cli ``` ```bash pip theme={null} pip install rafter-cli ``` ### 2. Add to Your MCP Client Add Rafter to your MCP client's server configuration: ```json Claude Desktop theme={null} // ~/Library/Application Support/Claude/claude_desktop_config.json { "mcpServers": { "rafter": { "command": "rafter", "args": ["mcp", "serve"] } } } ``` ```json Cursor theme={null} // .cursor/mcp.json { "mcpServers": { "rafter": { "command": "rafter", "args": ["mcp", "serve"] } } } ``` **Cursor users hitting a sandbox prompt:** prefer the per-project install — `rafter agent init --local --with-cursor` — which writes to `./.rafter/` and `./.cursor/` instead of `$HOME`. Global install (`rafter agent init --with-cursor`) requires elevated permissions if Cursor's sandbox restricts writes to your home directory. ```json Windsurf theme={null} // ~/.codeium/windsurf/mcp_config.json { "mcpServers": { "rafter": { "command": "rafter", "args": ["mcp", "serve"] } } } ``` ```json Generic MCP Client theme={null} { "rafter": { "command": "rafter", "args": ["mcp", "serve"] } } ``` ### 3. Restart Your Client Restart the MCP client to load Rafter's tools. You should see eight tools and two resources available: the four local, read-only tools described below, plus the four remote [Sites tools](#sites-tools-remote-api-key-gated) (the Sites tools work without further setup if `RAFTER_API_KEY` is set, but only calls to them require a key — the local tools never do). ## Tools Rafter exposes four read-only security tools over MCP. ### `scan_secrets` Scan files or directories for hardcoded secrets and credentials. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ---------------------------------------------- | | `path` | string | Yes | File or directory path to scan | | `engine` | string | No | `auto` (default), `betterleaks`, or `patterns` | Returns an array of scan results with file paths, pattern names, severity levels, and redacted matches. ```json theme={null} [ { "file": "src/config.ts", "matches": [ { "pattern": "AWS Access Key", "severity": "critical", "line": 12, "redacted": "AKIA****" } ] } ] ``` ### `evaluate_command` Evaluate whether a shell command is allowed by Rafter security policy. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------- | | `command` | string | Yes | Shell command to evaluate | Returns whether the command is allowed, its risk level, and whether it requires approval. ```json theme={null} { "allowed": false, "risk_level": "critical", "requires_approval": false, "reason": "Matches blocked pattern: rm -rf /" } ``` ### `read_audit_log` Read Rafter audit log entries with optional filtering. | Parameter | Type | Required | Description | | ------------ | ------ | -------- | ---------------------------------------------------------------------------------------- | | `limit` | number | No | Maximum entries to return (default: 20) | | `event_type` | string | No | Filter: `command_intercepted`, `secret_detected`, `content_sanitized`, `policy_override` | | `since` | string | No | ISO 8601 timestamp — only entries after this time | ### `get_config` Read Rafter configuration (full config or a specific key). | Parameter | Type | Required | Description | | --------- | ------ | -------- | ----------------------------------------------------------------------- | | `key` | string | No | Dot-path config key (e.g. `agent.commandPolicy`). Omit for full config. | ## Resources Two read-only resources expose Rafter's current state. | URI | Description | | ----------------- | ------------------------------------------------------------------------------ | | `rafter://config` | Current Rafter configuration (JSON) | | `rafter://policy` | Active security policy — merged `.rafter.yml` + `~/.rafter/config.json` (JSON) | ## How It Works The MCP server wraps Rafter's existing CLI classes: * `scan_secrets` uses `RegexScanner` (built-in 21+ patterns) with automatic fallback from Betterleaks (v0.8.0+; gitleaks successor) * `evaluate_command` uses `CommandInterceptor` with policy-driven risk assessment * `read_audit_log` reads from `~/.rafter/audit.jsonl` * `get_config` reads from `~/.rafter/config.json` merged with `.rafter.yml` All tools are **read-only**. Configuration changes go through the CLI (`rafter agent config set`). ## Configuration The MCP server uses the same configuration as all other Rafter commands. Set up your security policy once and it applies everywhere: ```bash theme={null} # Initialize Rafter (creates ~/.rafter/config.json) rafter agent init # Customize policy rafter agent config set agent.riskLevel moderate rafter agent config set agent.commandPolicy.mode approve-dangerous ``` Or use a `.rafter.yml` policy file in your project root. See [Policy File](/guides/agent-security/policy-file) for details. ## Verify Installation After adding Rafter to your MCP client, test that tools are working: 1. Ask the agent to scan a directory for secrets 2. Ask it to evaluate whether `rm -rf /` is safe 3. Ask it to show your Rafter configuration If the agent can call these tools, Rafter is connected. ## Sites Tools (Remote, API-Key-Gated) The four tools above are local-only, read-only, and require no API key. Rafter also exposes a separate set of **Sites** tools that are the opposite on every axis: they call Rafter's remote API, require an API key, and two of them mutate state (create a site, trigger a scan). Sites tools are not part of the "four tools" described above — they are a distinct surface for [live-application security monitoring](/guides/sites), not local secret scanning or command policy. | | Local Tools (above) | Sites Tools (below) | | ----------------- | ------------------------ | ------------------------------------------------------- | | **Where it runs** | Locally, on your machine | Rafter's remote API | | **API key** | Not required | Required (`x-api-key`, scope `read` or `read-and-scan`) | | **Mutates state** | No — all read-only | `sites_create` and `sites_scan` do | ### Authentication The Sites tools resolve your API key the same way the CLI does: the `RAFTER_API_KEY` environment variable, or your stored Rafter config, checked in that order. ### `sites_create` Register a new site and trigger its first scan. Requires an API key with the `read-and-scan` scope. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------ | | `url` | string | Yes | The URL of the site to monitor | ### `sites_scan` Trigger a re-scan of a site you already own. Requires an API key with the `read-and-scan` scope. | Parameter | Type | Required | Description | | ----------- | ---------------- | ------------------------ | ------------------------------------------------------------- | | `projectId` | string | One of `projectId`/`url` | The site's id | | `url` | string | One of `projectId`/`url` | The site's URL | | `sections` | array of strings | No | Restrict the scan to `"flight"`, `"security"`, and/or `"dns"` | ### `sites_list` List your sites, paginated. Requires an API key with the `read` scope. | Parameter | Type | Required | Description | | ------------------ | ------- | -------- | --------------------------------------------------- | | `limit` | number | No | Number of sites to return, `1`-`100` (default `25`) | | `offset` | number | No | Number of sites to skip (default `0`) | | `include_archived` | boolean | No | Include archived sites (default excludes them) | ### `sites_get` Get a site's status, latest run, and findings summary. Requires an API key with the `read` scope. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------- | | `id` | string | Yes | The site's id | See the [Sites API reference](/api-reference/endpoint/static/sites/create) for full request/response shapes, and the [Sites CLI guide](/guides/sites) for the equivalent `rafter sites` commands. ## Compared to Pretool Hooks | | MCP Server | Pretool Hooks | | ------------ | ---------------------------- | -------------------------------------- | | **Platform** | Any MCP client | Claude Code only | | **Model** | Agent calls tools explicitly | Hooks intercept before every tool call | | **Trust** | Agent chooses to use tools | Agent cannot bypass hooks | | **Setup** | Add to MCP config | `rafter agent init --with-claude-code` | For maximum security on Claude Code, use **both**: pretool hooks for enforcement + MCP tools for agent-initiated scans. For other platforms, the MCP server is the primary integration path. ## What's Next? 21+ secret patterns detected Define per-project security policies Full CLI reference # OpenClaw Integration Source: https://docs.rafter.so/guides/agent-security/openclaw-integration Set up Rafter security for OpenClaw # OpenClaw Integration Rafter integrates seamlessly with [OpenClaw](https://openclaw.com) to add local security to your development workflow. ## Setup ### 1. Install Rafter CLI Install globally: ```bash npm theme={null} npm install -g @rafter-security/cli ``` ```bash pnpm theme={null} pnpm add -g @rafter-security/cli ``` ### 2. Initialize Local Security Run initialization (auto-detects OpenClaw): ```bash theme={null} rafter agent init ``` If OpenClaw is detected, Rafter will: * ✓ Install skill to `~/.openclaw/workspace/skills/rafter-security/SKILL.md` (the canonical ClawHub path; was `~/.openclaw/skills/rafter-security.md` in v0.7.7 and earlier — reinstall on top of the old layout strips the legacy file) * ✓ Write ClawHub-required top-level frontmatter (`name`, `description`, `version`) alongside the `openclaw:` runtime block * ✓ Enable agent integration in config * ✓ Set up security policies **Alternative install:** since v0.8.0, the rafter-security skill is also auto-published to [ClawHub](https://clawhub.ai) on every prod release. OpenClaw users can install via `clawhub skill install rafter-security` as an alternative to `rafter agent init --with-openclaw`. ### 3. Restart OpenClaw Restart OpenClaw to load the Rafter skill: ```bash theme={null} # Stop OpenClaw openclaw stop # Start OpenClaw openclaw start ``` ## How It Works Once integrated, OpenClaw uses Rafter for security-sensitive operations: ``` User → OpenClaw → Rafter Security → Safe Execution ``` ### Example Flow **User request:** ``` "Commit these changes to git" ``` **OpenClaw processes:** 1. Generates commit message 2. Calls Rafter: `rafter agent exec "git commit -m '...'"` 3. Rafter evaluates command risk level 4. Rafter scans staged files for secrets (for git commands) 5. If clean: Executes commit 6. If secrets found or command blocked: Alerts user ## Skill Commands The Rafter skill provides these commands to OpenClaw: ### `/rafter-scan` Scan files for secrets before operations. **When OpenClaw uses it:** * Before git commits * When reading sensitive files * After generating code with credentials **Example:** ``` User: "Is there anything sensitive in this codebase?" OpenClaw: rafter secrets . ``` > **Note:** `rafter agent scan` still works but is deprecated — it will be removed in a future major version. ### `/rafter-bash` Execute shell commands with validation. **When OpenClaw uses it:** * For any shell command execution * Before destructive operations * When using sudo **Example:** ``` User: "Install the dependencies" OpenClaw: rafter agent exec "npm install" ``` ### `/rafter-audit` View security event logs. **When OpenClaw uses it:** * After blocked commands * When reviewing security events * For compliance reporting **Example:** ``` User: "Show me recent security events" OpenClaw: rafter agent audit --last 10 ``` ## Configuration ### Risk Levels for OpenClaw Choose based on your use case: Best for: Local development, prototyping ```bash theme={null} rafter agent config set agent.riskLevel minimal ``` * Allows most commands * Basic secret detection * Minimal interruption to workflow Best for: General use, team environments ```bash theme={null} rafter agent config set agent.riskLevel moderate ``` * Blocks critical commands * Requires approval for high-risk operations * Secret scanning on all git operations * **Default setting** Best for: Sensitive environments, compliance requirements ```bash theme={null} rafter agent config set agent.riskLevel aggressive ``` * Maximum security checks * Requires approval for most operations * Comprehensive audit logging * Best for production agents ### Command Policy Control how commands are handled: ```bash theme={null} # Default: Approve dangerous commands rafter agent config set agent.commandPolicy.mode approve-dangerous # Alternative: Block specific patterns only rafter agent config set agent.commandPolicy.mode deny-list # Permissive: Allow all (not recommended) rafter agent config set agent.commandPolicy.mode allow-all ``` ## Usage Examples ### Safe Development Workflow ``` User: "Create a new feature for user authentication" OpenClaw: 1. Generates code 2. Runs rafter secrets # Check for secrets 3. If clean, proceeds 4. Creates git commit with rafter agent exec 5. Scans staged files again 6. Commits successfully ``` ### Blocked Dangerous Operation ``` User: "Clean up all files in the project" OpenClaw generates: rm -rf / Rafter: 🚫 Command BLOCKED Risk Level: CRITICAL Reason: Matches blocked pattern: rm -rf / OpenClaw: "This command is too dangerous. Please specify which files to delete." ``` ### Approval Required ``` User: "Force push to main branch" OpenClaw generates: git push --force origin main Rafter: ⚠️ Command requires approval Risk Level: HIGH Approve this command? (yes/no): User: no OpenClaw: "Command cancelled. Would you like to push normally instead?" ``` ## Best Practices 1. **Start with moderate risk level**: Adjust based on experience 2. **Review audit logs daily**: `rafter agent audit --last 20` 3. **Train agents on Rafter commands**: Ensure agents know when to use security checks 4. **Test policies in development**: Before deploying to production 5. **Keep Rafter updated**: `npm update -g @rafter-security/cli` ## Monitoring ### View Agent Activity Check what your agent is doing: ```bash theme={null} # Recent command executions rafter agent audit --event command_intercepted # Secret detections rafter agent audit --event secret_detected # Filter by agent rafter agent audit --agent openclaw --last 50 ``` ### Audit Reports Generate reports for compliance: ```bash theme={null} # Export last 7 days as JSON rafter agent audit --since $(date -v-7d +%Y-%m-%d) --json > agent-audit.json ``` ## Troubleshooting ### Skill Not Loading If OpenClaw doesn't recognize Rafter commands: 1. **Check skill file exists:** ```bash theme={null} ls ~/.openclaw/workspace/skills/rafter-security/SKILL.md ``` (Pre-0.8.0 layout was `~/.openclaw/skills/rafter-security.md` — that path is no longer read by ClawHub at runtime.) 2. **Reinstall skill:** ```bash theme={null} rafter agent init --force ``` 3. **Restart OpenClaw:** ```bash theme={null} openclaw restart ``` ### Commands Not Being Validated If commands bypass Rafter: 1. **Check config:** ```bash theme={null} rafter agent config get agent.environments.openclaw.enabled # Should be: true ``` 2. **Verify policy mode:** ```bash theme={null} rafter agent config get agent.commandPolicy.mode ``` 3. **Enable if disabled:** ```bash theme={null} rafter agent config set agent.environments.openclaw.enabled true ``` ### False Positives If safe commands are being blocked: 1. **Check audit log:** ```bash theme={null} rafter agent audit --last 5 ``` 2. **Adjust risk level:** ```bash theme={null} rafter agent config set agent.riskLevel minimal ``` 3. **Report issue:** [rafter-cli/issues](https://github.com/raftersecurity/rafter-cli/issues) ## Advanced Configuration ### Custom Blocked Patterns Add organization-specific patterns: Edit `~/.rafter/config.json`: ```json theme={null} { "agent": { "commandPolicy": { "blockedPatterns": [ "rm -rf /", "kubectl delete namespace production", "terraform destroy" ] } } } ``` ### Approval Patterns Require approval for specific commands: ```json theme={null} { "agent": { "commandPolicy": { "requireApproval": [ "git push --force", "npm publish", "docker push.*production" ] } } } ``` ## Multi-Agent Setup Running multiple OpenClaw instances: ```bash theme={null} # Each agent gets same config by default # Customize per-agent if needed: # Agent 1 (aggressive) export RAFTER_RISK_LEVEL=aggressive openclaw start --name agent1 # Agent 2 (moderate) export RAFTER_RISK_LEVEL=moderate openclaw start --name agent2 ``` ## Support * Documentation: [docs.rafter.so](https://docs.rafter.so) * OpenClaw Docs: [openclaw.com/docs](https://openclaw.com/docs) * Issues: [rafter-cli/issues](https://github.com/raftersecurity/rafter-cli/issues) * Community: [OpenClaw Discord](https://openclaw.com/discord) ## Next Steps Complete CLI command reference Learn about secret detection # Policy File Source: https://docs.rafter.so/guides/agent-security/policy-file Configure project-level security policies with .rafter.yml # Policy File (.rafter.yml) The `.rafter.yml` file defines project-level security policies that override your global `~/.rafter/config.json` settings. Place it in your project root and Rafter picks it up automatically. ## How It Works When any `rafter agent` command runs, the CLI walks from your current directory up to the git root looking for `.rafter.yml` or `.rafter.yaml`. If found, its values merge into the loaded config with **policy file winning** on conflicts. Arrays like `blocked_patterns` **replace** the corresponding `~/.rafter/config.json` values entirely rather than appending. Note that hardcoded defaults (e.g. the built-in exclusion list and 21+ secret patterns) always apply regardless of what the policy file sets. ## Full Schema ```yaml theme={null} version: "1" # Override global risk level for this project risk_level: moderate # minimal | moderate | aggressive # Policy enforcement rules command_policy: mode: approve-dangerous # allow-all | approve-dangerous | deny-list blocked_patterns: - "rm -rf /" - "curl.*|.*sh" require_approval: - "npm publish" - "git push --force" # Secret scanning configuration scan: exclude_paths: - "vendor/" - "third_party/" - "fixtures/" custom_patterns: - name: "Internal API Key" regex: "INTERNAL_[A-Z0-9]{32}" severity: critical - name: "Staging Token" regex: "stg_[a-zA-Z0-9]{24}" severity: high # Audit log settings audit: retention_days: 90 log_level: info # debug | info | warn | error ``` All fields are optional. Only specify what you need to override. ## Custom Scan Patterns Add organization-specific secret patterns that the default 21 patterns don't cover: ```yaml theme={null} scan: custom_patterns: - name: "Internal API Key" regex: "INTERNAL_[A-Z0-9]{32}" severity: critical - name: "Deploy Token" regex: "deploy_[a-f0-9]{40}" severity: high ``` Each pattern requires: * **name**: Human-readable identifier shown in scan output * **regex**: JavaScript-compatible regular expression * **severity**: `critical`, `high`, `medium`, or `low` Custom patterns are added alongside the default patterns, not replacing them. ## Exclude Paths Skip directories during secret scanning: ```yaml theme={null} scan: exclude_paths: - "vendor/" - "third_party/" - "test/fixtures/" ``` These are directory names matched against path segments. The default exclusions (`node_modules`, `.git`, `dist`, `build`, `.next`, `coverage`, `.vscode`, `.idea`) always apply. Your `exclude_paths` add to that list. ## Command Policy Overrides Lock down command execution rules per project: ```yaml theme={null} command_policy: mode: deny-list blocked_patterns: - "rm -rf /" - "docker system prune" require_approval: - "npm publish" - "terraform apply" ``` This is useful for monorepos or shared projects where different teams need different security boundaries. ## Precedence Rules When both `~/.rafter/config.json` (global) and `.rafter.yml` (project) define the same setting, the project policy file wins. How the merge works depends on the setting type: | Setting | Merge behavior | | --------------------------------- | -------------------------------------------------------------------------- | | `risk_level` | Project policy overrides global config | | `command_policy.mode` | Project policy overrides global config | | `command_policy.blocked_patterns` | Project policy **replaces** global config (not merged) | | `command_policy.require_approval` | Project policy **replaces** global config (not merged) | | `scan.custom_patterns` | **Added** alongside the built-in 21+ patterns | | `scan.exclude_paths` | **Added** alongside the built-in exclusions (`node_modules`, `.git`, etc.) | In short: scalar values are overridden, `command_policy` arrays are replaced wholesale, and `scan` arrays are additive. ## Best Practices 1. Commit `.rafter.yml` to version control so the whole team gets the same policies 2. Start with `risk_level: moderate` and tighten as needed 3. Add custom patterns for any organization-specific secret formats 4. Use `exclude_paths` for vendored code or generated files ## Next Steps Learn about scan options and output Configure policy enforcement # Command Reference Source: https://docs.rafter.so/guides/agent-security/reference Complete reference for Rafter local security CLI commands # Command Reference Complete reference for all Rafter local security and MCP commands. ## `rafter agent init` Initialize local security system. ```bash theme={null} rafter agent init [options] ``` ### Options | Flag | Description | Default | | ---------------------- | -------------------------------------------------------------------------------------- | ---------- | | `--risk-level ` | Set risk level: `minimal`, `moderate`, `aggressive` | `moderate` | | `--with-openclaw` | Install OpenClaw integration | false | | `--with-claude-code` | Install Claude Code integration (hooks + skills) | false | | `--with-codex` | Install Codex CLI integration (skills) | false | | `--with-gemini` | Install Gemini CLI integration (MCP server) | false | | `--with-cursor` | Install Cursor integration (MCP server) | false | | `--with-windsurf` | Install Windsurf integration (MCP server) | false | | `--with-continue` | Install Continue.dev integration (MCP server) | false | | `--with-aider` | Install Aider integration (MCP server) | false | | `--with-openclaw` | Install OpenClaw integration (ClawHub-shaped skill) | false | | `--with-betterleaks` | Download and install Betterleaks binary (gitleaks successor) | false | | `--all` | Install all detected integrations and download Betterleaks | false | | `-i, --interactive` | Guided setup — prompts for each detected integration | false | | `--update` | Re-download betterleaks and reinstall integrations without resetting config | false | | `--dry-run` | Print every file path that would be created, modified, or downloaded — make no changes | false | The legacy `--with-gitleaks`, `--engine gitleaks`, and `rafter agent update-gitleaks` flags were removed in v0.8.0. Use the `-betterleaks` equivalents. `rafter agent verify` and `rafter agent status` still detect a leftover `~/.rafter/bin/gitleaks` and tell you to run `rafter agent update-betterleaks`. ### What It Does 1. Creates `~/.rafter/config.json` configuration 2. Initializes directory structure (`~/.rafter/`) 3. Detects installed development environments (`~/.claude`, `~/.codex`, `~/.gemini`, etc.) 4. Installs opted-in integrations (skills, hooks, sub-agents, per-skill rules, or MCP server configs) 5. Downloads Betterleaks binary if `--with-betterleaks` or `--all` is passed ### Examples ```bash theme={null} # Basic initialization (config only, no integrations) rafter agent init # Install all detected integrations rafter agent init --all # Preview every file path that would change — write nothing rafter agent init --all --dry-run # Set aggressive security from start rafter agent init --risk-level aggressive --all # Install only Claude Code integration rafter agent init --with-claude-code # Install only Codex CLI integration rafter agent init --with-codex # Re-download Betterleaks and reinstall rafter agent init --all --update ``` *** ## `rafter agent init-project` Generate project-level instruction files so AI agents discover Rafter at session start. ```bash theme={null} rafter agent init-project [options] ``` ### Options | Flag | Description | | -------------------- | ---------------------------------------------------------------- | | `--only ` | Comma-separated list of platforms to generate for | | `--list` | Dry-run — show which files would be created without writing them | ### What It Does Creates instruction files in the current project for all 7 supported agent platforms: | Platform | File Created | | ------------ | ----------------------------------- | | Claude Code | `.claude/CLAUDE.md` | | Codex CLI | `AGENTS.md` | | Gemini CLI | `GEMINI.md` | | Cursor | `.cursor/rules/rafter-security.mdc` | | Windsurf | `.windsurfrules` | | Continue.dev | `.continuerules` | | Aider | `.aider/conventions.md` | Each file contains a Rafter security context block with scanning commands, integration tips, and CLI reference pointers. Files use marker comments (``) for idempotent updates — safe to re-run without duplicating content. ### Examples ```bash theme={null} # Generate for all platforms rafter agent init-project # Preview what would be created rafter agent init-project --list # Generate only for specific platforms rafter agent init-project --only claude-code,cursor # Generate for a single platform rafter agent init-project --only codex ``` Commit the generated files so every contributor's agent session sees Rafter security context automatically. *** ## `rafter secrets` > **Note:** `rafter agent scan` still works but is deprecated — it will be removed in a future major version. Scan files or directories for secrets. ```bash theme={null} rafter secrets [path] [options] ``` ### Arguments | Argument | Description | Default | | -------- | ------------------------- | ----------------------- | | `path` | File or directory to scan | `.` (current directory) | ### Options | Flag | Description | | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `-q, --quiet` | Only output if secrets found | | `--json` | Output results as JSON (alias for `--format json`) | | `--format ` | Output format: `text` (default), `json`, or `sarif` | | `--staged` | Scan only git-staged files | | `--diff ` | Scan only files changed since a git ref (e.g. `HEAD~1`, `main`) | | `--engine ` | Scan engine: `patterns`, `betterleaks`, or `auto` (default) | | `--history` | Scan git history for secrets (requires `betterleaks` engine) | | `--baseline` | Filter findings present in the saved baseline | | `--watch` | Watch for file changes and re-scan on change | | `--gitignore` / `--no-gitignore` | Honor `.gitignore` when walking the scan target (default: on). Honors nested `.gitignore`, negations, `.git/info/exclude`, and the global excludes file. Outside any git work tree this flag is a no-op. | ### Exit Codes * `0` - No secrets found * `1` - Secrets detected * `2` - Runtime error (path not found, not a git repo, invalid ref) ### Examples ```bash theme={null} # Scan current directory rafter secrets # Scan specific file rafter secrets ./config.js # Scan with JSON output rafter secrets --json > results.json # CI/CD usage (quiet mode) rafter secrets --quiet || exit 1 # Scan only changed files rafter secrets --diff main # Use Betterleaks engine explicitly (default: auto-pick if installed) rafter secrets --engine betterleaks # Watch for changes and re-scan rafter secrets --watch . ``` ### Detected Patterns **Cloud Providers:** * AWS Access Keys (`AKIA...`) * AWS Secret Keys * Google API Keys (`AIza...`) * Google OAuth credentials **Version Control:** * GitHub Personal Access Tokens (`ghp_...`) * GitHub OAuth Tokens (`gho_...`) * GitHub App Tokens (`ghu_...`, `ghs_...`) * GitHub Refresh Tokens (`ghr_...`) **Payment & SaaS:** * Stripe API Keys (`sk_live_...`, `rk_live_...`) * Slack Tokens (`xox[baprs]-...`) * Slack Webhooks * Twilio API Keys (`SK...`) **Package Registries:** * npm Access Tokens (`npm_...`) * PyPI API Tokens (`pypi-...`) **General:** * Database connection strings * Private keys (RSA, DSA, EC, OpenSSH) * JWT tokens * Bearer tokens * Generic API keys * Generic secrets/passwords *** ## `rafter agent exec` Execute command with security validation. ```bash theme={null} rafter agent exec [options] ``` ### Arguments | Argument | Description | | --------- | ------------------------ | | `command` | Shell command to execute | ### Options | Flag | Description | | ------------- | --------------------------------------- | | `--skip-scan` | Skip pre-execution file scanning | | `--force` | Skip approval prompts (logged in audit) | ### Command Risk Levels * `rm -rf /` * `:(){ :|:& };:` (fork bomb) * `dd if=/dev/zero of=/dev/sda` * `> /dev/sda` * `mkfs.*` * `fdisk`, `parted` * `rm -rf ` * `sudo rm` * `chmod 777` * `curl ... | sh` * `git push --force` * `npm publish` * `docker system prune` * `sudo` * `chmod` * `chown` * `kill -9` * `systemctl` * `npm install` * `git commit` * File read operations (`ls`, `cat`, `grep`) * Basic file operations (`echo`, `touch`) ### Examples ```bash theme={null} # Safe command - executes immediately rafter agent exec "npm test" # Git commit - evaluates risk, then scans staged files rafter agent exec "git commit -m 'Add feature'" # High-risk - requires approval rafter agent exec "sudo systemctl restart nginx" # Force execution (skip approval, logged) rafter agent exec "git push --force" --force # Skip file scanning rafter agent exec "git commit -m 'Fix typo'" --skip-scan ``` ### Pre-Execution Scanning For all commands, Rafter first evaluates the command against risk rules. For git commands (`git commit`, `git push`), it additionally: 1. Gets list of staged files 2. Scans each file for secrets 3. Blocks if secrets detected 4. Allows if clean Skip with `--skip-scan` if needed. *** ## `rafter agent config` Manage agent configuration. ```bash theme={null} rafter agent config [options] ``` ### Subcommands #### `show` Display full configuration: ```bash theme={null} rafter agent config show ``` #### `get ` Get specific configuration value: ```bash theme={null} rafter agent config get ``` **Example:** ```bash theme={null} rafter agent config get agent.riskLevel # Output: moderate ``` #### `set ` Set configuration value: ```bash theme={null} rafter agent config set ``` **Example:** ```bash theme={null} rafter agent config set agent.riskLevel aggressive ``` ### Configuration Keys | Key | Type | Options | Description | | ------------------------------------- | ------- | --------------------------------------------- | ------------------------------------------ | | `agent.riskLevel` | string | `minimal`, `moderate`, `aggressive` | Overall security stance | | `agent.commandPolicy.mode` | string | `allow-all`, `approve-dangerous`, `deny-list` | Command handling mode | | `agent.commandPolicy.blockedPatterns` | array | - | Always-blocked command patterns | | `agent.commandPolicy.requireApproval` | array | - | Patterns requiring approval | | `agent.outputFiltering.redactSecrets` | boolean | `true`, `false` | Redact secrets in output | | `agent.audit.logAllActions` | boolean | `true`, `false` | Log all security events | | `agent.audit.retentionDays` | number | - | Log retention period (days) | | `agent.audit.logLevel` | string | `debug`, `info`, `warn`, `error` | Log verbosity | | `agent.notifications.webhook` | string | - | Webhook URL to POST notifications to | | `agent.notifications.minRiskLevel` | string | `"high"`, `"critical"` | Minimum risk level to trigger notification | ### Examples ```bash theme={null} # View all config rafter agent config show # Get risk level rafter agent config get agent.riskLevel # Set to aggressive rafter agent config set agent.riskLevel aggressive # Change policy mode rafter agent config set agent.commandPolicy.mode deny-list # Enable secret redaction rafter agent config set agent.outputFiltering.redactSecrets true # Set log retention rafter agent config set agent.audit.retentionDays 60 # Configure webhook notifications rafter agent config set agent.notifications.webhook https://hooks.slack.com/services/T.../B.../xxx rafter agent config set agent.notifications.minRiskLevel critical ``` *** ## `rafter agent audit` View security audit logs. For the full JSONL schema specification, see [Audit Log](/guides/agent-security/audit-log). ```bash theme={null} rafter agent audit [options] ``` ### Options | Flag | Description | Default | | ---------------- | ------------------------------------------- | ------- | | `--last ` | Show last N entries | `10` | | `--event ` | Filter by event type | - | | `--agent ` | Filter by agent (`openclaw`, `claude-code`) | - | | `--since ` | Show entries since date (YYYY-MM-DD) | - | ### Event Types | Event | Description | | --------------------- | ------------------------- | | `command_intercepted` | Command execution attempt | | `secret_detected` | Secret found in files | | `content_sanitized` | Output redacted | | `policy_override` | User override of policy | | `scan_executed` | File scan performed | | `config_changed` | Configuration modified | ### Examples ```bash theme={null} # Show recent logs rafter agent audit # Show last 20 entries rafter agent audit --last 20 # Filter by event type rafter agent audit --event command_intercepted # Filter by agent rafter agent audit --agent openclaw # Show logs since date rafter agent audit --since 2026-02-01 # Combine filters rafter agent audit --event secret_detected --last 50 ``` ### Output Format ``` 🛡️ [2026-02-02 10:30:45] command_intercepted Agent: openclaw Command: git commit -m 'Add feature' Risk: medium Check: PASSED Action: allowed 🔑 [2026-02-02 10:25:12] secret_detected Agent: openclaw Risk: critical Check: FAILED Reason: AWS Access Key detected in config.js Action: blocked ``` *** ## `rafter agent verify` Check local security integration status across all 8 supported platforms. ```bash theme={null} rafter agent verify [--json] [--probe] ``` ### What It Does Validates your Rafter setup by checking 10 things in order: 1. **Config** — `~/.rafter/config.json` exists and is valid JSON 2. **Betterleaks** — Binary available on PATH or at `~/.rafter/bin/betterleaks` (legacy `~/.rafter/bin/gitleaks` is detected and surfaced as an "upgrade needed" hint, not an error) 3. **Claude Code** — `~/.claude/settings.json` has `PreToolUse` hooks installed *(optional)* 4. **OpenClaw** — `~/.openclaw/workspace/skills/rafter-security/SKILL.md` exists with ClawHub frontmatter *(optional)* 5. **Codex CLI** — `~/.agents/skills/rafter/SKILL.md` and `~/.agents/skills/rafter-agent-security/SKILL.md` exist *(optional)* 6. **Gemini CLI** — MCP server configured for Gemini *(optional)* 7. **Cursor** — hooks + per-skill rules + sub-agent installed *(optional)* 8. **Windsurf** — per-skill rules + AGENTS.md + MCP entry installed *(optional)* 9. **Continue.dev** — MCP entry + per-skill rules installed *(optional)* 10. **Aider** — `RAFTER.md` present and listed in `.aider.conf.yml`'s `read:` *(optional)* Config and Betterleaks are hard requirements (failure → exit 1). Everything else is an optional integration (failure → warning only, exit 0). ### Options | Flag | Description | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `--json` | Emit a single JSON object (`checks[]` + `summary`) with stable `pass \| warn \| fail` status. Intended for CI consumption. | | `--probe` | Runtime probe for Claude Code: synthesize a `PreToolUse` stdin payload with a known-dangerous sentinel command, invoke `rafter hook pretool`, and confirm `~/.rafter/audit.jsonl` recorded a `command_intercepted` entry. Catches the "wrote file but the hook never fires" failure mode that file-presence checks miss. | ### Exit Codes | Code | Meaning | | ---- | ----------------------------------------------------- | | `0` | All required checks passed (optional checks may warn) | | `1` | One or more required checks failed | ### Examples ```bash theme={null} # Run health check rafter agent verify # CI consumption — single JSON object on stdout rafter agent verify --json # Runtime probe — confirms Claude Code's PreToolUse hook actually fires rafter agent verify --probe # Example output (all passing): # ✓ Config ~/.rafter/config.json # ✓ Betterleaks 1.1.2 (/home/you/.rafter/bin/betterleaks) # ✓ Claude Code PreToolUse hook installed # ✓ OpenClaw rafter-security SKILL.md present # Example output (legacy gitleaks needs upgrade): # ✓ Config ~/.rafter/config.json # ⚠ Betterleaks legacy gitleaks at ~/.rafter/bin/gitleaks — run: rafter agent update-betterleaks # ✓ Claude Code PreToolUse hook installed ``` Run `rafter agent verify` after `rafter agent init` to confirm everything installed correctly, and after system updates to catch binary incompatibilities. Use `--probe` in CI/post-install to catch hook regressions that file-presence checks miss. *** ## `rafter agent status` Show a live dashboard of your Rafter local security setup. ```bash theme={null} rafter agent status ``` ### What It Shows | Section | Details | | --------------- | ----------------------------------------------------------------------------------------- | | **Config** | Presence and validity of `~/.rafter/config.json`; risk level, audit log path | | **Betterleaks** | Version string and binary path (legacy `gitleaks` detected as upgrade-needed hint) | | **Hooks** | Whether `PreToolUse` and `PostToolUse` hooks are registered in Claude Code settings | | **OpenClaw** | Whether the `rafter-security` SKILL.md is installed under `~/.openclaw/workspace/skills/` | | **Audit Log** | Total event count + 5 most recent events (type, timestamp, risk) | ### Example Output ```bash theme={null} rafter agent status # Rafter Agent Status # ───────────────────────────────── # Config: ~/.rafter/config.json (risk: medium) # Betterleaks: 1.1.2 (/home/you/.rafter/bin/betterleaks) # Hooks: PreToolUse ✓ PostToolUse ✓ # OpenClaw: rafter-security SKILL.md ✓ # # Audit Log: 142 events # [2026-02-21 14:32] command_allowed low # [2026-02-21 14:31] secret_detected high # [2026-02-21 14:28] command_intercepted critical # [2026-02-21 14:20] command_allowed low # [2026-02-21 14:18] command_allowed low ``` *** ## `rafter agent install-hook` Install a git pre-commit hook that scans staged files for secrets before each commit. ```bash theme={null} rafter agent install-hook [options] ``` ### Options | Flag | Description | Default | | ---------- | ----------------------------------------- | ------------------ | | `--global` | Install for all git repos on this machine | false (local only) | ### What It Does **Without `--global`** (local install): * Writes hook to `.git/hooks/pre-commit` in the current repo * Backs up any existing hook before overwriting **With `--global`** (global install): * Writes hook to `~/.rafter/git-hooks/pre-commit` * Sets `git config --global core.hooksPath ~/.rafter/git-hooks` * Applies to every git repo on the machine When `git commit` runs, the hook calls `rafter secrets --staged`. If secrets are detected the commit is blocked. Pass `git commit --no-verify` to bypass (not recommended). ### Examples ```bash theme={null} # Install for current repo rafter agent install-hook # Install globally for all repos rafter agent install-hook --global # Remove global hook git config --global --unset core.hooksPath ``` *** ## `rafter agent audit-skill` Security audit of a Claude Code or OpenClaw skill file. ```bash theme={null} rafter agent audit-skill [options] ``` ### Arguments | Argument | Description | | -------------- | ------------------------------------------ | | `` | Path to the skill file to audit (required) | ### Options | Flag | Description | | ----------------- | ------------------------------------------------------------- | | `--skip-openclaw` | Skip OpenClaw integration; print manual review prompt instead | | `--json` | Output results as JSON | ### What It Does Performs deterministic security analysis on the skill file: 1. **Secret detection** — Scans for hardcoded API keys, tokens, and credentials 2. **URL extraction** — Lists all external HTTP/HTTPS URLs 3. **High-risk command patterns** — Detects 11 dangerous patterns: `rm -rf /`, `sudo rm`, `curl|sh`, `wget|sh`, `eval()`, `exec()`, `chmod 777`, fork bombs, `dd /dev/xyz`, `mkfs`, `base64 -d|sh` If OpenClaw is available, the command routes the skill to the `/rafter-audit-skill` slash command for a deeper 12-dimension security review covering trust, network access, credential handling, obfuscation, supply chain, and more. ### Exit Codes | Code | Meaning | | ---- | ----------------------------------------- | | `0` | No secrets or high-risk commands detected | | `1` | Secrets or high-risk commands found | ### Examples ```bash theme={null} # Audit a skill file rafter agent audit-skill ~/.claude/skills/github-integration/SKILL.md # JSON output for scripting rafter agent audit-skill skill.md --json # Skip OpenClaw (prints manual review prompt) rafter agent audit-skill skill.md --skip-openclaw ``` ### JSON Output ```bash theme={null} rafter agent audit-skill skill.md --json ``` ```json theme={null} { "skill": "skill.md", "path": "/absolute/path/to/skill.md", "quickScan": { "secrets": 0, "urls": ["https://api.example.com"], "highRiskCommands": [] }, "openClawAvailable": true, "rafterSkillInstalled": true } ``` *** ## `rafter ci init` Generate CI/CD workflow files for your project. ```bash theme={null} rafter ci init [options] ``` ### Options | Flag | Description | Default | | ------------------- | ----------------------------------------------- | ---------------- | | `--platform ` | Target platform: `github`, `gitlab`, `circleci` | Auto-detected | | `--output ` | Output file path | Platform default | | `--with-backend` | Include API-based security audit job | false | ### What It Does 1. Detects your CI platform from project files (`.github/`, `.gitlab-ci.yml`, `.circleci/`) 2. Generates a workflow file with secret scanning and security checks 3. Optionally adds a backend scan job using the Rafter API ### Examples ```bash theme={null} # Auto-detect platform and generate config rafter ci init # Generate GitHub Actions workflow rafter ci init --platform github # Include backend scanning job rafter ci init --platform github --with-backend ``` *** ## `rafter brief` Print rafter knowledge reformatted for CLI output. Designed for any agent on any platform — pipe to memory, save to instructions, or just read in-session. ```bash theme={null} rafter brief [topic] ``` ### Arguments | Argument | Description | | --------- | --------------------------------------------------------------- | | `[topic]` | Topic to display (optional — lists available topics if omitted) | ### Topics | Topic | Description | | ------------------ | ---------------------------------------------------------------------------------------------------------- | | `security` | Local security toolkit — scanning, auditing, policy enforcement | | `scanning` | Remote SAST/SCA code analysis via Rafter API | | `commands` | Condensed command reference for all rafter commands | | `setup` | Setup instructions for all supported agent platforms | | `setup/` | Platform-specific setup (claude-code, codex, gemini, cursor, windsurf, aider, openclaw, continue, generic) | | `all` | Everything — full security + scanning + setup briefing | ### Examples ```bash theme={null} # List available topics rafter brief # Get the local security briefing rafter brief security # Platform-specific setup guide rafter brief setup/claude-code # For agents without native skill support — load context manually rafter brief security # save to memory/instructions rafter brief commands # save command reference # Pipe to a file for manual skill creation rafter brief scanning > ~/.agents/skills/rafter/SKILL.md ``` `rafter brief` works on any platform — use it to bootstrap agent knowledge when skill auto-install isn't available. *** ## `rafter mcp serve` Start an MCP server exposing Rafter security tools over stdio transport. Works with any MCP-compatible client. ```bash theme={null} rafter mcp serve [options] ``` ### Options | Flag | Description | Default | | -------------------- | ------------------------ | ------- | | `--transport ` | Transport type (`stdio`) | `stdio` | ### Tools Provided | Tool | Description | Required Params | | ------------------ | ------------------------------------- | --------------- | | `scan_secrets` | Scan for hardcoded secrets | `path` | | `evaluate_command` | Check if command is allowed by policy | `command` | | `read_audit_log` | Read audit log entries | (none) | | `get_config` | Read Rafter configuration | (none) | ### Resources Provided | URI | Description | | ----------------- | ------------------------------------------------------ | | `rafter://config` | Current Rafter configuration | | `rafter://policy` | Active security policy (merged `.rafter.yml` + config) | ### MCP Client Config ```json theme={null} { "rafter": { "command": "rafter", "args": ["mcp", "serve"] } } ``` See [MCP Integration](/guides/agent-security/mcp-integration) for platform-specific setup. *** ## `rafter hook pretool` PreToolUse hook handler for Claude Code. Reads tool input JSON from stdin, writes decision to stdout. ```bash theme={null} rafter hook pretool ``` Evaluates `Bash` tool calls against command policy and scans `Write`/`Edit` content for secrets. See [Claude Code Integration](/guides/agent-security/claude-code-integration) for setup. *** ## `rafter hook posttool` PostToolUse hook handler for Claude Code. Reads tool result JSON from stdin, logs security-relevant events to the audit log. ```bash theme={null} rafter hook posttool ``` Logs completed `Bash`, `Write`, and `Edit` tool executions with their outcome and risk level. Useful for auditing what an agent actually did (vs. what was blocked at pretool). See [Claude Code Integration](/guides/agent-security/claude-code-integration) for setup. *** ## `rafter policy export` Export Rafter security policy for agent platforms. ```bash theme={null} rafter policy export --format [--output ] ``` ### Options | Flag | Description | | ----------------- | ------------------------------------------------------------------------------ | | `--format ` | Target format: `claude` (Claude Code hooks JSON) or `codex` (Codex rules TOML) | | `--output ` | Write to file instead of stdout | *** ## `rafter completion` Generate shell completion scripts for `rafter`. ```bash theme={null} rafter completion ``` ### Arguments | Argument | Description | | --------- | -------------------------------------- | | `` | Target shell: `bash`, `zsh`, or `fish` | ### Setup ```bash theme={null} # Bash — add to ~/.bashrc eval "$(rafter completion bash)" # Zsh — add to ~/.zshrc eval "$(rafter completion zsh)" # Fish — saves directly to completions directory rafter completion fish ``` *** ## Global Flags Available on all commands: | Flag | Description | | --------------- | ------------------------ | | `-h, --help` | Display help for command | | `-V, --version` | Output version number | *** ## Environment Variables | Variable | Description | | --------------------- | ------------------------------------------------------------------ | | `RAFTER_API_KEY` | API key for backend scanning | | `RAFTER_GITHUB_TOKEN` | GitHub PAT for private repo scanning (needs `Contents:Read` scope) | | `RAFTER_CONFIG_PATH` | Custom config file location | *** ## File Locations | Path | Description | | ------------------------------------------------------- | --------------------------------------------------------------------------------- | | `~/.rafter/config.json` | Configuration file | | `~/.rafter/audit.jsonl` | Audit log (JSONL format, see [Audit Log](/guides/agent-security/audit-log)) | | `~/.rafter/bin/` | Binary tools (Betterleaks, etc.) | | `~/.rafter/patterns/` | Custom secret patterns (`*.txt` or `*.json`) | | `~/.rafter/.rafterignore` | Findings suppression rules (path globs, optional `:pattern-name` qualifier) | | `.rafter.yml` | Project-level policy file (see [Policy File](/guides/agent-security/policy-file)) | | `~/.openclaw/workspace/skills/rafter-security/SKILL.md` | OpenClaw skill file (canonical ClawHub path; v0.8.0+) | *** ## Exit Codes ### Local Security (`rafter agent *`, `rafter secrets`) | Code | Meaning | | ---- | ----------------------------------------------------------- | | `0` | Success / no secrets found | | `1` | Error or secrets found | | `2` | Runtime error (path not found, not a git repo, invalid ref) | ### Remote Code Analysis (`rafter run`, `rafter get`, `rafter usage`) | Code | Meaning | | ---- | ------------------------------------------------- | | `0` | Success | | `1` | General error | | `2` | Scan not found (HTTP 404) | | `3` | Quota exhausted (HTTP 429 or 403 scan-mode limit) | | `4` | Insufficient scope / forbidden (HTTP 403) | *** ## Support * Documentation: [docs.rafter.so](https://docs.rafter.so) * GitHub: [rafter-cli/issues](https://github.com/raftersecurity/rafter-cli/issues) * Support: [rafter.so/help](https://rafter.so/help) # Secret Scanning Source: https://docs.rafter.so/guides/agent-security/secret-scanning Detect secrets in your code before they leak # Secret Scanning Rafter scans your code for secrets and credentials to prevent accidental leaks. ## Quick Start Scan a directory for secrets: ```bash theme={null} rafter secrets . ``` > **Note:** `rafter agent scan` still works but is deprecated — it will be removed in a future major version. ## Detected Secret Types Rafter detects 21+ types of secrets: * AWS Access Keys & Secret Keys * Google API Keys & OAuth credentials * Azure credentials * GitHub Personal Access Tokens * GitHub OAuth Tokens * GitHub App Tokens * GitHub Refresh Tokens * Stripe API Keys (live & restricted) * Slack Tokens & Webhooks * Twilio API Keys * npm Access Tokens * PyPI API Tokens * Database connection strings (postgres, mysql, mongodb) * Private keys (RSA, DSA, EC, OpenSSH) * JWT tokens * Generic API keys ## Usage Examples ### Scan Specific File ```bash theme={null} rafter secrets ./config.js ``` ### Scan Directory ```bash theme={null} rafter secrets ./src ``` ### Quiet Mode (CI/CD) Only output if secrets are found: ```bash theme={null} rafter secrets --quiet ``` Exits with code `1` if secrets found, perfect for CI pipelines. ### JSON Output Get machine-readable results: ```bash theme={null} rafter secrets --json > scan-results.json ``` ### Watch Mode Watch a path for file changes and re-scan automatically: ```bash theme={null} rafter secrets --watch . ``` Findings are printed inline and logged to `audit.jsonl` in real time. Press Ctrl+C to stop. Watch mode does not exit on findings — it keeps watching. Requires `chokidar` (Node, bundled) or `watchdog` (Python: `pip install watchdog`). ### Diff Scanning Scan only files changed since a git ref: ```bash theme={null} # Scan changes since last commit rafter secrets --diff HEAD~1 # Scan changes since a branch point rafter secrets --diff main # Scan changes since a tag rafter secrets --diff v1.0.0 ``` Useful for CI pipelines that only need to check new or modified files. ## Output Format When secrets are found, Rafter shows: ``` ⚠️ Found secrets in 1 file(s): 📄 src/config.js 🔴 [CRITICAL] AWS Access Key ID Location: Line 12 Pattern: AWS Access Key ID detected Redacted: AKIA************MPLE 🔴 [CRITICAL] GitHub Personal Access Token Location: Line 18 Pattern: GitHub Personal Access Token detected Redacted: ghp_****************************stuv ``` ### Severity Levels * 🔴 **Critical**: Immediate security risk (AWS keys, database passwords) * 🟠 **High**: Significant risk (generic API keys, bearer tokens) * 🟡 **Medium**: Moderate risk (connection strings without credentials) * 🟢 **Low**: Low risk (public keys, non-sensitive patterns) ## Smart Redaction Rafter uses smart redaction to show context without exposing secrets: * **Short secrets** (≤8 chars): Fully redacted (`********`) * **Long secrets** (>8 chars): Show first 4 and last 4 characters Example: `AKIAIOSFODNN7EXAMPLE` → `AKIA************MPLE` ## Pre-Commit Scanning Integrate with git commits: ```bash theme={null} # Before committing rafter secrets # Or use rafter agent exec (scans automatically) rafter agent exec "git commit -m 'Add feature'" ``` ## Excluding Files Rafter automatically skips: * Binary files (images, PDFs, executables) * Build directories (`node_modules`, `dist`, `build`, `.next`) * Version control (`.git`) * IDE folders (`.vscode`, `.idea`) ## CI/CD Integration ### GitHub Actions ```yaml theme={null} - name: Scan for secrets run: | npm install -g @rafter-security/cli rafter secrets --quiet ``` Exit code `1` will fail the pipeline if secrets are detected. ### GitLab CI ```yaml theme={null} scan-secrets: script: - npm install -g @rafter-security/cli - rafter secrets --quiet ``` ## Audit Trail All scans are logged to `~/.rafter/audit.jsonl`: ```bash theme={null} # View recent scans rafter agent audit --event scan_executed # View secret detections rafter agent audit --event secret_detected ``` ## False Positives If you encounter false positives: 1. **Exclude patterns** via config: ```bash theme={null} rafter agent config set agent.patterns.exclude '["test_key_*"]' ``` 2. **Report issues**: Help improve detection at [rafter-cli/issues](https://github.com/raftersecurity/rafter-cli/issues) ## Advanced Usage ### Scan with Custom Patterns Define custom patterns in `.rafter.yml`: ```yaml theme={null} scan: custom_patterns: - name: "Internal API Key" regex: "INTERNAL_[A-Z0-9]{32}" severity: critical ``` See [Policy File](/guides/agent-security/policy-file) for full configuration options. ### Engine Selection Rafter ships two scan engines, selectable via `--engine`: ```bash theme={null} rafter secrets --engine patterns # built-in regex (21+ patterns) rafter secrets --engine betterleaks # Betterleaks binary (more patterns; v0.8.0+) rafter secrets --engine auto # default: try Betterleaks, fall back to patterns ``` Install Betterleaks (the gitleaks successor maintained by the same authors) via `rafter agent init --with-betterleaks` for enhanced detection. ### Respecting `.gitignore` When the scan target sits inside a git work tree, Rafter honors `.gitignore` by default — files the repo has excluded (build outputs, vendored deps, scratch envs) are not scanned. Every gitignore semantic git itself supports is honored: nested `.gitignore` files, negations, `.git/info/exclude`, and the configured global excludes file. ```bash theme={null} rafter secrets . # default — respects .gitignore rafter secrets . --no-gitignore # scan everything, ignore .gitignore ``` Scans against directories outside a git work tree (a plain unversioned folder) fall back to scanning every candidate file, since there's no work tree for the filter to consult. The `betterleaks` engine has always honored `.gitignore` (gitleaks ancestry); the built-in `patterns` engine reached parity in the same release that introduced `--no-gitignore`. ## Best Practices 1. Run `rafter secrets` before every commit 2. Configure pre-commit hooks for automation 3. Use `--quiet` mode in CI/CD pipelines 4. Review audit logs regularly 5. Report false positives to improve accuracy ## Next Steps Learn about safe command execution Complete CLI command reference # Troubleshooting Source: https://docs.rafter.so/guides/agent-security/troubleshooting Common installation and runtime issues with Rafter local security # Troubleshooting ## Quick diagnostic: `rafter agent verify` Before diving into individual issues, run the built-in health check: ```bash theme={null} rafter agent verify ``` This validates your config, Betterleaks binary, and all 8 supported agent integrations in one pass. If something is broken, the output tells you exactly what failed and how to fix it. Add `--probe` to confirm hooks actually fire (not just that the file is on disk). *** ## Python environment issues on Linux **Symptom:** `pip install rafter-cli` fails with errors about missing `ensurepip`, `venv`, or `pip`. **Cause:** Minimal Linux installations (Ubuntu, Debian, containers) often ship with a bare Python that lacks `pip` and `venv`. **Fix — install the missing system packages:** ```bash Ubuntu / Debian theme={null} sudo apt update && sudo apt install -y python3 python3-pip python3-venv ``` ```bash Fedora / RHEL theme={null} sudo dnf install python3 python3-pip ``` ```bash Alpine (containers) theme={null} apk add python3 py3-pip ``` **Verify your Python version** (must be 3.10+): ```bash theme={null} python3 --version pip3 --version ``` If you see `python3: command not found` after installing, check that `/usr/bin/python3` exists. Some distros require `python3.x` (e.g., `python3.12`) — create a symlink or use the full path. *** ## `rafter --help` crashes on fresh install **Symptom:** Running any `rafter` command immediately crashes with a traceback referencing Click or Typer. **Cause:** Click 8.3 changed internal APIs in a way that broke Typer 0.13.x (`Parameter.make_metavar()` signature changed). This caused an immediate crash on any `rafter` invocation. **Fix:** Upgrade the `rafter-cli` package, which bundles a compatible Typer version: ```bash theme={null} pip install --upgrade rafter-cli ``` If you're pinning Typer in your own project and see this conflict: ```bash theme={null} pip install "typer>=0.13" ``` **Verify the fix:** ```bash theme={null} rafter --version rafter --help ``` *** ## Betterleaks not found after `rafter agent init` **Symptom:** After initialization, `rafter secrets` outputs a warning like: > **Note:** `rafter agent scan` still works but is deprecated — it will be removed in a future major version. ``` Betterleaks not found — using pattern-based scanning (21 patterns) ``` **Cause:** Betterleaks (the gitleaks successor maintained by the same authors, adopted in v0.8.0) is an optional enhancement. When the binary is not on your `PATH`, Rafter falls back to its built-in pattern engine (21 secret patterns covering API keys, tokens, and private keys). All core functionality still works. **If you want full Betterleaks coverage**, the easiest path is to let Rafter manage the binary for you: ```bash theme={null} rafter agent init --with-betterleaks # or, for an existing install: rafter agent update-betterleaks ``` That downloads the pinned, hash-verified binary to `~/.rafter/bin/betterleaks`. Or install it system-wide: ```bash macOS (Homebrew) theme={null} brew install betterleaks ``` ```bash Linux (binary) theme={null} # Download the latest release from https://github.com/betterleaks/betterleaks/releases # Example for Linux amd64: curl -sSL https://github.com/betterleaks/betterleaks/releases/latest/download/betterleaks_linux_amd64.tar.gz \ | tar -xz -C /usr/local/bin betterleaks ``` ```bash Go install theme={null} go install github.com/betterleaks/betterleaks/v1@latest ``` After installing, verify with: ```bash theme={null} rafter agent verify # Should print: ✓ Betterleaks available on PATH (or at ~/.rafter/bin/betterleaks) ``` **Upgrading from a pre-0.8.0 install?** If you previously ran `--with-gitleaks`, you'll have a leftover `~/.rafter/bin/gitleaks`. `rafter agent verify` and `rafter agent status` detect this and tell you to run `rafter agent update-betterleaks` — they no longer error out on the legacy binary. The CLI flags `--with-gitleaks`, `--engine gitleaks`, and `rafter agent update-gitleaks` were removed in v0.8.0; use the `-betterleaks` equivalents. `rafter agent init` prints detailed diagnostics when the Betterleaks binary fails to load — including binary architecture, system platform, and libc type (glibc vs musl). This helps diagnose binary incompatibilities on Linux. **If you prefer pattern-only scanning** (no Betterleaks), simply omit `--with-betterleaks` during init, or pass `--engine patterns` when scanning: ```bash theme={null} rafter secrets . --engine patterns ``` *** ## OpenClaw skill not installed after `rafter agent init` **Symptom:** After running `rafter agent init`, OpenClaw does not receive the Rafter skill. The init output does not mention OpenClaw. **Cause:** `rafter agent init` detects OpenClaw by checking for the `~/.openclaw` directory. If OpenClaw is installed but that directory does not exist yet (e.g., OpenClaw has never been run), detection fails silently. **Fix — run OpenClaw at least once first**, then re-initialize: ```bash theme={null} # Start OpenClaw so it creates ~/.openclaw openclaw start # Stop it, then re-run Rafter init openclaw stop rafter agent init ``` **Verify the skill was installed:** ```bash theme={null} ls ~/.openclaw/workspace/skills/rafter-security/SKILL.md ``` **If the directory exists but skill is still missing**, force reinstall: ```bash theme={null} rafter agent init --force ``` Then restart OpenClaw to load the skill: ```bash theme={null} openclaw restart ``` **Check that the integration is enabled in config:** ```bash theme={null} rafter agent config get agent.environments.openclaw.enabled # Should return: true ``` If it returns `false`, enable it manually: ```bash theme={null} rafter agent config set agent.environments.openclaw.enabled true ``` As of v0.5.2, `rafter agent init` surfaces detailed error context when OpenClaw skill installation fails—including source path, destination path, and the underlying exception. Check the init output for actionable guidance. *** ## Still stuck? * Documentation: [docs.rafter.so](https://docs.rafter.so) * GitHub Issues: [rafter-cli/issues](https://github.com/raftersecurity/rafter-cli/issues) * Support: [rafter.so/help](https://rafter.so/help) # Basics Source: https://docs.rafter.so/guides/basics Learn the fundamentals of using the Rafter CLI for security scanning workflows. ## Getting Started with the CLI The Rafter CLI provides a simple command-line interface for running security scans on your repositories. This guide covers the essential concepts and basic workflows. ## Core Concepts ### How Do I get My API Key? To use the Rafter CLI or API, you need an API key. [Sign up](https://rafter.so/) and get your API key from your [account page](https://rafter.so/account). Your API key starts with `RF` and should be kept secure. Never commit it to version control (e.g. GitHub). Use [environment variables](https://configu.com/blog/environment-variables-how-to-use-them-and-4-critical-best-practices/) instead. ### What Does the CLI Do? The Rafter CLI allows you to: * **Run security audits** of your remote repositories (`rafter run` or `rafter scan`) — agentic deep dives backed by a full SAST/SCA toolchain * **Choose scan depth** with scan modes — `fast` for rapid SAST/SCA analysis, `plus` for professional-grade agentic audits that trace data flows and reason about business logic * **Retrieve results** from completed scans * **Check usage** and quota information * **Automate security** workflows in scripts and CI/CD * **Enforce security locally** with secret scanning and policy enforcement ### How Does Scanning Work? The CLI scans **remote repositories** (e.g., on GitHub), not your local files. It can use your local Git configuration to determine which repository and branch to scan. When you run a scan: 1. The CLI detects your repository and branch from Git 2. It uploads your code securely to Rafter's analysis engine 3. The engine audits your code the way a professional penetration tester would — following data flows across files, reasoning about authentication and authorization logic, and identifying vulnerabilities that pattern-matching alone cannot catch — backed by industry-standard SAST, SCA, and secret-detection tooling 4. Your code is deleted from Rafter's engine immediately after analysis 5. Results are returned and displayed in your terminal ### Scan Modes Rafter supports two scan modes, selected with the `--mode` (or `-m`) flag: | Mode | Flag | Description | | -------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Fast** | `--mode fast` (default) | Rapid security scan using industry-standard SAST, secret detection, and dependency checks combined with Rafter's proprietary analysis. | | **Plus** | `--mode plus` | Everything in fast, plus agentic deep-dive passes that analyze your codebase the way a professional cybersecurity auditor would — tracing data flows, reasoning about business logic, and surfacing vulnerabilities that static rules miss. Takes longer but produces significantly more detailed findings. | ```bash theme={null} # Fast scan (default — same as omitting --mode) rafter run --format md --mode fast # Plus scan for deeper analysis rafter run --format md --mode plus # Short flag rafter run --format md -m plus ``` ## Basic Commands Make sure you configure an environment variable or pass in your `RAFTER API_KEY` with the flag `--api-key` or `-k` (more details below). ### Start a Scan with `rafter run` The most common command for running security scans are below. They auto-detect the repo and branch and require an environment variable `RAFTER_API_KEY`: ```bash theme={null} # Basic scan (defaults to fast mode) rafter run --format md # `scan` is an alias for `run` rafter scan --format md # Run a Plus scan for deeper coverage with additional agent passes rafter run --format md --mode plus # Save results to a file rafter run --format md > security-report-$(date +%Y-%m-%d-%H-%M-%S).md # Scan specific repository and branch rafter run --format md --repo myorg/myrepo --branch main # Non-interactive scan (don't wait for completion) rafter run --format md --skip-interactive ``` ### Retrieve Results with `rafter get` Get results from a completed scan: ```bash theme={null} # Get scan results by ID rafter get # Wait for scan completion rafter get --interactive # Get results in Markdown format rafter get --format md # Save results to a file rafter get --format md --interactive > security-report-$(date +%Y-%m-%d-%H-%M-%S).md ``` ### Check Quota with `rafter usage` Check your API usage and remaining scans: ```bash theme={null} rafter usage ``` ## Basic Workflow Here's a typical workflow for running your first scan: ### 1. Install the CLI ```bash npm theme={null} npm install -g @rafter-security/cli ``` ```bash pnpm theme={null} pnpm add -g @rafter-security/cli ``` ```bash yarn theme={null} yarn global add @rafter-security/cli ``` ```bash pip theme={null} pip install rafter-cli ``` **Python 3.10+ required for pip installs.** Verify your version: ```bash theme={null} python3 --version # Must be 3.10 or higher ``` On Ubuntu/Debian, Python and pip may not be installed by default: ```bash theme={null} sudo apt update && sudo apt install -y python3 python3-pip python3-venv ``` On Fedora/RHEL: `sudo dnf install python3 python3-pip`. macOS: `brew install python`. Windows: install from [python.org](https://python.org) — pip is included. ### 2. Set Your API Key ```bash theme={null} export RAFTER_API_KEY="RFabc-your-api-key-here" ``` ### 3. Run a Scan ```bash theme={null} # Navigate to your repository cd /path/to/your/repo # Run the scan rafter run --format md ``` ### 4. Check Results The CLI will display scan results directly in your terminal, showing: * **Vulnerabilities found** with severity levels * **File locations** where issues were detected * **Recommendations** for fixing the issues ## Output Formats The CLI supports multiple output formats for different use cases: ### JSON Format (Default) ```bash theme={null} rafter get --format json ``` JSON output is perfect for: * **Automation** and scripting * **Integration** with other tools * **Parsing** with tools like `jq` We'll go into detail on how to process these results in the [Output Processing](/guides/advanced#output-processing) section. ### Markdown Format ```bash theme={null} rafter get --format md ``` Markdown output is great for: * **Human-readable** reports * **Documentation** and sharing * **GitHub issues** and pull requests * **LLM-assisted remediation** — the report includes role-priming, step-by-step instructions, and structured issue metadata **Example output** (truncated): ```markdown theme={null} You are a senior application-security, web-application, and cloud-reliability engineer. Implement production-grade solutions that scale. Never mock data, suppress linter security rules, or shortcut the fix. Think step-by-step. # Security Issues and Vulnerabilities **Total Issues:** 2 This report contains 2 security issues found in the repository. Each issue requires attention and remediation. Proceed one-by-one, thinking step-by-step to understand and remediate each. ## Issues Summary ### Issue 1 **Rule ID:** a1b2c3d4 **File:** src/auth.js **Line:** 42 **Description:** Hardcoded API key detected ### Issue 2 **Rule ID:** e5f6a7b8 **File:** src/database.js **Line:** 78 **Description:** SQL injection vulnerability Please analyze these 2 security vulnerabilities and provide: 1. A comprehensive analysis of the security risks 2. Prioritized remediation steps 3. Code examples for fixes 4. Prevention strategies for future development ``` ## Next Steps Learn the fundamentals of using the Rafter CLI. Master advanced CLI features and automation. Build custom integrations with the REST API. Set up automated scanning in your pipelines. # CI/CD Integration Source: https://docs.rafter.so/guides/ci-cd Add Rafter security to your CI/CD pipelines — local secret scanning and remote code analysis with stable exit codes. ## Fastest Path: `rafter ci init` Auto-generate CI config for GitHub Actions, GitLab CI, or CircleCI: ```bash theme={null} rafter ci init # auto-detect platform rafter ci init --platform github # explicit rafter ci init --with-backend # include remote code analysis job (requires RAFTER_API_KEY) ``` This writes a ready-to-commit workflow file. Review it, push, done. *** ## Two CI Modes Rafter supports two approaches in CI. Choose based on whether you have a Rafter API key. ### Mode 1: Local Secret Scanning (no API key required) Uses `rafter secrets` — the fast, deterministic scanner that runs pattern matching and Betterleaks secret detection (v0.8.0+; gitleaks successor) directly on the runner. Same inputs, same findings, every time. ```yaml theme={null} - name: Rafter secret scan run: | npm install -g @rafter-security/cli rafter secrets . --json --quiet ``` Exit code `1` fails the pipeline if secrets are detected. No account or API key needed. **When to use:** Open-source projects, teams without a Rafter subscription, or any repo where fast secret scanning at commit time is enough. ### Mode 2: Backend Code Analysis (API key required) Uses `rafter run` to trigger the Rafter code analysis engine for full SAST coverage — a wider range of vulnerability classes beyond secrets. Your code is deleted immediately after the analysis engine completes. **When to use:** Teams with a Rafter subscription who want full SAST coverage on every push. See [Step 3 below](#step-3-create-github-workflow) for the complete workflow. *** ## Introduction Automated security scanning transforms security from an afterthought into a seamless part of your development workflow. Instead of remembering to run scans manually (and inevitably forgetting), your CI/CD pipeline automatically checks every commit and pull request for vulnerabilities. This guide shows you two approaches: * **Manual setup**: Step-by-step instructions for hands-on configuration * **AI-assisted setup**: Copy-paste workflows with AI prompts for rapid deployment I'd recommend skimming the manual setup first so you understand what's happening, then using the AI-assisted setup for a quick and easy setup. Plus, you'll learn how API keys work, why they're secure, and how to protect them properly in your CI/CD environment. If you're not familiar with GitHub Actions, you can learn more about them [here](https://docs.github.com/en/actions). ## Why Automated Security Scanning Matters ### The Manual Scanning Problem Manual security scanning has three critical flaws: 1. **Human Error**: Developers forget to run scans, especially under pressure 2. **Inconsistent Coverage**: Different team members use different tools or settings 3. **Late Detection**: Vulnerabilities are found after code reaches production ### The Automated Solution Automated scanning eliminates these problems by: * **Running on every push**: No forgotten scans * **Consistent configuration**: Same rules applied every time * **Early detection**: Vulnerabilities caught before deployment * **Build failure**: Critical issues block deployment automatically ## Understanding API Keys in CI/CD ### What Are API Keys? API keys are authentication tokens that allow automated tools to access services on your behalf. Think of them as digital keys that unlock specific capabilities—in this case, security scanning services like Rafter. ### Why API Keys Are Secure API keys are designed for programmatic access and include several security features: * **Scoped permissions**: Keys can only access specific services * **Usage tracking**: All API calls are logged and monitored * **Easy rotation**: Keys can be regenerated instantly if compromised * **Environment isolation**: Keys are stored separately from your code ### How GitHub Secrets Protect Your Keys GitHub Secrets provide enterprise-grade security for sensitive data: * **Encryption at rest**: Keys are encrypted when stored * **Encryption in transit**: Keys are encrypted when accessed * **Access control**: Only authorized workflows can use secrets * **Audit logging**: All secret access is logged ## Manual Setup: Step-by-Step Configuration ### Step 1: Choose Your Mode Refer to [Two CI Modes](#two-ci-modes) above. If you're using **local scan**, skip to [Step 3](#step-3-create-github-workflow) and use the local scan workflow. If you're using **backend scan**, continue with Step 2 to get your API key. ### Step 2: Get Your Rafter API Key *(Backend scan only — skip if using local scan.)* If you have an existing key saved to a safe place, copy it. Otherwise, generate a new key... Rafter protects your API keys by not storing them. You get access once, when you generate/refresh the key. Then, refreshing the key invalidates the previous key to keep it safe. It's a way to help you rotate keys, which is best practice. **Navigate to Account Settings** 1. Go to your Rafter account settings 2. Look for the "API Keys" section **Generate or Retrieve Key** 1. Click "Generate New API Key" or "Refresh API Key" 2. The key is automatically copied to your clipboard (it won't be shown/copiable again) > **API keys are sensitive credentials. Never commit them to your repository or share them in plain text.** **Add API Key to GitHub Secrets** 1. Navigate to your GitHub repository 2. Click "Settings" → "Secrets and variables" → "Actions" 3. Click "New repository secret" 4. **Name**: `RAFTER_API_KEY` 5. **Value**: Paste your API key 6. Click "Add secret" ### Step 3: Create GitHub Workflow **Create Workflow Directory** ```bash theme={null} mkdir -p .github/workflows ``` **Option A — Local Scan Workflow** (no API key) Create `.github/workflows/security-scan.yml`: ```yaml theme={null} # .github/workflows/security-scan.yml # No API key required. Runs pattern + Betterleaks secret scanning on the runner. name: Rafter Secret Scan on: push: branches: [ main ] pull_request: permissions: contents: read jobs: secret-scan: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Rafter secret scan run: | npm install -g @rafter-security/cli rafter secrets . --json --quiet ``` Exit code `1` fails the job automatically if secrets are detected. **Option B — Backend Code Analysis Workflow** (API key required) Create `.github/workflows/security-scan.yml`: ```yaml theme={null} # .github/workflows/security-scan.yml # # Prerequisites: # Add your Rafter API key as a GitHub repository secret: # Settings -> Secrets and variables -> Actions -> New repository secret # Name: RAFTER_API_KEY name: Rafter Code Analysis on: push: branches: [ main ] permissions: contents: read jobs: code-analysis: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Install Rafter CLI run: npm install -g @rafter-security/cli - name: Run code analysis env: RAFTER_API_KEY: ${{ secrets.RAFTER_API_KEY }} run: rafter run --format json --quiet > scan-results.json - name: Check for critical vulnerabilities run: | CRITICAL_COUNT=$(jq '.vulnerabilities | map(select(.level=="error")) | length' scan-results.json) if [ "$CRITICAL_COUNT" -gt 0 ]; then echo "Found $CRITICAL_COUNT critical vulnerabilities!" exit 1 fi echo "No critical vulnerabilities found" - name: Upload results uses: actions/upload-artifact@v4 if: always() with: name: security-scan-results path: scan-results.json retention-days: 30 ``` The CLI handles repo/branch auto-detection, polling, and retries — no manual curl loops needed. ### Step 4: Test Your Setup **Make a Test Commit** ```bash theme={null} git add .github/workflows/security-scan.yml git commit -m "Add automated security scanning" git push ``` **Check GitHub Actions** 1. Go to your repository's "Actions" tab 2. Look for the workflow 3. Verify it runs successfully ## AI-Assisted Setup Tell your AI assistant: ``` Set up Rafter security scanning for this repo. Run `rafter ci init --platform github` to generate the workflow, then commit it. If we have a RAFTER_API_KEY, use --with-backend for full SAST code analysis. Otherwise the local secret scan is fine. ``` Or generate it yourself: ```bash theme={null} rafter ci init --platform github --with-backend # Review .github/workflows/rafter-security.yml, then commit and push ``` ## Understanding the Workflow Components ### Trigger Configuration ```yaml theme={null} on: push: branches: [ main ] ``` This configuration ensures the analysis runs: * On every push to the main branch * Automatically, without manual intervention ### CLI-Based Code Analysis The backend workflow uses the Rafter CLI which handles auto-detection, polling, and retries: ```yaml theme={null} - name: Run code analysis env: RAFTER_API_KEY: ${{ secrets.RAFTER_API_KEY }} run: rafter run --format json --quiet > scan-results.json ``` The CLI: * **Auto-detects repo and branch** from the git checkout * **Polls until complete** — no manual loop needed * **Returns structured JSON** with consistent schema and documented exit codes ### Exit Codes The CLI uses stable exit codes that CI pipelines can rely on: | Code | Meaning | CI Action | | ---- | ------------------------------------------------- | ------------------------- | | 0 | Success — analysis completed | Proceed | | 1 | General error | Fail build | | 2 | Scan not found (HTTP 404) | Check scan ID | | 3 | Quota exhausted (HTTP 429 or 403 scan-mode limit) | Alert / back off | | 4 | Insufficient scope / forbidden (HTTP 403) | Check API key permissions | Results are also available in your Rafter dashboard. ### Vulnerability Checking ```yaml theme={null} - name: Check for critical vulnerabilities run: | CRITICAL_COUNT=$(cat scan-results.json | jq '.vulnerabilities | map(select(.level=="error")) | length') if [ $CRITICAL_COUNT -gt 0 ]; then echo "Found $CRITICAL_COUNT critical vulnerabilities!" exit 1 else echo "No critical vulnerabilities found" fi ``` This critical step: * Parses scan results using jq * Counts error-level vulnerabilities * Fails the build if critical issues are found * Provides clear feedback to developers ## Advanced Configuration Options While we've outlined some powerful use cases below, see our documentation for more advanced configuration options: [Rafter CI/CD Documentation](/api-reference/endpoint/usage). ### Customizing Triggers You can customize when Rafter runs: ```yaml theme={null} # Scan on all branches on: [push, pull_request] # Scan only on specific file changes on: push: paths: - 'src/**' - 'package.json' # Schedule regular scans on: schedule: - cron: '0 2 * * 1' # Every Monday at 2 AM ``` ### Adjusting Failure Thresholds Modify the vulnerability checking logic: ```bash theme={null} # Fail on warnings and errors WARNING_COUNT=$(cat scan-results.json | jq '.vulnerabilities | map(select(.level=="warning" or .level=="error")) | length') # Fail only on specific vulnerability types (using hashed rule IDs) CRITICAL_COUNT=$(cat scan-results.json | jq '.vulnerabilities | map(select(.ruleId | startswith("R-"))) | length') # Fail on specific vulnerability patterns SQL_INJECTION_COUNT=$(cat scan-results.json | jq '.vulnerabilities | map(select(.message | contains("SQL injection"))) | length') ``` ### Adding Notifications Integrate with Slack, Discord, or email: ```yaml theme={null} - name: Notify on failure if: failure() uses: 8398a7/action-slack@v3 with: status: failure text: "Security scan failed: ${{ github.event.head_commit.message }}" ``` ## Troubleshooting Common Issues ### API Key Not Found **Error**: `Error: RAFTER_API_KEY environment variable not set` **Solution**: 1. Verify the secret exists in GitHub repository settings 2. Check the secret name matches exactly: `RAFTER_API_KEY` 3. Ensure the workflow uses `${{ secrets.RAFTER_API_KEY }}` ### Scan Request Fails **Error**: `curl: (22) The requested URL returned error: 401` or `curl: (22) The requested URL returned error: 400` **Solution**: * **401 Unauthorized**: Check your API key is valid and not expired * **400 Bad Request**: Verify repository name format (should be owner/repo) * **Network issues**: The `-fsS` flags will cause curl to fail silently on HTTP errors * **Branch name issues**: Ensure `${{ github.ref_name }}` returns the correct branch name ### Scan Status Issues **Error**: Scan stuck in "processing" or "pending" status **Solution**: * **Timeout handling**: The workflow automatically fails after 10 minutes * **Status checking**: Verify the API returns valid status values (completed, failed, processing, pending) * **Polling frequency**: Adjust `sleep 10` if scans typically take longer * **API rate limits**: Check if you're hitting API rate limits ### Scan Results Not Found **Error**: `scan-results.json: No such file or directory` **Solution**: * **Check scan completion**: Ensure the scan reached "completed" status * **Verify file output**: The workflow saves results to `scan-results.json` and `scan-results.md` * **API response format**: Confirm the API returns results in the expected JSON format * **Error handling**: The `set -euo pipefail` ensures the script fails if curl commands fail ## Security Best Practices ### API Key Management * **Rotate keys regularly**: Generate new keys every 90 days * **Monitor usage**: Check API key usage logs for anomalies * **Use least privilege**: Only grant necessary permissions * **Never log keys**: Ensure keys don't appear in logs or outputs ### Workflow Security * **Pin action versions**: Use specific commit SHAs instead of tags * **Review permissions**: Limit workflow permissions to minimum required * **Audit regularly**: Review workflow changes and access patterns * **Use trusted sources**: Only use official GitHub Actions ### Repository Security * **Enable branch protection**: Require status checks before merging * **Use required reviewers**: Require security team review for workflow changes * **Monitor secrets**: Regularly audit repository secrets * **Enable security alerts**: Use GitHub's security features ## Measuring Success ### Key Metrics to Track * **Scan Coverage**: Percentage of commits scanned * **Detection Rate**: Vulnerabilities found per scan * **Fix Time**: Average time from detection to resolution * **False Positive Rate**: Incorrect vulnerability reports ### Success Indicators * Zero critical vulnerabilities in production deployments * Consistent scan execution across all branches * Rapid vulnerability resolution (under 24 hours) * Developer adoption of security-first practices ## Conclusion Whether you use the local secret scanner or the full code analysis engine, the result is the same: security coverage on every commit with stable exit codes and structured output that CI pipelines can act on. Start with `rafter ci init`, customize as needed, and let the code analysis engine do the work. # Quick Reference Source: https://docs.rafter.so/guides/quick-reference Go-to CLI commands for Rafter security. ## Remote Code Analysis For more detailed guides, see the [basic](/guides/basics) and [advanced](/guides/advanced) guides. ### Scan a Repo ```bash theme={null} rafter run --format md # `scan` is an alias for `run` rafter scan --format md ``` ### Scan Modes ```bash theme={null} # Fast scan (default) rafter run --format md --mode fast # Plus scan (agentic deep-dive — audits code like a professional cybersecurity analyst) rafter run --format md --mode plus rafter run --format md -m plus ``` ### Scan a Private Repo ```bash theme={null} # Pass a GitHub PAT directly rafter run --github-token ghp_... --format md # Or use an environment variable export RAFTER_GITHUB_TOKEN=ghp_... rafter run --format md ``` ### Scan a Specific Repo and Branch ```bash theme={null} rafter run --repo myorg/myrepo --branch main --format md ``` ### Scan in the Background ```bash theme={null} rafter run --skip-interactive ``` ### Save Report to File ```bash theme={null} rafter run --format md > security-report-$(date +%Y-%m-%d-%H-%M-%S).md ``` ### Count Vulnerabilities ```bash theme={null} rafter run | jq -r '.vulnerabilities | length // 0' # Count critical vulnerabilities rafter run | jq '[.vulnerabilities[] | select(.level == "error")] | length' ``` ### Check Quota ```bash theme={null} rafter usage ``` *** ## Local Security Toolkit Local security features. No API key required. ### Initialize ```bash theme={null} rafter agent init # config only, detect agents rafter agent init --risk-level aggressive # set risk level rafter agent init --with-claude-code # install Claude Code integration rafter agent init --all # install all detected integrations rafter agent init --interactive # guided setup with prompts ``` ### Project Setup ```bash theme={null} rafter agent init-project # generate instruction files for all platforms rafter agent init-project --only claude-code,cursor # specific platforms only rafter agent init-project --list # preview without writing ``` ### Secret Scanning ```bash theme={null} rafter secrets . # scan current directory (respects .gitignore by default) rafter secrets --staged # scan git staged files only rafter secrets --json # output as JSON rafter secrets --engine betterleaks # force Betterleaks binary (default: auto-pick if installed) rafter secrets --watch # watch for changes and re-scan rafter secrets --no-gitignore # scan everything, even files matched by .gitignore ``` ### Command Execution ```bash theme={null} rafter agent exec "git push" # execute with risk assessment rafter agent exec "rm -rf /" --force # bypass approval (not recommended) ``` ### Skill Auditing ```bash theme={null} rafter agent audit-skill path/to/skill.md ``` ### Pre-Commit Hook ```bash theme={null} rafter agent install-hook # current repo only rafter agent install-hook --global # all repos ``` ### Audit Logs ```bash theme={null} rafter agent audit # view recent events rafter agent audit --last 50 # last 50 events rafter agent audit --event secret_detected # filter by event type rafter agent audit --agent claude-code # filter by agent rafter agent audit --since 2026-02-01 # filter by date ``` ### Security Briefings ```bash theme={null} rafter brief # list available topics rafter brief security # local security briefing rafter brief setup/claude-code # platform-specific setup guide rafter brief commands # condensed command reference rafter brief all # everything ``` ### Configuration ```bash theme={null} rafter agent config show # view all config rafter agent config get agent.riskLevel # get a value rafter agent config set agent.riskLevel aggressive # set a value ``` *** ## Exit Codes ### Rafter Code Analysis (`rafter run`, `rafter get`, `rafter usage`) | Code | Meaning | | ---- | ------------------------------------------------- | | 0 | Success | | 1 | General error | | 2 | Scan not found (HTTP 404) | | 3 | Quota exhausted (HTTP 429 or 403 scan-mode limit) | | 4 | Insufficient scope / forbidden (HTTP 403) | ### Local Security (`rafter secrets`) | Code | Meaning | | ---- | ----------------------------------------------------------- | | 0 | No secrets found | | 1 | Secrets detected | | 2 | Runtime error (path not found, not a git repo, invalid ref) | # Sites Source: https://docs.rafter.so/guides/sites Monitor live applications for exposed backends, DNS misconfiguration, SEO, and accessibility issues with the Rafter CLI. ## What Are Sites? Sites are Rafter's live-application security monitoring feature. Instead of scanning your source code (that's what `rafter run` / `rafter scan` do — see [CLI Basics](/guides/basics)), Sites continuously monitor a **live, deployed domain** for: * Exposed backends and misconfigured services * DNS misconfiguration * SEO issues * Accessibility issues Register a site once, then re-scan it any time — after a deploy, on a schedule, or before a launch. Your API key starts with `RF` and should be kept secure. Never commit it to version control (e.g. GitHub). Use [environment variables](https://configu.com/blog/environment-variables-how-to-use-them-and-4-critical-best-practices/) instead. Sites require an API key with the `read-and-scan` scope to create sites or trigger scans, or the `read` scope to list and check them. A `read-and-scan` key can do both — that scope implies `read`. ## Basic Commands Make sure you configure an environment variable or pass in your `RAFTER_API_KEY` with the flag `--api-key` or `-k` (more details below). ### Register a Site with `rafter sites create` Registers a site and kicks off its first scan: ```bash theme={null} rafter sites create https://example.com ``` ### Re-Scan a Site with `rafter sites scan` Accepts either the site's id (from `rafter sites list` or `rafter sites create`) or its URL: ```bash theme={null} # By project id rafter sites scan b1b2c3d4-e5f6-7890-abcd-ef1234567890 # By URL rafter sites scan https://example.com ``` ### List Your Sites with `rafter sites list` ```bash theme={null} rafter sites list # Paginate rafter sites list --limit 10 --offset 10 # Include archived sites rafter sites list --include-archived ``` ### Check a Site's Status with `rafter sites get` Returns the site's status, latest run, and a findings summary: ```bash theme={null} rafter sites get b1b2c3d4-e5f6-7890-abcd-ef1234567890 ``` ## Command Reference | Command | Description | | ------------------------------------------------------------- | ----------------------------------------------------- | | `rafter sites create ` | Register a site and trigger its first scan | | `rafter sites scan ` | Trigger a re-scan of an existing site | | `rafter sites list [--limit] [--offset] [--include-archived]` | List your sites, paginated | | `rafter sites get ` | Get a site's status, latest run, and findings summary | All `rafter sites` commands support: | Flag | Description | | ----------------- | ---------------------------------------------------------------------- | | `-k`, `--api-key` | Pass your API key directly instead of reading it from `RAFTER_API_KEY` | | `-f`, `--format` | Output format: `json` (default) or `md` | | `--quiet` | Suppress non-essential output | ## Output Formats ```bash theme={null} # JSON (default) — for automation and scripting rafter sites get --format json # Markdown — for human-readable reports rafter sites get --format md ``` ## Error Handling The Sites CLI reads the actual `error` field from API responses rather than assuming what a status code means — this differs from `rafter run`'s error handling, which treats every 403 as a quota issue. | Exit Code | Meaning | | --------- | --------------------------------------- | | 0 | Success | | 1 | General error | | 2 | Not found or not owned (HTTP 404) | | 3 | Rate limited (HTTP 429) | | 4 | Wrong scope or limit reached (HTTP 403) | ## Example Workflow ```bash theme={null} # 1. Register a site and kick off its first scan export RAFTER_API_KEY="RFabc-your-api-key-here" rafter sites create https://example.com # 2. Check status until the scan completes rafter sites get # 3. Re-scan after fixing an issue rafter sites scan # 4. List all your monitored sites rafter sites list ``` ## API Reference For the underlying REST API, see the [Sites endpoints](/api-reference/endpoint/static/sites/create) in the API reference. ## Next Steps Learn the fundamentals of using the Rafter CLI. Master advanced CLI features and automation. Build custom integrations with the REST API. Set up automated scanning in your pipelines. # Introduction Source: https://docs.rafter.so/index Rafter is the way to shift security left — into your AI coding agent's feedback loop. Secret scanning, command interception, policy enforcement, extension auditing, audit logging, and remote SAST/SCA — one CLI, every agent. ## Welcome to Rafter **Rafter is the way to shift security left.** It moves vulnerability detection, secret scanning, dependency auditing, and policy enforcement out of post-merge review queues and into your AI coding agent's feedback loop — where mistakes get caught while code is still being written, not after it ships. Rafter sits between your agent and your codebase, scanning for secrets, intercepting dangerous commands, evaluating extensions, and (with an API key) running deep SAST/SCA passes through the Code Security Engine. One command installs across every supported agent. Free to start, MIT-licensed, works offline. Install Rafter and put security inside your agent's loop in under a minute. ## The Shift-Left Loop Rafter's job is to make security a first-class signal your agent consults at every step: Your agent anticipates risks before code is written — auth, data flow, permissions, external integrations. Sensitive logic gets scanned the moment it appears. Secrets never reach git. Risky dependencies are flagged on install. Your agent runs Rafter against the diff and explains tradeoffs as part of its review pass. A final scan with the Code Security Engine catches anything the local pass missed — SAST, SCA, agentic deep dive. ## Two Layers, One Loop Lives inside your agent's session. Secret scanning, command interception, policy enforcement, extension auditing, MCP server, pre-commit hooks, and audit logging. Works offline. Supports Claude Code, Codex CLI, Gemini CLI, Cursor, Windsurf, Continue.dev, Aider, and OpenClaw. Hand your agent an API key and it can run deep SAST, SCA, secret detection, and agentic deep-dive audits whenever it needs to — tracing data flows, reasoning about business logic, cross-referencing with static analysis. Structured reports the agent can act on directly. ## Agent-First Design JSON to stdout, status to stderr, documented exit codes. Agents classify outcomes without parsing prose. Same inputs produce the same findings for a given CLI version. No flaky scans, no surprises. `rafter agent init --all` auto-detects and installs across every supported agent and IDE. ## Platform Integrations PreToolUse hooks and security skills. Security skills for OpenAI Codex. Cursor, Windsurf, Gemini CLI, Continue.dev, Aider, Claude Desktop, Cline. ## Quick Start ```bash theme={null} npm install -g @rafter-security/cli rafter agent init --all ``` That's it. Your agents now have secret scanning, command interception, and policy enforcement. Detailed setup including remote scanning, CI/CD, and API access. ## More Resources All commands at a glance. Programmatic scanning for custom integrations. GitHub Actions, GitLab CI, CircleCI. # Quick Start Source: https://docs.rafter.so/quickstart Wire Rafter into your AI coding agent's feedback loop and run your first scan in under a minute. The fastest path to shifting security left: install the CLI, hand your agent an API key, and let it consult Rafter on every meaningful change. ## Get started in three steps Install the Rafter security CLI using your preferred package manager. ```bash npm theme={null} npm install -g @rafter-security/cli ``` ```bash pnpm theme={null} pnpm add -g @rafter-security/cli ``` ```bash yarn theme={null} yarn global add @rafter-security/cli ``` ```bash pip theme={null} pip install rafter-cli ``` **Python 3.10+ required for pip installs.** Verify your version: ```bash theme={null} python3 --version # Must be 3.10 or higher ``` On Ubuntu/Debian, Python and pip may not be installed by default: ```bash theme={null} sudo apt update && sudo apt install -y python3 python3-pip python3-venv ``` On Fedora/RHEL: `sudo dnf install python3 python3-pip`. macOS: `brew install python`. Windows: install from [python.org](https://python.org) — pip is included. Verify the install worked: ```bash theme={null} rafter --version ``` [Sign up](https://rafter.so/) and grab your API key from your [account page](https://rafter.so/account). Your API key starts with `RF` and should be kept secure. Never commit it to version control (e.g. GitHub). Use [environment variables](https://configu.com/blog/environment-variables-how-to-use-them-and-4-critical-best-practices/) instead. Navigate to a Git repository, then run: ```bash theme={null} cd /path/to/your/repo rafter run --api-key "RFabc-your-api-key-here" --format md ``` Or set the key as an environment variable and skip the flag: ```bash theme={null} export RAFTER_API_KEY="RFabc-your-api-key-here" cd /path/to/your/repo rafter run --format md ``` The CLI auto-detects your repository and branch from Git, then displays scan results in your terminal. `rafter scan` is an alias for `rafter run` — use whichever you prefer. Add `--mode plus` (or `-m plus`) for deeper analysis with additional agent passes beyond the default fast scan. ## Local Security (No Account Required) Rafter's local features work with zero setup — no API key, no sign-up: ```bash theme={null} # Set up agent security for all detected platforms rafter agent init --all # Scan for secrets locally rafter secrets . ``` This gives you secret scanning, pre-commit hooks, command interception, and audit logging — all offline, all free. See the [agent security guide](/guides/agent-security/getting-started) for details. ## Hand Rafter to Your Coding Agent The whole point of Rafter is that your agent should be the one reaching for it — during design, while writing code, when reviewing diffs, before finalizing changes. Paste this prompt into Claude Code, Cursor, Codex, Windsurf, Aider, or any other agent so security becomes part of its loop instead of an afterthought: ```text theme={null} Use Rafter as a lightweight security layer throughout your development process. Rafter is an open-source CLI that helps identify vulnerabilities, prevent secret leaks, audit dependencies and extensions, and provide security context as you build. If it's not initialized yet, run: npm install -g @rafter-security/cli && rafter agent init --all (or if you can't install globally / are inside a sandboxed agent shell: npx @rafter-security/cli agent init --local --all which writes only to ./.rafter and the per-platform ././ dirs.) (No API key required for either form. The bare `npx rafter-cli` is a different, unrelated package — always use the scoped @rafter-security/cli.) Use Rafter to shift security left: - during design and planning, to anticipate risks (auth, data flow, permissions, integrations) - while writing and modifying code, especially around sensitive logic - when reviewing changes or diffs - before finalizing implementations Treat it as part of your workflow: - check for issues early and iteratively - incorporate findings into implementation decisions - fix what's straightforward and call out non-trivial risks - avoid patterns that could lead to vulnerabilities, secret exposure, or unnecessary privilege expansion The goal is not just auditing after the fact, but continuously informing safer design and implementation choices. With an API key (RAFTER_API_KEY), unlock the Rafter Code Security Engine to deeply analyze your project with SAST, SCA, secret detection, agentic deep dives, and more. Docs: https://docs.rafter.so/llms.txt Repo: https://github.com/Raftersecurity/rafter-cli ``` Set `RAFTER_API_KEY` in your shell or your agent's environment so every scan it runs goes through the Code Security Engine — you stop thinking about security; the agent never stops doing it. ## What's happening? When you run `rafter run`, the CLI will: 1. **Auto-detect** your repository and branch from Git 2. **Upload** your code securely to Rafter's scanning engine from Github 3. **Scan** for vulnerabilities, secrets, and security issues 4. **Delete** your code from Rafter's scanning engine 5. **Display** results directly in your terminal The CLI only scans remote repositories, not your current local branch. Make sure your changes are pushed to the remote repository before scanning. ## Bonus: Saving Results to a File To run a scan and save the results to a file, you can use the following command: ```bash theme={null} rafter run --api-key "RFabc-your-api-key-here" --format md > security-report-$(date +%Y-%m-%d-%H-%M-%S).md ``` ## Next Steps Learn the fundamentals of using the Rafter CLI. Master advanced CLI features and automation. Build custom integrations with the REST API. Set up automated scanning in your pipelines. **Want to know more about how we scan?** See our [handbook](https://rafter.so/handbook) for detailed information about our scanning technology and security coverage. # Suppressing Findings Source: https://docs.rafter.so/suppression Mark investigated false positives as ignored — with a reason — so they stop adding noise without losing the audit trail. When a scan surfaces a finding you've investigated and confirmed is a false positive *for this project*, suppress it — **with a written reason** — so it stops adding noise. Suppressed findings are hidden, not deleted: the reason travels with the code and the audit trail stays intact. ## `.rafter.yml` ignore rules Add an `ignore:` list to your project's [`.rafter.yml`](/guides/agent-security/policy-file). Each rule names the file path(s), optionally the specific rule(s), and a `reason`: ```yaml theme={null} ignore: - paths: ["tests/fixtures/**", "src/legacy/config.py"] rules: ["AWS Access Key ID"] # omit `rules` to suppress every finding on those paths reason: "fake test keys — no live path" - paths: ["docs/**"] reason: "documentation examples" ``` | Field | Required | Notes | | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `paths` | **yes** | Glob(s). Matched anywhere along the absolute file path — `tests/fixtures/**` matches `/home/you/app/tests/fixtures/x`. A rule with no `paths` is skipped with a warning. | | `rules` | no | Rule name(s) to suppress, matched **case-insensitively**. Omit to suppress *every* rule on those paths. A name that matches nothing is harmless. | | `reason` | no | Free text — your justification. Surfaced verbatim in the output, so write the proof. | Rules are evaluated top-to-bottom and the **first matching entry wins**, so put more specific entries first. Because `.rafter.yml` is committed to your repo, the suppression (and its reason) persists across scans and travels with the code. Match `rules` on the finding's **rule name** (e.g. `"AWS Access Key ID"`) — the exact string shown as the `rule` in the scan JSON / SARIF. Not sure of the name? Run `rafter agent scan --json` and copy the `rule` field from the finding. Don't use a hashed `R-…` id from a PR comment; those are display-only and won't match. ## What suppression does to a scan On a local scan (`rafter scan`), suppressed findings move into a `_suppressed[]` array in `--json` output, so you can still see exactly what was hidden and why: ```json theme={null} { "results": [ /* findings still in play */ ], "_suppressed": [ { "file": "/abs/path/tests/fixtures/fake.env", "line": 3, "column": 7, "rule": "AWS Access Key ID", "severity": "critical", "reason": "fake test keys — no live path", "source": ".rafter.yml" } ] } ``` Suppression **never changes the exit code** — `rafter scan` exits non-zero only when a *non-suppressed* finding remains. A clean run stays green, and your diligence stays on the record. `.rafter.yml` `ignore:` rules are applied by the **local scanner** (`rafter scan`, the pre-commit hook, CI). For findings from a **hosted scan** (`rafter run`) or shown in the dashboard, ignore them from the dashboard — those ignores are tied to the repo and persist the same way. ## Baseline — adopting on a noisy repo To start using Rafter on a codebase that already has findings, snapshot the current state and only surface *new* findings from then on: ```bash theme={null} rafter agent baseline create # snapshot today's findings as the baseline rafter scan --baseline # subsequent scans show only NEW findings ``` The baseline lives at `~/.rafter/baseline.json` and is applied only when you pass `--baseline`. ## `.rafterignore` (legacy) A plain `.rafterignore` file — one glob per line — is still honored for path-based suppression. Prefer `.rafter.yml` `ignore:`: it carries per-rule scoping and a `reason`. ## When *not* to suppress Suppress only a genuine false positive for this context, with a reason. Don't: * comment out or delete a rule globally, * broaden a suppression beyond the specific file/context, * drop the scan from CI. If a finding is real but you can't fix it yet, track it — don't bury it.