OpenClaw EnterpriseDOCSGitHub

QA Matrix Advisory

Human verified

A human reviewed this page, but it may be out of date. Later edits may not have been reviewed.

Overview

Scheduled QA runs Console Secret management on Compose/Kubernetes, OpenShell security and lifecycle files, local installation, and OIDC Agent chat. Jobs use real dependencies on disposable installations. Results are advisory, not merge or publication gates.

Trigger

Trigger Jobs selected
Schedule on main, every 6 hours at minute 17 UTC All four groups
Manual run of qa-advisory.yml on main All four groups
Eligible PR with full-qa All four groups
Eligible PR with only qa-openshell-compose Compose OpenShell first-Agent job only
Eligible PR with qa-keycloak-installation Keycloak installation shard only
Eligible PR with qa-openclaw-model-ui Kubernetes / OpenClaw / model-ui only
Push to main, when QA_ADVISORY_ON_PUSH=true QA matrix, OIDC Agent chat and all OpenShell jobs; no local installation job

Maintainers label reviewed same-repository PRs. Dependabot authors and triggers are ineligible. Narrow labels select their union. full-qa overrides them and runs the default Codex/console-secrets cells. The focused Compose job checks native redeployment and required-worker execution on Kubernetes workloads.

PR runs test the merge commit. New commits replace opted-in runs; unrelated labels cannot restart or cancel them. Remove labels before pushing unreviewed code; removal stops future selection but does not cancel active runs. Eligible main pushes finish independently. The author of a breaking change owns triage.

Keycloak needs no model credential and allows 180 minutes; OpenClaw allows 120. Together they allow 300 runtime runner-minutes per attempt, plus selection—not a duration or billing estimate. Both require sandboxed packaged Chrome.

OpenClaw requires OPENAI_API_KEY and nonblank OCC_TEST_OPENAI_MODEL in integration-qa-pr, mapped to OCC_TEST_QA_OPENAI_MODEL. Missing inputs fail before the lane. Each cell materializes only its provider credential, removed after success or failure.

Push execution is opt-in through QA_ADVISORY_ON_PUSH; the schedule does not require that variable. Credentialed QA and OpenShell jobs use integration-qa-pr. Dependabot cannot start a manual advisory run.

Scenarios

The QA matrix creates separate Agents on disposable control planes with Kubernetes compute, preserving existing clusters and kubeconfig. Both Plugin catalogs stay enabled across presets; setup checks Google Workspace for OpenClaw and Linear for Codex.

Scenario In advisory Presets Checks
sandbox-policy Yes — OpenShell jobs Codex Discover and preview configuration, then apply, update, and withdraw OpenShell network policy in a prepared environment.
plugin-install Yes — OpenShell jobs Codex Install a dedicated Codex plugin, find it after the Codex process restarts, then remove it from the Agent selection.
model-ui Focused label only OpenClaw Real model turn and native browser response.
scratch-volume Yes — OpenShell job Codex Admitted scratch and workspace access through real tools, frozen selection, and missing/wrong-UID claim refusal.
oidc-agent-chat Yes, separate job OpenClaw First-login Default user enrollment, returning Keycloak sign-in, signed admission claims, owner creation and deployment, browser reply, administrative and sibling-Agent denial.
console-secrets Yes (Codex) OpenClaw, Codex Create and manage Console Secrets referenced by Agent drafts. Refusing Namespace deletion identifies the deployed Agent and links to its cleanup controls.
git-write No OpenClaw, Codex Clone, edit, commit, push to the run's granted branch, dispose credentials.
git-push-denied No Codex Reject a push to any other branch and dispose credentials.
slack No Codex Threaded reply and new root message.
openshell-linear-read No Codex Opt-in shipped OpenShell setup, Linear installation and verified native read.
codex-search-config No Codex API-key Agent user configuration with omitted, false and true capability declarations; persistence after supported stop/deploy.

QA matrix and scenario selection own these checks.

Scenario details

To run OpenShell scenarios locally, prepare the matching fixture for network policy, scratch storage, or plugin installation.

