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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 164 additions & 0 deletions .github/workflows/openclaw-plugin-e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
name: OpenClaw Plugin E2E

on:
pull_request:
branches:
- main
- 'release/agent-sec-core/**'
paths:
- ".github/workflows/openclaw-plugin-e2e.yml"
- "src/agent-sec-core/openclaw-plugin/src/**"
- "src/agent-sec-core/openclaw-plugin/scripts/**"
- "src/agent-sec-core/openclaw-plugin/tests/e2e/**"
- "src/agent-sec-core/openclaw-plugin/package.json"
- "src/agent-sec-core/openclaw-plugin/package-lock.json"
- "src/agent-sec-core/openclaw-plugin/tsconfig.json"
push:
branches:
- main
- 'release/agent-sec-core/**'
paths:
- ".github/workflows/openclaw-plugin-e2e.yml"
- "src/agent-sec-core/openclaw-plugin/src/**"
- "src/agent-sec-core/openclaw-plugin/scripts/**"
- "src/agent-sec-core/openclaw-plugin/tests/e2e/**"
- "src/agent-sec-core/openclaw-plugin/package.json"
- "src/agent-sec-core/openclaw-plugin/package-lock.json"
- "src/agent-sec-core/openclaw-plugin/tsconfig.json"
workflow_dispatch:

permissions:
contents: read

jobs:
build-agent-sec-cli:
name: Build one agent-sec-cli wheel
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-22.04' || 'anolisa-k8s-general-ci-x64' }}
defaults:
run:
working-directory: src/agent-sec-core
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11.6"

- name: Set up Rust
uses: dtolnay/rust-toolchain@stable

- name: Set up uv
uses: astral-sh/setup-uv@v5

- name: Build agent-sec-cli wheel
run: make build-cli

