CAUTION
Proof of concept only — do not merge, ship, or deploy as production architecture.
This draft demonstrates one narrow native Slack vertical slice and intentionally retains security, lifecycle, and coverage gaps. Companion OpenClaw draft: openclaw/openclaw#123963.
Relationship to current main
vercel-labs/vercel-openclaw#2 is merged and remains the default behavior on main: the Vercel host owns Slack policy/session/reply behavior and may invoke openclaw agent.
This PR changes behavior only when both native host-bridge variables are configured. In that PoC mode:
Connect -> verified raw Slack envelope -> native OpenClaw /slack/events -> channels.slack.* policy/session/thread pipeline -> host Slack API proxy -> Connect getToken() -> Slack
Only native PoC mode bypasses generic CLI invocation. Default mode remains unchanged.
What the PoC adds
- Connect verifies Slack;
/api/slackpreserves the complete raw body and forwards it with a narrow host assertion. - OpenClaw's native Slack plugin remains authoritative for allowlists, activation, sessions, threading, dedupe, reactions, lookups, and replies.
/api/slack-proxy/{method}authenticates the sandbox, calls@vercel/connect.getToken(), strips sandbox token overrides, and calls Slack. The Slack token never enters the VM.- Direct OpenAI model access is separately brokered: the host key is injected by the Vercel firewall only for
api.openai.com. The VM stores only the exact nonsecret sentinelsk-vercel-firewall-brokered-placeholder-not-a-real-keyrequired to pass OpenClaw's provider-key validation. - Streaming is disabled because several token-only/fresh-client paths are not yet bridged.
- Ingress/proxy logs record event IDs, raw-body hashes, methods, Connect token source, Slack status, and request IDs without payloads, message text, or credentials.
The sandbox still receives a shared PoC host-bridge bearer. It is not a Slack credential; production needs scoped workload identity or signed assertions.
Live evidence
Tested in the Local Claw workspace, private connect-poc-test channel, with the Connect-installed openclaw-poc app.
Native policy denial
Two verified events (Ev0BQSBVQE21, Ev0BQPRL8F5Z) entered the native plugin. Its configured channels.slack.* policy denied the user after native auth.test, conversations.info, and users.info; it posted chat.postEphemeral, made no model call, and started no generic agent process. All Slack operations used tokenSource=connect and returned Slack HTTP 200.
This is the important configuration proof: Connect did not reimplement or override the OpenClaw allowlist decision.
Successful native model round trip
User mention parent: 1787028584.664219
- Connect accepted the corresponding native app mention as
Ev0BQSH9AP29, HTTP 200, raw-body SHA-2568f10d3360de38da414e684af1f44a011ec872bb398f4f7b09796d42f3b16822e. - OpenClaw logged native session key
agent:main:slack:channel:c0bqckh5h1c:thread:1787028584.664219. - Native WebClient operations
auth.test,conversations.info,users.info,reactions.add,assistant.threads.setStatus, andchat.postMessagetraversed the host proxy withtokenSource=connect; Slack returned HTTP 200. - OpenClaw's built-in runtime called
https://api.openai.com/v1/responseswithopenai/gpt-5.4; the firewall-injected host credential produced HTTP 200. - Slack visibly rendered the native eyes reaction and exactly one threaded model reply:
CONNECT POC OK. - Native mode did not invoke
openclaw agent.
The host logs the exact received raw-body hash; unit coverage separately proves that those bytes are forwarded unchanged into native /slack/events.
Final sandbox boundary verifier
{
"slackCredentialsAbsent": true,
"modelCredentialsAbsent": true,
"modelPlaceholderIsExactSentinel": true,
"modelPlaceholderDiffersFromHostKey": true,
"modelPlaceholderExactMatchCount": 1,
"nodeCompileCacheExcludedAsCodeArtifact": true,
"genericAgentProcessCount": 0,
"config": {
"configuredPolicyFieldCount": 1,
"streamingDisabled": true,
"hostBridgeApiUrlConfigured": true,
"hostBridgeAuthIsEnvSecretRef": true
},
"slackPluginEnabled": true
}The verifier scans command/process env, argv, config, all OpenClaw state, and non-compile-cache /tmp files. Node's compile cache is excluded explicitly because it contains bytecode copies of immutable source credential fixtures/patterns, not runtime state.
Validation
- Host tests: 132/132 passed.
- ESLint, TypeScript,
git diff --check, and local Next production build passed. - Vercel production build passed for deployment
dpl_F8RQoqGan92VLMhwLeQfGYiNx2ct. - Direct firewall probe: OpenAI HTTP 200; sandbox model credentials absent; exact sentinel differs from host key.
- Companion OpenClaw proof: 151 focused Slack tests plus extension typecheck/static gates passed.
Known gaps / do not merge until resolved
- Private Slack downloads bypass the proxy; upload API calls may proxy while upload bytes go to absolute Slack upload URLs.
- Detached/proactive sends, directory/actions/probes, and other fresh WebClient paths need one bridge-aware client factory.
- Bolt
response_url, interactive actions, and slash commands are not end-to-end bridged. - Streaming remains disabled; absolute Slack URLs need an explicit broker contract.
- The host proxy needs a method allowlist and tighter request/response bounds.
- Connect token refresh/revocation, Slack retries/rate limits, replay protection, and durable dedupe need explicit contracts.
- Multi-workspace/install routing needs connector/installation identity, not one fixed connector.
- The host acknowledges before durable sandbox admission; a later failure can still lose an event.
- The shared host assertion needs connector/install scoping, rotation, expiry, and replay protection.
- Activity/dedupe stores are in-memory in this Hobby deployment; idle suspension is nonfunctional across serverless functions.
- Sandbox timeout extension hits the Hobby ceiling and the gateway can briefly drain/retry during cold restart; lifecycle needs production design.
- Live host and VM do not yet log a shared raw-envelope correlation hash; byte equality is currently code/unit proven plus host-side live hash.
Please keep this PR in draft. Do not mark ready, merge, or release it.
Activity
20This pull request is a draft
Merging is unavailable until it is marked ready for review.
@Patrick-Erichsen is attempting to deploy a commit to the andrewqu2-vtest314 Team on Vercel.
A member of the Team first needs to authorize it.