docs: harden external connector implementation plans

This commit is contained in:
2026-06-03 10:32:50 +08:00
parent d335199a64
commit ee972441f5
3 changed files with 448 additions and 279 deletions

View File

@ -99,6 +99,15 @@ Initial provider:
- `VendorCliProvider`: runs the real CLI/plugin commands required by the current Weixin and Feishu/Lark vendor flows.
`VendorCliProvider` command execution is intentionally constrained:
- Command templates are read only from sidecar startup environment variables.
- Frontend requests and sidecar HTTP request bodies cannot provide command strings.
- Command working directory is fixed to `CONNECTOR_HOME`.
- Per-connection state paths may be passed to commands as formatted arguments.
- Every command has a hard timeout.
- stdout and stderr are redacted before storage or API responses.
Future providers can be added without changing Beaver runtime code:
- `WechatyProvider`
@ -232,6 +241,7 @@ services:
CONNECTOR_API_TOKEN: ${EXTERNAL_CONNECTOR_TOKEN}
CONNECTOR_HOME: /var/lib/external-connector
CONNECTOR_PROVIDER: vendor_cli
CONNECTOR_COMMAND_TIMEOUT_SECONDS: 120
volumes:
- external-connector-state:/var/lib/external-connector
```
@ -347,7 +357,17 @@ Allowed connector session statuses:
}
```
`requestId` is required. Beaver must generate a stable request id for each outbound delivery attempt from the outbound message identity, and must reuse the same `requestId` if the same outbound delivery is retried. The sidecar dedupes `connectionId + requestId`; duplicate requests return the original send result and must not send a second platform message.
`requestId` is required. Beaver must generate a stable request id for each outbound delivery attempt and must reuse the same `requestId` if the same outbound delivery is retried. The first-version rule is:
```text
out_{channel}:{session_id}:{message_id or sha256(content + inbound_message_id + peer_id + finish_reason)}
```
The sidecar dedupes `connectionId + requestId`:
- `completed`: return the original send result and do not send a second platform message.
- `processing` updated less than 60 seconds ago: return `409 Conflict` with `{"retryAfterSeconds": 5}` so Beaver retries later.
- `processing` updated 60 seconds or more ago: treat as stale and retry the provider send.
## Beaver Bridge API
@ -497,7 +517,8 @@ The old `/api/channels` static config editor may remain for advanced runtime con
- Duplicate completed bridge event: return idempotent success and do not call runtime again.
- Duplicate in-flight bridge event: return `409 Conflict` until the 60-second processing TTL expires, then allow one reprocess.
- Outbound send failure: mark outbound delivery failed and record connector error.
- Duplicate outbound send `requestId`: sidecar returns the original send result and does not send a second platform message.
- Duplicate completed outbound send `requestId`: sidecar returns the original send result and does not send a second platform message.
- Duplicate in-flight outbound send `requestId`: sidecar returns `409 Conflict` until the 60-second processing TTL expires, then allows one retry.
- Sidecar restart: persisted provider state should survive through sidecar volume.
## Security
@ -507,6 +528,7 @@ The old `/api/channels` static config editor may remain for advanced runtime con
- Sidecar can only call bridge endpoints with the service-level bridge token.
- Beaver can only call sidecar control and send endpoints with the service-level connector token.
- Sidecar state volume contains login state and must be treated as sensitive.
- Vendor command strings are deployment configuration, not user input.
- Feishu user-identity mode has stronger privacy risk than bot-identity mode; UI must label it clearly if exposed.
## Testing
@ -533,6 +555,7 @@ Sidecar tests:
- fake provider status transitions
- provider command runner error redaction
- send idempotency for duplicate `connectionId + requestId`
- send `processing` TTL returns `409 Conflict` before stale retry
Frontend tests: