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
103 changes: 103 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
name: CD

on:
push:
branches: [main]
paths:
- 'src/**'
- 'deploy/**'
- 'hack/docker-compose.yml'
- 'Makefile'
workflow_dispatch:
inputs:
environment:
description: 'Target environment'
required: true
default: 'staging'
type: choice
options:
- staging
- production

env:
REGISTRY: ghcr.io/${{ github.repository_owner }}

jobs:
# ── Build and push Docker images to GHCR ───────────────────────
build-push:
name: Build & Push (${{ matrix.service }})
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
service:
- aex-gateway
- aex-work-publisher
- aex-bid-gateway
- aex-bid-evaluator
- aex-contract-engine
- aex-provider-registry
- aex-trust-broker
- aex-identity
- aex-settlement
- aex-telemetry
- aex-certauth
- aex-credentials-provider
- aex-token-bank
steps:
- uses: actions/checkout@v4

- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ matrix.service }}
tags: |
type=sha,prefix=
type=raw,value=latest,enable={{is_default_branch}}

- name: Build and push
uses: docker/build-push-action@v5
with:
context: src/
file: src/${{ matrix.service }}/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

# ── Deploy to staging (optional) ───────────────────────────────
deploy-staging:
name: Deploy to Staging
needs: [build-push]
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment: staging
steps:
- uses: actions/checkout@v4

- name: Set image tags
run: |
SHA="${{ github.sha }}"
SHORT_SHA="${SHA:0:7}"
echo "IMAGE_TAG=${SHORT_SHA}" >> $GITHUB_ENV

- name: Deploy with kustomize (dry-run)
run: |
echo "Would deploy to staging with image tag: ${{ env.IMAGE_TAG }}"
echo "Registry: ${{ env.REGISTRY }}"
echo ""
echo "To enable real deployment:"
echo " 1. Configure KUBECONFIG secret in GitHub"
echo " 2. Uncomment kubectl apply below"
echo " 3. Set up staging environment in GitHub settings"
# kubectl apply -k deploy/k8s/overlays/staging
104 changes: 104 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

env:
GO_VERSION: '1.26'

