diff --git a/.github/workflows/build-and-sign.yml b/.github/workflows/build-and-sign.yml new file mode 100644 index 00000000..ee5044ce --- /dev/null +++ b/.github/workflows/build-and-sign.yml @@ -0,0 +1,83 @@ +# Cross-compile selected platforms, then DigiCert-sign artifacts. Add triggers under `on:` as needed. +# Fork PRs are skipped (no secrets). Requires SM_* repository secrets and SM_* vars for DigiCert. + +name: Build and sign (DigiCert) + +permissions: + contents: read + actions: write + +on: + pull_request: + branches: [main] + +env: + # Unique per run; safe for PR, manual runs, and future triggers. + SIGNING_ARTIFACT_NAME: launchpad-signing-${{ github.run_id }} + +jobs: + build-for-signing: + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + name: Build binaries for signing + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 + with: + go-version-file: go.mod + - name: Build binaries + shell: bash + run: | + set -euo pipefail + mkdir -p dist + read -r -a platforms <<< "windows/amd64 darwin/amd64" + for platform in "${platforms[@]}"; do + GOOS=${platform%/*} + GOARCH=${platform#*/} + output_name="dist/launchpad_${GOOS}_${GOARCH}" + if [ "$GOOS" = "windows" ]; then + output_name+=".exe" + fi + echo "Building $output_name" + GOOS=$GOOS GOARCH=$GOARCH go build -o "$output_name" ./main.go + done + - uses: actions/upload-artifact@v4 + with: + name: ${{ env.SIGNING_ARTIFACT_NAME }} + path: dist/ + + sign-binaries: + needs: build-for-signing + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + name: Sign binaries + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/download-artifact@v4 + with: + name: ${{ env.SIGNING_ARTIFACT_NAME }} + path: dist/ + + - name: Decode SM client certificate + run: | + SM_CLIENT_CERT_FILE="${{ runner.temp }}/sm_client_cert.p12" + echo "${{ secrets.SM_CLIENT_CERT_FILE_B64 }}" | base64 --decode > "$SM_CLIENT_CERT_FILE" + echo "SM_CLIENT_CERT_FILE=$SM_CLIENT_CERT_FILE" >> "$GITHUB_ENV" + shell: bash + + - name: DigiCert Software Trust Manager + uses: digicert/code-signing-software-trust-action@v1 + with: + simple-signing-mode: true + keypair-alias: ${{ vars.SM_KEYPAIR_ALIAS }} + input: dist/ + env: + SM_HOST: ${{ vars.SM_HOST }} + SM_API_KEY: ${{ secrets.SM_API_KEY }} + SM_CLIENT_CERT_FILE: ${{ env.SM_CLIENT_CERT_FILE }} + SM_CLIENT_CERT_PASSWORD: ${{ secrets.SM_CLIENT_CERT_PASSWORD }} + + - uses: actions/upload-artifact@v4 + with: + name: launchpad-binaries-signed + path: dist/ diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 49513723..4364d734 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,32 +1,30 @@ -# Build and test workflow for Launchpad -# Triggered on PRs and pushes to main. +# Build and test on push to main (unsigned); DigiCert build+sign is in build-and-sign.yml. name: Build and Test + permissions: contents: read - packages: write # Required for uploading artifacts + actions: write # upload-artifact on: push: - branches: [ main ] + branches: [main] jobs: build: - name: Build Binaries + name: Build binaries runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 with: - go-version: "1.25" - + go-version-file: go.mod - name: Build binaries + shell: bash run: | + set -euo pipefail mkdir -p dist - platforms=("linux/amd64" "linux/arm64" "windows/amd64" "windows/arm64" "darwin/amd64" "darwin/arm64") + platforms=(linux/amd64 linux/arm64 windows/amd64 windows/arm64 darwin/amd64 darwin/arm64) for platform in "${platforms[@]}"; do GOOS=${platform%/*} GOARCH=${platform#*/} @@ -37,28 +35,23 @@ jobs: echo "Building $output_name" GOOS=$GOOS GOARCH=$GOARCH go build -o "$output_name" ./main.go done - - - name: Upload artifacts - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v4 with: name: launchpad-binaries path: dist/ test: - name: Run Tests + name: Tests runs-on: ubuntu-latest needs: build steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 with: - go-version: "1.22" - - - name: Run unit tests - run: go test -v ./... - - - name: Run integration tests - run: go test -v -tags=integration ./test/integration + go-version-file: go.mod + - name: Unit tests + run: make unit-test + env: + TEST_FLAGS: -short + - name: Integration tests + run: make integration-test diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml deleted file mode 100644 index 6f5dbb6c..00000000 --- a/.github/workflows/go.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Go unit tests - -on: - pull_request: - paths: - - '**.go' - - go.mod - - go.sum - - Makefile - -jobs: - unit-test: - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - runs-on: ${{ matrix.os }} - - steps: - - uses: actions/checkout@v6 - - - name: Set up Go - uses: actions/setup-go@v6 - with: - go-version-file: go.mod - - - name: Unit Tests - run: make unit-test - env: - TEST_FLAGS: -short diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 6fa57186..b9b7776e 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -1,88 +1,71 @@ -# PR validation workflow for Launchpad -# Triggered on PRs to main branch. +# PR validation for Launchpad (lint, tests, security). Build+sign is in build-and-sign.yml. name: PR Validation permissions: contents: read - pull-requests: write # Required for PR comments or labels on: pull_request: - branches: [ main ] - paths: - - "**.go" - - "go.mod" - - "go.sum" - - "test/**" - - "examples/**" - - ".github/workflows/**" - paths-ignore: - - "**.md" - - "docs/**" + branches: [main] jobs: lint: - name: Lint Code + name: Lint runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 with: - go-version: "1.25" - - - name: Run golangci-lint - run: make lint + go-version-file: go.mod + - name: go mod tidy check + run: go mod tidy -v && git diff --exit-code + - name: golangci-lint + uses: golangci/golangci-lint-action@v9.2.0 + with: + version: latest + skip-cache: true + only-new-issues: false + args: --verbose unit-test: - name: Unit Tests - runs-on: ubuntu-latest + name: Unit Tests (${{ matrix.os }}) + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 with: - go-version: "1.25" - - - name: Run unit tests + go-version-file: go.mod + - name: Unit tests run: make unit-test + env: + TEST_FLAGS: -short - integration-test: - name: Integration Tests + security-scan: + name: Security scan runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 with: - go-version: "1.25" - - - name: Run integration tests - run: make integration-test - - + go-version-file: go.mod + - name: govulncheck + run: go install golang.org/x/vuln/cmd/govulncheck@latest + - name: Run security scan + run: make security-scan - security-scan: - name: Security Scan + integration-test: + name: Integration Tests + needs: security-scan runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 with: - go-version: "1.25" - - - name: Install govulncheck - run: go install golang.org/x/vuln/cmd/govulncheck@latest - - - name: Run security scan - run: govulncheck ./... \ No newline at end of file + go-version-file: go.mod + - name: Integration tests + run: make integration-test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d8cd0a61..f2b64864 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,10 +1,11 @@ -# Release workflow for Launchpad -# Triggered on tags (e.g., v1.5.16). +# Release on version tags. Security scan runs before integration tests, then build and publish. +# DigiCert build+sign is in build-and-sign.yml; wire it in here when ready. name: Release + permissions: - contents: read # Top-level: Restricts all jobs by default - packages: write # Required for uploading artifacts + contents: read + actions: write # upload-artifact in build job on: push: @@ -12,22 +13,46 @@ on: - "v*" jobs: - build: - name: Build Release Binaries + security-scan: + name: Security scan runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v4 + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 + with: + go-version-file: go.mod + - name: govulncheck + run: go install golang.org/x/vuln/cmd/govulncheck@latest + - name: Run security scan + run: make security-scan - - name: Set up Go - uses: actions/setup-go@v5 + integration-test: + name: Integration Tests + needs: security-scan + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 with: - go-version: "1.25" + go-version-file: go.mod + - name: Integration tests + run: make integration-test + build: + name: Build release binaries + needs: integration-test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 + with: + go-version-file: go.mod - name: Build binaries + shell: bash run: | + set -euo pipefail mkdir -p dist - platforms=("linux/amd64" "linux/arm64" "windows/amd64" "windows/arm64" "darwin/amd64" "darwin/arm64") + platforms=(linux/amd64 linux/arm64 windows/amd64 windows/arm64 darwin/amd64 darwin/arm64) for platform in "${platforms[@]}"; do GOOS=${platform%/*} GOARCH=${platform#*/} @@ -38,34 +63,28 @@ jobs: echo "Building $output_name" GOOS=$GOOS GOARCH=$GOARCH go build -o "$output_name" ./main.go done - - - name: Upload artifacts - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v4 with: name: launchpad-release-binaries path: dist/ release: - name: Create GitHub Release + name: GitHub Release runs-on: ubuntu-latest needs: build permissions: contents: write steps: - - name: Download binaries - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v4 with: name: launchpad-release-binaries path: dist/ - - name: Create GitHub Release - uses: softprops/action-gh-release@v1 + - name: Create release + uses: softprops/action-gh-release@v2 with: files: dist/* generate_release_notes: true draft: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # TODO: Add Digicert signing here. - # TODO: Push signed artifacts to S3 here. \ No newline at end of file diff --git a/.github/workflows/smoke-test-full.yaml b/.github/workflows/smoke-test-full.yaml index f27f4b97..97170817 100644 --- a/.github/workflows/smoke-test-full.yaml +++ b/.github/workflows/smoke-test-full.yaml @@ -19,7 +19,7 @@ jobs: - name: Checkout code uses: actions/checkout@v6 - name: Setup Terraform - uses: hashicorp/setup-terraform@v3 + uses: hashicorp/setup-terraform@v4 - name: Run full Smoke Tests env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} diff --git a/.github/workflows/smoke-test-small.yaml b/.github/workflows/smoke-test-small.yaml index 34f9b464..8fa84a86 100644 --- a/.github/workflows/smoke-test-small.yaml +++ b/.github/workflows/smoke-test-small.yaml @@ -17,7 +17,7 @@ jobs: - name: Checkout code uses: actions/checkout@v6 - name: Setup Terraform - uses: hashicorp/setup-terraform@v3 + uses: hashicorp/setup-terraform@v4 - name: Run small Smoke Tests env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}