Ver código fonte

ci(e2b): add manual live sandbox workflow

Tianyi Cui 1 mês atrás
pai
commit
f34b2bb634
2 arquivos alterados com 85 adições e 0 exclusões
  1. 58 0
      .github/workflows/e2b-e2e.yml
  2. 27 0
      scripts/ci-workflow.spec.ts

+ 58 - 0
.github/workflows/e2b-e2e.yml

@@ -0,0 +1,58 @@
+name: E2E (E2B sandbox)
+
+# This suite provisions external E2B sandboxes and is intentionally opt-in.
+# It has no push, pull_request, schedule, or workflow_call trigger.
+on:
+  workflow_dispatch:
+
+permissions:
+  contents: read
+
+env:
+  # CI runs must never report to the production telemetry endpoint baked
+  # into apps/cli/cordis.yml (AppCLIEntry disables the row when set).
+  DSH_TELEMETRY_DISABLED: '1'
+
+jobs:
+  e2b:
+    runs-on: ubuntu-latest
+    name: E2B live Loader composition
+    timeout-minutes: 30
+    steps:
+      - uses: actions/checkout@v6
+
+      - uses: pnpm/action-setup@v4
+
+      - uses: actions/setup-node@v6
+        with:
+          node-version: 24
+          cache: pnpm
+
+      - name: Install (immutable)
+        run: pnpm install --frozen-lockfile
+
+      # The tests self-skip locally when the credential is absent. A manually
+      # dispatched run must fail instead of reporting an all-skipped green.
+      - name: Preflight (require E2B API key)
+        env:
+          E2B_API_KEY: ${{ secrets.E2B_API_KEY_EXTERNAL }}
+        run: |
+          set -euo pipefail
+          if [ -z "${E2B_API_KEY:-}" ]; then
+            echo "::error::E2B_API_KEY is empty. Configure the E2B_API_KEY_EXTERNAL repository secret."
+            exit 1
+          fi
+          echo "E2B_API_KEY present."
+
+      # The Loader smoke runs package exports under plain Node in lib mode.
+      - name: Build (lib for the E2B Loader smoke)
+        run: pnpm run build
+
+      - name: E2B tests (live sandbox)
+        env:
+          E2B_API_KEY: ${{ secrets.E2B_API_KEY_EXTERNAL }}
+          DSH_E2E_MAX_WORKERS: '1'
+          DSH_EXAMPLE_MODE: lib
+        run: >-
+          pnpm exec vitest run --config vitest.e2e.config.ts
+          packages/e2b/e2b/tests/composition.e2e.ts

+ 27 - 0
scripts/ci-workflow.spec.ts

@@ -28,6 +28,33 @@ describe('CI workflow', () => {
   })
 })
 
+describe('E2B e2e workflow', () => {
+  it('is manual-only and fails loud before running the focused live suite', () => {
+    const workflow = loadWorkflow('.github/workflows/e2b-e2e.yml')
+    expect(workflow.on).toEqual({ workflow_dispatch: null })
+    if (!isRecord(workflow.jobs) || !isRecord(workflow.jobs.e2b) || !Array.isArray(workflow.jobs.e2b.steps)) {
+      throw new TypeError('E2B e2e workflow must define the e2b job steps')
+    }
+
+    const steps = workflow.jobs.e2b.steps.filter(isRecord)
+    const preflight = steps.find(step => step.name === 'Preflight (require E2B API key)')
+    const e2b = steps.find(step => step.name === 'E2B tests (live sandbox)')
+
+    expect(preflight).toMatchObject({
+      env: { E2B_API_KEY: '${{ secrets.E2B_API_KEY_EXTERNAL }}' },
+    })
+    expect(preflight?.run).toContain('E2B_API_KEY_EXTERNAL repository secret')
+    expect(e2b).toMatchObject({
+      env: {
+        E2B_API_KEY: '${{ secrets.E2B_API_KEY_EXTERNAL }}',
+        DSH_E2E_MAX_WORKERS: '1',
+        DSH_EXAMPLE_MODE: 'lib',
+      },
+    })
+    expect(e2b?.run).toContain('packages/e2b/e2b/tests/composition.e2e.ts')
+  })
+})
+
 describe('Issue lifecycle workflow', () => {
   it('uses review signals instead of rerunning when a draft becomes ready', () => {
     const lifecycle = loadWorkflow('.github/workflows/issue-lifecycle.yml')