106 lines
5.1 KiB
Markdown
106 lines
5.1 KiB
Markdown
# Chatbot V1 — User Allow-List, 8 Capabilities, Audit Log
|
|
|
|
Built on top of the [MVP](./chatbot-mvp.md). V1 ships:
|
|
|
|
- 8 capabilities (MVP 3 + `data_read` + 4 high-risk).
|
|
- Per-user override via the new `TenantChatbotAccess` table.
|
|
- Audit-event-per-high-risk-call through `@toolctrl/db/audit-events.server`.
|
|
- Per-capability sliding-window rate-limits via `@toolctrl/shared-store`.
|
|
|
|
## Capability matrix
|
|
|
|
| Capability | Risk | Tool name | Notes |
|
|
| ------------------ | ------ | ---------------------- | ------------------------------------------------------------------ |
|
|
| `qa_help` | low | `search_help` | Bundled docs ranker. No DB. |
|
|
| `kb_search` | low | `search_knowledge_base`| Tenant-scoped KB. Wraps results in `---KB ARTICLE---` markers. |
|
|
| `account_info` | low | `get_account_info` | Whitelist projection. Never returns billing tokens / customer ids. |
|
|
| `data_read` | medium | `read_entities` | Strict entity enum, tenant-scoped read. |
|
|
| `data_write` | high | `write_entity` | Audit + rate-limit (30/min default). |
|
|
| `workflow_trigger` | high | `start_workflow` | Audit + rate-limit (10/min default). |
|
|
| `admin_actions` | high | `admin_action` | Audit + rate-limit (5/min) + OWNER/ADMIN role gate. |
|
|
| `external_tools` | high | `invoke_external_tool` | MCP-tool registry. Audit + rate-limit (60/min default). |
|
|
|
|
## Allow-list semantics
|
|
|
|
`TenantChatbotAccess` is a per-`(tenantId, userId)` override row.
|
|
|
|
1. Master-flag `chatbot` OFF → no capabilities.
|
|
2. Row exists with `enabled = false` → explicit deny (wins over any tenant default).
|
|
3. Row exists with `enabled = true` and non-empty `capabilityScopes` → those scopes.
|
|
4. Row exists with `enabled = true` and empty scopes → fall through to tenant default.
|
|
5. No row, `chatbotAccessMode = 'all_members'` → `Tenant.chatbotDefaultCapabilities`.
|
|
6. No row, `chatbotAccessMode = 'allow_list'` → no capabilities.
|
|
|
|
## Audit pipeline
|
|
|
|
`auditChatbotToolCall` writes through `createAuditEvent`. Action format:
|
|
`chatbot.tool_call.<capability>.<toolName>`. Payload uses an allow-list
|
|
projection (`ALLOWED_ARG_KEYS`); anything not on the list is dropped so
|
|
prompt-injection cannot exfiltrate secrets into the audit table.
|
|
|
|
Outcomes:
|
|
|
|
- `success` — inner tool ran cleanly.
|
|
- `failure` — inner tool threw (rethrown to the SDK).
|
|
- `blocked` — rate-limit denied or role-check returned `forbidden`.
|
|
|
|
## Rate-limit defaults (sliding window, 60 s)
|
|
|
|
| Capability | Max / window |
|
|
| ------------------ | ------------ |
|
|
| `qa_help` | 1000 |
|
|
| `kb_search` | 1000 |
|
|
| `account_info` | 1000 |
|
|
| `data_read` | 200 |
|
|
| `data_write` | 30 |
|
|
| `workflow_trigger` | 10 |
|
|
| `admin_actions` | 5 |
|
|
| `external_tools` | 60 |
|
|
|
|
Bucket key: `chatbot:<capability>:<tenantId>:<userId|anon>`. Backed by
|
|
the shared-store (Redis in prod, MemoryAdapter in tests).
|
|
|
|
## Operator commands
|
|
|
|
```sh
|
|
# Toggle the master flag
|
|
toolctrl chatbot enable | disable | status
|
|
|
|
# Grant / revoke per-user access
|
|
toolctrl chatbot grant --tenant acme --email alice@example.com --capabilities=qa_help,kb_search,data_read
|
|
toolctrl chatbot revoke --tenant acme --email bob@example.com # disables override
|
|
toolctrl chatbot revoke --tenant acme --email bob@example.com --hard # removes the row
|
|
|
|
# Update tenant default
|
|
toolctrl chatbot set-capabilities --tenant acme --mode allow_list \
|
|
--capabilities qa_help,kb_search,account_info
|
|
```
|
|
|
|
## Files
|
|
|
|
- `apps/web/app/modules/chatbot/lib/capabilities/{data-read,data-write,workflow-trigger,admin-actions,external-tools}.server.ts`
|
|
- `apps/web/app/modules/chatbot/lib/capabilities/{audit,rate-limit,high-risk-wrapper}.server.ts`
|
|
- `apps/web/app/modules/chatbot/lib/capabilities/resolver.server.ts` — V1 lookup matrix
|
|
- `apps/web/app/modules/chatbot/db/chatbot-access.db.server.ts`
|
|
- `apps/web/app/routes/app.$tenant/settings/chatbot.tsx` — V1 settings UI
|
|
- `packages/cli/src/commands/chatbot/access.ts`
|
|
- `prisma/schema/accounts.prisma` (`TenantChatbotAccess`, `Tenant.chatbotAccessMode`, `Tenant.chatbotDefaultCapabilities`)
|
|
|
|
## Troubleshooting
|
|
|
|
- **A user sees no chatbot tools even with override.** Check the master
|
|
flag (`toolctrl chatbot status`) and the row's `enabled` field.
|
|
- **`admin_action` returns `forbidden`.** Role gate. Only OWNER / ADMIN
|
|
may run admin actions even with the capability in scope.
|
|
- **`rate_limited` returned from a high-risk tool.** Inspect the
|
|
`chatbot:<capability>:<tenantId>:<userId>` bucket in Redis or wait the
|
|
60 s window.
|
|
|
|
## Known limitations
|
|
|
|
- No confirmation UI step yet — the wrapper is ready to return a
|
|
`{ ok: false, reason: 'awaiting_confirmation' }` shape but the chat
|
|
widget doesn't yet render it.
|
|
- `external_tools` provider is a stub. Phase 07 V2 will wire the MCP
|
|
client into it.
|