mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 03:15:46 -06:00
7bc994aee8
* fix(install): make lifecycle mutations transactional Standalone installers now apply npm-version-aware lifecycle approval. Updates verify and repair the installation before reporting success and preserve the prior install owner during method switches. Uninstall now exits nonzero when requested cleanup is only partially completed. Plugin update behavior is unchanged. Closes #125925 * test(uninstall): assert aggregated live-owner failure * fix(install): satisfy standalone shell checks * fix(update): scan PATH for prior Git wrapper * test(hooks): await Gmail watcher descendant exit * fix(install): verify Windows npm candidate * fix(ci): normalize package acceptance version * fix(update): preserve staged local package links * test(update): fold staged symlink coverage * fix(update): retire every legacy Git wrapper * test(docs): align consolidated ownership checks
1078 lines
45 KiB
YAML
1078 lines
45 KiB
YAML
name: Package Acceptance
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
workflow_ref:
|
|
description: Trusted repo ref for workflow scripts and Docker E2E harness
|
|
required: true
|
|
default: main
|
|
type: string
|
|
source:
|
|
description: Package candidate source
|
|
required: true
|
|
default: npm
|
|
type: choice
|
|
options:
|
|
- npm
|
|
- ref
|
|
- url
|
|
- trusted-url
|
|
- artifact
|
|
package_ref:
|
|
description: Trusted package source ref when source=ref
|
|
required: true
|
|
default: main
|
|
type: string
|
|
package_spec:
|
|
description: Published package spec when source=npm
|
|
required: false
|
|
default: openclaw@beta
|
|
type: string
|
|
package_url:
|
|
description: HTTPS .tgz URL when source=url or source=trusted-url
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
package_sha256:
|
|
description: Expected package SHA-256; required for source=url, source=trusted-url, or source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
trusted_source_id:
|
|
description: Named trusted source policy when source=trusted-url
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
artifact_run_id:
|
|
description: GitHub Actions run id when source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
artifact_name:
|
|
description: Artifact name containing one .tgz when source=artifact
|
|
required: false
|
|
default: package-under-test
|
|
type: string
|
|
artifact_id:
|
|
description: Immutable GitHub artifact id when source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
artifact_digest:
|
|
description: GitHub artifact service SHA-256 digest without the sha256 prefix
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
artifact_run_attempt:
|
|
description: Producer run attempt when source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
package_file_name:
|
|
description: Exact package tarball filename when source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
package_source_sha:
|
|
description: Exact source commit recorded in the package when source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
package_version:
|
|
description: Exact package version when source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
shared_image_policy:
|
|
description: Shared Docker image transport for package acceptance
|
|
required: true
|
|
default: no-push-artifact
|
|
type: choice
|
|
options:
|
|
- existing-only
|
|
- no-push-artifact
|
|
shared_image_artifact_namespace:
|
|
description: Unique artifact namespace when shared_image_policy=no-push-artifact
|
|
required: false
|
|
default: package-acceptance
|
|
type: string
|
|
suite_profile:
|
|
description: Acceptance profile
|
|
required: true
|
|
default: package
|
|
type: choice
|
|
options:
|
|
- smoke
|
|
- package
|
|
- product
|
|
- full
|
|
- custom
|
|
docker_lanes:
|
|
description: Comma/space separated Docker lanes when suite_profile=custom
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
published_upgrade_survivor_baseline:
|
|
description: Published OpenClaw package baseline for the published-upgrade-survivor Docker lane
|
|
required: false
|
|
default: openclaw@latest
|
|
type: string
|
|
published_upgrade_survivor_baselines:
|
|
description: Optional baseline list for published-upgrade-survivor/update-migration; use last-stable-4, all-since-2026.4.23, release-history, or exact versions
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
published_upgrade_survivor_scenarios:
|
|
description: Optional scenario list for published-upgrade-survivor/update-migration; use reported-issues for known upgrade failure shapes
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
telegram_mode:
|
|
description: Optional Telegram QA lane for the resolved package candidate
|
|
required: true
|
|
default: none
|
|
type: choice
|
|
options:
|
|
- none
|
|
- mock-openai
|
|
- live-frontier
|
|
telegram_scenarios:
|
|
description: Optional comma-separated Telegram scenario ids
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
advisory:
|
|
description: Treat acceptance failures as advisory for the caller
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
workflow_call:
|
|
inputs:
|
|
advisory:
|
|
description: Treat acceptance failures as advisory for the caller
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
telegram_advisory:
|
|
description: Treat only Telegram acceptance failures as advisory
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
workflow_ref:
|
|
description: Trusted repo ref for workflow scripts and Docker E2E harness
|
|
required: false
|
|
default: main
|
|
type: string
|
|
source:
|
|
description: "Package candidate source: npm, ref, url, trusted-url, or artifact"
|
|
required: true
|
|
type: string
|
|
package_ref:
|
|
description: Trusted package source ref when source=ref
|
|
required: false
|
|
default: main
|
|
type: string
|
|
package_spec:
|
|
description: Published package spec when source=npm
|
|
required: false
|
|
default: openclaw@beta
|
|
type: string
|
|
package_url:
|
|
description: HTTPS .tgz URL when source=url or source=trusted-url
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
package_sha256:
|
|
description: Expected package SHA-256; required for source=url, source=trusted-url, or source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
trusted_source_id:
|
|
description: Named trusted source policy when source=trusted-url
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
artifact_run_id:
|
|
description: GitHub Actions run id when source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
artifact_name:
|
|
description: Artifact name containing one .tgz when source=artifact
|
|
required: false
|
|
default: package-under-test
|
|
type: string
|
|
artifact_id:
|
|
description: Immutable GitHub artifact id when source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
artifact_digest:
|
|
description: GitHub artifact service SHA-256 digest without the sha256 prefix
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
artifact_run_attempt:
|
|
description: Producer run attempt when source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
package_file_name:
|
|
description: Exact package tarball filename when source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
package_source_sha:
|
|
description: Exact source commit recorded in the package when source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
package_version:
|
|
description: Exact package version when source=artifact
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
shared_image_policy:
|
|
description: "Shared Docker image transport: existing-only or no-push-artifact"
|
|
required: false
|
|
default: no-push-artifact
|
|
type: string
|
|
shared_image_artifact_namespace:
|
|
description: Unique artifact namespace when shared_image_policy=no-push-artifact
|
|
required: false
|
|
default: package-acceptance
|
|
type: string
|
|
candidate_artifact_json:
|
|
description: Immutable Docker image artifact tuple from Full Release Validation
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
suite_profile:
|
|
description: "Acceptance profile: smoke, package, product, full, or custom"
|
|
required: false
|
|
default: package
|
|
type: string
|
|
docker_lanes:
|
|
description: Comma/space separated Docker lanes when suite_profile=custom
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
published_upgrade_survivor_baseline:
|
|
description: Published OpenClaw package baseline for the published-upgrade-survivor Docker lane
|
|
required: false
|
|
default: openclaw@latest
|
|
type: string
|
|
published_upgrade_survivor_baselines:
|
|
description: Optional baseline list for published-upgrade-survivor/update-migration; use last-stable-4, all-since-2026.4.23, release-history, or exact versions
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
published_upgrade_survivor_scenarios:
|
|
description: Optional scenario list for published-upgrade-survivor/update-migration; use reported-issues for known upgrade failure shapes
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
allow_frozen_target_scenario_omissions:
|
|
description: Trusted opt-in to omit survivor scenarios absent from a canonical frozen target
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
telegram_mode:
|
|
description: Optional Telegram QA lane for the resolved package candidate
|
|
required: false
|
|
default: none
|
|
type: string
|
|
telegram_scenarios:
|
|
description: Optional comma-separated Telegram scenario ids
|
|
required: false
|
|
default: ""
|
|
type: string
|
|
outputs:
|
|
package_artifact_digest:
|
|
description: GitHub artifact service digest for the canonical package
|
|
value: ${{ jobs.resolve_package.outputs.package_artifact_digest }}
|
|
package_artifact_id:
|
|
description: Immutable GitHub artifact id for the canonical package
|
|
value: ${{ jobs.resolve_package.outputs.package_artifact_id }}
|
|
package_artifact_run_attempt:
|
|
description: Producer run attempt for the canonical package artifact
|
|
value: ${{ jobs.resolve_package.outputs.package_artifact_run_attempt }}
|
|
package_artifact_run_id:
|
|
description: Producer run id for the canonical package artifact
|
|
value: ${{ jobs.resolve_package.outputs.package_artifact_run_id }}
|
|
package_file_name:
|
|
description: Canonical package tarball filename
|
|
value: ${{ jobs.resolve_package.outputs.package_file_name }}
|
|
package_source_sha:
|
|
description: Source commit recorded in the canonical package
|
|
value: ${{ jobs.resolve_package.outputs.package_source_sha }}
|
|
package_sha256:
|
|
description: Canonical OpenClaw package SHA-256
|
|
value: ${{ jobs.resolve_package.outputs.package_sha256 }}
|
|
package_version:
|
|
description: Canonical OpenClaw package version
|
|
value: ${{ jobs.resolve_package.outputs.package_version }}
|
|
secrets:
|
|
OPENCLAW_TRUSTED_PACKAGE_TOKEN:
|
|
required: false
|
|
OPENAI_API_KEY:
|
|
required: false
|
|
OPENAI_BASE_URL:
|
|
required: false
|
|
ANTHROPIC_API_KEY:
|
|
required: false
|
|
ANTHROPIC_API_KEY_OLD:
|
|
required: false
|
|
ANTHROPIC_API_TOKEN:
|
|
required: false
|
|
FACTORY_API_KEY:
|
|
required: false
|
|
BYTEPLUS_API_KEY:
|
|
required: false
|
|
CEREBRAS_API_KEY:
|
|
required: false
|
|
DEEPINFRA_API_KEY:
|
|
required: false
|
|
DASHSCOPE_API_KEY:
|
|
required: false
|
|
GROQ_API_KEY:
|
|
required: false
|
|
KIMI_API_KEY:
|
|
required: false
|
|
MODELSTUDIO_API_KEY:
|
|
required: false
|
|
MOONSHOT_API_KEY:
|
|
required: false
|
|
MISTRAL_API_KEY:
|
|
required: false
|
|
MINIMAX_API_KEY:
|
|
required: false
|
|
OPENCODE_API_KEY:
|
|
required: false
|
|
OPENCODE_ZEN_API_KEY:
|
|
required: false
|
|
OPENCLAW_LIVE_BROWSER_CDP_URL:
|
|
required: false
|
|
OPENCLAW_LIVE_SETUP_TOKEN:
|
|
required: false
|
|
OPENCLAW_LIVE_SETUP_TOKEN_MODEL:
|
|
required: false
|
|
OPENCLAW_LIVE_SETUP_TOKEN_PROFILE:
|
|
required: false
|
|
OPENCLAW_LIVE_SETUP_TOKEN_VALUE:
|
|
required: false
|
|
GEMINI_API_KEY:
|
|
required: false
|
|
GOOGLE_API_KEY:
|
|
required: false
|
|
OPENROUTER_API_KEY:
|
|
required: false
|
|
QWEN_API_KEY:
|
|
required: false
|
|
FAL_KEY:
|
|
required: false
|
|
RUNWAY_API_KEY:
|
|
required: false
|
|
DEEPGRAM_API_KEY:
|
|
required: false
|
|
TOGETHER_API_KEY:
|
|
required: false
|
|
VYDRA_API_KEY:
|
|
required: false
|
|
XAI_API_KEY:
|
|
required: false
|
|
ZAI_API_KEY:
|
|
required: false
|
|
Z_AI_API_KEY:
|
|
required: false
|
|
BYTEPLUS_ACCESS_KEY_ID:
|
|
required: false
|
|
BYTEPLUS_SECRET_ACCESS_KEY:
|
|
required: false
|
|
CLAUDE_CODE_OAUTH_TOKEN:
|
|
required: false
|
|
OPENCLAW_CODEX_AUTH_JSON:
|
|
required: false
|
|
OPENCLAW_CODEX_CONFIG_TOML:
|
|
required: false
|
|
OPENCLAW_CLAUDE_JSON:
|
|
required: false
|
|
OPENCLAW_CLAUDE_CREDENTIALS_JSON:
|
|
required: false
|
|
OPENCLAW_CLAUDE_SETTINGS_JSON:
|
|
required: false
|
|
OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON:
|
|
required: false
|
|
OPENCLAW_GEMINI_SETTINGS_JSON:
|
|
required: false
|
|
FIREWORKS_API_KEY:
|
|
required: false
|
|
OPENCLAW_QA_CONVEX_SITE_URL:
|
|
required: false
|
|
OPENCLAW_QA_CONVEX_SECRET_CI:
|
|
required: false
|
|
|
|
permissions:
|
|
actions: read
|
|
contents: read
|
|
packages: read
|
|
pull-requests: read
|
|
|
|
concurrency:
|
|
group: package-acceptance-${{ github.run_id }}
|
|
cancel-in-progress: false
|
|
|
|
env:
|
|
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
|
NODE_VERSION: "24.16.0"
|
|
PACKAGE_ARTIFACT_NAME: package-under-test-${{ github.run_id }}-${{ github.run_attempt }}
|
|
|
|
jobs:
|
|
resolve_package:
|
|
name: Resolve package candidate
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 60
|
|
outputs:
|
|
docker_lanes: ${{ steps.profile.outputs.docker_lanes }}
|
|
include_live_suites: ${{ steps.profile.outputs.include_live_suites }}
|
|
include_openwebui: ${{ steps.profile.outputs.include_openwebui }}
|
|
include_release_path_suites: ${{ steps.profile.outputs.include_release_path_suites }}
|
|
package_artifact_name: ${{ steps.profile.outputs.package_artifact_name }}
|
|
package_artifact_digest: ${{ steps.upload_package.outputs.artifact-digest }}
|
|
package_artifact_id: ${{ steps.upload_package.outputs.artifact-id }}
|
|
package_artifact_run_attempt: ${{ github.run_attempt }}
|
|
package_artifact_run_id: ${{ github.run_id }}
|
|
package_file_name: ${{ steps.resolve.outputs.package_file_name }}
|
|
package_source_sha: ${{ steps.resolve.outputs.package_source_sha }}
|
|
package_sha256: ${{ steps.resolve.outputs.sha256 }}
|
|
package_version: ${{ steps.resolve.outputs.package_version }}
|
|
published_upgrade_survivor_baseline: ${{ steps.upgrade_survivor_baselines.outputs.baseline }}
|
|
published_upgrade_survivor_baselines: ${{ steps.upgrade_survivor_baselines.outputs.baselines }}
|
|
published_upgrade_survivor_scenarios: ${{ inputs.published_upgrade_survivor_scenarios }}
|
|
telegram_enabled: ${{ steps.profile.outputs.telegram_enabled }}
|
|
telegram_mode: ${{ steps.profile.outputs.telegram_mode }}
|
|
steps:
|
|
- name: Checkout package workflow ref
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
with:
|
|
ref: ${{ inputs.workflow_ref }}
|
|
fetch-depth: 0
|
|
filter: blob:none
|
|
persist-credentials: false
|
|
|
|
- name: Setup Node environment
|
|
uses: ./.github/actions/setup-node-env
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
install-bun: ${{ inputs.source == 'ref' && 'true' || 'false' }}
|
|
install-deps: "true"
|
|
|
|
- name: Validate package artifact input identity
|
|
id: input_artifact
|
|
if: inputs.source == 'artifact'
|
|
env:
|
|
ARTIFACT_DIGEST: ${{ inputs.artifact_digest }}
|
|
ARTIFACT_ID: ${{ inputs.artifact_id }}
|
|
GH_TOKEN: ${{ github.token }}
|
|
ARTIFACT_NAME: ${{ inputs.artifact_name }}
|
|
ARTIFACT_RUN_ATTEMPT: ${{ inputs.artifact_run_attempt }}
|
|
ARTIFACT_RUN_ID: ${{ inputs.artifact_run_id }}
|
|
EXPECTED_PACKAGE_SHA256: ${{ inputs.package_sha256 }}
|
|
EXPECTED_PACKAGE_FILE_NAME: ${{ inputs.package_file_name }}
|
|
EXPECTED_PACKAGE_SOURCE_SHA: ${{ inputs.package_source_sha }}
|
|
EXPECTED_PACKAGE_VERSION: ${{ inputs.package_version }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ ! "$ARTIFACT_DIGEST" =~ ^[0-9a-f]{64}$ ||
|
|
! "$ARTIFACT_ID" =~ ^[1-9][0-9]*$ ||
|
|
-z "${ARTIFACT_NAME// }" ||
|
|
! "$ARTIFACT_RUN_ATTEMPT" =~ ^[1-9][0-9]*$ ||
|
|
! "$ARTIFACT_RUN_ID" =~ ^[1-9][0-9]*$ ||
|
|
! "$EXPECTED_PACKAGE_FILE_NAME" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*\.tgz$ ||
|
|
! "$EXPECTED_PACKAGE_SHA256" =~ ^[0-9a-f]{64}$ ||
|
|
! "$EXPECTED_PACKAGE_SOURCE_SHA" =~ ^[0-9a-f]{40}$ ||
|
|
-z "${EXPECTED_PACKAGE_VERSION// }" ]]; then
|
|
echo "source=artifact requires the complete immutable artifact and package identity tuple." >&2
|
|
exit 1
|
|
fi
|
|
[[ "$ARTIFACT_NAME" == *"-${ARTIFACT_RUN_ID}-${ARTIFACT_RUN_ATTEMPT}" ]] || {
|
|
echo "Package artifact name does not bind the declared producer run attempt." >&2
|
|
exit 1
|
|
}
|
|
artifact_json="$(gh api "repos/${GITHUB_REPOSITORY}/actions/artifacts/${ARTIFACT_ID}")"
|
|
jq -e \
|
|
--arg digest "sha256:${ARTIFACT_DIGEST}" \
|
|
--arg id "$ARTIFACT_ID" \
|
|
--arg name "$ARTIFACT_NAME" \
|
|
--arg run_id "$ARTIFACT_RUN_ID" \
|
|
'
|
|
(.id | tostring) == $id and
|
|
.name == $name and
|
|
.expired == false and
|
|
.digest == $digest and
|
|
(.workflow_run.id | tostring) == $run_id
|
|
' <<< "$artifact_json" >/dev/null || {
|
|
echo "Package artifact identity does not match the requested immutable tuple." >&2
|
|
exit 1
|
|
}
|
|
attempt_json="$(
|
|
gh api \
|
|
"repos/${GITHUB_REPOSITORY}/actions/runs/${ARTIFACT_RUN_ID}/attempts/${ARTIFACT_RUN_ATTEMPT}"
|
|
)"
|
|
jq -e \
|
|
--arg attempt "$ARTIFACT_RUN_ATTEMPT" \
|
|
--arg run_id "$ARTIFACT_RUN_ID" \
|
|
'(.id | tostring) == $run_id and (.run_attempt | tostring) == $attempt' \
|
|
<<< "$attempt_json" >/dev/null || {
|
|
echo "Package artifact producer run attempt does not match the requested tuple." >&2
|
|
exit 1
|
|
}
|
|
{
|
|
echo "artifact_digest=$ARTIFACT_DIGEST"
|
|
echo "run_attempt=$ARTIFACT_RUN_ATTEMPT"
|
|
echo "run_id=$ARTIFACT_RUN_ID"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Download package artifact input
|
|
if: inputs.source == 'artifact'
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
artifact-ids: ${{ inputs.artifact_id }}
|
|
path: .artifacts/package-candidate-input
|
|
run-id: ${{ inputs.artifact_run_id }}
|
|
github-token: ${{ github.token }}
|
|
|
|
- name: Resolve package candidate
|
|
id: resolve
|
|
env:
|
|
SOURCE: ${{ inputs.source }}
|
|
PACKAGE_REF: ${{ inputs.package_ref }}
|
|
PACKAGE_SPEC: ${{ inputs.package_spec }}
|
|
PACKAGE_URL: ${{ inputs.package_url }}
|
|
PACKAGE_SHA256: ${{ inputs.package_sha256 }}
|
|
PACKAGE_FILE_NAME: ${{ inputs.package_file_name }}
|
|
PACKAGE_SOURCE_SHA: ${{ inputs.package_source_sha }}
|
|
PACKAGE_VERSION: ${{ inputs.package_version }}
|
|
TRUSTED_SOURCE_ID: ${{ inputs.trusted_source_id }}
|
|
OPENCLAW_TRUSTED_PACKAGE_TOKEN: ${{ secrets.OPENCLAW_TRUSTED_PACKAGE_TOKEN }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
artifact_dir=""
|
|
if [[ "$SOURCE" == "artifact" ]]; then
|
|
artifact_dir=".artifacts/package-candidate-input"
|
|
artifact_tarball="${artifact_dir}/${PACKAGE_FILE_NAME}"
|
|
[[ -f "$artifact_tarball" ]] || {
|
|
echo "Declared package tarball is missing from the selected artifact." >&2
|
|
exit 1
|
|
}
|
|
artifact_sha256="$(sha256sum "$artifact_tarball" | awk '{print $1}')"
|
|
[[ "$artifact_sha256" == "$PACKAGE_SHA256" ]] || {
|
|
echo "Selected artifact package SHA-256 differs from package_sha256." >&2
|
|
exit 1
|
|
}
|
|
fi
|
|
|
|
node --import tsx scripts/resolve-openclaw-package-candidate.mts \
|
|
--source "$SOURCE" \
|
|
--package-ref "$PACKAGE_REF" \
|
|
--package-spec "$PACKAGE_SPEC" \
|
|
--package-url "$PACKAGE_URL" \
|
|
--package-sha256 "$PACKAGE_SHA256" \
|
|
--trusted-source-id "$TRUSTED_SOURCE_ID" \
|
|
--artifact-dir "${artifact_dir:-.}" \
|
|
--output-dir .artifacts/docker-e2e-package \
|
|
--output-name openclaw-current.tgz \
|
|
--metadata .artifacts/docker-e2e-package/package-candidate.json \
|
|
--github-output "$GITHUB_OUTPUT"
|
|
echo "package_file_name=openclaw-current.tgz" >> "$GITHUB_OUTPUT"
|
|
if [[ "$SOURCE" == "artifact" ]]; then
|
|
jq -e \
|
|
--arg digest "$PACKAGE_SHA256" \
|
|
--arg source_sha "$PACKAGE_SOURCE_SHA" \
|
|
--arg version "$PACKAGE_VERSION" \
|
|
'
|
|
.name == "openclaw" and
|
|
.sha256 == $digest and
|
|
.packageSourceSha == $source_sha and
|
|
.version == $version
|
|
' .artifacts/docker-e2e-package/package-candidate.json >/dev/null || {
|
|
echo "Resolved package identity differs from the declared immutable tuple." >&2
|
|
exit 1
|
|
}
|
|
fi
|
|
|
|
- name: Select acceptance profile
|
|
id: profile
|
|
env:
|
|
SOURCE: ${{ inputs.source }}
|
|
SUITE_PROFILE: ${{ inputs.suite_profile }}
|
|
CUSTOM_DOCKER_LANES: ${{ inputs.docker_lanes }}
|
|
TELEGRAM_MODE: ${{ inputs.telegram_mode }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
include_release_path_suites=false
|
|
include_openwebui=false
|
|
include_live_suites=false
|
|
docker_lanes=""
|
|
|
|
case "$SUITE_PROFILE" in
|
|
smoke)
|
|
docker_lanes="npm-onboard-channel-agent gateway-network config-reload"
|
|
;;
|
|
package)
|
|
docker_lanes="npm-onboard-channel-agent doctor-switch update-channel-switch skill-install update-corrupt-plugin upgrade-survivor published-upgrade-survivor root-managed-vps-upgrade update-restart-auth plugins-offline plugin-update"
|
|
;;
|
|
product)
|
|
docker_lanes="npm-onboard-channel-agent doctor-switch update-channel-switch skill-install update-corrupt-plugin upgrade-survivor published-upgrade-survivor root-managed-vps-upgrade update-restart-auth plugins plugin-update mcp-channels cron-mcp-cleanup openai-web-search-minimal openwebui"
|
|
include_openwebui=true
|
|
;;
|
|
full)
|
|
include_release_path_suites=true
|
|
include_openwebui=true
|
|
;;
|
|
custom)
|
|
docker_lanes="$CUSTOM_DOCKER_LANES"
|
|
if [[ -z "${docker_lanes// }" ]]; then
|
|
echo "docker_lanes is required when suite_profile=custom." >&2
|
|
exit 1
|
|
fi
|
|
if [[ "$docker_lanes" == *"openwebui"* ]]; then
|
|
include_openwebui=true
|
|
fi
|
|
;;
|
|
*)
|
|
echo "Unknown suite_profile: $SUITE_PROFILE" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
telegram_enabled=false
|
|
if [[ "$TELEGRAM_MODE" != "none" ]]; then
|
|
telegram_enabled=true
|
|
fi
|
|
|
|
{
|
|
echo "docker_lanes=$docker_lanes"
|
|
echo "include_release_path_suites=$include_release_path_suites"
|
|
echo "include_openwebui=$include_openwebui"
|
|
echo "include_live_suites=$include_live_suites"
|
|
echo "telegram_enabled=$telegram_enabled"
|
|
echo "telegram_mode=$TELEGRAM_MODE"
|
|
echo "package_artifact_name=${PACKAGE_ARTIFACT_NAME}"
|
|
} >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Resolve published upgrade survivor baselines
|
|
id: upgrade_survivor_baselines
|
|
env:
|
|
FALLBACK_BASELINE: ${{ inputs.published_upgrade_survivor_baseline }}
|
|
REQUESTED_BASELINES: ${{ inputs.published_upgrade_survivor_baselines }}
|
|
GH_TOKEN: ${{ github.token }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
fallback_baseline="$FALLBACK_BASELINE"
|
|
if [[ "$fallback_baseline" == "openclaw@latest" ]]; then
|
|
fallback_version="$(npm view openclaw@latest version)"
|
|
[[ "$fallback_version" =~ ^[0-9]{4}\.[0-9]+\.[0-9]+(-[A-Za-z0-9.-]+)?$ ]] || {
|
|
echo "Could not resolve openclaw@latest to an exact release version." >&2
|
|
exit 1
|
|
}
|
|
fallback_baseline="openclaw@${fallback_version}"
|
|
fi
|
|
releases_json=""
|
|
npm_versions_json=""
|
|
if [[ "$REQUESTED_BASELINES" == *"release-history"* || "$REQUESTED_BASELINES" == *"all-since-"* || "$REQUESTED_BASELINES" == *"last-stable-"* ]]; then
|
|
releases_json=".artifacts/package-candidate-input/openclaw-releases.json"
|
|
npm_versions_json=".artifacts/package-candidate-input/openclaw-npm-versions.json"
|
|
mkdir -p "$(dirname "$releases_json")"
|
|
gh release list --repo "$GITHUB_REPOSITORY" --limit 100 --json tagName,publishedAt,isPrerelease > "$releases_json"
|
|
npm view openclaw versions --json > "$npm_versions_json"
|
|
fi
|
|
args=(
|
|
--requested "$REQUESTED_BASELINES"
|
|
--fallback "$fallback_baseline"
|
|
--github-output "$GITHUB_OUTPUT"
|
|
)
|
|
if [[ -n "$releases_json" ]]; then
|
|
args+=(
|
|
--releases-json "$releases_json"
|
|
--npm-versions-json "$npm_versions_json"
|
|
--history-count 6
|
|
--include-version 2026.4.23
|
|
--pre-date 2026-03-15T00:00:00Z
|
|
)
|
|
fi
|
|
node --import tsx scripts/resolve-upgrade-survivor-baselines.mts "${args[@]}" >/dev/null
|
|
echo "baseline=$fallback_baseline" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Upload package-under-test artifact
|
|
id: upload_package
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: ${{ env.PACKAGE_ARTIFACT_NAME }}
|
|
path: |
|
|
.artifacts/docker-e2e-package/openclaw-current.tgz
|
|
.artifacts/docker-e2e-package/package-candidate.json
|
|
retention-days: 14
|
|
if-no-files-found: error
|
|
|
|
- name: Summarize package candidate
|
|
env:
|
|
INPUT_ARTIFACT_DIGEST: ${{ steps.input_artifact.outputs.artifact_digest }}
|
|
INPUT_ARTIFACT_ID: ${{ inputs.artifact_id }}
|
|
INPUT_ARTIFACT_RUN_ATTEMPT: ${{ steps.input_artifact.outputs.run_attempt }}
|
|
INPUT_ARTIFACT_RUN_ID: ${{ steps.input_artifact.outputs.run_id }}
|
|
OUTPUT_ARTIFACT_DIGEST: ${{ steps.upload_package.outputs.artifact-digest }}
|
|
OUTPUT_ARTIFACT_ID: ${{ steps.upload_package.outputs.artifact-id }}
|
|
PACKAGE_SHA256: ${{ steps.resolve.outputs.sha256 }}
|
|
PACKAGE_VERSION: ${{ steps.resolve.outputs.package_version }}
|
|
PACKAGE_REF: ${{ inputs.package_ref }}
|
|
TRUSTED_SOURCE_ID: ${{ inputs.trusted_source_id }}
|
|
SOURCE: ${{ inputs.source }}
|
|
SUITE_PROFILE: ${{ inputs.suite_profile }}
|
|
WORKFLOW_REF: ${{ inputs.workflow_ref }}
|
|
PUBLISHED_UPGRADE_SURVIVOR_BASELINE: ${{ steps.upgrade_survivor_baselines.outputs.baseline }}
|
|
PUBLISHED_UPGRADE_SURVIVOR_BASELINES: ${{ steps.upgrade_survivor_baselines.outputs.baselines }}
|
|
PUBLISHED_UPGRADE_SURVIVOR_SCENARIOS: ${{ inputs.published_upgrade_survivor_scenarios }}
|
|
shell: bash
|
|
run: |
|
|
{
|
|
echo "## Package acceptance"
|
|
echo
|
|
echo "- Source: \`${SOURCE}\`"
|
|
echo "- Workflow ref: \`${WORKFLOW_REF}\`"
|
|
if [[ "${SOURCE}" == "ref" ]]; then
|
|
echo "- Package ref: \`${PACKAGE_REF}\`"
|
|
fi
|
|
if [[ "${SOURCE}" == "trusted-url" ]]; then
|
|
echo "- Trusted source: \`${TRUSTED_SOURCE_ID}\`"
|
|
fi
|
|
echo "- Version: \`${PACKAGE_VERSION}\`"
|
|
echo "- SHA-256: \`${PACKAGE_SHA256}\`"
|
|
echo "- Artifact id: \`${OUTPUT_ARTIFACT_ID}\`"
|
|
echo "- Artifact digest: \`${OUTPUT_ARTIFACT_DIGEST}\`"
|
|
echo "- Artifact producer: run \`${GITHUB_RUN_ID}\`, attempt \`${GITHUB_RUN_ATTEMPT}\`"
|
|
if [[ "$SOURCE" == "artifact" ]]; then
|
|
echo "- Input artifact id: \`${INPUT_ARTIFACT_ID}\`"
|
|
echo "- Input artifact digest: \`${INPUT_ARTIFACT_DIGEST}\`"
|
|
echo "- Input artifact producer: run \`${INPUT_ARTIFACT_RUN_ID}\`, attempt \`${INPUT_ARTIFACT_RUN_ATTEMPT}\`"
|
|
fi
|
|
echo "- Profile: \`${SUITE_PROFILE}\`"
|
|
echo "- Published upgrade survivor baseline: \`${PUBLISHED_UPGRADE_SURVIVOR_BASELINE}\`"
|
|
echo "- Published upgrade survivor baselines: \`${PUBLISHED_UPGRADE_SURVIVOR_BASELINES}\`"
|
|
echo "- Published upgrade survivor scenarios: \`${PUBLISHED_UPGRADE_SURVIVOR_SCENARIOS}\`"
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
package_integrity:
|
|
name: Package integrity
|
|
needs: resolve_package
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 10
|
|
steps:
|
|
- name: Checkout package workflow ref
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
with:
|
|
ref: ${{ inputs.workflow_ref }}
|
|
fetch-depth: 1
|
|
persist-credentials: false
|
|
|
|
- name: Setup package validation dependencies
|
|
uses: ./.github/actions/setup-node-env
|
|
with:
|
|
node-version: ${{ env.NODE_VERSION }}
|
|
install-bun: "false"
|
|
install-deps: "true"
|
|
|
|
- name: Download package-under-test artifact
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
artifact-ids: ${{ needs.resolve_package.outputs.package_artifact_id }}
|
|
path: .artifacts/docker-e2e-package
|
|
run-id: ${{ needs.resolve_package.outputs.package_artifact_run_id }}
|
|
github-token: ${{ github.token }}
|
|
|
|
- name: Enforce public package integrity
|
|
env:
|
|
EXPECTED_PACKAGE_SHA256: ${{ needs.resolve_package.outputs.package_sha256 }}
|
|
OPENCLAW_PACKAGE_TARBALL_CHECK_TIMINGS: "0"
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
package=".artifacts/docker-e2e-package/openclaw-current.tgz"
|
|
actual_sha256="$(sha256sum "$package" | awk '{print $1}')"
|
|
[[ "$actual_sha256" == "$EXPECTED_PACKAGE_SHA256" ]] || {
|
|
echo "Canonical package artifact SHA-256 differs from the resolver output." >&2
|
|
exit 1
|
|
}
|
|
node scripts/check-openclaw-package-tarball.mjs "$package"
|
|
|
|
npm_12_install_sh:
|
|
name: npm 12 install.sh acceptance
|
|
needs: [resolve_package, package_integrity]
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 15
|
|
permissions:
|
|
actions: read
|
|
contents: read
|
|
steps:
|
|
- name: Checkout package workflow ref
|
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
with:
|
|
ref: ${{ inputs.workflow_ref }}
|
|
fetch-depth: 1
|
|
persist-credentials: false
|
|
|
|
- name: Setup Node 24
|
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
with:
|
|
node-version: 24
|
|
|
|
- name: Download package-under-test artifact
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
artifact-ids: ${{ needs.resolve_package.outputs.package_artifact_id }}
|
|
path: .artifacts/docker-e2e-package
|
|
run-id: ${{ needs.resolve_package.outputs.package_artifact_run_id }}
|
|
github-token: ${{ github.token }}
|
|
|
|
- name: Run install.sh with npm 12
|
|
env:
|
|
EXPECTED_PACKAGE_SHA256: ${{ needs.resolve_package.outputs.package_sha256 }}
|
|
EXPECTED_PACKAGE_VERSION: ${{ needs.resolve_package.outputs.package_version }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
package="$PWD/.artifacts/docker-e2e-package/openclaw-current.tgz"
|
|
[[ "$(sha256sum "$package" | awk '{print $1}')" == "$EXPECTED_PACKAGE_SHA256" ]]
|
|
npm_tool="$RUNNER_TEMP/openclaw-npm12-tool"
|
|
install_home="$RUNNER_TEMP/openclaw-npm12-home"
|
|
install_prefix="$RUNNER_TEMP/openclaw-npm12-prefix"
|
|
mkdir -p "$install_home" "$install_prefix"
|
|
npm install -g --prefix "$npm_tool" npm@12.0.2
|
|
export PATH="$npm_tool/bin:$install_prefix/bin:$PATH"
|
|
[[ "$(npm --version)" == "12.0.2" ]]
|
|
HOME="$install_home" \
|
|
NPM_CONFIG_CACHE="$RUNNER_TEMP/openclaw-npm12-cache" \
|
|
NPM_CONFIG_PREFIX="$install_prefix" \
|
|
OPENCLAW_VERSION="$package" \
|
|
bash scripts/install.sh --install-method npm --no-prompt --no-onboard
|
|
source scripts/docker/install-sh-common/version-parse.sh
|
|
installed_version="$(extract_openclaw_semver "$("$install_prefix/bin/openclaw" --version)")"
|
|
[[ "$installed_version" == "$EXPECTED_PACKAGE_VERSION" ]] || {
|
|
echo "Installed OpenClaw version $installed_version differs from expected $EXPECTED_PACKAGE_VERSION." >&2
|
|
exit 1
|
|
}
|
|
guard="$install_prefix/lib/node_modules/openclaw/dist/openclaw-install-guard"
|
|
[[ ! -e "$guard" ]]
|
|
|
|
docker_acceptance:
|
|
name: Docker product acceptance (artifact-only)
|
|
needs: [resolve_package, package_integrity]
|
|
if: inputs.shared_image_policy == 'no-push-artifact'
|
|
permissions:
|
|
actions: read
|
|
contents: read
|
|
packages: read
|
|
pull-requests: read
|
|
uses: ./.github/workflows/openclaw-live-and-e2e-checks-reusable.yml
|
|
with: &docker_acceptance_inputs
|
|
advisory: ${{ inputs.advisory }}
|
|
ref: ${{ needs.resolve_package.outputs.package_source_sha || inputs.workflow_ref }}
|
|
include_repo_e2e: false
|
|
include_release_path_suites: ${{ needs.resolve_package.outputs.include_release_path_suites == 'true' }}
|
|
include_openwebui: ${{ needs.resolve_package.outputs.include_openwebui == 'true' }}
|
|
docker_lanes: ${{ needs.resolve_package.outputs.docker_lanes }}
|
|
published_upgrade_survivor_baseline: ${{ needs.resolve_package.outputs.published_upgrade_survivor_baseline }}
|
|
published_upgrade_survivor_baselines: ${{ needs.resolve_package.outputs.published_upgrade_survivor_baselines }}
|
|
published_upgrade_survivor_scenarios: ${{ needs.resolve_package.outputs.published_upgrade_survivor_scenarios }}
|
|
allow_frozen_target_scenario_omissions: ${{ inputs.allow_frozen_target_scenario_omissions || false }}
|
|
package_artifact_name: ${{ needs.resolve_package.outputs.package_artifact_name }}
|
|
package_artifact_digest: ${{ needs.resolve_package.outputs.package_artifact_digest }}
|
|
package_artifact_id: ${{ needs.resolve_package.outputs.package_artifact_id }}
|
|
package_artifact_run_attempt: ${{ needs.resolve_package.outputs.package_artifact_run_attempt }}
|
|
package_artifact_run_id: ${{ needs.resolve_package.outputs.package_artifact_run_id }}
|
|
package_file_name: ${{ needs.resolve_package.outputs.package_file_name }}
|
|
package_sha256: ${{ needs.resolve_package.outputs.package_sha256 }}
|
|
package_source_sha: ${{ needs.resolve_package.outputs.package_source_sha }}
|
|
package_version: ${{ needs.resolve_package.outputs.package_version }}
|
|
enable_prepublish_plugin_registry: ${{ contains(fromJSON('["artifact","ref"]'), inputs.source) }}
|
|
prepublish_plugin_registry_artifact_name: ${{ fromJSON(inputs.candidate_artifact_json || '{}').prepublishPluginRegistryArtifactName || '' }}
|
|
prepublish_plugin_registry_artifact_id: ${{ fromJSON(inputs.candidate_artifact_json || '{}').prepublishPluginRegistryArtifactId || '' }}
|
|
prepublish_plugin_registry_artifact_digest: ${{ fromJSON(inputs.candidate_artifact_json || '{}').prepublishPluginRegistryArtifactDigest || '' }}
|
|
prepublish_plugin_registry_artifact_run_id: ${{ fromJSON(inputs.candidate_artifact_json || '{}').prepublishPluginRegistryArtifactRunId || '' }}
|
|
prepublish_plugin_registry_artifact_run_attempt: ${{ fromJSON(inputs.candidate_artifact_json || '{}').prepublishPluginRegistryArtifactRunAttempt || '' }}
|
|
prepublish_plugin_registry_manifest_sha256: ${{ fromJSON(inputs.candidate_artifact_json || '{}').prepublishPluginRegistryManifestSha256 || '' }}
|
|
include_live_suites: ${{ needs.resolve_package.outputs.include_live_suites == 'true' }}
|
|
live_models_only: false
|
|
shared_image_artifact_namespace: ${{ inputs.shared_image_artifact_namespace }}
|
|
shared_image_artifact_name: ${{ fromJSON(inputs.candidate_artifact_json || '{}').imageArtifactName || '' }}
|
|
shared_image_artifact_id: ${{ fromJSON(inputs.candidate_artifact_json || '{}').imageArtifactId || '' }}
|
|
shared_image_artifact_digest: ${{ fromJSON(inputs.candidate_artifact_json || '{}').imageArtifactDigest || '' }}
|
|
shared_image_artifact_run_id: ${{ fromJSON(inputs.candidate_artifact_json || '{}').imageArtifactRunId || '' }}
|
|
shared_image_artifact_run_attempt: ${{ fromJSON(inputs.candidate_artifact_json || '{}').imageArtifactRunAttempt || '' }}
|
|
shared_image_archive_sha256: ${{ fromJSON(inputs.candidate_artifact_json || '{}').imageArchiveSha256 || '' }}
|
|
shared_image_policy: ${{ inputs.shared_image_policy }}
|
|
secrets: &docker_acceptance_secrets
|
|
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
|
|
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
ANTHROPIC_API_KEY_OLD: ${{ secrets.ANTHROPIC_API_KEY_OLD }}
|
|
ANTHROPIC_API_TOKEN: ${{ secrets.ANTHROPIC_API_TOKEN }}
|
|
FACTORY_API_KEY: ${{ secrets.FACTORY_API_KEY }}
|
|
BYTEPLUS_API_KEY: ${{ secrets.BYTEPLUS_API_KEY }}
|
|
CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }}
|
|
DEEPINFRA_API_KEY: ${{ secrets.DEEPINFRA_API_KEY }}
|
|
DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
|
|
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
|
KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }}
|
|
MODELSTUDIO_API_KEY: ${{ secrets.MODELSTUDIO_API_KEY }}
|
|
MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }}
|
|
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
|
|
MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
|
|
OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
|
|
OPENCODE_ZEN_API_KEY: ${{ secrets.OPENCODE_ZEN_API_KEY }}
|
|
OPENCLAW_LIVE_BROWSER_CDP_URL: ${{ secrets.OPENCLAW_LIVE_BROWSER_CDP_URL }}
|
|
OPENCLAW_LIVE_SETUP_TOKEN: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN }}
|
|
OPENCLAW_LIVE_SETUP_TOKEN_MODEL: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_MODEL }}
|
|
OPENCLAW_LIVE_SETUP_TOKEN_PROFILE: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_PROFILE }}
|
|
OPENCLAW_LIVE_SETUP_TOKEN_VALUE: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_VALUE }}
|
|
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
|
GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
|
|
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
|
|
QWEN_API_KEY: ${{ secrets.QWEN_API_KEY }}
|
|
FAL_KEY: ${{ secrets.FAL_KEY }}
|
|
RUNWAY_API_KEY: ${{ secrets.RUNWAY_API_KEY }}
|
|
DEEPGRAM_API_KEY: ${{ secrets.DEEPGRAM_API_KEY }}
|
|
TOGETHER_API_KEY: ${{ secrets.TOGETHER_API_KEY }}
|
|
VYDRA_API_KEY: ${{ secrets.VYDRA_API_KEY }}
|
|
XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
|
|
ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }}
|
|
Z_AI_API_KEY: ${{ secrets.Z_AI_API_KEY }}
|
|
BYTEPLUS_ACCESS_KEY_ID: ${{ secrets.BYTEPLUS_ACCESS_KEY_ID }}
|
|
BYTEPLUS_SECRET_ACCESS_KEY: ${{ secrets.BYTEPLUS_SECRET_ACCESS_KEY }}
|
|
CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
OPENCLAW_CODEX_AUTH_JSON: ${{ secrets.OPENCLAW_CODEX_AUTH_JSON }}
|
|
OPENCLAW_CODEX_CONFIG_TOML: ${{ secrets.OPENCLAW_CODEX_CONFIG_TOML }}
|
|
OPENCLAW_CLAUDE_JSON: ${{ secrets.OPENCLAW_CLAUDE_JSON }}
|
|
OPENCLAW_CLAUDE_CREDENTIALS_JSON: ${{ secrets.OPENCLAW_CLAUDE_CREDENTIALS_JSON }}
|
|
OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
|
|
OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
|
|
OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
|
|
FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
|
|
|
|
docker_acceptance_registry:
|
|
name: Docker product acceptance (existing registry images)
|
|
needs: [resolve_package, package_integrity]
|
|
if: inputs.shared_image_policy == 'existing-only'
|
|
permissions:
|
|
actions: read
|
|
contents: read
|
|
packages: read
|
|
pull-requests: read
|
|
uses: ./.github/workflows/openclaw-live-and-e2e-checks-reusable.yml
|
|
with: *docker_acceptance_inputs
|
|
secrets: *docker_acceptance_secrets
|
|
|
|
package_telegram:
|
|
name: Telegram package acceptance
|
|
needs: [resolve_package, package_integrity]
|
|
if: needs.resolve_package.outputs.telegram_enabled == 'true'
|
|
uses: ./.github/workflows/npm-telegram-beta-e2e.yml
|
|
with:
|
|
advisory: ${{ inputs.advisory || inputs.telegram_advisory }}
|
|
package_spec: ${{ inputs.package_spec }}
|
|
package_artifact_name: ${{ needs.resolve_package.outputs.package_artifact_name }}
|
|
package_artifact_digest: ${{ needs.resolve_package.outputs.package_artifact_digest }}
|
|
package_artifact_id: ${{ needs.resolve_package.outputs.package_artifact_id }}
|
|
package_artifact_run_attempt: ${{ needs.resolve_package.outputs.package_artifact_run_attempt }}
|
|
package_artifact_run_id: ${{ needs.resolve_package.outputs.package_artifact_run_id }}
|
|
package_file_name: ${{ needs.resolve_package.outputs.package_file_name }}
|
|
package_sha256: ${{ needs.resolve_package.outputs.package_sha256 }}
|
|
package_source_sha: ${{ needs.resolve_package.outputs.package_source_sha }}
|
|
package_version: ${{ needs.resolve_package.outputs.package_version }}
|
|
package_label: openclaw@${{ needs.resolve_package.outputs.package_version }}
|
|
harness_ref: ${{ inputs.workflow_ref }}
|
|
provider_mode: ${{ needs.resolve_package.outputs.telegram_mode }}
|
|
scenario: ${{ inputs.telegram_scenarios }}
|
|
secrets:
|
|
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 }}
|
|
|
|
summary:
|
|
name: Verify package acceptance
|
|
needs:
|
|
[
|
|
resolve_package,
|
|
package_integrity,
|
|
npm_12_install_sh,
|
|
docker_acceptance,
|
|
docker_acceptance_registry,
|
|
package_telegram,
|
|
]
|
|
if: always()
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 5
|
|
steps:
|
|
- name: Verify package acceptance results
|
|
env:
|
|
ADVISORY: ${{ inputs.advisory }}
|
|
DOCKER_ARTIFACT_RESULT: ${{ needs.docker_acceptance.result }}
|
|
DOCKER_REGISTRY_RESULT: ${{ needs.docker_acceptance_registry.result }}
|
|
PACKAGE_INTEGRITY_RESULT: ${{ needs.package_integrity.result }}
|
|
NPM_12_INSTALL_RESULT: ${{ needs.npm_12_install_sh.result }}
|
|
PACKAGE_TELEGRAM_RESULT: ${{ needs.package_telegram.result }}
|
|
RESOLVE_RESULT: ${{ needs.resolve_package.result }}
|
|
TELEGRAM_ENABLED: ${{ needs.resolve_package.outputs.telegram_enabled }}
|
|
TELEGRAM_ADVISORY: ${{ inputs.telegram_advisory }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
docker_result="$DOCKER_ARTIFACT_RESULT"
|
|
if [[ "$docker_result" == "skipped" ]]; then
|
|
docker_result="$DOCKER_REGISTRY_RESULT"
|
|
fi
|
|
if [[ "$DOCKER_ARTIFACT_RESULT" != "skipped" && "$DOCKER_REGISTRY_RESULT" != "skipped" ]]; then
|
|
echo "::error::Both Docker acceptance transports ran; expected exactly one."
|
|
exit 1
|
|
fi
|
|
if [[ "$DOCKER_ARTIFACT_RESULT" == "skipped" && "$DOCKER_REGISTRY_RESULT" == "skipped" ]]; then
|
|
echo "::error::No Docker acceptance transport ran; expected exactly one."
|
|
exit 1
|
|
fi
|
|
failed=0
|
|
for item in \
|
|
"resolve_package=${RESOLVE_RESULT}" \
|
|
"package_integrity=${PACKAGE_INTEGRITY_RESULT}" \
|
|
"npm_12_install_sh=${NPM_12_INSTALL_RESULT}" \
|
|
"docker_acceptance=${docker_result}" \
|
|
"package_telegram=${PACKAGE_TELEGRAM_RESULT}"
|
|
do
|
|
name="${item%%=*}"
|
|
result="${item#*=}"
|
|
result_failed=false
|
|
if [[ "$result" != "success" && "$result" != "skipped" ]]; then
|
|
result_failed=true
|
|
fi
|
|
if [[ "$name" == "package_telegram" &&
|
|
"$TELEGRAM_ENABLED" == "true" &&
|
|
"$result" != "success" ]]; then
|
|
result_failed=true
|
|
fi
|
|
if [[ "$result_failed" == "true" ]]; then
|
|
if [[ ("$ADVISORY" == "true" && "$name" != "resolve_package") ||
|
|
("$TELEGRAM_ADVISORY" == "true" && "$name" == "package_telegram") ]]; then
|
|
echo "::warning::${name} ended with ${result}; package acceptance is advisory for this caller."
|
|
continue
|
|
fi
|
|
echo "::error::${name} ended with ${result}"
|
|
failed=1
|
|
fi
|
|
done
|
|
exit "$failed"
|