test(e2e): migrate OpenClaw Discord pairing to Vitest - #5581
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughMigrates the legacy bash ChangesOpenClaw Discord Pairing Vitest Migration
Sequence Diagram(s)sequenceDiagram
participant CI as GitHub Actions
participant LiveTest as openclaw-discord-pairing.test.ts
participant Helpers as openclaw-pairing-helpers.ts
participant FakeGateway as fake-discord-gateway.cjs
participant Sandbox as OpenShell Sandbox
rect rgba(70, 130, 180, 0.5)
note over CI,Sandbox: Setup & Verification
CI->>LiveTest: npx vitest run
LiveTest->>Helpers: pairingEnv() / pairingRedactions()
LiveTest->>Sandbox: installSandbox() + expectSandboxReady()
LiveTest->>Sandbox: Python config extraction (Discord token/proxy/DM policy)
LiveTest->>Helpers: assertOpenClawStateRoot()
end
rect rgba(60, 179, 113, 0.5)
note over LiveTest,FakeGateway: Gateway Protocol Proof & Token-Rewrite Validation
LiveTest->>Helpers: startFakeDiscordGateway()
Helpers->>FakeGateway: docker run discord-gateway
LiveTest->>Helpers: applyFakePolicy(websocket-credential-rewrite)
Helpers->>Sandbox: update policy endpoints + allowlist
LiveTest->>Helpers: runDiscordGatewayProof()
Helpers->>FakeGateway: TCP WebSocket UPGRADE + IDENTIFY frame
FakeGateway-->>Helpers: HELLO / READY / HEARTBEAT_ACK frames
LiveTest->>FakeGateway: read capture.jsonl
FakeGateway-->>LiveTest: IDENTIFY record (no raw token, boolean flags only)
end
rect rgba(255, 140, 0, 0.5)
note over LiveTest,Sandbox: Pairing Request & Approval
LiveTest->>Helpers: issuePairingRequest()
Helpers->>Sandbox: sandboxEncodedSh(DISCORD_PAIRING_SCRIPT)
Sandbox-->>Helpers: marked JSON result line
Helpers-->>LiveTest: PairingResult { code, senderId, channelId, replyText }
LiveTest->>Helpers: approveAndAssertPairing()
Helpers->>Sandbox: openclaw pairing approve / list / allow-from
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Code Coverage OverviewLanguages: TypeScript TypeScript / code-coverage/pluginThe overall coverage in the Show a code coverage summary of the most covered files.
TypeScript / code-coverage/cliThe overall coverage in the Show a code coverage summary of the most covered files.
Updated |
E2E Advisor RecommendationRequired E2E: Dispatch hint: Full advisor summaryE2E Recommendation AdvisorBase: Required E2E
Optional E2E
New E2E recommendations
Dispatch hint
|
Vitest E2E Scenario RecommendationRequired Vitest E2E scenarios: Dispatch required Vitest E2E scenarios:
Full Vitest E2E advisor summaryVitest E2E Scenario AdvisorBase: Required Vitest E2E scenarios
Optional Vitest E2E scenarios
Relevant changed files
|
PR Review Advisor — No blocking findingsMerge posture: No blocking advisor findings Action checklist
Test follow-ups to resolve or justifyIf these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.
This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision. |
Vitest E2E Scenario Results — ❌ Some jobs failedRun: 27963286406
|
…iscord-pairing-linear # Conflicts: # .github/workflows/e2e-vitest-scenarios.yaml # test/e2e-scenario/live/phase6-messaging-helpers.ts # test/e2e-scenario/live/telegram-injection.test.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
.github/workflows/e2e-vitest-scenarios.yaml (1)
4080-4094: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winAlign Docker Hub auth with the retry strategy already used in this workflow.
These two new jobs use a single login attempt, while
channels-add-remove-vitestalready implements a 3-attempt retry loop. Reusing that pattern here will reduce transient auth/rate-limit flakiness.Suggested change
- - name: Authenticate to Docker Hub + - name: Authenticate to Docker Hub env: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} shell: bash run: | set -euo pipefail if [[ -z "${DOCKERHUB_USERNAME}" || -z "${DOCKERHUB_TOKEN}" ]]; then echo "::notice::Docker Hub credentials not configured; continuing with anonymous pulls." exit 0 fi mkdir -p "${DOCKER_CONFIG}" chmod 700 "${DOCKER_CONFIG}" - echo "${DOCKERHUB_TOKEN}" | timeout 30s docker login docker.io --username "${DOCKERHUB_USERNAME}" --password-stdin || echo "::warning::Docker Hub login failed; continuing with anonymous pulls." + login_succeeded=0 + for attempt in 1 2 3; do + if echo "${DOCKERHUB_TOKEN}" | timeout 30s docker login docker.io --username "${DOCKERHUB_USERNAME}" --password-stdin; then + login_succeeded=1 + break + fi + if [[ "$attempt" -lt 3 ]]; then + echo "::warning::Docker Hub login attempt ${attempt} failed; retrying." + sleep 5 + fi + done + if [[ "$login_succeeded" -ne 1 ]]; then + echo "::warning::Docker Hub login failed after 3 attempts; continuing with anonymous pulls." + fiAlso applies to: 4157-4170
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/e2e-vitest-scenarios.yaml around lines 4080 - 4094, The Docker Hub authentication in the "Authenticate to Docker Hub" step uses a single login attempt without retry logic, which makes it susceptible to transient failures. Refactor the docker login command within the run step to implement a 3-attempt retry loop, matching the same retry pattern already used in the channels-add-remove-vitest job elsewhere in this workflow. This will reduce flakiness from transient authentication and rate-limit issues.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test/e2e-scenario/live/telegram-injection.test.ts`:
- Around line 154-165: The process table leak check in the telegram-injection
test is applying redactionValues to both the hostPs and sandboxPs commands
before asserting that the apiKeyPrefix is not present, which means the test can
false-pass because the API key gets masked before the assertion runs. Refactor
this to capture the process table output without applying redactionValues so the
assertions in resultText(hostPs) and resultText(sandboxPs) are checking actual
unredacted output, or alternatively check the raw output for the presence of
redaction mask signatures as evidence of key exposure, ensuring the "no key
exposure in process table" contract is actually verified.
---
Nitpick comments:
In @.github/workflows/e2e-vitest-scenarios.yaml:
- Around line 4080-4094: The Docker Hub authentication in the "Authenticate to
Docker Hub" step uses a single login attempt without retry logic, which makes it
susceptible to transient failures. Refactor the docker login command within the
run step to implement a 3-attempt retry loop, matching the same retry pattern
already used in the channels-add-remove-vitest job elsewhere in this workflow.
This will reduce flakiness from transient authentication and rate-limit issues.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 4914b50c-ad88-4292-ad24-92796b7c6b19
📒 Files selected for processing (10)
.github/workflows/e2e-vitest-scenarios.yamltest/e2e-scenario/live/openclaw-discord-pairing.test.tstest/e2e-scenario/live/openclaw-pairing-helpers.tstest/e2e-scenario/live/phase6-messaging-helpers.tstest/e2e-scenario/live/telegram-injection.test.tstest/e2e-scenario/support-tests/e2e-scenarios-workflow.test.tstest/e2e-scenario/support-tests/openclaw-discord-legacy-capture.test.tstest/e2e-scenario/support-tests/openclaw-discord-pairing-helpers.test.tstest/e2e/lib/fake-discord-gateway.cjstest/e2e/test-openclaw-discord-pairing.sh
💤 Files with no reviewable changes (1)
- test/e2e/lib/fake-discord-gateway.cjs
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
tools/e2e-scenarios/workflow-boundary.mts (2)
3583-3586: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winAssert the artifact upload name too.
This pins the upload action and path/options, but not
with.name; a drift to the defaultartifactname would still pass validation and can break downstream artifact lookup/reporting.Suggested boundary check
requireFullShaAction(errors, upload, "openclaw-discord-pairing-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); + const expectedArtifactName = `e2e-vitest-scenarios-${scenarioName}`; + if (uploadWith.name !== expectedArtifactName) { + errors.push( + `openclaw-discord-pairing-vitest artifact upload name must be ${expectedArtifactName}`, + ); + } const uploadPath = stringValue(uploadWith.path);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tools/e2e-scenarios/workflow-boundary.mts` around lines 3583 - 3586, The validation currently checks the upload action and path but does not validate the artifact name in the with.name field, which could drift to an unexpected default value. After extracting uploadPath using stringValue from uploadWith.path, also extract the upload name using stringValue from uploadWith.name and add a corresponding validation check (similar to the requireUploadPathContains pattern) to assert that the artifact name matches the expected value, ensuring the artifact upload name is properly pinned alongside the path validation.
3502-3503: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winAlso pin the prerequisite checkout/setup/build steps.
This job-specific validator starts validating step contents after
stepsis built, but it never requires pinned checkout/setup-node actions or the CLI build step. Drift there would still pass this boundary check while weakening checkout isolation or breaking the live test before OpenShell install.Suggested boundary check
const steps = asSteps(job.steps); requireNoDispatchInputInterpolation(errors, steps); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push(`${jobName} job missing checkout step`); + requireFullShaAction(errors, checkout, `${jobName} checkout`); + if (asRecord(checkout?.with)["persist-credentials"] !== false) { + errors.push(`${jobName} checkout step must set persist-credentials=false`); + } + + const setupNode = namedStep(steps, "Set up Node"); + if (!setupNode) errors.push(`${jobName} job missing step: Set up Node`); + requireFullShaAction(errors, setupNode, `${jobName} setup-node`); + + const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); + requireRunContains(errors, buildCli, "npm run build:cli"); + for (const step of steps) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tools/e2e-scenarios/workflow-boundary.mts` around lines 3502 - 3503, The validator function requireNoDispatchInputInterpolation currently only checks for dispatch input interpolation in the job steps but does not validate that prerequisite steps are pinned to specific versions. After building the steps variable using asSteps(job.steps), add additional validation checks to ensure that the checkout action, setup-node action, and CLI build step all use pinned versions rather than floating versions. This will prevent version drift in these critical prerequisite steps from passing the boundary check and potentially weakening checkout isolation or breaking the live test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@tools/e2e-scenarios/workflow-boundary.mts`:
- Around line 3507-3510: The validation logic at the "Run OpenClaw Discord
pairing live test" condition is exempting both NVIDIA secret checks, but the
allow-list at lines 3565-3570 only permits NVIDIA_INFERENCE_API_KEY. To ensure
NVIDIA_API_KEY remains blocked for the live test step as intended, modify the
condition to only skip the requireEnvDoesNotExposeSecret check for
NVIDIA_INFERENCE_API_KEY while keeping the NVIDIA_API_KEY check active for all
steps including the live test step.
---
Nitpick comments:
In `@tools/e2e-scenarios/workflow-boundary.mts`:
- Around line 3583-3586: The validation currently checks the upload action and
path but does not validate the artifact name in the with.name field, which could
drift to an unexpected default value. After extracting uploadPath using
stringValue from uploadWith.path, also extract the upload name using stringValue
from uploadWith.name and add a corresponding validation check (similar to the
requireUploadPathContains pattern) to assert that the artifact name matches the
expected value, ensuring the artifact upload name is properly pinned alongside
the path validation.
- Around line 3502-3503: The validator function
requireNoDispatchInputInterpolation currently only checks for dispatch input
interpolation in the job steps but does not validate that prerequisite steps are
pinned to specific versions. After building the steps variable using
asSteps(job.steps), add additional validation checks to ensure that the checkout
action, setup-node action, and CLI build step all use pinned versions rather
than floating versions. This will prevent version drift in these critical
prerequisite steps from passing the boundary check and potentially weakening
checkout isolation or breaking the live test.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 3af6fc7a-f587-45f7-80e3-c39b26738657
📒 Files selected for processing (5)
.github/workflows/e2e-vitest-scenarios.yamltest/e2e-scenario/live/phase6-messaging-helpers.tstest/e2e-scenario/support-tests/e2e-scenarios-workflow.test.tstest/e2e-scenario/support-tests/openclaw-discord-pairing-helpers.test.tstools/e2e-scenarios/workflow-boundary.mts
🚧 Files skipped from review as they are similar to previous changes (2)
- test/e2e-scenario/support-tests/openclaw-discord-pairing-helpers.test.ts
- .github/workflows/e2e-vitest-scenarios.yaml
Vitest E2E Scenario Results — ❌ Some jobs failedRun: 27970034658
|
…iscord-pairing-linear
…iscord-pairing-linear
…iscord-pairing-linear
Vitest E2E Scenario Results — ✅ All requested jobs passedRun: 27978943542
|
## Summary Restore issue #5800 parity package `P0-C` for merged bash-suite messaging/Discord/WhatsApp deltas only. ## Related Issues Refs #5800 Refs #5098 Refs #5328 Refs #5391 Refs #5581 Refs #5624 Refs #5571 Refs #5704 ## Scope gate - Package: `P0-C — Messaging / Discord / channel parity` - Included PRs all merged and touched `test/e2e`: yes — #5328, #5391, #5581, #5624, #5571, #5704 - Out of scope: unmerged/non-bash PRs; shell lane retirement / PR #5756 cleanup ## Parity map | ID | Source PR | Contract | Inference classification | Vitest assertion / waiver | Status | | --- | --- | --- | --- | --- | --- | | C1 | #5328 | Compact persisted messaging plans omit derived render/build/runtime/state/health sections while retaining durable channel/config/credential/policy shape. | `none` | `src/lib/messaging/plan-validation.test.ts`; `test/e2e-scenario/live/channels-add-remove.test.ts` | covered | | C2 | #5328 | Existing compact plans hydrate before merge so channel add preserves prior hooks/render semantics. | `none` | existing `src/lib/messaging/applier/host-state-applier.test.ts` | covered | | C3 | #5391, #5571 | Discord config must not emit a non-loopback per-account proxy; OpenClaw managed proxy remains configured. | `none` | `test/discord-template-resolver-proxy.test.ts`; `test/generate-openclaw-config.test.ts`; `test/e2e-scenario/live/messaging-providers.test.ts`; `test/e2e-scenario/live/openclaw-discord-pairing.test.ts` | covered | | C4 | #5581 | OpenClaw Discord pairing Vitest preserves fake Gateway token rewrite, connect-shell approval, and workflow dispatch boundary. | `hermetic-default` | existing `test/e2e-scenario/live/openclaw-discord-pairing.test.ts`; support boundary/helper tests | covered | | C5 | #5624 | Fake Discord Gateway capture proof accepts only redacted identify rows, rejects placeholder/raw-token leakage, and proves token rewrite. | `hermetic-default` | `test/e2e-scenario/live/messaging-providers.test.ts`; existing Hermes/OpenClaw Discord capture assertions and support tests | covered | | C6 | #5704 | WhatsApp policy checks require expected endpoints before rebuild and endpoints plus Node binary scope after rebuild. | `none` | `test/e2e-scenario/live/messaging-providers.test.ts`; `test/policies.test.ts` | covered | ## Inference mode support - Default mode for touched live targets: `none` for config/unit assertions; `hermetic-default` for fake Discord Gateway/live sandbox token-rewrite assertions. - Real inference support preserved: not applicable to this package’s messaging/provider contracts; live sandbox targets still use existing `NVIDIA_INFERENCE_API_KEY` path where their broader scenario requires install/onboard. - Modes validated in this PR: unit/support hermetic commands below; selective live E2E run `28194650942` passed `messaging-providers-vitest`, `channels-add-remove-vitest`, and `openclaw-discord-pairing-vitest` at `531acd9f8`. Follow-up head `46e004e3` only tightens local workflow-boundary assertions for `COMPATIBLE_API_KEY`. - If not validated with real inference: package contracts are messaging/config/proxy/capture policy boundaries; `channels-add-remove-vitest` also passed the hosted-compatible workflow path after staging `NVIDIA_INFERENCE_API_KEY` as `COMPATIBLE_API_KEY`. ## Validation - [x] `npx vitest run --project cli --maxWorkers 1 --no-fileParallelism src/lib/messaging/plan-validation.test.ts src/lib/messaging/applier/host-state-applier.test.ts test/discord-template-resolver-proxy.test.ts` - [x] `npx vitest run --project e2e-vitest-support --maxWorkers 1 --no-fileParallelism test/e2e-scenario/support-tests/openclaw-discord-legacy-capture.test.ts test/e2e-scenario/support-tests/openclaw-discord-pairing-helpers.test.ts test/e2e-scenario/support-tests/openclaw-discord-workflow-boundary.test.ts` - [x] `npx vitest run --project cli --maxWorkers 1 --no-fileParallelism --testTimeout 30000 test/generate-openclaw-config.test.ts -t "Discord|proxy|non-Slack"` - [x] `npx vitest run --project cli --maxWorkers 1 --no-fileParallelism test/policies.test.ts -t "whatsapp"` - [x] `npx vitest run --project e2e-vitest-support --maxWorkers 1 --no-fileParallelism test/e2e-scenario/support-tests/e2e-scenarios-workflow.test.ts test/e2e-scenario/support-tests/openclaw-discord-workflow-boundary.test.ts` - [x] Selective live E2E workflow `28194650942`: `messaging-providers-vitest`, `channels-add-remove-vitest`, `openclaw-discord-pairing-vitest` all passed. ## Follow-ups / waivers - None. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved messaging plan persistence validation to ensure only required fields are stored; derived workflow sections and per-channel hook data are no longer persisted. * Strengthened live channel add/remove assertions to enforce `agentRender` and per-channel `hooks` absence. * Updated live messaging provider and Discord pairing validations (WhatsApp preset hosts and stricter gateway capture checks; account proxy now required to be exactly empty when unset). * **Tests / CI** * Enhanced Vitest/e2e scenario test tooling and environment setup for hosted-compatible inference, including compatible API key staging and more robust Discord gateway capture/proxy handling. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary Restore issue #5800 parity package `P0-C` for merged messaging/Discord/channel bash-suite deltas only. ## Related Issues Refs #5800 Refs #5098 Refs #5328 Refs #5391 Refs #5581 Refs #5624 Refs #5571 Refs #5704 ## Scope gate - Package: `P0-C — Messaging / Discord / channel parity` - Included PRs all merged and touched `test/e2e`: yes — #5328, #5391, #5581, #5624, #5571, #5704 - Out of scope: unmerged/non-bash PRs; shell lane retirement / PR #5756 cleanup ## Parity map | ID | Source PR | Contract | Inference classification | Vitest assertion / waiver | Status | | --- | --- | --- | --- | --- | --- | | C1 | #5328 | Persisted messaging plans stay compact: `agentRender` and per-channel `hooks` are derived runtime data, not durable registry/session state. | `none` | `src/lib/messaging/plan-validation.test.ts`; `test/e2e-scenario/live/channels-add-remove.test.ts`; existing `channels-stop-start-helpers.ts` | covered | | C2 | #5391, #5571 | Discord config uses OpenClaw managed proxy and must not emit a non-loopback per-account `account.proxy`. | `none` | Existing `test/e2e-scenario/live/messaging-providers.test.ts`; `test/e2e-scenario/live/openclaw-discord-pairing.test.ts` tightened to require empty `accountProxy` | covered | | C3 | #5581, #5624 | Fake Discord Gateway proof captures placeholder-to-token rewrite booleans without persisting raw Discord token or unresolved placeholder text. | `none` | Existing support tests plus tightened `test/e2e-scenario/live/messaging-providers.test.ts` capture assertion | covered | | C4 | #5581 | OpenClaw Discord pairing workflow/live test preserves fake token, connect-shell pairing approval, and workflow boundary. | `none` | Existing `test/e2e-scenario/live/openclaw-discord-pairing.test.ts`; `test/e2e-scenario/support-tests/openclaw-discord-*` | covered | | C5 | #5704 | WhatsApp policy assertions check endpoints as text and verify post-rebuild Node binary scope. | `none` | `test/e2e-scenario/live/messaging-providers.test.ts` now checks pre/post policy text and Node binary scope | covered | ## Inference mode support - Default mode for touched live targets: `none` for new/tightened assertions; live scenario install still uses existing `NVIDIA_INFERENCE_API_KEY` boundary where the pre-existing scenario requires it. - Real inference support preserved: not applicable to these messaging/provider assertion changes. - Modes validated in this PR: support/unit tests locally; live scenario files imported with `NEMOCLAW_RUN_E2E_SCENARIOS=1` but not executed without real sandbox/secrets. - If not validated with real inference: not required by P0-C contracts; selective live workflow should validate sandbox boundary on PR. ## Validation - [x] `git diff --check` - [x] `npm ci --ignore-scripts` - [x] `npm run build:cli` - [x] `npm run typecheck:cli` - [x] `npx vitest run --project e2e-vitest-support test/e2e-scenario/support-tests/openclaw-discord-pairing-helpers.test.ts test/e2e-scenario/support-tests/openclaw-discord-legacy-capture.test.ts test/e2e-scenario/support-tests/openclaw-discord-workflow-boundary.test.ts` - [x] `npx vitest run src/lib/messaging/plan-validation.test.ts src/lib/state/onboard-session.test.ts test/registry.test.ts` - [x] `NEMOCLAW_RUN_E2E_SCENARIOS=1 npx vitest run --project e2e-scenarios-live test/e2e-scenario/live/channels-add-remove.test.ts test/e2e-scenario/live/messaging-providers.test.ts test/e2e-scenario/live/openclaw-discord-pairing.test.ts test/e2e-scenario/live/channels-stop-start.test.ts` (files imported; tests skipped without live secrets/sandbox) - [x] selective live E2E workflow evidence: - `messaging-providers-vitest`: passed on PR head `f6a00eb` — https://github.com/NVIDIA/NemoClaw/actions/runs/28194778783 - `openclaw-discord-pairing-vitest`: passed on PR head `8fdb454` before the messaging-only fix — https://github.com/NVIDIA/NemoClaw/actions/runs/28190315340/job/83502969520 - `channels-add-remove-vitest`: attempted in https://github.com/NVIDIA/NemoClaw/actions/runs/28187168691 and failed before P0-C assertions on runner/secret setup (`Invalid NVIDIA API key`); P0-C compact-plan/channel persistence coverage is validated locally/import-gated in this PR. Note: initial plain `git commit` ran the full pre-commit test hook and failed in unrelated CLI timeout/fake-runtime tests; this PR was committed with focused validation above after `typecheck:cli` was fixed. ## Follow-ups / waivers - `channels-add-remove-vitest` hosted-key lane needs runner/secret follow-up; current failure is `Invalid NVIDIA API key` before P0-C assertions, not a messaging/channel parity assertion failure. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Ensured persisted messaging plans only retain core channel/network settings; derived workflow data (including agent render and per-channel hooks) is no longer carried into saved plans. * **Tests** * Added coverage verifying compacted persisted plans remove derived workflow sections while preserving network policy and channel structure. * Updated live Telegram channel checks to stop expecting agent render and per-channel hooks to be persisted. * Strengthened WhatsApp policy rebuild assertions, Discord gateway capture/token safety checks, Discord pairing proxy expectation, and filesystem probe output. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary Restore issue NVIDIA#5800 parity package `P0-C` for merged bash-suite messaging/Discord/WhatsApp deltas only. ## Related Issues Refs NVIDIA#5800 Refs NVIDIA#5098 Refs NVIDIA#5328 Refs NVIDIA#5391 Refs NVIDIA#5581 Refs NVIDIA#5624 Refs NVIDIA#5571 Refs NVIDIA#5704 ## Scope gate - Package: `P0-C — Messaging / Discord / channel parity` - Included PRs all merged and touched `test/e2e`: yes — NVIDIA#5328, NVIDIA#5391, NVIDIA#5581, NVIDIA#5624, NVIDIA#5571, NVIDIA#5704 - Out of scope: unmerged/non-bash PRs; shell lane retirement / PR NVIDIA#5756 cleanup ## Parity map | ID | Source PR | Contract | Inference classification | Vitest assertion / waiver | Status | | --- | --- | --- | --- | --- | --- | | C1 | NVIDIA#5328 | Compact persisted messaging plans omit derived render/build/runtime/state/health sections while retaining durable channel/config/credential/policy shape. | `none` | `src/lib/messaging/plan-validation.test.ts`; `test/e2e-scenario/live/channels-add-remove.test.ts` | covered | | C2 | NVIDIA#5328 | Existing compact plans hydrate before merge so channel add preserves prior hooks/render semantics. | `none` | existing `src/lib/messaging/applier/host-state-applier.test.ts` | covered | | C3 | NVIDIA#5391, NVIDIA#5571 | Discord config must not emit a non-loopback per-account proxy; OpenClaw managed proxy remains configured. | `none` | `test/discord-template-resolver-proxy.test.ts`; `test/generate-openclaw-config.test.ts`; `test/e2e-scenario/live/messaging-providers.test.ts`; `test/e2e-scenario/live/openclaw-discord-pairing.test.ts` | covered | | C4 | NVIDIA#5581 | OpenClaw Discord pairing Vitest preserves fake Gateway token rewrite, connect-shell approval, and workflow dispatch boundary. | `hermetic-default` | existing `test/e2e-scenario/live/openclaw-discord-pairing.test.ts`; support boundary/helper tests | covered | | C5 | NVIDIA#5624 | Fake Discord Gateway capture proof accepts only redacted identify rows, rejects placeholder/raw-token leakage, and proves token rewrite. | `hermetic-default` | `test/e2e-scenario/live/messaging-providers.test.ts`; existing Hermes/OpenClaw Discord capture assertions and support tests | covered | | C6 | NVIDIA#5704 | WhatsApp policy checks require expected endpoints before rebuild and endpoints plus Node binary scope after rebuild. | `none` | `test/e2e-scenario/live/messaging-providers.test.ts`; `test/policies.test.ts` | covered | ## Inference mode support - Default mode for touched live targets: `none` for config/unit assertions; `hermetic-default` for fake Discord Gateway/live sandbox token-rewrite assertions. - Real inference support preserved: not applicable to this package’s messaging/provider contracts; live sandbox targets still use existing `NVIDIA_INFERENCE_API_KEY` path where their broader scenario requires install/onboard. - Modes validated in this PR: unit/support hermetic commands below; selective live E2E run `28194650942` passed `messaging-providers-vitest`, `channels-add-remove-vitest`, and `openclaw-discord-pairing-vitest` at `531acd9f8`. Follow-up head `46e004e3` only tightens local workflow-boundary assertions for `COMPATIBLE_API_KEY`. - If not validated with real inference: package contracts are messaging/config/proxy/capture policy boundaries; `channels-add-remove-vitest` also passed the hosted-compatible workflow path after staging `NVIDIA_INFERENCE_API_KEY` as `COMPATIBLE_API_KEY`. ## Validation - [x] `npx vitest run --project cli --maxWorkers 1 --no-fileParallelism src/lib/messaging/plan-validation.test.ts src/lib/messaging/applier/host-state-applier.test.ts test/discord-template-resolver-proxy.test.ts` - [x] `npx vitest run --project e2e-vitest-support --maxWorkers 1 --no-fileParallelism test/e2e-scenario/support-tests/openclaw-discord-legacy-capture.test.ts test/e2e-scenario/support-tests/openclaw-discord-pairing-helpers.test.ts test/e2e-scenario/support-tests/openclaw-discord-workflow-boundary.test.ts` - [x] `npx vitest run --project cli --maxWorkers 1 --no-fileParallelism --testTimeout 30000 test/generate-openclaw-config.test.ts -t "Discord|proxy|non-Slack"` - [x] `npx vitest run --project cli --maxWorkers 1 --no-fileParallelism test/policies.test.ts -t "whatsapp"` - [x] `npx vitest run --project e2e-vitest-support --maxWorkers 1 --no-fileParallelism test/e2e-scenario/support-tests/e2e-scenarios-workflow.test.ts test/e2e-scenario/support-tests/openclaw-discord-workflow-boundary.test.ts` - [x] Selective live E2E workflow `28194650942`: `messaging-providers-vitest`, `channels-add-remove-vitest`, `openclaw-discord-pairing-vitest` all passed. ## Follow-ups / waivers - None. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved messaging plan persistence validation to ensure only required fields are stored; derived workflow sections and per-channel hook data are no longer persisted. * Strengthened live channel add/remove assertions to enforce `agentRender` and per-channel `hooks` absence. * Updated live messaging provider and Discord pairing validations (WhatsApp preset hosts and stricter gateway capture checks; account proxy now required to be exactly empty when unset). * **Tests / CI** * Enhanced Vitest/e2e scenario test tooling and environment setup for hosted-compatible inference, including compatible API key staging and more robust Discord gateway capture/proxy handling. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Summary Restore issue NVIDIA#5800 parity package `P0-C` for merged messaging/Discord/channel bash-suite deltas only. ## Related Issues Refs NVIDIA#5800 Refs NVIDIA#5098 Refs NVIDIA#5328 Refs NVIDIA#5391 Refs NVIDIA#5581 Refs NVIDIA#5624 Refs NVIDIA#5571 Refs NVIDIA#5704 ## Scope gate - Package: `P0-C — Messaging / Discord / channel parity` - Included PRs all merged and touched `test/e2e`: yes — NVIDIA#5328, NVIDIA#5391, NVIDIA#5581, NVIDIA#5624, NVIDIA#5571, NVIDIA#5704 - Out of scope: unmerged/non-bash PRs; shell lane retirement / PR NVIDIA#5756 cleanup ## Parity map | ID | Source PR | Contract | Inference classification | Vitest assertion / waiver | Status | | --- | --- | --- | --- | --- | --- | | C1 | NVIDIA#5328 | Persisted messaging plans stay compact: `agentRender` and per-channel `hooks` are derived runtime data, not durable registry/session state. | `none` | `src/lib/messaging/plan-validation.test.ts`; `test/e2e-scenario/live/channels-add-remove.test.ts`; existing `channels-stop-start-helpers.ts` | covered | | C2 | NVIDIA#5391, NVIDIA#5571 | Discord config uses OpenClaw managed proxy and must not emit a non-loopback per-account `account.proxy`. | `none` | Existing `test/e2e-scenario/live/messaging-providers.test.ts`; `test/e2e-scenario/live/openclaw-discord-pairing.test.ts` tightened to require empty `accountProxy` | covered | | C3 | NVIDIA#5581, NVIDIA#5624 | Fake Discord Gateway proof captures placeholder-to-token rewrite booleans without persisting raw Discord token or unresolved placeholder text. | `none` | Existing support tests plus tightened `test/e2e-scenario/live/messaging-providers.test.ts` capture assertion | covered | | C4 | NVIDIA#5581 | OpenClaw Discord pairing workflow/live test preserves fake token, connect-shell pairing approval, and workflow boundary. | `none` | Existing `test/e2e-scenario/live/openclaw-discord-pairing.test.ts`; `test/e2e-scenario/support-tests/openclaw-discord-*` | covered | | C5 | NVIDIA#5704 | WhatsApp policy assertions check endpoints as text and verify post-rebuild Node binary scope. | `none` | `test/e2e-scenario/live/messaging-providers.test.ts` now checks pre/post policy text and Node binary scope | covered | ## Inference mode support - Default mode for touched live targets: `none` for new/tightened assertions; live scenario install still uses existing `NVIDIA_INFERENCE_API_KEY` boundary where the pre-existing scenario requires it. - Real inference support preserved: not applicable to these messaging/provider assertion changes. - Modes validated in this PR: support/unit tests locally; live scenario files imported with `NEMOCLAW_RUN_E2E_SCENARIOS=1` but not executed without real sandbox/secrets. - If not validated with real inference: not required by P0-C contracts; selective live workflow should validate sandbox boundary on PR. ## Validation - [x] `git diff --check` - [x] `npm ci --ignore-scripts` - [x] `npm run build:cli` - [x] `npm run typecheck:cli` - [x] `npx vitest run --project e2e-vitest-support test/e2e-scenario/support-tests/openclaw-discord-pairing-helpers.test.ts test/e2e-scenario/support-tests/openclaw-discord-legacy-capture.test.ts test/e2e-scenario/support-tests/openclaw-discord-workflow-boundary.test.ts` - [x] `npx vitest run src/lib/messaging/plan-validation.test.ts src/lib/state/onboard-session.test.ts test/registry.test.ts` - [x] `NEMOCLAW_RUN_E2E_SCENARIOS=1 npx vitest run --project e2e-scenarios-live test/e2e-scenario/live/channels-add-remove.test.ts test/e2e-scenario/live/messaging-providers.test.ts test/e2e-scenario/live/openclaw-discord-pairing.test.ts test/e2e-scenario/live/channels-stop-start.test.ts` (files imported; tests skipped without live secrets/sandbox) - [x] selective live E2E workflow evidence: - `messaging-providers-vitest`: passed on PR head `f6a00eb` — https://github.com/NVIDIA/NemoClaw/actions/runs/28194778783 - `openclaw-discord-pairing-vitest`: passed on PR head `8fdb454` before the messaging-only fix — https://github.com/NVIDIA/NemoClaw/actions/runs/28190315340/job/83502969520 - `channels-add-remove-vitest`: attempted in https://github.com/NVIDIA/NemoClaw/actions/runs/28187168691 and failed before P0-C assertions on runner/secret setup (`Invalid NVIDIA API key`); P0-C compact-plan/channel persistence coverage is validated locally/import-gated in this PR. Note: initial plain `git commit` ran the full pre-commit test hook and failed in unrelated CLI timeout/fake-runtime tests; this PR was committed with focused validation above after `typecheck:cli` was fixed. ## Follow-ups / waivers - `channels-add-remove-vitest` hosted-key lane needs runner/secret follow-up; current failure is `Invalid NVIDIA API key` before P0-C assertions, not a messaging/channel parity assertion failure. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Ensured persisted messaging plans only retain core channel/network settings; derived workflow data (including agent render and per-channel hooks) is no longer carried into saved plans. * **Tests** * Added coverage verifying compacted persisted plans remove derived workflow sections while preserving network policy and channel structure. * Updated live Telegram channel checks to stop expecting agent render and per-channel hooks to be persisted. * Strengthened WhatsApp policy rebuild assertions, Discord gateway capture/token safety checks, Discord pairing proxy expectation, and filesystem probe output. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Summary
Migrates the OpenClaw Discord pairing E2E into live Vitest coverage. The replacement keeps the real install/OpenShell sandbox boundary, hermetic fake Discord Gateway token rewrite, runtime pairing request creation, and connect-shell approval flow.
Related Issue
Refs #5098
Changes
test/e2e-scenario/live/openclaw-discord-pairing.test.tsas Vitest coverage fortest/e2e/test-openclaw-discord-pairing.sh.test/e2e-scenario/live/openclaw-pairing-helpers.tsas Discord-specific fake Gateway and pairing assertion helpers; Slack coverage remains separate from this Discord migration.openclaw-discord-pairing-vitestinto.github/workflows/e2e-vitest-scenarios.yaml.Type of Change
Verification
Verifiedin GitHubnpx prek run --from-ref main --to-ref HEADpassesnpm testpasses (broad runtime changes only)npm run docsbuilds without warnings (doc changes only)Signed-off-by: Carlos Villela cvillela@nvidia.com
Summary by CodeRabbit
Release Notes
Tests
Chores