jobs:
# ── Lint & Test all Go modules ──────────────────────────────────
lint-test:
name: Lint & Test (${{ matrix.module }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
module:
# Shared libraries
- internal/events
- internal/httpclient
- internal/nats
- internal/telemetry
- internal/certauth
- internal/ap2
- internal/testutil
# Services
- aex-gateway
- aex-work-publisher
- aex-bid-gateway
- aex-bid-evaluator
- aex-contract-engine
- aex-provider-registry
- aex-trust-broker
- aex-identity
- aex-settlement
- aex-telemetry
- aex-certauth
- aex-credentials-provider
- aex-token-bank
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: src/${{ matrix.module }}/go.sum

- name: Go vet
working-directory: src/${{ matrix.module }}
run: go vet ./...

- name: Go test
working-directory: src/${{ matrix.module }}
run: go test ./... -timeout 120s

# ── Build all Docker images ─────────────────────────────────────
docker-build:
name: Docker Build (${{ matrix.service }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
service:
- aex-gateway
- aex-work-publisher
- aex-bid-gateway
- aex-bid-evaluator
- aex-contract-engine
- aex-provider-registry
- aex-trust-broker
- aex-identity
- aex-settlement
- aex-telemetry
- aex-certauth
- aex-credentials-provider
- aex-token-bank
steps:
- uses: actions/checkout@v4

- name: Build Docker image
run: |
docker build \
-f src/${{ matrix.service }}/Dockerfile \
-t agent-exchange/${{ matrix.service }}:ci \
src/

# ── Summary gate ────────────────────────────────────────────────
ci-pass:
name: CI Pass
needs: [lint-test, docker-build]
runs-on: ubuntu-latest
if: always()
steps:
- name: Check results
run: |
if [ "${{ needs.lint-test.result }}" != "success" ] || [ "${{ needs.docker-build.result }}" != "success" ]; then
echo "CI failed: lint-test=${{ needs.lint-test.result }}, docker-build=${{ needs.docker-build.result }}"
exit 1
fi
echo "All CI checks passed"
65 changes: 65 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: E2E Tests

on:
pull_request:
branches: [main]
workflow_dispatch:

jobs:
e2e:
name: E2E Integration Tests
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- uses: actions/checkout@v4

- name: Build all Docker images
run: make docker-build

- name: Start services
run: |
docker compose -f hack/docker-compose.yml up -d
echo "Waiting for services to be healthy..."
sleep 30

- name: Check service health
run: |
for port in 8080 8081 8082 8083 8084 8085 8086 8087 8088 8091; do
echo "Checking port $port..."
curl -sf http://localhost:$port/health || echo "Port $port not healthy"
done

- name: Run E2E test suite
run: bash hack/tests/e2e_test.sh

- name: Run NATS event tests
run: bash hack/tests/test_nats_events.sh
continue-on-error: true

- name: Run circuit breaker tests
run: bash hack/tests/test_circuit_breaker.sh
continue-on-error: true

- name: Run rate limiter tests
run: bash hack/tests/test_rate_limiter.sh
continue-on-error: true

- name: Collect logs on failure
if: failure()
run: |
docker compose -f hack/docker-compose.yml logs --tail=100 > docker-logs.txt
echo "=== Docker container status ==="
docker compose -f hack/docker-compose.yml ps

- name: Upload logs artifact
if: failure()
uses: actions/upload-artifact@v4
with:
name: docker-logs
path: docker-logs.txt
retention-days: 7

- name: Tear down
if: always()
run: docker compose -f hack/docker-compose.yml down -v
105 changes: 105 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
name: Security Scan

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 6 * * 1' # Weekly Monday 6am UTC
workflow_dispatch:

env:
GO_VERSION: '1.26'

jobs:
# ── Go vulnerability check ─────────────────────────────────────
govulncheck:
name: govulncheck (${{ matrix.module }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
module:
- internal/events
- internal/httpclient
- internal/nats
- internal/telemetry
- internal/certauth
- internal/ap2
- aex-gateway
- aex-work-publisher
- aex-bid-gateway
- aex-bid-evaluator
- aex-contract-engine
- aex-provider-registry
- aex-trust-broker
- aex-identity
- aex-settlement
- aex-certauth
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache-dependency-path: src/${{ matrix.module }}/go.sum

- name: Install govulncheck
run: go install golang.org/x/vuln/cmd/govulncheck@latest

- name: Run govulncheck
working-directory: src/${{ matrix.module }}
run: govulncheck ./...

# ── Docker image vulnerability scan ────────────────────────────
trivy-scan:
name: Trivy (${{ matrix.service }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
service:
- aex-gateway
- aex-work-publisher
- aex-bid-gateway
- aex-bid-evaluator
- aex-contract-engine
- aex-provider-registry
- aex-trust-broker
- aex-identity
- aex-settlement
- aex-certauth
steps:
- uses: actions/checkout@v4

- name: Build Docker image
run: |
docker build \
-f src/${{ matrix.service }}/Dockerfile \
-t ${{ matrix.service }}:scan \
src/

- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: '${{ matrix.service }}:scan'
format: 'table'
exit-code: '1'
severity: 'CRITICAL,HIGH'
ignore-unfixed: true

# ── Summary gate ────────────────────────────────────────────────
security-pass:
name: Security Pass
needs: [govulncheck, trivy-scan]
runs-on: ubuntu-latest
if: always()
steps:
- name: Check results
run: |
if [ "${{ needs.govulncheck.result }}" != "success" ] || [ "${{ needs.trivy-scan.result }}" != "success" ]; then
echo "Security scan failed: govulncheck=${{ needs.govulncheck.result }}, trivy=${{ needs.trivy-scan.result }}"
exit 1
fi
echo "All security scans passed"
2 changes: 1 addition & 1 deletion hack/tests/e2e_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ assert_json_field "$_BODY" '.status' "ACTIVE" "10.4e: Verified status is ACTIVE"
# 10.4f Check CRL
http_both GET "$CERTAUTH_URL/v1/crl"
assert_status "200" "$_STATUS" "10.4f: Get CRL"
assert_json_field "$_BODY" '.issuer' "aex-certauth" "10.4f: CRL issuer"
assert_json_field "$_BODY" '.issuer_id' "aex-certauth" "10.4f: CRL issuer"

# 10.4g Get reputation
http_both GET "$CERTAUTH_URL/v1/providers/${PROVIDER_A_ID}/reputation"
Expand Down
Loading
Loading