Skip to content

Feat/additional workspaces #3

Feat/additional workspaces

Feat/additional workspaces #3

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
GO_VERSION: '1.24'
REGISTRY: ghcr.io
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.64.5
install-mode: goinstall
args: --timeout=5m
reconcile-guard:
name: Reconcile Guard
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check for unconditional Update on managed resources
run: |
# Detect bare r.Update/r.Create calls in the controller that bypass
# controllerutil.CreateOrUpdate. Only r.Update(ctx, instance) and
# r.Status().Update(ctx, instance) are allowed (CR-level updates).
# See: https://github.com/openclaw-rocks/k8s-operator/issues/28
VIOLATIONS=$(grep -n 'r\.Update(ctx,' internal/controller/openclawinstance_controller.go \
| grep -v 'instance)' \
| grep -v '// reconcile-guard:allow' || true)
if [ -n "$VIOLATIONS" ]; then
echo "::error::Found bare r.Update() calls on managed resources. Use controllerutil.CreateOrUpdate instead."
echo "Violations:"
echo "$VIOLATIONS"
echo ""
echo "If this is intentional, add '// reconcile-guard:allow' to the line."
exit 1
fi
echo "No unconditional Update calls on managed resources found."
helm-rbac-sync:
name: Helm RBAC Sync
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check Helm chart RBAC matches kubebuilder markers
run: bash hack/check-helm-rbac-sync.sh
helm-crd-sync:
name: Helm CRD Sync
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check Helm chart CRD templates match generated CRDs
run: bash hack/sync-chart-crds.sh --check
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Run tests
run: make test
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
files: ./cover.out
fail_ci_if_error: false
security-scan:
name: Security Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Run gosec
uses: securego/gosec@master
with:
args: -exclude-generated ./...
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
severity: 'CRITICAL,HIGH'
build:
name: Build
needs: [lint, test, security-scan]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Lowercase image name
id: image
run: echo "name=${GITHUB_REPOSITORY,,}" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ steps.image.outputs.name }}
tags: |
type=sha,prefix=
type=ref,event=branch
type=ref,event=pr
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
# Only build arm64 on main (where we push). PRs only need amd64 to
# verify the build -- arm64 cross-compilation via QEMU adds ~15 min.
platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
e2e:
name: E2E Tests
needs: [lint, test, security-scan]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Lowercase image name
id: image
run: echo "name=${GITHUB_REPOSITORY,,}" >> $GITHUB_OUTPUT
- name: Create kind cluster
uses: helm/kind-action@v1
with:
cluster_name: e2e-test
- name: Build operator image for kind
run: |
docker build -t ${{ env.REGISTRY }}/${{ steps.image.outputs.name }}:e2e .
- name: Load image into kind
run: |
kind load docker-image ${{ env.REGISTRY }}/${{ steps.image.outputs.name }}:e2e --name e2e-test
- name: Pre-pull test images
run: |
docker pull chromedp/headless-shell:stable
kind load docker-image chromedp/headless-shell:stable --name e2e-test
docker pull curlimages/curl
kind load docker-image curlimages/curl --name e2e-test
- name: Install CRDs
run: make install
- name: Deploy operator
run: |
make deploy IMG=${{ env.REGISTRY }}/${{ steps.image.outputs.name }}:e2e
- name: Wait for operator
run: |
kubectl wait --for=condition=available --timeout=180s deployment/openclaw-operator-controller-manager -n openclaw-operator-system
- name: Debug operator status
if: failure()
run: |
echo "=== Deployment status ==="
kubectl get deployment -n openclaw-operator-system
echo "=== Pod status ==="
kubectl get pods -n openclaw-operator-system
echo "=== Pod logs ==="
kubectl logs -n openclaw-operator-system -l control-plane=controller-manager --tail=100 || true
echo "=== Pod describe ==="
kubectl describe pods -n openclaw-operator-system || true
- name: Run E2E tests
run: make test-e2e
env:
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
- name: Install operator-sdk
run: |
export ARCH=$(case $(uname -m) in x86_64) echo -n amd64 ;; aarch64) echo -n arm64 ;; *) echo -n $(uname -m) ;; esac)
export OS=$(uname | awk '{print tolower($0)}')
curl -sSLo /usr/local/bin/operator-sdk "https://github.com/operator-framework/operator-sdk/releases/download/v1.38.0/operator-sdk_${OS}_${ARCH}"
chmod +x /usr/local/bin/operator-sdk
operator-sdk version
- name: Run scorecard tests
run: operator-sdk scorecard bundle --wait-time 120s || true
- name: Dump operator logs
if: failure()
run: |
echo "=== Operator pod status ==="
kubectl get pods -n openclaw-operator-system
echo "=== OpenClawInstance resources ==="
kubectl get openclawinstances -A -o wide || true
echo "=== OpenClawSelfConfig resources ==="
kubectl get openclawselfconfigs -A -o wide || true
echo "=== Operator logs (all) ==="
kubectl logs -n openclaw-operator-system -l control-plane=controller-manager --tail=-1 || true