Files
certctl/.github/workflows/ci.yml
T
shankar0123 596d86a206 feat(M48): continuous TLS health monitoring — endpoint state machine, shared tlsprobe, 8 API endpoints, GUI
Adds continuous TLS endpoint health monitoring that closes the deploy→verify→monitor loop.
After M25 verifies a deployment succeeded once, M48 continuously confirms it stays healthy.

Key components:
- Shared `internal/tlsprobe/` package extracted from network scanner for reuse
- Health status state machine: healthy → degraded (2 failures) → down (5 failures),
  plus cert_mismatch when served fingerprint differs from expected
- 8th scheduler loop (60s tick, per-endpoint configurable intervals)
- PostgreSQL migration 000011: endpoint_health_checks + endpoint_health_history tables
- 8 REST API endpoints (CRUD, history, acknowledge, summary)
- Health Monitor GUI page with summary bar, status table, create modal, auto-refresh
- 38 new tests (5 tlsprobe + 11 domain + 10 service + 8 handler + 4 frontend)
- All coverage thresholds maintained (service 68%, handler 83%, domain 87%, middleware 63%)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-15 21:45:45 -04:00

145 lines
5.1 KiB
YAML

name: CI
on:
push:
branches:
- master
- v2-dev
pull_request:
branches:
- master
jobs:
go-build-and-test:
name: Go Build & Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.25.9'
- name: Go Build
run: |
go build ./cmd/server/...
go build ./cmd/agent/...
go build ./cmd/mcp-server/...
go build ./cmd/cli/...
- name: Go Vet
run: go vet ./...
- name: Install golangci-lint
run: |
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.11.4
- name: Run golangci-lint
run: golangci-lint run ./... --timeout 5m
- name: Install govulncheck
run: go install golang.org/x/vuln/cmd/govulncheck@latest
- name: Run govulncheck
run: govulncheck ./...
- name: Race Detection
run: go test -race ./internal/service/... ./internal/api/handler/... ./internal/api/middleware/... ./internal/scheduler/... ./internal/connector/... ./internal/domain/... ./internal/validation/... ./internal/tlsprobe/... -count=1 -timeout 300s
- name: Go Test with Coverage
run: |
go test ./internal/service/... ./internal/api/handler/... ./internal/api/middleware/... ./internal/integration/... ./internal/connector/issuer/... ./internal/connector/target/... ./internal/connector/notifier/... ./internal/mcp/... ./internal/cli/... ./internal/domain/... ./internal/validation/... ./internal/tlsprobe/... -count=1 -cover -coverprofile=coverage.out
- name: Check Coverage Thresholds
run: |
# Extract per-package coverage from test output
echo "=== Coverage Report ==="
go tool cover -func=coverage.out | tail -1
# Check service layer coverage (target: 60%+)
SERVICE_COV=$(go tool cover -func=coverage.out | grep 'internal/service' | awk '{print $NF}' | sed 's/%//' | awk '{sum+=$1; n++} END {if(n>0) printf "%.1f", sum/n; else print "0"}')
echo "Service layer coverage: ${SERVICE_COV}%"
# Check handler layer coverage (target: 60%+)
HANDLER_COV=$(go tool cover -func=coverage.out | grep 'internal/api/handler' | awk '{print $NF}' | sed 's/%//' | awk '{sum+=$1; n++} END {if(n>0) printf "%.1f", sum/n; else print "0"}')
echo "Handler layer coverage: ${HANDLER_COV}%"
# Check domain layer coverage (target: 40%+)
DOMAIN_COV=$(go tool cover -func=coverage.out | grep 'internal/domain' | awk '{print $NF}' | sed 's/%//' | awk '{sum+=$1; n++} END {if(n>0) printf "%.1f", sum/n; else print "0"}')
echo "Domain layer coverage: ${DOMAIN_COV}%"
# Check middleware layer coverage (target: 50%+)
MIDDLEWARE_COV=$(go tool cover -func=coverage.out | grep 'internal/api/middleware' | awk '{print $NF}' | sed 's/%//' | awk '{sum+=$1; n++} END {if(n>0) printf "%.1f", sum/n; else print "0"}')
echo "Middleware layer coverage: ${MIDDLEWARE_COV}%"
# Fail if thresholds not met
if [ "$(echo "$SERVICE_COV < 55" | bc -l)" -eq 1 ]; then
echo "::error::Service layer coverage ${SERVICE_COV}% is below 55% threshold"
exit 1
fi
if [ "$(echo "$HANDLER_COV < 60" | bc -l)" -eq 1 ]; then
echo "::error::Handler layer coverage ${HANDLER_COV}% is below 60% threshold"
exit 1
fi
if [ "$(echo "$DOMAIN_COV < 40" | bc -l)" -eq 1 ]; then
echo "::error::Domain layer coverage ${DOMAIN_COV}% is below 40% threshold"
exit 1
fi
if [ "$(echo "$MIDDLEWARE_COV < 30" | bc -l)" -eq 1 ]; then
echo "::error::Middleware layer coverage ${MIDDLEWARE_COV}% is below 30% threshold"
exit 1
fi
echo "Coverage thresholds passed!"
- name: Upload Coverage Report
uses: actions/upload-artifact@v4
with:
name: go-coverage
path: coverage.out
retention-days: 30
frontend-build:
name: Frontend Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
- name: Install Dependencies
working-directory: web
run: npm ci
- name: TypeScript Check
working-directory: web
run: npx tsc --noEmit
- name: Run Frontend Tests
working-directory: web
run: npx vitest run
- name: Build Frontend
working-directory: web
run: npx vite build
helm-lint:
name: Helm Chart Validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Helm
uses: azure/setup-helm@v4
with:
version: '3.13.0'
- name: Lint Helm Chart
run: helm lint deploy/helm/certctl/
- name: Template Helm Chart
run: helm template certctl deploy/helm/certctl/ > /dev/null