feat(dns): pod-network cluster-DNS probe via overlay-test pods (task 242) #204
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: | |
| - main | |
| tags: | |
| - 'v*' | |
| pull_request: | |
| branches: | |
| - main | |
| env: | |
| GO_VERSION: '1.25' | |
| REGISTRY: docker.io/supporttools | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | |
| jobs: | |
| # Lint job - runs golangci-lint | |
| lint: | |
| name: Lint | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Setup Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Install golangci-lint | |
| run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.64.8 | |
| - name: Run golangci-lint | |
| run: golangci-lint run --timeout=5m | |
| # Test job - runs unit and integration tests | |
| test: | |
| name: Test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Setup Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Download dependencies | |
| run: go mod download | |
| - name: Run unit tests | |
| run: go test ./pkg/... ./cmd/... -v -race -covermode=atomic -coverprofile=coverage.out -short | |
| - name: Run integration tests | |
| run: | | |
| if [ -d "test/integration" ]; then | |
| go test ./test/integration/... -v -race -covermode=atomic -coverprofile=coverage-integration.out | |
| else | |
| echo "Integration tests not yet implemented - skipping" | |
| fi | |
| - name: Generate coverage report | |
| run: | | |
| go tool cover -func=coverage.out | grep total | awk '{print "Unit test coverage: " $3}' | |
| if [ -f coverage-integration.out ]; then | |
| go tool cover -func=coverage-integration.out | grep total | awk '{print "Integration test coverage: " $3}' | |
| fi | |
| - name: Check coverage threshold | |
| run: | | |
| if [ ! -f coverage.out ]; then | |
| echo "::error::Coverage file not found" | |
| exit 1 | |
| fi | |
| COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//') | |
| if [ -z "$COVERAGE" ]; then | |
| echo "::error::Failed to extract coverage percentage" | |
| exit 1 | |
| fi | |
| THRESHOLD=70 | |
| echo "Current coverage: ${COVERAGE}%" | |
| echo "Minimum threshold: ${THRESHOLD}%" | |
| if (( $(echo "$COVERAGE < $THRESHOLD" | bc -l) )); then | |
| echo "::error::Coverage ${COVERAGE}% is below minimum threshold of ${THRESHOLD}%" | |
| exit 1 | |
| fi | |
| echo "Coverage check passed!" | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v5 | |
| continue-on-error: true # Codecov is informational; inline check above is the hard gate | |
| with: | |
| files: ./coverage.out,./coverage-integration.out | |
| flags: unittests | |
| name: codecov-umbrella | |
| fail_ci_if_error: false | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| # Pinger ICMP integration - runs the real raw-ICMP loopback test under privilege. | |
| # | |
| # Kept as a SEPARATE job (not a step in `test`) so a privileged-socket flake on | |
| # the runner does not block the main unit-test/coverage job. The runner user | |
| # compiles the test binary (preserving the Go env / cache), then runs ONLY the | |
| # integration test via sudo so it has CAP_NET_RAW. NODE_DOCTOR_ICMP_INTEGRATION=1 | |
| # makes socket/permission errors HARD failures so a misconfigured runner surfaces | |
| # loudly instead of silently passing without exercising real ICMP. | |
| pinger-icmp-integration: | |
| name: Pinger ICMP Integration | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Setup Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Download dependencies | |
| run: go mod download | |
| - name: Compile network test binary | |
| run: go test -c -o /tmp/nd-network.test ./pkg/monitors/network/ | |
| - name: Run ICMP integration test (privileged) | |
| run: | | |
| sudo NODE_DOCTOR_ICMP_INTEGRATION=1 /tmp/nd-network.test \ | |
| -test.run '^TestDefaultPinger_Integration$' -test.v | |
| # Security scan - gosec | |
| security-gosec: | |
| name: Security Scan (gosec) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| security-events: write | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Setup Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Run gosec | |
| uses: securego/gosec@v2.25.0 | |
| with: | |
| args: '-no-fail -fmt sarif -out gosec-results.sarif ./...' | |
| - name: Upload gosec results to GitHub Security | |
| uses: github/codeql-action/upload-sarif@v4 | |
| continue-on-error: true # gosec SARIF format may have compatibility issues | |
| with: | |
| sarif_file: gosec-results.sarif | |
| # Build job - builds the binary | |
| build: | |
| name: Build | |
| runs-on: ubuntu-latest | |
| needs: [lint, test] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Setup Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache: true | |
| - name: Download dependencies | |
| run: go mod download | |
| - name: Build binary | |
| run: | | |
| VERSION=$(date +%s) | |
| GIT_COMMIT=$(git rev-parse HEAD) | |
| BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") | |
| mkdir -p bin | |
| cd cmd/node-doctor | |
| go build \ | |
| -ldflags="-X main.Version=${VERSION} -X main.GitCommit=${GIT_COMMIT} -X main.BuildTime=${BUILD_TIME}" \ | |
| -o ../../bin/node-doctor | |
| - name: Build overlay-test-server binary | |
| run: | | |
| mkdir -p bin | |
| cd cmd/overlay-test-server | |
| go build -o ../../bin/overlay-test-server | |
| - name: Test binary | |
| run: ./bin/node-doctor --version | |
| - name: Upload binary artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: node-doctor-binary | |
| path: bin/node-doctor | |
| retention-days: 7 | |
| # Docker build and push - only on tags | |
| docker: | |
| name: Docker Build & Push | |
| runs-on: ubuntu-latest | |
| needs: [lint, test, build, security-gosec] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| permissions: | |
| security-events: write | |
| contents: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Extract tag name | |
| id: tag | |
| run: echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT | |
| - name: Build metadata | |
| id: meta | |
| run: | | |
| VERSION=${{ steps.tag.outputs.TAG }} | |
| GIT_COMMIT=$(git rev-parse HEAD) | |
| BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") | |
| echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT | |
| echo "GIT_COMMIT=${GIT_COMMIT}" >> $GITHUB_OUTPUT | |
| echo "BUILD_TIME=${BUILD_TIME}" >> $GITHUB_OUTPUT | |
| - name: Build and push Docker image | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: ./Dockerfile | |
| platforms: linux/amd64 | |
| push: true | |
| tags: | | |
| ${{ env.REGISTRY }}/node-doctor:${{ steps.tag.outputs.TAG }} | |
| ${{ env.REGISTRY }}/node-doctor:latest | |
| build-args: | | |
| VERSION=${{ steps.meta.outputs.VERSION }} | |
| GIT_COMMIT=${{ steps.meta.outputs.GIT_COMMIT }} | |
| BUILD_TIME=${{ steps.meta.outputs.BUILD_TIME }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| - name: Run Trivy security scan on image | |
| uses: aquasecurity/trivy-action@v0.35.0 | |
| with: | |
| image-ref: ${{ env.REGISTRY }}/node-doctor:${{ steps.tag.outputs.TAG }} | |
| format: 'sarif' | |
| output: 'trivy-results.sarif' | |
| - name: Upload Trivy results to GitHub Security | |
| uses: github/codeql-action/upload-sarif@v4 | |
| with: | |
| sarif_file: trivy-results.sarif | |
| # Summary job - provides overall status | |
| ci-success: | |
| name: CI Success | |
| runs-on: ubuntu-latest | |
| needs: [lint, test, build, security-gosec] | |
| if: always() | |
| steps: | |
| - name: Check job results | |
| run: | | |
| if [[ "${{ needs.lint.result }}" != "success" ]] || \ | |
| [[ "${{ needs.test.result }}" != "success" ]] || \ | |
| [[ "${{ needs.build.result }}" != "success" ]] || \ | |
| [[ "${{ needs.security-gosec.result }}" != "success" ]]; then | |
| echo "One or more CI jobs failed" | |
| exit 1 | |
| fi | |
| echo "All CI jobs passed successfully!" |