The OpenClaw model-ui case checks the example Console theme through sign-in and Agent use. It also redeploys the Agent with a provider alias, the existing OCC Secret, and OCE_MODEL_API_KEY, then requires a real model turn.

Harness destination overrides

The explicit harness-overrides QA scenario runs dedicated Codex and OpenClaw through an installed Kubernetes/OpenShell workflow. It deploys two Agents with distinct authorized destinations and a third inheriting the default, performs real model turns, restarts the controllers with changed and removed defaults, and withdraws one Agent's source while the other Agents continue serving.

Select OCC_TEST_QA_INSTALLATION=kubernetes, OCC_TEST_QA_PRESET=all, and OCC_TEST_QA_SCENARIOS=harness-overrides. Provide two authorized HTTPS port-443 endpoints in OCC_TEST_QA_HARNESS_ENDPOINT_A and _B, protected API-key file paths in OCC_TEST_QA_HARNESS_KEY_FILE_A and _B, and a model authorized at both endpoints in OCC_TEST_QA_HARNESS_MODEL. Use the normal source-built QA images and disposable cluster prerequisites. Missing inputs fail before setup. This scenario is explicit until hosted credentials for both destinations are configured; ordinary PR checks run HTTP and PostgreSQL override coverage. The scenario does not collect independent upstream access logs.

OpenShell file coverage

OpenShell needs Landlock, unavailable on QA's Blacksmith runners. Each file runs on an Ubuntu 24.04 VM with a Landlock check, Docker daemon, cluster and private state. Job names use QA advisory (OpenShell / <test-file-basename>).

Each OpenShell manifest file gets a run-ci-lane job with lane: openshell and its selected test-file. The qa-openshell-compose label selects only the first row below.

Test (source) Coverage
Compose first Agent Compose control plane with Kubernetes workloads: Agent deployment and reuse, key replacement denial, native redeployment, retained session/files, and required-worker execution.
OpenShell installation Pinned OpenShell installation with Kubernetes-only and Compose control planes.
Gateway tool policy Gateway model tool restrictions, positive administrator controls, and policy replacement.
Namespace isolation Bootstrap gateways and Workspaces before Agents, then run Agents in both Namespaces.
Credential lifecycle Credential routing, replacement, non-model sources, and absence from Agent material.
Live credential withdrawal Credential update, revocation without restarting the Harness, embedded refusal, and authenticated native policy scopes.
Upstream outages Untrusted model TLS, tool outages, and model provider outages with recovery.
Gateway and OAuth recovery Gateway restart, fresh OAuth minting, rotation, revocation, expiry, and source deletion.
Sandbox enforcement Provider credential delivery, authenticated Codex access, filesystem enforcement, and Agent network policy.
Scratch storage Real scratch and workspace writes, immutable binding, and missing/wrong-UID claim refusal.
Kubernetes first Agent The first-Agent and native redeployment workflow with the control plane in Kubernetes.
Codex plugin installation Selected Codex plugin installation and retention through the OpenShell Agent workflow.
Repository retention Standing Git and a live conversation survive a refused controller-only upgrade. Finite cases cover expiry and two-Agent withdrawal.
Single-Agent finite removal Before-deadline removal, ordered supervisor denial after worker replacement, same-runtime conversation, and actual retirement after model-authority withdrawal.

For finite Git conversation checks, persisted reply; read=… means the model returned the expected nonce. The readback category identifies the failed check. For example, answer_missing means the reader found the prompt but no matching assistant answer in its bounded transcript window. The prompt and terminal answer must belong to the logical run returned by the Gateway. Codex can finish that run on a new native turn after an internal retry. The check sends each authenticated nonce prompt once.

The runner requires the selected files' credentials, expected tests, and cleanup. Local installation also uses one runner per manifest file: input and network-policy refusals, Kubernetes and Compose profiles, and Keycloak sign-in and recovery. The six original installation cases remain required. A failed job does not cancel its peers. Hosted preparation builds first-Agent images from the current checkout using read-only caches. Local Setup then creates and cleans up each installation without duplicate clusters. See OpenShell CI preparation and timing for image selection, runner requirements, and interpretation of setup and model-execution timings.

