From 91f0fc9ab8d0384264410d2c6b833d63cb186149 Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Mon, 8 Dec 2025 02:32:46 +0000 Subject: [PATCH] Switch to go releaser --- .github/workflows/pr-validation.yml | 622 ---------------------------- .github/workflows/pr.yaml | 23 + .github/workflows/release.yml | 21 + .goreleaser.yaml | 49 +++ 4 files changed, 93 insertions(+), 622 deletions(-) delete mode 100644 .github/workflows/pr-validation.yml create mode 100644 .github/workflows/pr.yaml create mode 100644 .github/workflows/release.yml create mode 100644 .goreleaser.yaml diff --git a/.github/workflows/pr-validation.yml b/.github/workflows/pr-validation.yml deleted file mode 100644 index bf656a0..0000000 --- a/.github/workflows/pr-validation.yml +++ /dev/null @@ -1,622 +0,0 @@ -name: PR Validation - -on: - pull_request: - branches: [ main ] - push: - branches: [ main ] - -permissions: - contents: read - pull-requests: write - checks: write - security-events: write - -jobs: - # Fast feedback - format and basic checks - quick-checks: - name: Quick Checks - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Format check - run: | - # Exclude vendor directory from format checks - UNFORMATTED=$(gofmt -s -l . | grep -v "^vendor/" || true) - if [ -n "$UNFORMATTED" ]; then - echo "Code is not formatted. Run: gofmt -s -w ." - echo "Unformatted files:" - echo "$UNFORMATTED" - gofmt -s -d $(echo "$UNFORMATTED") - exit 1 - fi - - - name: Go vet - run: go vet ./... - - - name: Go mod verify - run: go mod verify - - - name: Go mod tidy check - run: | - go mod tidy - git diff --exit-code go.mod go.sum - - # Static analysis with golangci-lint (advisory - will not fail the build) - golangci-lint: - name: golangci-lint - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: golangci-lint - uses: golangci/golangci-lint-action@v8 - with: - version: latest - args: --timeout=10m - continue-on-error: true # Allow pipeline to continue even with linting warnings - - # Staticcheck analysis - staticcheck: - name: Staticcheck - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Install staticcheck - run: go install honnef.co/go/tools/cmd/staticcheck@latest - - - name: Run staticcheck - run: staticcheck ./... - - # Security scanning with gosec - gosec: - name: Gosec Security Scanner - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Run Gosec Security Scanner - run: | - go install github.com/securego/gosec/v2/cmd/gosec@latest - gosec -no-fail -fmt sarif -out results.sarif ./... || echo "Gosec completed with warnings" - continue-on-error: true - - - name: Upload SARIF file - if: always() && hashFiles('results.sarif') != '' - uses: github/codeql-action/upload-sarif@v3 - with: - sarif_file: results.sarif - continue-on-error: true - - # Vulnerability scanning - govulncheck: - name: Vulnerability Scan - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Install govulncheck - run: go install golang.org/x/vuln/cmd/govulncheck@latest - - - name: Run govulncheck - run: govulncheck ./... - - # CodeQL analysis - codeql: - name: CodeQL Analysis - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: go - continue-on-error: true - - - name: Autobuild - uses: github/codeql-action/autobuild@v3 - continue-on-error: true - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - continue-on-error: true - - # Unit tests with race detection - test-race: - name: Unit Tests (Race Detector) - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Run tests with race detector - run: go test -race -timeout=15m -count=1 -v ./... - env: - GOMAXPROCS: 4 - - # Coverage analysis with threshold check - test-coverage: - name: Test Coverage - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Run tests with coverage - run: | - go test -coverprofile=coverage.out -covermode=atomic -timeout=15m ./... - go tool cover -func=coverage.out -o=coverage.txt - - - name: Calculate coverage - id: coverage - run: | - COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//') - echo "coverage=$COVERAGE" >> $GITHUB_OUTPUT - echo "Total Coverage: $COVERAGE%" - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 - with: - file: ./coverage.out - flags: unittests - name: codecov-umbrella - fail_ci_if_error: false - continue-on-error: true - - - name: Comment coverage on PR - if: github.event_name == 'pull_request' - uses: actions/github-script@v8 - with: - script: | - const coverage = '${{ steps.coverage.outputs.coverage }}'; - const threshold = 70; - const coverageNum = parseFloat(coverage); - const emoji = coverageNum >= threshold ? '✅' : '⚠️'; - const status = coverageNum >= threshold ? 'meets' : 'below'; - - const body = `## ${emoji} Test Coverage Report - - | Metric | Value | - |--------|-------| - | **Total Coverage** | ${coverage}% | - | **Threshold** | ${threshold}% | - | **Status** | ${emoji} Coverage ${status} threshold |`; - - // Find existing comment - const { data: comments } = await github.rest.issues.listComments({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - }); - - const botComment = comments.find(comment => - comment.user.type === 'Bot' && - comment.body.includes('Test Coverage Report') - ); - - if (botComment) { - await github.rest.issues.updateComment({ - comment_id: botComment.id, - owner: context.repo.owner, - repo: context.repo.repo, - body: body - }); - } else { - await github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: body - }); - } - - - name: Check coverage threshold - run: | - COVERAGE=${{ steps.coverage.outputs.coverage }} - THRESHOLD=70 - echo "Coverage: $COVERAGE%" - echo "Threshold: $THRESHOLD%" - if (( $(echo "$COVERAGE < $THRESHOLD" | bc -l) )); then - echo "⚠️ Coverage $COVERAGE% is below threshold $THRESHOLD%" - exit 1 - fi - echo "✅ Coverage $COVERAGE% meets threshold $THRESHOLD%" - - # Memory leak detection - test-memory-leaks: - name: Memory Leak Detection - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Run goroutine leak tests - run: | - echo "Running goroutine leak detection tests..." - go test -v -timeout=20m -run='.*[Gg]oroutine.*[Ll]eak.*' ./... || echo "No goroutine leak tests found" - - - name: Run memory leak tests - run: | - echo "Running memory leak detection tests..." - go test -v -timeout=20m -run='.*[Mm]emory.*[Ll]eak.*' ./... || echo "No memory leak tests found" - - - name: Run cleanup tests - run: | - echo "Running cleanup and resource management tests..." - go test -v -timeout=20m -run='.*[Cc]leanup.*' ./... || echo "No cleanup tests found" - - # Integration tests - test-integration: - name: Integration Tests - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Run integration tests - run: | - if [ -d "./integration" ]; then - go test -v -timeout=20m ./integration/... - else - echo "Running integration tests from all packages..." - go test -v -timeout=20m -run='.*[Ii]ntegration.*' ./... - fi - - # Regression tests - test-regression: - name: Regression Tests - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Run regression tests - run: | - echo "Running regression tests..." - go test -v -timeout=20m -run='.*[Rr]egression.*' ./... - - # Provider-specific tests (parallel matrix) - test-providers: - name: Provider Tests (${{ matrix.provider }}) - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - provider: - - google - - azure - - auth0 - - okta - - keycloak - - cognito - - gitlab - - github - - generic - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Run ${{ matrix.provider }} provider tests - run: | - PROVIDER_CAP=$(echo "${{ matrix.provider }}" | sed 's/.*/\u&/') - echo "Testing $PROVIDER_CAP provider..." - go test -v -timeout=10m -run=".*$PROVIDER_CAP.*" ./internal/providers/... || true - go test -v -timeout=10m -run=".*${{ matrix.provider }}.*" ./... || true - - # Benchmark tests with performance tracking - benchmark: - name: Benchmark Tests - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Run benchmarks - run: | - echo "Running benchmark tests..." - go test -bench=. -benchmem -benchtime=1s -run=^$ ./... | tee benchmark.txt - - - name: Upload benchmark results - uses: actions/upload-artifact@v4 - with: - name: benchmark-results - path: benchmark.txt - retention-days: 30 - - - name: Compare benchmarks - if: github.event_name == 'pull_request' - continue-on-error: true - run: | - echo "Benchmark results available in artifacts" - echo "To compare with main branch, download previous benchmark results" - - # Build validation across platforms - build: - name: Build (${{ matrix.os }}/${{ matrix.arch }}) - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - os: [linux, darwin] - arch: [amd64, arm64] - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Build for ${{ matrix.os }}/${{ matrix.arch }} - env: - GOOS: ${{ matrix.os }} - GOARCH: ${{ matrix.arch }} - run: | - echo "Building for $GOOS/$GOARCH..." - go build -v -ldflags="-s -w" ./... - - # Security-specific edge case tests - test-security-edge-cases: - name: Security Edge Cases - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Run security edge case tests - run: | - echo "Running security edge case tests..." - go test -v -timeout=15m -run='.*[Ss]ecurity.*' ./... - - # Session management tests - test-session: - name: Session Management Tests - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Run session tests - run: | - echo "Running session management tests..." - go test -v -timeout=15m -run='.*[Ss]ession.*' ./... - - # Token validation tests - test-token: - name: Token Validation Tests - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Run token validation tests - run: | - echo "Running token validation tests..." - go test -v -timeout=15m -run='.*[Tt]oken.*' ./... - - # CSRF and security tests - test-csrf: - name: CSRF and Security Tests - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go - uses: actions/setup-go@v6 - with: - go-version: '1.24' - cache: true - - - name: Run CSRF tests - run: | - echo "Running CSRF and security tests..." - go test -v -timeout=15m -run='.*[Cc][Ss][Rr][Ff].*' ./... - - # Multi-Go version compatibility - test-go-versions: - name: Go ${{ matrix.go-version }} Compatibility - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - go-version: ['1.24'] - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup Go ${{ matrix.go-version }} - uses: actions/setup-go@v6 - with: - go-version: ${{ matrix.go-version }} - cache: true - - - name: Run tests on Go ${{ matrix.go-version }} - run: go test -short -timeout=10m ./... - - # Final validation - all checks must pass (golangci-lint is advisory) - all-checks-passed: - name: ✅ All Checks Passed - runs-on: ubuntu-latest - needs: - - quick-checks - - golangci-lint - - staticcheck - - gosec - - govulncheck - - codeql - - test-race - - test-coverage - - test-memory-leaks - - test-integration - - test-regression - - test-providers - - benchmark - - build - - test-security-edge-cases - - test-session - - test-token - - test-csrf - - test-go-versions - if: always() - steps: - - name: Check all jobs status - run: | - echo "Checking status of all jobs..." - - # Check critical jobs (excluding golangci-lint which is advisory) - CRITICAL_FAILURES=false - - if [ "${{ needs.quick-checks.result }}" == "failure" ] || \ - [ "${{ needs.staticcheck.result }}" == "failure" ] || \ - [ "${{ needs.test-race.result }}" == "failure" ] || \ - [ "${{ needs.test-coverage.result }}" == "failure" ] || \ - [ "${{ needs.build.result }}" == "failure" ]; then - CRITICAL_FAILURES=true - fi - - if [ "$CRITICAL_FAILURES" == "true" ]; then - echo "❌ Critical checks failed" - exit 1 - elif [ "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]; then - echo "⚠️ Some checks were cancelled" - exit 1 - else - echo "✅ All critical checks passed successfully!" - if [ "${{ needs.golangci-lint.result }}" != "success" ]; then - echo "ℹ️ Note: golangci-lint reported issues (advisory only)" - fi - fi - - - name: Post summary - if: always() - run: | - echo "# PR Validation Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "## Job Status" >> $GITHUB_STEP_SUMMARY - echo "- Quick Checks: ${{ needs.quick-checks.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Linting (advisory): ${{ needs.golangci-lint.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Static Analysis: ${{ needs.staticcheck.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Security Scan (gosec): ${{ needs.gosec.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Vulnerability Scan: ${{ needs.govulncheck.result }}" >> $GITHUB_STEP_SUMMARY - echo "- CodeQL: ${{ needs.codeql.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Race Detection: ${{ needs.test-race.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Coverage: ${{ needs.test-coverage.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Memory Leaks: ${{ needs.test-memory-leaks.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Integration Tests: ${{ needs.test-integration.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Regression Tests: ${{ needs.test-regression.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Provider Tests: ${{ needs.test-providers.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Benchmarks: ${{ needs.benchmark.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Build: ${{ needs.build.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Security Edge Cases: ${{ needs.test-security-edge-cases.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Session Tests: ${{ needs.test-session.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Token Tests: ${{ needs.test-token.result }}" >> $GITHUB_STEP_SUMMARY - echo "- CSRF Tests: ${{ needs.test-csrf.result }}" >> $GITHUB_STEP_SUMMARY - echo "- Go Version Compatibility: ${{ needs.test-go-versions.result }}" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml new file mode 100644 index 0000000..c570826 --- /dev/null +++ b/.github/workflows/pr.yaml @@ -0,0 +1,23 @@ +name: Pull Request + +on: + pull_request: + branches: + - main + push: + branches: + - "**" + - "!main" + +permissions: + contents: read + pull-requests: write + security-events: write + +jobs: + pr-checks: + uses: lukaszraczylo/shared-actions/.github/workflows/go-pr.yaml@main + with: + go-version: "1.24" + coverage-threshold: 70 + secrets: inherit diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..7b69c99 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,21 @@ +name: Release + +on: + push: + branches: + - main + paths: + - "**.go" + - "go.mod" + - "go.sum" + workflow_dispatch: + +permissions: + contents: write + +jobs: + release: + uses: lukaszraczylo/shared-actions/.github/workflows/go-release.yaml@main + with: + go-version: "1.24" + secrets: inherit diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000..6e49b26 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,49 @@ +version: 2 + +# Traefik plugins are source-only - no binary builds +# Traefik loads plugins via Yaegi interpreter at runtime +builds: + - skip: true + +# Create source archive for GitHub releases +archives: + - format: tar.gz + name_template: "{{ .ProjectName }}_{{ .Version }}_source" + files: + - "*.go" + - "**/*.go" + - go.mod + - go.sum + - .traefik.yml + - LICENSE* + - README* + # Exclude test files and vendor from release archive + - "!**/*_test.go" + - "!vendor/**" + - "!docker/**" + - "!integration/**" + - "!regression/**" + - "!examples/**" + - "!docs/**" + +checksum: + name_template: "{{ .ProjectName }}_{{ .Version }}_checksums.txt" + algorithm: sha256 + +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" + - "^Merge" + - "^WIP" + - "^chore:" + +release: + github: + owner: lukaszraczylo + name: traefikoidc + name_template: "v{{ .Version }}" + draft: false + prerelease: auto