Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
213 changes: 213 additions & 0 deletions .github/workflows/e2e-regression.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
name: E2E Regression (Nightly)

# Runs the full e2e test glob (tests/**/*.smoke.ts) once per night against the
# dev MCP. Independent of the deploy gate - failures here do NOT block prod
# tagging. They post to Slack so the team sees them in the morning and can
# triage from the forensics artifact on the run page.
#
# As later phases add more tests (one per tool, across every service in src/),
# this is the workflow that exercises them. The deploy gate stays at the
# 1 read + 1 write per service minimum defined in e2e/tests/gate.manifest.ts.

on:
schedule:
- cron: '0 3 * * *' # 03:00 UTC daily
workflow_dispatch:
inputs:
ref:
description: 'Git SHA to test (defaults to current main)'
required: false
type: string

permissions:
contents: read

jobs:
claude-desktop:
runs-on: [self-hosted, macOS, mac-studio]
timeout-minutes: 60
env:
CLIENT: claude-desktop
ARTIFACTS_DIR: ${{ github.workspace }}/e2e/.artifacts
APPIUM_HOST: 127.0.0.1
APPIUM_PORT: '4723'
RESPONSE_TIMEOUT_MS: '120000'
# --- Read fixtures (readonly identity, per service) ---
E2E_FIXTURE_DOC_ID: ${{ vars.E2E_FIXTURE_DOC_ID }}
E2E_FIXTURE_DOC_NEEDLE: ${{ vars.E2E_FIXTURE_DOC_NEEDLE }}
E2E_FIXTURE_DRIVE_FOLDER_ID: ${{ vars.E2E_FIXTURE_DRIVE_FOLDER_ID }}
E2E_FIXTURE_DRIVE_NEEDLE: ${{ vars.E2E_FIXTURE_DRIVE_NEEDLE }}
E2E_FIXTURE_GMAIL_QUERY: ${{ vars.E2E_FIXTURE_GMAIL_QUERY }}
E2E_FIXTURE_GMAIL_NEEDLE: ${{ vars.E2E_FIXTURE_GMAIL_NEEDLE }}
E2E_FIXTURE_CALENDAR_ID: ${{ vars.E2E_FIXTURE_CALENDAR_ID }}
E2E_FIXTURE_CALENDAR_NEEDLE: ${{ vars.E2E_FIXTURE_CALENDAR_NEEDLE }}
E2E_FIXTURE_SHEET_ID: ${{ vars.E2E_FIXTURE_SHEET_ID }}
E2E_FIXTURE_SHEET_NEEDLE: ${{ vars.E2E_FIXTURE_SHEET_NEEDLE }}
E2E_FIXTURE_SLIDES_ID: ${{ vars.E2E_FIXTURE_SLIDES_ID }}
E2E_FIXTURE_SLIDES_NEEDLE: ${{ vars.E2E_FIXTURE_SLIDES_NEEDLE }}
E2E_FIXTURE_CLICKUP_LIST_ID: ${{ vars.E2E_FIXTURE_CLICKUP_LIST_ID }}
E2E_FIXTURE_CLICKUP_NEEDLE: ${{ vars.E2E_FIXTURE_CLICKUP_NEEDLE }}
E2E_FIXTURE_SLACK_CHANNEL_ID: ${{ vars.E2E_FIXTURE_SLACK_CHANNEL_ID }}
E2E_FIXTURE_SLACK_NEEDLE: ${{ vars.E2E_FIXTURE_SLACK_NEEDLE }}
E2E_FIXTURE_SLACK_USER_CHANNEL_ID: ${{ vars.E2E_FIXTURE_SLACK_USER_CHANNEL_ID }}
E2E_FIXTURE_SLACK_USER_NEEDLE: ${{ vars.E2E_FIXTURE_SLACK_USER_NEEDLE }}
# Optional read-fixture overrides; the tests fall back to a sane default
# when these are unset (Actions passes '' for an unconfigured var).
E2E_FIXTURE_SHEET_RANGE: ${{ vars.E2E_FIXTURE_SHEET_RANGE }}
E2E_FIXTURE_CALENDAR_TIME_MIN: ${{ vars.E2E_FIXTURE_CALENDAR_TIME_MIN }}
E2E_FIXTURE_CALENDAR_TIME_MAX: ${{ vars.E2E_FIXTURE_CALENDAR_TIME_MAX }}
# --- Write scratch scopes (write identity, per backend) ---
E2E_SCRATCH_FOLDER_ID: ${{ vars.E2E_SCRATCH_FOLDER_ID }}
E2E_CALENDAR_SCRATCH_ID: ${{ vars.E2E_CALENDAR_SCRATCH_ID }}
E2E_GMAIL_SCRATCH_LABEL: ${{ vars.E2E_GMAIL_SCRATCH_LABEL }}
E2E_GMAIL_SCRATCH_RECIPIENT: ${{ vars.E2E_GMAIL_SCRATCH_RECIPIENT }}
E2E_CLICKUP_SCRATCH_LIST_ID: ${{ vars.E2E_CLICKUP_SCRATCH_LIST_ID }}
E2E_CLICKUP_SCRATCH_SPACE_ID: ${{ vars.E2E_CLICKUP_SCRATCH_SPACE_ID }}
E2E_SLACK_SCRATCH_CHANNEL_ID: ${{ vars.E2E_SLACK_SCRATCH_CHANNEL_ID }}
# --- Direct-API credentials for setup/teardown (never the MCP's own) ---
E2E_WRITE_GOOGLE_REFRESH_TOKEN: ${{ secrets.E2E_WRITE_GOOGLE_REFRESH_TOKEN }}
E2E_GOOGLE_CLIENT_ID: ${{ secrets.E2E_GOOGLE_CLIENT_ID }}
E2E_GOOGLE_CLIENT_SECRET: ${{ secrets.E2E_GOOGLE_CLIENT_SECRET }}
E2E_CLICKUP_API_TOKEN: ${{ secrets.E2E_CLICKUP_API_TOKEN }}
E2E_SLACK_BOT_TOKEN: ${{ secrets.E2E_SLACK_BOT_TOKEN }}
E2E_SLACK_USER_TOKEN: ${{ secrets.E2E_SLACK_USER_TOKEN }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
ref: ${{ inputs.ref || 'main' }}
persist-credentials: false

- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20

- name: Pre-flight - Appium reachable
run: |
curl --fail --silent --show-error --max-time 5 \
"http://${APPIUM_HOST}:${APPIUM_PORT}/status" \
| head -c 300

- name: Install e2e deps
working-directory: e2e
run: npm install

- name: Run full regression (Claude Desktop)
id: tests
working-directory: e2e
run: npm run test:full

- name: Upload forensics bundle
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: e2e-regression-claude-desktop-${{ github.run_id }}
path: e2e/.artifacts/**
retention-days: 90
if-no-files-found: warn

- name: Notify Slack on failure
if: failure() && env.SLACK_WEBHOOK_URL != ''
env:
SLACK_WEBHOOK_URL: ${{ secrets.E2E_SLACK_WEBHOOK_URL }}
run: |
curl --fail --silent --show-error -X POST -H 'Content-type: application/json' \
--data "$(cat <<EOF
{"text": ":rotating_light: E2E nightly regression FAILED (claude-desktop)\nRun: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\nSee forensics artifact for details."}
EOF
)" \
"$SLACK_WEBHOOK_URL"

chatgpt-web:
runs-on: [self-hosted, macOS, mac-studio]
needs: [claude-desktop]
# Advisory regardless of the gate's status - same posture as the smoke job.
continue-on-error: true
timeout-minutes: 60
env:
CLIENT: chatgpt-web
ARTIFACTS_DIR: ${{ github.workspace }}/e2e/.artifacts
CHATGPT_CDP_ENDPOINT: http://127.0.0.1:9222
RESPONSE_TIMEOUT_MS: '120000'
# --- Read fixtures (readonly identity, per service) ---
E2E_FIXTURE_DOC_ID: ${{ vars.E2E_FIXTURE_DOC_ID }}
E2E_FIXTURE_DOC_NEEDLE: ${{ vars.E2E_FIXTURE_DOC_NEEDLE }}
E2E_FIXTURE_DRIVE_FOLDER_ID: ${{ vars.E2E_FIXTURE_DRIVE_FOLDER_ID }}
E2E_FIXTURE_DRIVE_NEEDLE: ${{ vars.E2E_FIXTURE_DRIVE_NEEDLE }}
E2E_FIXTURE_GMAIL_QUERY: ${{ vars.E2E_FIXTURE_GMAIL_QUERY }}
E2E_FIXTURE_GMAIL_NEEDLE: ${{ vars.E2E_FIXTURE_GMAIL_NEEDLE }}
E2E_FIXTURE_CALENDAR_ID: ${{ vars.E2E_FIXTURE_CALENDAR_ID }}
E2E_FIXTURE_CALENDAR_NEEDLE: ${{ vars.E2E_FIXTURE_CALENDAR_NEEDLE }}
E2E_FIXTURE_SHEET_ID: ${{ vars.E2E_FIXTURE_SHEET_ID }}
E2E_FIXTURE_SHEET_NEEDLE: ${{ vars.E2E_FIXTURE_SHEET_NEEDLE }}
E2E_FIXTURE_SLIDES_ID: ${{ vars.E2E_FIXTURE_SLIDES_ID }}
E2E_FIXTURE_SLIDES_NEEDLE: ${{ vars.E2E_FIXTURE_SLIDES_NEEDLE }}
E2E_FIXTURE_CLICKUP_LIST_ID: ${{ vars.E2E_FIXTURE_CLICKUP_LIST_ID }}
E2E_FIXTURE_CLICKUP_NEEDLE: ${{ vars.E2E_FIXTURE_CLICKUP_NEEDLE }}
E2E_FIXTURE_SLACK_CHANNEL_ID: ${{ vars.E2E_FIXTURE_SLACK_CHANNEL_ID }}
E2E_FIXTURE_SLACK_NEEDLE: ${{ vars.E2E_FIXTURE_SLACK_NEEDLE }}
E2E_FIXTURE_SLACK_USER_CHANNEL_ID: ${{ vars.E2E_FIXTURE_SLACK_USER_CHANNEL_ID }}
E2E_FIXTURE_SLACK_USER_NEEDLE: ${{ vars.E2E_FIXTURE_SLACK_USER_NEEDLE }}
# Optional read-fixture overrides; the tests fall back to a sane default
# when these are unset (Actions passes '' for an unconfigured var).
E2E_FIXTURE_SHEET_RANGE: ${{ vars.E2E_FIXTURE_SHEET_RANGE }}
E2E_FIXTURE_CALENDAR_TIME_MIN: ${{ vars.E2E_FIXTURE_CALENDAR_TIME_MIN }}
E2E_FIXTURE_CALENDAR_TIME_MAX: ${{ vars.E2E_FIXTURE_CALENDAR_TIME_MAX }}
# --- Write scratch scopes (write identity, per backend) ---
E2E_SCRATCH_FOLDER_ID: ${{ vars.E2E_SCRATCH_FOLDER_ID }}
E2E_CALENDAR_SCRATCH_ID: ${{ vars.E2E_CALENDAR_SCRATCH_ID }}
E2E_GMAIL_SCRATCH_LABEL: ${{ vars.E2E_GMAIL_SCRATCH_LABEL }}
E2E_GMAIL_SCRATCH_RECIPIENT: ${{ vars.E2E_GMAIL_SCRATCH_RECIPIENT }}
E2E_CLICKUP_SCRATCH_LIST_ID: ${{ vars.E2E_CLICKUP_SCRATCH_LIST_ID }}
E2E_CLICKUP_SCRATCH_SPACE_ID: ${{ vars.E2E_CLICKUP_SCRATCH_SPACE_ID }}
E2E_SLACK_SCRATCH_CHANNEL_ID: ${{ vars.E2E_SLACK_SCRATCH_CHANNEL_ID }}
# --- Direct-API credentials for setup/teardown (never the MCP's own) ---
E2E_WRITE_GOOGLE_REFRESH_TOKEN: ${{ secrets.E2E_WRITE_GOOGLE_REFRESH_TOKEN }}
E2E_GOOGLE_CLIENT_ID: ${{ secrets.E2E_GOOGLE_CLIENT_ID }}
E2E_GOOGLE_CLIENT_SECRET: ${{ secrets.E2E_GOOGLE_CLIENT_SECRET }}
E2E_CLICKUP_API_TOKEN: ${{ secrets.E2E_CLICKUP_API_TOKEN }}
E2E_SLACK_BOT_TOKEN: ${{ secrets.E2E_SLACK_BOT_TOKEN }}
E2E_SLACK_USER_TOKEN: ${{ secrets.E2E_SLACK_USER_TOKEN }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
ref: ${{ inputs.ref || 'main' }}
persist-credentials: false

- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 20

- name: Pre-flight - Chrome CDP reachable
run: |
curl --fail --silent --show-error --max-time 5 \
"${CHATGPT_CDP_ENDPOINT}/json/version" \
| head -c 300

- name: Install e2e deps
working-directory: e2e
run: npm install

- name: Run full regression (ChatGPT web)
working-directory: e2e
run: npm run test:full

- name: Upload forensics bundle
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: e2e-regression-chatgpt-web-${{ github.run_id }}
path: e2e/.artifacts/**
retention-days: 90
if-no-files-found: warn

- name: Notify Slack on failure
if: failure() && env.SLACK_WEBHOOK_URL != ''
env:
SLACK_WEBHOOK_URL: ${{ secrets.E2E_SLACK_WEBHOOK_URL }}
run: |
curl --fail --silent --show-error -X POST -H 'Content-type: application/json' \
--data "$(cat <<EOF
{"text": ":warning: E2E nightly regression failed (chatgpt-web, advisory)\nRun: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"}
EOF
)" \
"$SLACK_WEBHOOK_URL"
86 changes: 82 additions & 4 deletions .github/workflows/e2e-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ name: E2E Smoke (Live Clients)
# Claude Desktop is the blocking signal for prod promotion.
# ChatGPT is advisory in v1 (continue-on-error) while OpenAI's MCP surface
# is still shifting. Promote to blocking once flake rate is acceptable.
#
# The gate is the explicit file list in e2e/tests/gate.manifest.ts: one read +
# one write smoke for every service in src/ that has write tools. It is not a
# glob — breadth belongs in e2e-regression.yml.

on:
workflow_run:
Expand All @@ -32,8 +36,45 @@ jobs:
APPIUM_HOST: 127.0.0.1
APPIUM_PORT: '4723'
RESPONSE_TIMEOUT_MS: '120000'
# --- Read fixtures (readonly identity, per service) ---
E2E_FIXTURE_DOC_ID: ${{ vars.E2E_FIXTURE_DOC_ID }}
E2E_FIXTURE_DOC_NEEDLE: ${{ vars.E2E_FIXTURE_DOC_NEEDLE }}
E2E_FIXTURE_DRIVE_FOLDER_ID: ${{ vars.E2E_FIXTURE_DRIVE_FOLDER_ID }}
E2E_FIXTURE_DRIVE_NEEDLE: ${{ vars.E2E_FIXTURE_DRIVE_NEEDLE }}
E2E_FIXTURE_GMAIL_QUERY: ${{ vars.E2E_FIXTURE_GMAIL_QUERY }}
E2E_FIXTURE_GMAIL_NEEDLE: ${{ vars.E2E_FIXTURE_GMAIL_NEEDLE }}
E2E_FIXTURE_CALENDAR_ID: ${{ vars.E2E_FIXTURE_CALENDAR_ID }}
E2E_FIXTURE_CALENDAR_NEEDLE: ${{ vars.E2E_FIXTURE_CALENDAR_NEEDLE }}
E2E_FIXTURE_SHEET_ID: ${{ vars.E2E_FIXTURE_SHEET_ID }}
E2E_FIXTURE_SHEET_NEEDLE: ${{ vars.E2E_FIXTURE_SHEET_NEEDLE }}
E2E_FIXTURE_SLIDES_ID: ${{ vars.E2E_FIXTURE_SLIDES_ID }}
E2E_FIXTURE_SLIDES_NEEDLE: ${{ vars.E2E_FIXTURE_SLIDES_NEEDLE }}
E2E_FIXTURE_CLICKUP_LIST_ID: ${{ vars.E2E_FIXTURE_CLICKUP_LIST_ID }}
E2E_FIXTURE_CLICKUP_NEEDLE: ${{ vars.E2E_FIXTURE_CLICKUP_NEEDLE }}
E2E_FIXTURE_SLACK_CHANNEL_ID: ${{ vars.E2E_FIXTURE_SLACK_CHANNEL_ID }}
E2E_FIXTURE_SLACK_NEEDLE: ${{ vars.E2E_FIXTURE_SLACK_NEEDLE }}
E2E_FIXTURE_SLACK_USER_CHANNEL_ID: ${{ vars.E2E_FIXTURE_SLACK_USER_CHANNEL_ID }}
E2E_FIXTURE_SLACK_USER_NEEDLE: ${{ vars.E2E_FIXTURE_SLACK_USER_NEEDLE }}
# Optional read-fixture overrides; the tests fall back to a sane default
# when these are unset (Actions passes '' for an unconfigured var).
E2E_FIXTURE_SHEET_RANGE: ${{ vars.E2E_FIXTURE_SHEET_RANGE }}
E2E_FIXTURE_CALENDAR_TIME_MIN: ${{ vars.E2E_FIXTURE_CALENDAR_TIME_MIN }}
E2E_FIXTURE_CALENDAR_TIME_MAX: ${{ vars.E2E_FIXTURE_CALENDAR_TIME_MAX }}
# --- Write scratch scopes (write identity, per backend) ---
E2E_SCRATCH_FOLDER_ID: ${{ vars.E2E_SCRATCH_FOLDER_ID }}
E2E_CALENDAR_SCRATCH_ID: ${{ vars.E2E_CALENDAR_SCRATCH_ID }}
E2E_GMAIL_SCRATCH_LABEL: ${{ vars.E2E_GMAIL_SCRATCH_LABEL }}
E2E_GMAIL_SCRATCH_RECIPIENT: ${{ vars.E2E_GMAIL_SCRATCH_RECIPIENT }}
E2E_CLICKUP_SCRATCH_LIST_ID: ${{ vars.E2E_CLICKUP_SCRATCH_LIST_ID }}
E2E_CLICKUP_SCRATCH_SPACE_ID: ${{ vars.E2E_CLICKUP_SCRATCH_SPACE_ID }}
E2E_SLACK_SCRATCH_CHANNEL_ID: ${{ vars.E2E_SLACK_SCRATCH_CHANNEL_ID }}
# --- Direct-API credentials for setup/teardown (never the MCP's own) ---
E2E_WRITE_GOOGLE_REFRESH_TOKEN: ${{ secrets.E2E_WRITE_GOOGLE_REFRESH_TOKEN }}
E2E_GOOGLE_CLIENT_ID: ${{ secrets.E2E_GOOGLE_CLIENT_ID }}
E2E_GOOGLE_CLIENT_SECRET: ${{ secrets.E2E_GOOGLE_CLIENT_SECRET }}
E2E_CLICKUP_API_TOKEN: ${{ secrets.E2E_CLICKUP_API_TOKEN }}
E2E_SLACK_BOT_TOKEN: ${{ secrets.E2E_SLACK_BOT_TOKEN }}
E2E_SLACK_USER_TOKEN: ${{ secrets.E2E_SLACK_USER_TOKEN }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
Expand All @@ -54,9 +95,9 @@ jobs:
working-directory: e2e
run: npm install

- name: Run Claude Desktop smoke tests
- name: Run smoke gate (1 read + 1 write per service)
working-directory: e2e
run: npm test
run: npm run test:gate

- name: Upload forensics bundle
if: always()
Expand All @@ -81,8 +122,45 @@ jobs:
ARTIFACTS_DIR: ${{ github.workspace }}/e2e/.artifacts
CHATGPT_CDP_ENDPOINT: http://127.0.0.1:9222
RESPONSE_TIMEOUT_MS: '120000'
# --- Read fixtures (readonly identity, per service) ---
E2E_FIXTURE_DOC_ID: ${{ vars.E2E_FIXTURE_DOC_ID }}
E2E_FIXTURE_DOC_NEEDLE: ${{ vars.E2E_FIXTURE_DOC_NEEDLE }}
E2E_FIXTURE_DRIVE_FOLDER_ID: ${{ vars.E2E_FIXTURE_DRIVE_FOLDER_ID }}
E2E_FIXTURE_DRIVE_NEEDLE: ${{ vars.E2E_FIXTURE_DRIVE_NEEDLE }}
E2E_FIXTURE_GMAIL_QUERY: ${{ vars.E2E_FIXTURE_GMAIL_QUERY }}
E2E_FIXTURE_GMAIL_NEEDLE: ${{ vars.E2E_FIXTURE_GMAIL_NEEDLE }}
E2E_FIXTURE_CALENDAR_ID: ${{ vars.E2E_FIXTURE_CALENDAR_ID }}
E2E_FIXTURE_CALENDAR_NEEDLE: ${{ vars.E2E_FIXTURE_CALENDAR_NEEDLE }}
E2E_FIXTURE_SHEET_ID: ${{ vars.E2E_FIXTURE_SHEET_ID }}
E2E_FIXTURE_SHEET_NEEDLE: ${{ vars.E2E_FIXTURE_SHEET_NEEDLE }}
E2E_FIXTURE_SLIDES_ID: ${{ vars.E2E_FIXTURE_SLIDES_ID }}
E2E_FIXTURE_SLIDES_NEEDLE: ${{ vars.E2E_FIXTURE_SLIDES_NEEDLE }}
E2E_FIXTURE_CLICKUP_LIST_ID: ${{ vars.E2E_FIXTURE_CLICKUP_LIST_ID }}
E2E_FIXTURE_CLICKUP_NEEDLE: ${{ vars.E2E_FIXTURE_CLICKUP_NEEDLE }}
E2E_FIXTURE_SLACK_CHANNEL_ID: ${{ vars.E2E_FIXTURE_SLACK_CHANNEL_ID }}
E2E_FIXTURE_SLACK_NEEDLE: ${{ vars.E2E_FIXTURE_SLACK_NEEDLE }}
E2E_FIXTURE_SLACK_USER_CHANNEL_ID: ${{ vars.E2E_FIXTURE_SLACK_USER_CHANNEL_ID }}
E2E_FIXTURE_SLACK_USER_NEEDLE: ${{ vars.E2E_FIXTURE_SLACK_USER_NEEDLE }}
# Optional read-fixture overrides; the tests fall back to a sane default
# when these are unset (Actions passes '' for an unconfigured var).
E2E_FIXTURE_SHEET_RANGE: ${{ vars.E2E_FIXTURE_SHEET_RANGE }}
E2E_FIXTURE_CALENDAR_TIME_MIN: ${{ vars.E2E_FIXTURE_CALENDAR_TIME_MIN }}
E2E_FIXTURE_CALENDAR_TIME_MAX: ${{ vars.E2E_FIXTURE_CALENDAR_TIME_MAX }}
# --- Write scratch scopes (write identity, per backend) ---
E2E_SCRATCH_FOLDER_ID: ${{ vars.E2E_SCRATCH_FOLDER_ID }}
E2E_CALENDAR_SCRATCH_ID: ${{ vars.E2E_CALENDAR_SCRATCH_ID }}
E2E_GMAIL_SCRATCH_LABEL: ${{ vars.E2E_GMAIL_SCRATCH_LABEL }}
E2E_GMAIL_SCRATCH_RECIPIENT: ${{ vars.E2E_GMAIL_SCRATCH_RECIPIENT }}
E2E_CLICKUP_SCRATCH_LIST_ID: ${{ vars.E2E_CLICKUP_SCRATCH_LIST_ID }}
E2E_CLICKUP_SCRATCH_SPACE_ID: ${{ vars.E2E_CLICKUP_SCRATCH_SPACE_ID }}
E2E_SLACK_SCRATCH_CHANNEL_ID: ${{ vars.E2E_SLACK_SCRATCH_CHANNEL_ID }}
# --- Direct-API credentials for setup/teardown (never the MCP's own) ---
E2E_WRITE_GOOGLE_REFRESH_TOKEN: ${{ secrets.E2E_WRITE_GOOGLE_REFRESH_TOKEN }}
E2E_GOOGLE_CLIENT_ID: ${{ secrets.E2E_GOOGLE_CLIENT_ID }}
E2E_GOOGLE_CLIENT_SECRET: ${{ secrets.E2E_GOOGLE_CLIENT_SECRET }}
E2E_CLICKUP_API_TOKEN: ${{ secrets.E2E_CLICKUP_API_TOKEN }}
E2E_SLACK_BOT_TOKEN: ${{ secrets.E2E_SLACK_BOT_TOKEN }}
E2E_SLACK_USER_TOKEN: ${{ secrets.E2E_SLACK_USER_TOKEN }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
Expand All @@ -103,9 +181,9 @@ jobs:
working-directory: e2e
run: npm install

- name: Run ChatGPT web smoke tests
- name: Run smoke gate (1 read + 1 write per service)
working-directory: e2e
run: npm test
run: npm run test:gate

- name: Upload forensics bundle
if: always()
Expand Down
Loading
Loading