Skip to content

feat: implement Rust-only Zeroshot v2 MVP #2487

feat: implement Rust-only Zeroshot v2 MVP

feat: implement Rust-only Zeroshot v2 MVP #2487

Workflow file for this run

name: CI
# Codecov setup:
# 1. Go to https://codecov.io and sign in with GitHub
# 2. Add the covibes/zeroshot repository
# 3. Get the upload token from Settings > General
# 4. Add it as a GitHub secret: Settings > Secrets and variables > Actions > New repository secret
# Name: CODECOV_TOKEN
# Value: <your-token-from-codecov>
on:
push:
branches: [main]
pull_request:
branches: [main]
merge_group:
types: [checks_requested]
workflow_dispatch:
inputs:
include_docker_e2e:
description: Run the non-hermetic live-provider Docker E2E job
required: false
type: boolean
default: false
jobs:
# Fast quality gates - must pass before anything else
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 22
cache: 'npm'
- name: Setup Rust 1.97.0
uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.97.0
components: clippy,rustfmt
- name: Install Opcore Rust metrics analyzer
run: npm run opcore:install:rust-metrics
- name: Install dependencies
run: npm ci
- name: Build Opcore graph
run: npm run opcore:graph:build
- name: Opcore introduced-change gate
env:
CARGO_BUILD_JOBS: 1
OPCORE_BASE: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before || 'HEAD^' }}
run: npm run opcore:check -- --base "$OPCORE_BASE"
- name: Check generated Cluster Protocol artifacts
run: npm run protocol:check
- name: Check Rust formatting
run: cargo fmt --all -- --check
- name: Lint Rust
run: cargo clippy --workspace --all-targets -- -D warnings
- name: Test Rust workspace
run: cargo test --workspace
- name: Security audit
run: npm run audit:production
continue-on-error: false
- name: Lint
run: npm run lint
- name: Duplicate code check
run: npm run dupcheck
- name: Type check
run: npm run typecheck
- name: Check provider CLI helper
run: npm run check:agent-cli-provider:ci
- name: Hosted private CLI and target tests
run: npm run test:hosted
timeout-minutes: 5
- name: Unit tests with coverage (fast)
run: npm run test:coverage
timeout-minutes: 3
- name: E2E tests (fake provider)
run: npm run test:e2e
timeout-minutes: 5
- name: Integration tests (slow)
run: npm run test:slow
timeout-minutes: 15
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/lcov.info
flags: unittests
name: codecov-zeroshot
fail_ci_if_error: false
continue-on-error: true
# Tier 2: worktree/container isolation e2e (real Docker). Non-blocking and
# opt-in via workflow_dispatch - the Docker sub-tests in `check`'s
# "Integration tests (slow)" step self-skip under CI (this is what that
# step's Docker coverage was previously silently missing).
e2e-docker:
if: github.event_name == 'workflow_dispatch' && inputs.include_docker_e2e
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 22
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Link CLI
run: npm link
- name: Docker isolation e2e
run: npm run test:e2e:docker
timeout-minutes: 15
hosted-oecp-relevance:
name: Hosted OECP image relevance
runs-on: ubuntu-latest
outputs:
relevant: ${{ steps.relevance.outputs.relevant }}
steps:
- name: Checkout candidate
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
ref: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha || github.sha }}
- name: Determine hosted image relevance
id: relevance
run: node scripts/hosted-oecp-ci-relevance.js
hosted-oecp-image:
name: Hosted OECP private image
needs: hosted-oecp-relevance
if: needs.hosted-oecp-relevance.outputs.relevant == 'true'
runs-on: ubuntu-latest
timeout-minutes: 30
env:
HOSTED_OECP_IMAGE: zeroshot-oecp:ci-${{ github.run_id }}-${{ github.run_attempt }}
TRIVY_IMAGE: docker.io/aquasec/trivy:0.73.0@sha256:7cced7cae583819fc7806d4cbc0dbbc7cad18b99f7d3e235192e6da8c091045c
steps:
- name: Checkout candidate
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Setup Node.js
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 22
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build agent CLI provider
run: npm run build:agent-cli-provider
- name: Build hosted OECP image
run: node scripts/hosted-oecp-image.js build "$HOSTED_OECP_IMAGE"
- name: Inspect hosted OECP image
run: node scripts/hosted-oecp-image.js inspect "$HOSTED_OECP_IMAGE"
- name: Smoke hosted OECP image
run: node scripts/hosted-oecp-image.js smoke "$HOSTED_OECP_IMAGE"
- name: Record Trivy and vulnerability database identity
shell: bash
env:
TRIVY_CACHE_DIR: ${{ runner.temp }}/trivy-cache
run: |
set -euo pipefail
mkdir -p "$TRIVY_CACHE_DIR"
echo "Trivy scanner image: $TRIVY_IMAGE"
docker run --rm \
--volume "$TRIVY_CACHE_DIR:/root/.cache/trivy" \
"$TRIVY_IMAGE" image --cache-dir /root/.cache/trivy --download-db-only
docker run --rm \
--volume "$TRIVY_CACHE_DIR:/root/.cache/trivy" \
"$TRIVY_IMAGE" version --cache-dir /root/.cache/trivy --format json
- name: Scan hosted OECP npm lockfile vulnerabilities
shell: bash
env:
TRIVY_CACHE_DIR: ${{ runner.temp }}/trivy-cache
run: |
set -euo pipefail
echo "Trivy filesystem scan target: docker/zeroshot-oecp"
echo "Trivy vulnerability scope: library lockfiles, fixed HIGH/CRITICAL vulnerabilities"
docker run --rm \
--volume "$TRIVY_CACHE_DIR:/root/.cache/trivy" \
--volume "$GITHUB_WORKSPACE:/workspace:ro" \
--workdir /workspace \
"$TRIVY_IMAGE" fs \
--cache-dir /root/.cache/trivy \
--scanners vuln \
--pkg-types library \
--severity HIGH,CRITICAL \
--ignore-unfixed \
--exit-code 1 \
--skip-db-update \
--offline-scan \
--no-progress \
docker/zeroshot-oecp
# Cross-platform/version compatibility (main only)
# NOTE: macOS runners cost 10x Linux minutes - keep this scoped to main.
install-matrix:
needs: check
if: |
always() &&
needs.check.result == 'success' &&
(
github.ref == 'refs/heads/main' ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'pull_request' && github.base_ref == 'main') ||
(github.event_name == 'merge_group' && (
github.event.merge_group.base_ref == 'main' ||
github.event.merge_group.base_ref == 'refs/heads/main' ||
startsWith(github.ref, 'refs/heads/gh-readonly-queue/main/')
))
)
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
node: 22
- os: macos-latest
node: 22
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js ${{ matrix.node }}
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Link CLI
run: npm link
- name: CLI smoke test
run: |
zeroshot --help
zeroshot --version
zeroshot list
- name: Test process-metrics (platform-specific)
run: |
node -e "
(async () => {
const { getProcessMetrics, formatMetrics, getStateIcon, isPlatformSupported, getPlatformInfo } = require('./src/process-metrics');
const os = require('os');
console.log('Platform:', os.platform());
console.log('Supported:', isPlatformSupported());
console.log('Platform info:', JSON.stringify(getPlatformInfo()));
// Test metrics collection
const metrics = await getProcessMetrics(process.pid, { samplePeriodMs: 100 });
console.log('Metrics:', JSON.stringify(metrics, null, 2));
// Validate required fields
if (!metrics.exists) throw new Error('Process should exist');
if (typeof metrics.cpuPercent !== 'number') throw new Error('cpuPercent must be number');
if (typeof metrics.memoryMB !== 'number') throw new Error('memoryMB must be number');
if (!metrics.state) throw new Error('state must be set');
console.log('Formatted:', formatMetrics(metrics));
console.log('State icon:', getStateIcon(metrics.state, metrics.network?.hasActivity));
console.log('✓ Process metrics test passed on', os.platform());
})().catch(e => { console.error(e); process.exit(1); });
"
- name: Test status-footer
run: |
node -e "
const { StatusFooter } = require('./src/status-footer');
const footer = new StatusFooter({ enabled: false });
footer.setCluster('test-cluster');
footer.setClusterState('running');
footer.updateAgent({ id: 'worker', state: 'executing_task', pid: process.pid, iteration: 1 });
const statusLine = footer.buildStatusLine(80);
if (!statusLine.includes('running')) throw new Error('Status line missing state');
if (!statusLine.includes('1/1')) throw new Error('Status line missing agent count');
footer.stop();
console.log('✓ StatusFooter test passed');
"
release-preflight:
name: Release preflight
if: |
(github.event_name == 'pull_request' && github.base_ref == 'main') ||
(github.event_name == 'merge_group' && (
github.event.merge_group.base_ref == 'main' ||
github.event.merge_group.base_ref == 'refs/heads/main' ||
startsWith(github.ref, 'refs/heads/gh-readonly-queue/main/')
))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version: 22
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Validate release contract
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run release:preflight
required:
name: required
if: ${{ always() }}
needs:
- check
- install-matrix
- release-preflight
- hosted-oecp-relevance
- hosted-oecp-image
runs-on: ubuntu-latest
steps:
- name: Require every applicable CI gate
env:
CHECK_RESULT: ${{ needs.check.result }}
INSTALL_MATRIX_RESULT: ${{ needs.install-matrix.result }}
RELEASE_PREFLIGHT_RESULT: ${{ needs.release-preflight.result }}
HOSTED_OECP_RELEVANCE_RESULT: ${{ needs.hosted-oecp-relevance.result }}
HOSTED_OECP_RELEVANT: ${{ needs.hosted-oecp-relevance.outputs.relevant }}
HOSTED_OECP_IMAGE_RESULT: ${{ needs.hosted-oecp-image.result }}
run: |
if [[ "$CHECK_RESULT" != "success" ]]; then
echo "::error::check concluded with $CHECK_RESULT"
exit 1
fi
if [[ "$INSTALL_MATRIX_RESULT" != "success" ]]; then
echo "::error::install-matrix concluded with $INSTALL_MATRIX_RESULT"
exit 1
fi
if [[ "$RELEASE_PREFLIGHT_RESULT" != "success" && "$RELEASE_PREFLIGHT_RESULT" != "skipped" ]]; then
echo "::error::release-preflight concluded with $RELEASE_PREFLIGHT_RESULT"
exit 1
fi
if [[ "$HOSTED_OECP_RELEVANCE_RESULT" != "success" ]]; then
echo "::error::hosted-oecp-relevance concluded with $HOSTED_OECP_RELEVANCE_RESULT"
exit 1
fi
if [[ "$HOSTED_OECP_RELEVANT" != "true" && "$HOSTED_OECP_RELEVANT" != "false" ]]; then
echo "::error::hosted-oecp-relevance emitted invalid relevance: $HOSTED_OECP_RELEVANT"
exit 1
fi
if [[ "$HOSTED_OECP_RELEVANT" == "true" && "$HOSTED_OECP_IMAGE_RESULT" != "success" ]]; then
echo "::error::hosted-oecp-image concluded with $HOSTED_OECP_IMAGE_RESULT for relevant changes"
exit 1
fi
if [[ "$HOSTED_OECP_RELEVANT" == "false" && "$HOSTED_OECP_IMAGE_RESULT" != "skipped" ]]; then
echo "::error::hosted-oecp-image concluded with $HOSTED_OECP_IMAGE_RESULT for irrelevant changes"
exit 1
fi