Full Integration can also run this suite with lane=openshell or lane=all; that workflow runs the same files serially. The separately prepared OAuth and Linear tests are not included in advisory coverage.

Execution

To run the same coverage as the schedule, configure the hosted credentials, then start the workflow:

sh
gh workflow run qa-advisory.yml --repo openclaw/openclaw-enterprise --ref main

For only OpenShell, use Full Integration with lane=openshell.

Local instructions run the QA matrix only. For other suites, follow OpenShell setup or local installation tests.

Select scenarios

OCC_TEST_QA_INSTALLATION accepts all (default), compose, kubernetes; OCC_TEST_QA_PRESET accepts all (default), OpenClaw, Codex. OCC_TEST_QA_SCENARIOS accepts all (default) or comma-separated selectors. all excludes namespace-lifecycle, sandbox-policy, scratch-volume, plugin-install, openshell-linear-read, codex-search-config, harness-overrides and oidc-agent-chat selectors. Invalid or wholly inapplicable selections fail before provisioning; missing inputs fail selected checks. Omitting OCC_TEST_QA_MATRIX=1 skips the suite.

Select oidc-agent-chat alone with kubernetes and OpenClaw. It uses the gateway-routing lane to prepare Keycloak, PostgreSQL, native routing and runtime images. Follow the native browser proof for inputs, execution and proof limits. It does not use the ordinary matrix's installation launcher.

Select scratch-volume with kubernetes and Codex. The fixture uses an OpenAI API key for https://api.openai.com/v1. NVMe and node-loss recovery need separate proof.

Select codex-search-config alone. It requires OCC_TEST_QA_CODEX_MODEL_BASE_URL, OCC_TEST_QA_CODEX_MODEL, and an API key through OCC_TEST_QA_MODEL_API_KEY or OCC_TEST_QA_OPENAI_KEY_FILE. Environment keys are redacted and excluded from launcher children; key files must be private regular files, not symlinks. This scenario checks configuration persistence and native startup, not live web-search results. Its API-key setup differs from the scheduled account-login tests.

Ordinary matrix cells check startup and authenticated console login. Only Git scenarios start the broker. openshell-linear-read instead starts its own OpenShell stack and needs a connected identity and Linear read fixture. OCC_TEST_QA_CONCURRENCY=1..4 selects workers (default 2); installations and Slack run sequentially. Allow up to 4 GiB per gateway beyond shared services.

Local inputs

Prepare Kubernetes and Compose: workspace dependencies, Docker, k3d, kubectl, Helm, Go, OpenSSL, Chromium/Playwright, and certutil. Store selected inputs in a private environment file. Credential files must be regular files without group/other permissions. Hosted settings are under integration environments.

Scenario/preset Inputs
OpenClaw model OCC_TEST_QA_OPENAI_KEY_FILE
Codex OCC_TEST_QA_CODEX_TOKEN_FILE: authorized service-account PAT
Scratch storage OCC_TEST_QA_OPENAI_KEY_FILE, OCC_TEST_QA_OPENAI_MODEL, and OCC_TEST_QA_SANDBOX_ENV: protected prepared OpenShell environment file, including its migrator connection.
Git OCC_TEST_QA_REPOSITORY_AUTHORIZED=1, OCC_TEST_QA_REPOSITORY_INPUT_DIRECTORY, and OCC_TEST_QA_GITHUB_OBSERVER_TOKEN_FILE or absolute managed OCC_TEST_QA_GITHUB_OBSERVER_BINARY
Slack OCC_TEST_QA_SLACK_APP_TOKEN_FILE, OCC_TEST_QA_SLACK_BOT_TOKEN_FILE, OCC_TEST_QA_SLACK_SENDER_TOKEN_FILE, OCC_TEST_QA_SLACK_CHANNEL_ID

Slack sender and gateway bot must be distinct channel members; the sender needs post/history/reply access. Reserve the Socket Mode app for this run.