- name: Upload agent-sec-cli wheel
uses: actions/upload-artifact@v4
with:
name: agent-sec-cli-wheel
path: src/agent-sec-core/target/wheels/*.whl
if-no-files-found: error

openclaw-plugin-e2e:
name: OpenClaw ${{ matrix.openclaw.label }} E2E
needs: build-agent-sec-cli
runs-on: ${{ github.event_name == 'workflow_dispatch' && 'ubuntu-22.04' || 'anolisa-k8s-general-ci-x64' }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
openclaw:
- label: "2026.4.14"
version: "2026.4.14"
expected-version: "2026.4.14"
expect-unsafe-install: "true"
- label: "2026.4.23"
version: "2026.4.23"
expected-version: "2026.4.23"
expect-unsafe-install: "true"
- label: "2026.4.24"
version: "2026.4.24"
expected-version: "2026.4.24"
expect-unsafe-install: "true"
- label: "2026.4.29"
version: "2026.4.29"
expected-version: "2026.4.29"
expect-unsafe-install: "true"
- label: "2026.5.7"
version: "2026.5.7"
expected-version: "2026.5.7"
expect-unsafe-install: "true"
- label: "2026.5.28"
version: "2026.5.28"
expected-version: "2026.5.28"
expect-unsafe-install: "true"
- label: "2026.6.10"
version: "2026.6.10"
expected-version: "2026.6.10"
expect-unsafe-install: "true"
- label: latest
version: "latest"
expected-version: ""
expect-unsafe-install: ""
defaults:
run:
working-directory: src/agent-sec-core
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
cache-dependency-path: src/agent-sec-core/openclaw-plugin/package-lock.json

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11.6"

- name: Set up uv
uses: astral-sh/setup-uv@v5

- name: Install jq
run: |
sudo apt-get update
sudo apt-get install -y jq

- name: Download agent-sec-cli wheel
uses: actions/download-artifact@v4
with:
name: agent-sec-cli-wheel
path: src/agent-sec-core/target/wheels

- name: Run OpenClaw plugin E2E
env:
OPENCLAW_VERSION: ${{ matrix.openclaw.version }}
OPENCLAW_EXPECTED_VERSION: ${{ matrix.openclaw.expected-version }}
OPENCLAW_MATRIX_LABEL: ${{ matrix.openclaw.label }}
EXPECT_UNSAFE_INSTALL_FLAG: ${{ matrix.openclaw.expect-unsafe-install }}
AGENT_SEC_CLI_WHEEL: target/wheels/*.whl
OPENCLAW_E2E_RESULT_ROOT: target/openclaw-e2e/results
run: scripts/ci/run-openclaw-plugin-e2e.sh

- name: Upload E2E evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: openclaw-plugin-e2e-${{ matrix.openclaw.label }}
path: |
src/agent-sec-core/target/openclaw-e2e/results/${{ matrix.openclaw.label }}/**/summary.json
src/agent-sec-core/target/openclaw-e2e/results/${{ matrix.openclaw.label }}/**/summary.md
src/agent-sec-core/target/openclaw-e2e/results/${{ matrix.openclaw.label }}/**/workdir/pilot-result.json
src/agent-sec-core/target/openclaw-e2e/results/${{ matrix.openclaw.label }}/**/workdir/logs/**
src/agent-sec-core/target/openclaw-e2e/results/${{ matrix.openclaw.label }}/**/workdir/agent-sec-cli-overrides.json
src/agent-sec-core/target/openclaw-e2e/results/${{ matrix.openclaw.label }}/**/workdir/agent-sec-data/*.jsonl
src/agent-sec-core/target/openclaw-e2e/results/${{ matrix.openclaw.label }}/**/workdir/agent-sec-data/*.db
src/agent-sec-core/target/openclaw-e2e/results/${{ matrix.openclaw.label }}/**/workdir/openclaw-state/openclaw.json
src/agent-sec-core/target/openclaw-e2e/results/${{ matrix.openclaw.label }}/**/workdir/openclaw-state/logs/*.jsonl
if-no-files-found: warn
73 changes: 73 additions & 0 deletions src/agent-sec-core/openclaw-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ openclaw-plugin/
│ ├── helpers.ts # generic parsing helpers
│ └── types.ts # shared observability types
├── tests/ # Test utilities (not compiled into dist/)
│ ├── e2e/ # OpenClaw plugin E2E pilot runner
│ ├── test-harness.ts # Mock OpenClaw API for local testing
│ ├── smoke-test.ts # Smoke test for all capabilities
│ └── unit/ # Unit tests
Expand Down Expand Up @@ -230,6 +231,78 @@ Runs against the real `agent-sec-cli` binary:
AGENT_SEC_LIVE=1 npm run smoke
```

### OpenClaw Plugin E2E Pilot

`npm run e2e:openclaw` is the reusable pilot entry for
`OPENCLAW-PLUGIN-E2E-PILOT`. It uses isolated state directories, builds and
packs this plugin, starts `agent-sec-daemon`, installs the plugin into the
selected OpenClaw runtime, starts a local Gateway, verifies runtime plugin
loading, and writes structured evidence to `pilot-result.json`.

```bash
npm run e2e:openclaw -- \
--openclaw-bin /path/to/openclaw \
--agent-sec-cli /path/to/agent-sec-cli \
--agent-sec-daemon /path/to/agent-sec-daemon
```

If the binaries are already on `PATH` or in the repository root `.venv/bin/`,
the explicit `--agent-sec-*` arguments can be omitted. From the repository root,
`source .venv/bin/activate` also works for manual runs, but the pilot runner
does not require the shell to be activated because it detects `.venv/bin`
directly. The same values can be provided with
`AGENT_SEC_OPENCLAW_PILOT_AGENT_SEC_CLI` and
`AGENT_SEC_OPENCLAW_PILOT_AGENT_SEC_DAEMON`. Use `--workdir <dir>` to keep
logs and artifacts in a stable directory.

Optional pilot arguments:

| Option | Purpose |
|--------|---------|
| `--workdir <dir>` | Store isolated OpenClaw state, daemon data, logs, and `pilot-result.json` under a stable directory. |
| `--openclaw-bin <path>` | Use a specific OpenClaw executable or `openclaw.mjs`. |
| `--agent-sec-cli <path>` | Use a specific installed `agent-sec-cli` binary. |
| `--agent-sec-daemon <path>` | Use a specific installed `agent-sec-daemon` binary. |
| `--port <port>` | Bind Gateway to an explicit port. Without this, the runner picks a local port and retries initial startup if that port is claimed before Gateway binds. |
| `--gateway-timeout-ms <ms>` | Override the Gateway health wait budget. |
| `--gateway-token <token>` | Override the generated local Gateway token. |
| `--skip-gateway` | Stop after install/runtime inspection and skip Gateway traffic plus policy matrix probes. |
| `--skip-failure-probes` | Skip direct hook fail-open probes for missing, broken, invalid, and slow CLI behavior. |

The pilot runner does not control unsafe-install behavior. It calls `deploy.sh`
directly and records the actual install command path through the deploy
stdout/stderr logs.

The runner starts the local Gateway with token auth and redacts the token in
recorded command arguments. Override the generated local token with
`--gateway-token` or `AGENT_SEC_OPENCLAW_PILOT_GATEWAY_TOKEN` only when needed.
The default Gateway health wait is 180 seconds because first startup from an
OpenClaw source checkout may build Control UI assets before binding the port.

The runner records:

- `openclaw --version`, `agent-sec-cli --version`, and package tarball path
- isolated `OPENCLAW_STATE_DIR`, `OPENCLAW_CONFIG_PATH`, daemon socket, and
Gateway URL
- `agent-sec-daemon` health over the Unix socket
- `deploy.sh` stdout/stderr and whether the unsafe install flag was used
- `openclaw plugins inspect agent-sec --runtime --json` summary
- Gateway-driven `sessions.create` / `sessions.send` / `agent.wait` evidence
against a local OpenAI-compatible mock model, including a model-issued `exec`
tool call and tool-result follow-up request
- Gateway log evidence that `prompt-scan` and `scan-code` ran on that real turn
- `AGENT_SEC_DATA_DIR/observability.jsonl` records for the same Gateway run ID
- hook-level capability probes for `prompt-scan`, `scan-code`,
`pii-scan-user-input`, `skill-ledger`, and `observability`
- negative fail-open probes for missing CLI, nonzero exit, invalid JSON, and
timeout

The Gateway traffic probe proves the installed plugin participates in a real
OpenClaw chat/tool turn. The direct hook probes remain as supplemental capability
and fail-open coverage for edge cases that are hard to force through a single
model turn. The matrix task should keep this pilot as the bootstrap lane and
run the same acceptance checks per supported host version.

---

## Plugin Capabilities
Expand Down
1 change: 1 addition & 0 deletions src/agent-sec-core/openclaw-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"scripts": {
"clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
"build": "npm run clean && tsc --project tsconfig.json",
"e2e:openclaw": "node tests/e2e/openclaw-plugin-e2e-pilot.mjs",
"pack": "npm run build && npm pack",
"smoke": "npx tsx tests/smoke-test.ts",
"test": "npx tsx --test tests/unit/*test.ts",
Expand Down
Loading
Loading