Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11), free to diverge. Tree copied sans upstream .git; upstream remote added for future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19. Preserves docs/ARCHITECTURE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
804 lines
29 KiB
YAML
804 lines
29 KiB
YAML
name: QA-Lab - All Lanes
|
|
|
|
on:
|
|
schedule:
|
|
- cron: "41 4 * * *"
|
|
workflow_dispatch:
|
|
inputs:
|
|
ref:
|
|
description: Ref, tag, or SHA to run
|
|
required: true
|
|
default: main
|
|
type: string
|
|
scenario:
|
|
description: Optional comma-separated Telegram scenario ids
|
|
required: false
|
|
type: string
|
|
discord_scenario:
|
|
description: Optional comma-separated Discord scenario ids
|
|
required: false
|
|
type: string
|
|
whatsapp_scenario:
|
|
description: Optional comma-separated WhatsApp scenario ids
|
|
required: false
|
|
type: string
|
|
slack_scenario:
|
|
description: Optional comma-separated Slack scenario ids
|
|
required: false
|
|
type: string
|
|
matrix_profile:
|
|
description: Matrix QA profile for the live Matrix lane
|
|
required: false
|
|
default: all
|
|
type: choice
|
|
options:
|
|
- fast
|
|
- all
|
|
- transport
|
|
- media
|
|
- e2ee-smoke
|
|
- e2ee-deep
|
|
- e2ee-cli
|
|
|
|
permissions:
|
|
contents: read
|
|
pull-requests: read
|
|
|
|
concurrency:
|
|
group: qa-lab-all-lanes-${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.sha }}
|
|
cancel-in-progress: false
|
|
|
|
env:
|
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
|
NODE_VERSION: "24.x"
|
|
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL || 'openai/gpt-5.5' }}
|
|
OPENCLAW_CI_OPENAI_FALLBACK_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_FALLBACK_MODEL || 'openai/gpt-5.4' }}
|
|
OPENCLAW_BUILD_PRIVATE_QA: "1"
|
|
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
|
|
|
|
jobs:
|
|
authorize_actor:
|
|
name: Authorize workflow actor
|
|
runs-on: blacksmith-8vcpu-ubuntu-2404
|
|
outputs:
|
|
authorized: ${{ steps.permission.outputs.authorized }}
|
|
steps:
|
|
- name: Require maintainer-level repository access
|
|
id: permission
|
|
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
|
|
with:
|
|
script: |
|
|
if (context.eventName === "schedule") {
|
|
core.info("Scheduled default-branch QA run; actor permission check is only required for manual dispatch.");
|
|
core.setOutput("authorized", "true");
|
|
return;
|
|
}
|
|
const allowed = new Set(["admin", "maintain", "write"]);
|
|
const { owner, repo } = context.repo;
|
|
const { data } = await github.rest.repos.getCollaboratorPermissionLevel({
|
|
owner,
|
|
repo,
|
|
username: context.actor,
|
|
});
|
|
const permission = data.permission;
|
|
core.info(`Actor ${context.actor} permission: ${permission}`);
|
|
if (!allowed.has(permission)) {
|
|
core.notice(
|
|
`Workflow requires write/maintain/admin access. Actor "${context.actor}" has "${permission}".`,
|
|
);
|
|
core.setOutput("authorized", "false");
|
|
return;
|
|
}
|
|
core.setOutput("authorized", "true");
|
|
|
|
validate_selected_ref:
|
|
name: Validate selected ref
|
|
needs: authorize_actor
|
|
if: needs.authorize_actor.outputs.authorized == 'true'
|
|
runs-on: blacksmith-8vcpu-ubuntu-2404
|
|
outputs:
|
|
selected_revision: ${{ steps.validate.outputs.selected_revision }}
|
|
trusted_reason: ${{ steps.validate.outputs.trusted_reason }}
|
|
steps:
|
|
- name: Checkout selected ref
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
with:
|
|
persist-credentials: false
|
|
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.sha }}
|
|
fetch-depth: 0
|
|
|
|
- name: Validate selected ref
|
|
id: validate
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
INPUT_REF: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.sha }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
selected_revision="$(git rev-parse HEAD)"
|
|
trusted_reason=""
|
|
|
|
git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main
|
|
|
|
if git merge-base --is-ancestor "$selected_revision" refs/remotes/origin/main; then
|
|
trusted_reason="main-ancestor"
|
|
elif git tag --points-at "$selected_revision" | grep -Eq '^v'; then
|
|
trusted_reason="release-tag"
|
|
elif [[ "$INPUT_REF" =~ ^release/[0-9]{4}\.[0-9]+\.[0-9]+$ ]]; then
|
|
git fetch --no-tags origin "+refs/heads/${INPUT_REF}:refs/remotes/origin/${INPUT_REF}"
|
|
release_branch_sha="$(git rev-parse "refs/remotes/origin/${INPUT_REF}")"
|
|
if [[ "$selected_revision" == "$release_branch_sha" ]]; then
|
|
trusted_reason="release-branch-head"
|
|
fi
|
|
else
|
|
pr_head_count="$(
|
|
gh api \
|
|
-H "Accept: application/vnd.github+json" \
|
|
"repos/${GITHUB_REPOSITORY}/commits/${selected_revision}/pulls" \
|
|
--jq '[.[] | select(.state == "open" and .head.repo.full_name == "'"${GITHUB_REPOSITORY}"'" and .head.sha == "'"${selected_revision}"'")] | length'
|
|
)"
|
|
if [[ "$pr_head_count" != "0" ]]; then
|
|
trusted_reason="open-pr-head"
|
|
fi
|
|
fi
|
|
|
|
if [[ -z "$trusted_reason" ]]; then
|
|
echo "Ref '${INPUT_REF}' resolved to $selected_revision, which is not trusted for this secret-bearing QA run." >&2
|
|
echo "Allowed refs must be on main, point to a release tag, match a release branch head, or match an open PR head in ${GITHUB_REPOSITORY}." >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "selected_revision=$selected_revision" >> "$GITHUB_OUTPUT"
|
|
echo "trusted_reason=$trusted_reason" >> "$GITHUB_OUTPUT"
|
|
{
|
|
echo "Validated ref: \`${INPUT_REF}\`"
|
|
echo "Resolved SHA: \`$selected_revision\`"
|
|
echo "Trust reason: \`$trusted_reason\`"
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
run_mock_parity:
|
|
name: Run QA Lab mock parity lane
|
|
needs: [validate_selected_ref]
|
|
runs-on: blacksmith-16vcpu-ubuntu-2404
|
|
timeout-minutes: 30
|
|
env:
|
|
QA_PARITY_CONCURRENCY: "1"
|
|
OPENCLAW_QA_TRANSPORT_READY_TIMEOUT_MS: "180000"
|
|
OPENAI_API_KEY: ""
|
|
ANTHROPIC_API_KEY: ""
|
|
OPENCLAW_LIVE_OPENAI_KEY: ""
|
|
OPENCLAW_LIVE_ANTHROPIC_KEY: ""
|
|
OPENCLAW_LIVE_GEMINI_KEY: ""
|
|
OPENCLAW_LIVE_SETUP_TOKEN_VALUE: ""
|
|
steps:
|
|
- name: Checkout selected ref
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
with:
|
|
persist-credentials: false
|
|
ref: ${{ needs.validate_selected_ref.outputs.selected_revision }}
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Node environment
|
|
uses: ./.github/actions/setup-node-env
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
install-bun: "true"
|
|
|
|
- name: Build private QA runtime
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=12288
|
|
run: pnpm build
|
|
|
|
- name: Run OpenAI candidate lane
|
|
run: |
|
|
pnpm openclaw qa suite \
|
|
--provider-mode mock-openai \
|
|
--parity-pack agentic \
|
|
--concurrency "${QA_PARITY_CONCURRENCY}" \
|
|
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
|
--alt-model openai/gpt-5.5-alt \
|
|
--output-dir .artifacts/qa-e2e/openai-candidate
|
|
|
|
- name: Run Opus 4.8 lane
|
|
run: |
|
|
pnpm openclaw qa suite \
|
|
--provider-mode mock-openai \
|
|
--parity-pack agentic \
|
|
--concurrency "${QA_PARITY_CONCURRENCY}" \
|
|
--model anthropic/claude-opus-4-8 \
|
|
--alt-model anthropic/claude-sonnet-4-6 \
|
|
--output-dir .artifacts/qa-e2e/anthropic-baseline
|
|
|
|
- name: Generate parity report
|
|
run: |
|
|
pnpm openclaw qa parity-report \
|
|
--repo-root . \
|
|
--candidate-summary .artifacts/qa-e2e/openai-candidate/qa-suite-summary.json \
|
|
--baseline-summary .artifacts/qa-e2e/anthropic-baseline/qa-suite-summary.json \
|
|
--candidate-label "${OPENCLAW_CI_OPENAI_MODEL}" \
|
|
--baseline-label anthropic/claude-opus-4-8 \
|
|
--output-dir .artifacts/qa-e2e/parity
|
|
|
|
- name: Upload parity artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: qa-parity-${{ github.run_id }}-${{ github.run_attempt }}
|
|
path: .artifacts/qa-e2e/
|
|
retention-days: 14
|
|
if-no-files-found: error
|
|
|
|
run_live_runtime_token_efficiency:
|
|
name: Run live runtime token-efficiency lane
|
|
needs: [authorize_actor, validate_selected_ref]
|
|
if: github.event_name == 'schedule'
|
|
runs-on: blacksmith-16vcpu-ubuntu-2404
|
|
timeout-minutes: 45
|
|
environment: qa-live-shared
|
|
env:
|
|
QA_PARITY_CONCURRENCY: "1"
|
|
OPENCLAW_QA_TRANSPORT_READY_TIMEOUT_MS: "180000"
|
|
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
|
|
steps:
|
|
- name: Checkout selected ref
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
with:
|
|
persist-credentials: false
|
|
ref: ${{ needs.validate_selected_ref.outputs.selected_revision }}
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Node environment
|
|
uses: ./.github/actions/setup-node-env
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
install-bun: "true"
|
|
|
|
- name: Validate required QA credential env
|
|
env:
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
if [[ -z "${OPENAI_API_KEY:-}" ]]; then
|
|
echo "Missing required OPENAI_API_KEY." >&2
|
|
exit 1
|
|
fi
|
|
|
|
- name: Build private QA runtime
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=12288
|
|
run: pnpm build
|
|
|
|
- name: Run live runtime parity lane
|
|
id: run_lane
|
|
shell: bash
|
|
env:
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
OPENCLAW_LIVE_OPENAI_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
output_dir=".artifacts/qa-e2e/runtime-token-efficiency-live-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
|
|
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
|
|
|
|
pnpm openclaw qa suite \
|
|
--repo-root . \
|
|
--provider-mode live-frontier \
|
|
--runtime-parity-tier standard \
|
|
--runtime-parity-tier live-only \
|
|
--concurrency "${QA_PARITY_CONCURRENCY}" \
|
|
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
|
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
|
|
--runtime-pair openclaw,codex \
|
|
--fast \
|
|
--allow-failures \
|
|
--output-dir "${output_dir}/runtime-suite"
|
|
|
|
- name: Generate live runtime token-efficiency report
|
|
if: always() && steps.run_lane.outcome != 'skipped' && steps.run_lane.outcome != 'cancelled'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
pnpm openclaw qa parity-report \
|
|
--repo-root . \
|
|
--runtime-axis \
|
|
--token-efficiency \
|
|
--summary "${{ steps.run_lane.outputs.output_dir }}/runtime-suite/qa-suite-summary.json" \
|
|
--output-dir "${{ steps.run_lane.outputs.output_dir }}/runtime-report"
|
|
|
|
- name: Upload live runtime token-efficiency artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: qa-live-runtime-token-efficiency-${{ github.run_id }}-${{ github.run_attempt }}
|
|
path: ${{ steps.run_lane.outputs.output_dir }}
|
|
retention-days: 14
|
|
if-no-files-found: error
|
|
|
|
run_live_matrix:
|
|
name: Run Matrix live QA lane
|
|
needs: [authorize_actor, validate_selected_ref]
|
|
if: ${{ !(github.event_name == 'workflow_dispatch' && inputs.matrix_profile == 'all') }}
|
|
runs-on: blacksmith-16vcpu-ubuntu-2404
|
|
timeout-minutes: 60
|
|
environment: qa-live-shared
|
|
steps:
|
|
- name: Checkout selected ref
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
with:
|
|
persist-credentials: false
|
|
ref: ${{ needs.validate_selected_ref.outputs.selected_revision }}
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Node environment
|
|
uses: ./.github/actions/setup-node-env
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
install-bun: "true"
|
|
|
|
- name: Validate required QA credential env
|
|
env:
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
if [[ -z "${OPENAI_API_KEY:-}" ]]; then
|
|
echo "Missing required OPENAI_API_KEY." >&2
|
|
exit 1
|
|
fi
|
|
|
|
- name: Build private QA runtime
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=12288
|
|
run: pnpm build
|
|
|
|
- name: Run Matrix live lane
|
|
id: run_lane
|
|
shell: bash
|
|
env:
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
INPUT_MATRIX_PROFILE: ${{ github.event_name == 'workflow_dispatch' && inputs.matrix_profile || 'fast' }}
|
|
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
|
|
OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS: "3000"
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
output_dir=".artifacts/qa-e2e/matrix-live-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
|
|
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
|
|
|
|
matrix_args=(
|
|
--repo-root . \
|
|
--output-dir "${output_dir}" \
|
|
--provider-mode live-frontier \
|
|
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
|
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
|
|
--profile "${INPUT_MATRIX_PROFILE}" \
|
|
--fast
|
|
)
|
|
if pnpm openclaw qa matrix --help 2>/dev/null | grep -F -q -- "--fail-fast"; then
|
|
matrix_args+=(--fail-fast)
|
|
fi
|
|
|
|
pnpm openclaw qa matrix "${matrix_args[@]}"
|
|
|
|
- name: Upload Matrix QA artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: qa-live-matrix-${{ github.run_id }}-${{ github.run_attempt }}
|
|
path: ${{ steps.run_lane.outputs.output_dir }}
|
|
retention-days: 14
|
|
if-no-files-found: error
|
|
|
|
run_live_matrix_sharded:
|
|
name: Run Matrix live QA lane (${{ matrix.profile }})
|
|
needs: [authorize_actor, validate_selected_ref]
|
|
if: ${{ github.event_name == 'workflow_dispatch' && inputs.matrix_profile == 'all' }}
|
|
runs-on: blacksmith-16vcpu-ubuntu-2404
|
|
timeout-minutes: 60
|
|
environment: qa-live-shared
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
profile:
|
|
- transport
|
|
- media
|
|
- e2ee-smoke
|
|
- e2ee-deep
|
|
- e2ee-cli
|
|
steps:
|
|
- name: Checkout selected ref
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
with:
|
|
persist-credentials: false
|
|
ref: ${{ needs.validate_selected_ref.outputs.selected_revision }}
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Node environment
|
|
uses: ./.github/actions/setup-node-env
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
install-bun: "true"
|
|
|
|
- name: Validate required QA credential env
|
|
env:
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
if [[ -z "${OPENAI_API_KEY:-}" ]]; then
|
|
echo "Missing required OPENAI_API_KEY." >&2
|
|
exit 1
|
|
fi
|
|
|
|
- name: Build private QA runtime
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=12288
|
|
run: pnpm build
|
|
|
|
- name: Run Matrix live lane shard
|
|
id: run_lane
|
|
shell: bash
|
|
env:
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
|
|
OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS: "3000"
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
output_dir=".artifacts/qa-e2e/matrix-live-${{ matrix.profile }}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
|
|
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
|
|
|
|
matrix_args=(
|
|
--repo-root . \
|
|
--output-dir "${output_dir}" \
|
|
--provider-mode live-frontier \
|
|
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
|
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
|
|
--profile "${{ matrix.profile }}" \
|
|
--fast
|
|
)
|
|
if pnpm openclaw qa matrix --help 2>/dev/null | grep -F -q -- "--fail-fast"; then
|
|
matrix_args+=(--fail-fast)
|
|
fi
|
|
|
|
pnpm openclaw qa matrix "${matrix_args[@]}"
|
|
|
|
- name: Upload Matrix QA shard artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: qa-live-matrix-${{ matrix.profile }}-${{ github.run_id }}-${{ github.run_attempt }}
|
|
path: ${{ steps.run_lane.outputs.output_dir }}
|
|
retention-days: 14
|
|
if-no-files-found: error
|
|
|
|
run_live_telegram:
|
|
name: Run Telegram live QA lane with Convex leases
|
|
needs: [authorize_actor, validate_selected_ref]
|
|
runs-on: blacksmith-16vcpu-ubuntu-2404
|
|
timeout-minutes: 60
|
|
environment: qa-live-shared
|
|
steps:
|
|
- name: Checkout selected ref
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
with:
|
|
persist-credentials: false
|
|
ref: ${{ needs.validate_selected_ref.outputs.selected_revision }}
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Node environment
|
|
uses: ./.github/actions/setup-node-env
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
install-bun: "true"
|
|
|
|
- &qa_live_required_credentials_step
|
|
name: Validate required QA credential env
|
|
env:
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
|
|
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
require_var() {
|
|
local key="$1"
|
|
if [[ -z "${!key:-}" ]]; then
|
|
echo "Missing required ${key}." >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
require_var OPENAI_API_KEY
|
|
require_var OPENCLAW_QA_CONVEX_SITE_URL
|
|
require_var OPENCLAW_QA_CONVEX_SECRET_CI
|
|
|
|
- name: Build private QA runtime
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=12288
|
|
run: pnpm build
|
|
|
|
- name: Run Telegram live lane
|
|
id: run_lane
|
|
shell: bash
|
|
env:
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
|
|
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
|
|
OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS: "1800000"
|
|
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
|
|
OPENCLAW_QA_TRANSPORT_READY_TIMEOUT_MS: "180000"
|
|
INPUT_SCENARIO: ${{ github.event_name == 'workflow_dispatch' && inputs.scenario || '' }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
output_dir=".artifacts/qa-e2e/telegram-live-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
|
|
scenario_args=()
|
|
|
|
if [[ -n "${INPUT_SCENARIO// }" ]]; then
|
|
IFS=',' read -r -a raw_scenarios <<<"${INPUT_SCENARIO}"
|
|
for raw in "${raw_scenarios[@]}"; do
|
|
scenario="$(printf '%s' "${raw}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
|
|
if [[ -n "${scenario}" ]]; then
|
|
scenario_args+=(--scenario "${scenario}")
|
|
fi
|
|
done
|
|
fi
|
|
|
|
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
|
|
|
|
pnpm openclaw qa telegram \
|
|
--repo-root . \
|
|
--output-dir "${output_dir}" \
|
|
--provider-mode live-frontier \
|
|
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
|
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
|
|
--fast \
|
|
--credential-source convex \
|
|
--credential-role ci \
|
|
"${scenario_args[@]}"
|
|
|
|
- name: Upload Telegram QA artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: qa-live-telegram-${{ github.run_id }}-${{ github.run_attempt }}
|
|
path: ${{ steps.run_lane.outputs.output_dir }}
|
|
retention-days: 14
|
|
if-no-files-found: error
|
|
|
|
run_live_discord:
|
|
name: Run Discord live QA lane with Convex leases
|
|
needs: [authorize_actor, validate_selected_ref]
|
|
runs-on: blacksmith-16vcpu-ubuntu-2404
|
|
timeout-minutes: 60
|
|
environment: qa-live-shared
|
|
steps:
|
|
- name: Checkout selected ref
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
with:
|
|
persist-credentials: false
|
|
ref: ${{ needs.validate_selected_ref.outputs.selected_revision }}
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Node environment
|
|
uses: ./.github/actions/setup-node-env
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
install-bun: "true"
|
|
|
|
- *qa_live_required_credentials_step
|
|
- name: Build private QA runtime
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=12288
|
|
run: pnpm build
|
|
|
|
- name: Run Discord live lane
|
|
id: run_lane
|
|
shell: bash
|
|
env:
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
|
|
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
|
|
OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS: "1800000"
|
|
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
|
|
OPENCLAW_QA_DISCORD_CAPTURE_CONTENT: "1"
|
|
INPUT_SCENARIO: ${{ github.event_name == 'workflow_dispatch' && inputs.discord_scenario || '' }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
output_dir=".artifacts/qa-e2e/discord-live-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
|
|
scenario_args=()
|
|
|
|
if [[ -n "${INPUT_SCENARIO// }" ]]; then
|
|
IFS=',' read -r -a raw_scenarios <<<"${INPUT_SCENARIO}"
|
|
for raw in "${raw_scenarios[@]}"; do
|
|
scenario="$(printf '%s' "${raw}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
|
|
if [[ -n "${scenario}" ]]; then
|
|
scenario_args+=(--scenario "${scenario}")
|
|
fi
|
|
done
|
|
fi
|
|
|
|
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
|
|
|
|
pnpm openclaw qa discord \
|
|
--repo-root . \
|
|
--output-dir "${output_dir}" \
|
|
--provider-mode live-frontier \
|
|
--model openai/gpt-5.5 \
|
|
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
|
|
--fast \
|
|
--credential-source convex \
|
|
--credential-role ci \
|
|
"${scenario_args[@]}"
|
|
|
|
- name: Upload Discord QA artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: qa-live-discord-${{ github.run_id }}-${{ github.run_attempt }}
|
|
path: ${{ steps.run_lane.outputs.output_dir }}
|
|
retention-days: 14
|
|
if-no-files-found: error
|
|
|
|
run_live_whatsapp:
|
|
name: Run WhatsApp live QA lane with Convex leases
|
|
needs: [authorize_actor, validate_selected_ref]
|
|
runs-on: blacksmith-16vcpu-ubuntu-2404
|
|
timeout-minutes: 60
|
|
concurrency:
|
|
group: qa-live-whatsapp-shared
|
|
cancel-in-progress: false
|
|
environment: qa-live-shared
|
|
steps:
|
|
- name: Checkout selected ref
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
with:
|
|
persist-credentials: false
|
|
ref: ${{ needs.validate_selected_ref.outputs.selected_revision }}
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Node environment
|
|
uses: ./.github/actions/setup-node-env
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
install-bun: "true"
|
|
|
|
- *qa_live_required_credentials_step
|
|
- name: Build private QA runtime
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=12288
|
|
run: pnpm build
|
|
|
|
- name: Run WhatsApp live lane
|
|
id: run_lane
|
|
shell: bash
|
|
env:
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
|
|
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
|
|
OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS: "1800000"
|
|
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
|
|
OPENCLAW_QA_WHATSAPP_CAPTURE_CONTENT: "1"
|
|
INPUT_SCENARIO: ${{ github.event_name == 'workflow_dispatch' && inputs.whatsapp_scenario || '' }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
output_dir=".artifacts/qa-e2e/whatsapp-live-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
|
|
scenario_args=()
|
|
|
|
if [[ -n "${INPUT_SCENARIO// }" ]]; then
|
|
IFS=',' read -r -a raw_scenarios <<<"${INPUT_SCENARIO}"
|
|
for raw in "${raw_scenarios[@]}"; do
|
|
scenario="$(printf '%s' "${raw}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
|
|
if [[ -n "${scenario}" ]]; then
|
|
scenario_args+=(--scenario "${scenario}")
|
|
fi
|
|
done
|
|
fi
|
|
|
|
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
|
|
|
|
pnpm openclaw qa whatsapp \
|
|
--repo-root . \
|
|
--output-dir "${output_dir}" \
|
|
--provider-mode live-frontier \
|
|
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
|
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
|
|
--fast \
|
|
--credential-source convex \
|
|
--credential-role ci \
|
|
"${scenario_args[@]}"
|
|
|
|
- name: Upload WhatsApp QA artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: qa-live-whatsapp-${{ github.run_id }}-${{ github.run_attempt }}
|
|
path: ${{ steps.run_lane.outputs.output_dir }}
|
|
retention-days: 14
|
|
if-no-files-found: error
|
|
|
|
run_live_slack:
|
|
name: Run Slack live QA lane with Convex leases
|
|
needs: [authorize_actor, validate_selected_ref]
|
|
runs-on: blacksmith-16vcpu-ubuntu-2404
|
|
timeout-minutes: 60
|
|
environment: qa-live-shared
|
|
steps:
|
|
- name: Checkout selected ref
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
with:
|
|
persist-credentials: false
|
|
ref: ${{ needs.validate_selected_ref.outputs.selected_revision }}
|
|
fetch-depth: 1
|
|
|
|
- name: Setup Node environment
|
|
uses: ./.github/actions/setup-node-env
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
install-bun: "true"
|
|
|
|
- *qa_live_required_credentials_step
|
|
- name: Build private QA runtime
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=12288
|
|
run: pnpm build
|
|
|
|
- name: Run Slack live lane
|
|
id: run_lane
|
|
shell: bash
|
|
env:
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
|
|
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
|
|
OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS: "1800000"
|
|
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
|
|
OPENCLAW_QA_SLACK_CAPTURE_CONTENT: "1"
|
|
OPENCLAW_QA_TRANSPORT_READY_TIMEOUT_MS: "180000"
|
|
INPUT_SCENARIO: ${{ github.event_name == 'workflow_dispatch' && inputs.slack_scenario || '' }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
output_dir=".artifacts/qa-e2e/slack-live-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
|
|
scenario_args=()
|
|
|
|
if [[ -n "${INPUT_SCENARIO// }" ]]; then
|
|
IFS=',' read -r -a raw_scenarios <<<"${INPUT_SCENARIO}"
|
|
for raw in "${raw_scenarios[@]}"; do
|
|
scenario="$(printf '%s' "${raw}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
|
|
if [[ -n "${scenario}" ]]; then
|
|
scenario_args+=(--scenario "${scenario}")
|
|
fi
|
|
done
|
|
fi
|
|
|
|
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
|
|
|
|
pnpm openclaw qa slack \
|
|
--repo-root . \
|
|
--output-dir "${output_dir}" \
|
|
--provider-mode live-frontier \
|
|
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
|
--alt-model "${OPENCLAW_CI_OPENAI_FALLBACK_MODEL}" \
|
|
--fast \
|
|
--credential-source convex \
|
|
--credential-role ci \
|
|
"${scenario_args[@]}"
|
|
|
|
- name: Upload Slack QA artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: qa-live-slack-${{ github.run_id }}-${{ github.run_attempt }}
|
|
path: ${{ steps.run_lane.outputs.output_dir }}
|
|
retention-days: 14
|
|
if-no-files-found: error
|