Git's private input directory contains registry.json, private-key.pem, and upstream-cidrs.json. Follow fixture setup: exactly one authorized repository, ${OCC_INITIAL_NAMESPACE_ID}, approved IPv4 /32 endpoints, and run-branch push permissions. The run grants git-write with git-only transport on one branch, oce-qa-<run>, and opens no PR. The run generates the worker's custody key. OCC_TEST_QA_GITHUB_OBSERVER_APP_INPUT_DIRECTORY instead supplies an isolated observer App's registry.json and private-key.pem. Observer credentials stay outside Agents and clean only verified run-owned refs.

OCC_TEST_QA_ARTIFACTS selects private results; otherwise the runner prints its temporary path. Set OCC_TEST_QA_CONTROLLER_IMAGE and OCC_TEST_QA_RUNTIME_IMAGE together to reuse prebuilt images; OCC_TEST_QA_REPOSITORY_IMAGE selects the broker. Model defaults are in shared configuration; the manifest lists overrides.

Prebuild local QA images

Prebuild Kubernetes QA images from a clean checkout with immutable references and matching source labels. Use the same local Unix-socket Docker context with the containerd image store for both build and QA. Use Buildx, Node.js 24+, and CLI and daemon support for docker image save --platform (API 1.48+). The commands select the daemon's Linux amd64 or arm64 platform.

In a fresh Bash shell at the repository root, replace the builder name with an existing builder you own. No QA credentials are needed.

bash
set -euo pipefailumask 077qa_builder="your-existing-builder"qa_platform="$(docker version --format '{{.Server.Os}}/{{.Server.Arch}}')"[[ "$qa_platform" == linux/amd64 || "$qa_platform" == linux/arm64 ]]unset OCC_TEST_QA_CONTROLLER_IMAGE OCC_TEST_QA_RUNTIME_IMAGEqa_commit="$(git rev-parse HEAD)"qa_status="$(git status --porcelain --untracked-files=all)"[[ -z "$qa_status" ]]qa_metadata="$(mktemp -d)"qa_prefix="localhost/oce-qa-$(date +%s)-$$"qa_node_base="$(node -p 'require("./scripts/ci/test-suites/images-packaging.json").prepare.defaultEnv.NODE_BASE_IMAGE')"qa_source="$(node scripts/lib/openclaw-source.mjs build-args)"qa_runtime_args=()while IFS= read -r argument; do  qa_runtime_args+=(--build-arg "$argument")done <<< "$qa_source"docker buildx inspect "$qa_builder" for role in controller runtime; do  qa_recipe=(--target runtime)  if [[ "$role" == runtime ]]; then    qa_recipe=(-f deploy/runtime/Dockerfile "${qa_runtime_args[@]}")  fi  docker buildx build --builder "$qa_builder" --platform "$qa_platform" \    --load --provenance=false --sbom=false "${qa_recipe[@]}" \    --build-arg NODE_BASE_IMAGE="$qa_node_base" \    --build-arg OCC_BUILD_REVISION="$qa_commit" \    --label "org.opencontainers.image.revision=$qa_commit" \    --metadata-file "$qa_metadata/$role.json" \    --tag "$qa_prefix/$role:source" .  qa_digest="$(node -p 'JSON.parse(require("node:fs").readFileSync(process.argv[1]))["containerimage.digest"]' "$qa_metadata/$role.json")"  [[ "$qa_digest" =~ ^sha256:[a-f0-9]{64}$ ]]  qa_ref="$qa_prefix/$role@$qa_digest"  [[ "$(docker image inspect --format '{{.Os}}/{{.Architecture}}' "$qa_ref")" == "$qa_platform" ]]  [[ "$(docker image inspect --format '{{ index .Config.Labels "org.opencontainers.image.revision" }}' "$qa_ref")" == "$qa_commit" ]]  if [[ "$role" == controller ]]; then    CONTROLLER_IMAGE="$qa_ref"  else    RUNTIME_IMAGE="$qa_ref"  fidoneqa_status="$(git status --porcelain --untracked-files=all)"qa_final_commit="$(git rev-parse HEAD)"[[ "$qa_final_commit" == "$qa_commit" && -z "$qa_status" ]]printf 'Build metadata: %s\n' "$qa_metadata"

Failed digest resolution or inspection stops the procedure. Do not substitute tags or invent digests. These images omit publication attestations; source labels prove consistency, not provenance. Retain metadata through qualification. Keep CONTROLLER_IMAGE and RUNTIME_IMAGE unchanged. In the image checks, skip both pulls and run the command starting with OCC_TEST_PRODUCTION_IMAGE=. After all required cases pass without skips, select the pair:

bash
export OCC_TEST_QA_CONTROLLER_IMAGE="$CONTROLLER_IMAGE"export OCC_TEST_QA_RUNTIME_IMAGE="$RUNTIME_IMAGE"

Reuse the builder's intermediate cache, including Node compilation, with consistent platform and build arguments. Loading final images does not restore intermediate cache. For portability, use Docker's cache export/import options; mode=max includes intermediate stages. Hosted CI cache is separate. These commands do not export cache, change networking, or select a global builder.

Run local QA

After preparing those inputs, run from the repository root:

sh
pnpm cli:buildOCC_TEST_QA_MATRIX=1 node --env-file="$TEST_ENV_FILE" \  --test tests/integration/qa-matrix-real.test.mjs

TEST_ENV_FILE is the private environment file described above.

Results and limits

Check the tested commit, selected scenarios, failed or skipped tests, and cleanup. Missing, filtered, or interrupted tests are not passes. The selection summary records the run, attempt and tested SHA. Focused PR runs also verify and record the merge ref and ordered base/head parents before starting jobs. Compare the leaf result's sourceSha with that merge SHA; a passing earlier head is not proof of the current composition.

For focused Keycloak, require both manifest cases and their cleanup to pass. For OpenClaw, inspect matrix.json: one kubernetes/OpenClaw cell with only model-ui, successful real model/browser stages, and Agent/installation cleanup. Its partial:selected scope is intentional; missing stages or artifacts leave verification incomplete. Preserve the job link and attempt-specific results.

Results Where to look
QA matrix stages (passed, failed, or blocked) matrix.json in qa-advisory-<installation>-<run-id>-<attempt>
OpenShell tests qa-advisory-<test-file-basename>-openshell (omit .test.mjs or .test.ts)
Local installation tests qa-advisory-local-installation-<test-file-basename>-dev-up-k3d

Startup failures report elapsed time, the 1,100,000 ms limit, and the observed exit code or signal. timed out identifies deadline expiry. A later SIGPIPE can follow teardown closing output pipes. Failure detail is redacted and command arguments and protected output stay private.

When available, startup timings in the failure message names a JSON file in the same artifact. It retains the last 64 recognized CLI timing records: stage, elapsed milliseconds, and failure status, plus the number of older records omitted. These describe completed commands, including commands that failed; they do not identify an unfinished command. Durations can overlap, so do not sum them as wall time. Unknown or malformed records and other stdout remain private. Commands with protected output produce no timing artifact.

Artifacts expire after seven days. Each OpenShell job reports scope: focused because it runs one file; complete advisory OpenShell coverage requires every manifest file to pass.

In matrix.json, scope: full means both installations and presets with the all scenarios; advisory QA has narrower coverage. See Select scenarios for the exclusions from all.

First-Agent timing results include overlapping stages; do not sum them as elapsed time. A Codex timeout alone does not permit a retry: the client must report model capacity exhaustion before any action started.

Cleanup stops the Agents and installations created by the run. If credential disposal is uncertain, cleanup keeps the installation and reports the required recovery. Keep its broker until sessions are DISPOSED without active uses or pending, uncertain or auxiliary cleanup. Preserve other runs' resources. For Git TLS errors, compare broker DNS with approved endpoints/NetworkPolicy, refresh approved inputs, complete disposal, then recreate only this run's installation.

Files

Search documentation