diff --git a/.github/actions/install-convox/action.yml b/.github/actions/install-convox/action.yml new file mode 100644 index 00000000..5906c131 --- /dev/null +++ b/.github/actions/install-convox/action.yml @@ -0,0 +1,28 @@ +name: Install Convox CLI +description: Install a pinned, checksum-verified Convox CLI (linux amd64) into /usr/local/bin. + +inputs: + version: + description: Convox CLI release version + default: "3.25.7" + sha256: + description: SHA-256 of the convox-linux asset for that version + default: 6a0ffe6faf269302c311c2f8e4d1cdc116902c933c7d91f461c47d8a25190759 + +runs: + using: composite + steps: + - name: Install Convox CLI + shell: bash + env: + CONVOX_VERSION: ${{ inputs.version }} + CONVOX_SHA256: ${{ inputs.sha256 }} + run: | + set -euo pipefail + tmp="$(mktemp -d)" + curl -fsSL -o "${tmp}/convox" \ + "https://github.com/convox/convox/releases/download/${CONVOX_VERSION}/convox-linux" + echo "${CONVOX_SHA256} ${tmp}/convox" | sha256sum --check --strict + sudo install -m 0755 "${tmp}/convox" /usr/local/bin/convox + rm -rf "${tmp}" + convox version || true diff --git a/.github/actions/install-task/action.yml b/.github/actions/install-task/action.yml new file mode 100644 index 00000000..47868220 --- /dev/null +++ b/.github/actions/install-task/action.yml @@ -0,0 +1,29 @@ +name: Install Task +description: Install a pinned, checksum-verified Task (taskfile.dev) binary into /usr/local/bin. + +inputs: + version: + description: Task release version + default: "3.53.1" + sha256: + description: SHA-256 of task_linux_amd64.tar.gz for that version (from task_checksums.txt) + default: a54a408f6861ff921f6e87774180db31bacd8c1e7c944ca696db9fea49a82fc7 + +runs: + using: composite + steps: + - name: Install Task + shell: bash + env: + TASK_VERSION: ${{ inputs.version }} + TASK_SHA256: ${{ inputs.sha256 }} + run: | + set -euo pipefail + tmp="$(mktemp -d)" + curl -fsSL -o "${tmp}/task.tar.gz" \ + "https://github.com/go-task/task/releases/download/v${TASK_VERSION}/task_linux_amd64.tar.gz" + echo "${TASK_SHA256} ${tmp}/task.tar.gz" | sha256sum --check --strict + tar -xzf "${tmp}/task.tar.gz" -C "${tmp}" task + sudo install -m 0755 "${tmp}/task" /usr/local/bin/task + rm -rf "${tmp}" + task --version diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..4dcc6101 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,43 @@ +version: 2 + +updates: + - package-ecosystem: gomod + directory: / + schedule: + interval: weekly + ignore: + # Replaced by the local modules in internal/shims (see go.mod replace directives) + - dependency-name: github.com/docker/docker + - dependency-name: github.com/moby/buildkit + groups: + go-minor-patch: + update-types: [minor, patch] + + - package-ecosystem: bun + directories: + - /web + - /docs + - /mock-oauth + schedule: + interval: weekly + groups: + bun-minor-patch: + update-types: [minor, patch] + + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + actions-minor-patch: + update-types: [minor, patch] + + - package-ecosystem: docker + directories: + - / + - /mock-oauth + schedule: + interval: weekly + groups: + docker-minor-patch: + update-types: [minor, patch] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 557e4917..59195aac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [main] +permissions: + contents: read + jobs: go-tests: runs-on: ubuntu-latest @@ -14,10 +17,10 @@ jobs: TEST_DATABASE_URL: postgres://postgres:postgres@localhost:55432/gateway_test?sslmode=disable GOLANGCI_LINT_VERSION: v2.11.1 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: go-version: "1.26.9" @@ -27,25 +30,13 @@ jobs: sudo apt-get install -y libfido2-dev libudev-dev pkg-config - name: Install Task - run: | - curl -sL https://taskfile.dev/install.sh | sh -s -- -b /usr/local/bin - task --version + uses: ./.github/actions/install-task - name: Go deps run: task go:deps - name: Install Convox CLI - run: | - set -euo pipefail - ARCH=$(uname -m) - URL="https://github.com/convox/convox/releases/latest/download/convox-linux" - if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then - URL="https://github.com/convox/convox/releases/latest/download/convox-linux-arm64" - fi - curl -fsSL "$URL" -o /tmp/convox - sudo mv /tmp/convox /usr/local/bin/convox - sudo chmod 755 /usr/local/bin/convox - convox version || true + uses: ./.github/actions/install-convox - name: Install Go tools run: task go:tools @@ -58,15 +49,15 @@ jobs: env: GOLANGCI_LINT_VERSION: v2.11.1 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: go-version: "1.26.9" - name: Cache golangci-lint cache - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/.cache/golangci-lint @@ -78,24 +69,15 @@ jobs: sudo apt-get install -y libfido2-dev libudev-dev pkg-config - name: Install Task - run: | - curl -sL https://taskfile.dev/install.sh | sh -s -- -b /usr/local/bin - task --version - - - name: Install golangci-lint - run: | - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh \ - | sudo sh -s -- -b /usr/local/bin "${GOLANGCI_LINT_VERSION}" - golangci-lint version + uses: ./.github/actions/install-task - name: Go deps (lint warmup) run: task go:deps - - name: Verify golangci-lint config - run: task go:lint:config - + # The action installs the pinned golangci-lint release and verifies .golangci.yml + # against its JSON schema (verify: true) before linting. - name: golangci-lint - uses: golangci/golangci-lint-action@v8 + uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 with: version: ${{ env.GOLANGCI_LINT_VERSION }} env: @@ -121,14 +103,25 @@ jobs: run: task shellcheck - name: Install govulncheck - run: go install golang.org/x/vuln/cmd/govulncheck@latest + run: go install golang.org/x/vuln/cmd/govulncheck@v1.8.0 - name: Check for vulnerabilities run: task go:sec:vuln - name: Install TruffleHog + env: + TRUFFLEHOG_VERSION: "3.97.9" + TRUFFLEHOG_SHA256: 40377e6572495412fb9ba0bc21c9401f73b72f1d2afd11b9931bc4a5ed622866 run: | - curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b /usr/local/bin + set -euo pipefail + tmp="$(mktemp -d)" + curl -fsSL -o "${tmp}/trufflehog.tar.gz" \ + "https://github.com/trufflesecurity/trufflehog/releases/download/v${TRUFFLEHOG_VERSION}/trufflehog_${TRUFFLEHOG_VERSION}_linux_amd64.tar.gz" + echo "${TRUFFLEHOG_SHA256} ${tmp}/trufflehog.tar.gz" | sha256sum --check --strict + tar -xzf "${tmp}/trufflehog.tar.gz" -C "${tmp}" trufflehog + sudo install -m 0755 "${tmp}/trufflehog" /usr/local/bin/trufflehog + rm -rf "${tmp}" + trufflehog --version - name: Scan for secrets run: task go:sec:secrets @@ -136,15 +129,15 @@ jobs: web-tests: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: "20" - name: Setup Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: "1.3.1" @@ -154,9 +147,7 @@ jobs: bun install --frozen-lockfile - name: Install Task - run: | - curl -sL https://taskfile.dev/install.sh | sh -s -- -b /usr/local/bin - task --version + uses: ./.github/actions/install-task - name: Web lint (Typecheck, Biome, and knip) run: task web:lint @@ -170,17 +161,15 @@ jobs: mock-oauth-tests: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Setup Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: "1.3.1" - name: Install Task - run: | - curl -sL https://taskfile.dev/install.sh | sh -s -- -b /usr/local/bin - task --version + uses: ./.github/actions/install-task - name: Mock OAuth lint (Typecheck and Biome) run: task mock-oauth:lint diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 540e6968..f36da583 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -6,11 +6,8 @@ on: paths: ["docs/**"] workflow_dispatch: -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read - pages: write - id-token: write # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. @@ -23,32 +20,38 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Setup Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 + with: + bun-version: "1.3.1" - name: Install dependencies - run: cd docs && bun install + run: cd docs && bun install --frozen-lockfile - name: Build docs run: cd docs && bun run build - name: Setup Pages - uses: actions/configure-pages@v5 + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 - name: Upload artifact - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1 with: path: docs/dist deploy: needs: build runs-on: ubuntu-latest + # Only the deploy job may publish to GitHub Pages + permissions: + pages: write + id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index e1912131..fbad9928 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -5,6 +5,9 @@ on: branches: [main] pull_request: +permissions: + contents: read + jobs: build-image: runs-on: ubuntu-latest @@ -12,13 +15,13 @@ jobs: GATEWAY_IMAGE: rack-gateway-api:e2e-${{ github.sha }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Build gateway image (with web UI) and export - uses: docker/build-push-action@v6 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . file: Dockerfile @@ -31,7 +34,7 @@ jobs: outputs: type=docker,dest=${{ runner.temp }}/gateway-api.tar - name: Upload image artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: gateway-image path: ${{ runner.temp }}/gateway-api.tar @@ -54,12 +57,10 @@ jobs: CGO_ENABLED: 1 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Install Task - run: | - curl -sL https://taskfile.dev/install.sh | sh -s -- -b /usr/local/bin - task --version + uses: ./.github/actions/install-task - name: Install libfido2 dependencies run: | @@ -67,24 +68,24 @@ jobs: sudo apt-get install -y libfido2-dev libudev-dev pkg-config - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: "20" - name: Setup Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: "1.3.1" - name: Download gateway image - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: gateway-image path: ${{ runner.temp }} - name: Load gateway image run: | - docker load --input ${{ runner.temp }}/gateway-api.tar + docker load --input "${RUNNER_TEMP}/gateway-api.tar" docker image ls -a | grep rack-gateway-api || true - name: Build mock services @@ -108,8 +109,8 @@ jobs: run: | set -x docker compose ps - curl -sv http://127.0.0.1:${GATEWAY_PORT}/api/v1/health || true - curl -sv http://127.0.0.1:${GATEWAY_PORT}/app/login -o /dev/null || true + curl -sv "http://127.0.0.1:${GATEWAY_PORT}/api/v1/health" || true + curl -sv "http://127.0.0.1:${GATEWAY_PORT}/app/login" -o /dev/null || true - name: Install Playwright and deps working-directory: web @@ -142,12 +143,10 @@ jobs: CGO_ENABLED: 1 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Install Task - run: | - curl -sL https://taskfile.dev/install.sh | sh -s -- -b /usr/local/bin - task --version + uses: ./.github/actions/install-task - name: Install libfido2 dependencies run: | @@ -155,19 +154,19 @@ jobs: sudo apt-get install -y libfido2-dev libudev-dev pkg-config - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: go-version: "1.26.9" - name: Download gateway image - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: gateway-image path: ${{ runner.temp }} - name: Load gateway image run: | - docker load --input ${{ runner.temp }}/gateway-api.tar + docker load --input "${RUNNER_TEMP}/gateway-api.tar" docker image ls -a | grep rack-gateway-api || true - name: Build mock services @@ -187,17 +186,7 @@ jobs: GATEWAY_PORT=9447 WEB_PORT=9447 MOCK_OAUTH_PORT=9345 CHECK_VITE_PROXY=false ./scripts/wait-for-services.sh - name: Install Convox CLI - run: | - set -euo pipefail - ARCH=$(uname -m) - URL="https://github.com/convox/convox/releases/latest/download/convox-linux" - if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then - URL="https://github.com/convox/convox/releases/latest/download/convox-linux-arm64" - fi - curl -fsSL "$URL" -o /tmp/convox - sudo mv /tmp/convox /usr/local/bin/convox - sudo chmod 755 /usr/local/bin/convox - convox version || true + uses: ./.github/actions/install-convox - name: Run CLI E2E run: GATEWAY_PORT=9447 MOCK_OAUTH_PORT=9345 MOCK_CONVOX_PORT=6443 E2E_DATABASE_NAME=gateway_test E2E_GATEWAY_SERVICE=gateway-api-test ./scripts/cli-e2e.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a5d7f30b..210c1566 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,177 +1,230 @@ name: Release +# Releases are built only from v* tags. A repository ruleset restricts creating, +# moving and deleting v* tags to repository admins. on: push: tags: - v* - workflow_dispatch: {} -permissions: - contents: write - checks: read +# Each job declares the minimum permissions it needs. +permissions: {} jobs: - docker_build: + verify_tag: runs-on: ubuntu-latest + permissions: + contents: read + checks: read # wait-for-checks.js reads check runs for the tagged commit + outputs: + version: ${{ steps.version.outputs.version }} + tag: ${{ steps.version.outputs.tag }} + short_sha: ${{ steps.version.outputs.short_sha }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 with: - fetch-depth: 0 - fetch-tags: true - - uses: actions/github-script@v7 + persist-credentials: false + + - name: Validate tag and version + id: version + env: + TAG: ${{ github.ref_name }} + COMMIT: ${{ github.sha }} + run: | + set -euo pipefail + if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then + echo "Error: invalid tag '$TAG' (expected vMAJOR.MINOR.PATCH[-PRERELEASE])" >&2 + exit 1 + fi + VERSION="${TAG#v}" + PACKAGE_VERSION="$(jq -r '.version' web/package.json)" + if [ "$VERSION" != "$PACKAGE_VERSION" ]; then + echo "Error: tag $TAG does not match web/package.json version $PACKAGE_VERSION" >&2 + exit 1 + fi + { + echo "version=$VERSION" + echo "tag=$TAG" + echo "short_sha=${COMMIT:0:7}" + } >> "$GITHUB_OUTPUT" + + - name: Wait for CI and E2E checks on the tagged commit + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 with: script: | const script = require('./.github/wait-for-checks.js'); await script({ github, context, core }); + docker_build: + runs-on: ubuntu-latest + needs: verify_tag + permissions: + contents: read + id-token: write # sign the build provenance attestation + attestations: write + outputs: + digest: ${{ steps.build.outputs.digest }} + env: + IMAGE: docker.io/docspringcom/rack-gateway + VERSION: ${{ needs.verify_tag.outputs.version }} + SHORT_SHA: ${{ needs.verify_tag.outputs.short_sha }} + steps: + - name: Checkout repository + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false + - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Log in to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_TOKEN }} - - name: Extract version info - run: | - if [ "${{ github.event_name }}" = "push" ]; then - TAG="${GITHUB_REF#refs/tags/}" - echo "VERSION=${TAG#v}" >> "$GITHUB_ENV" - echo "GIT_TAG=${TAG}" >> "$GITHUB_ENV" - else - TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "latest") - echo "VERSION=${TAG#v}" >> "$GITHUB_ENV" - echo "GIT_TAG=${TAG}" >> "$GITHUB_ENV" - fi - echo "COMMIT_SHA=$(git rev-parse --short HEAD)" >> "$GITHUB_ENV" - + # No build cache: release images are built from scratch so a cache written by + # another workflow run can't influence what gets published. - name: Build and push Docker image - uses: docker/build-push-action@v6 + id: build + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . platforms: linux/amd64 push: true + no-cache: true build-args: | COMMIT_SHA=${{ github.sha }} tags: | - docker.io/docspringcom/rack-gateway:${{ env.COMMIT_SHA }} - docker.io/docspringcom/rack-gateway:latest - cache-from: type=gha - cache-to: type=gha,mode=max + ${{ env.IMAGE }}:v${{ env.VERSION }} + ${{ env.IMAGE }}:${{ env.SHORT_SHA }} + ${{ env.IMAGE }}:latest + + - name: Attest image build provenance + uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3.2.0 + with: + subject-name: index.docker.io/docspringcom/rack-gateway + subject-digest: ${{ steps.build.outputs.digest }} + push-to-registry: true release_build: runs-on: ubuntu-latest + needs: verify_tag + permissions: + contents: read + id-token: write # sign the build provenance attestation + attestations: write + env: + VERSION: ${{ needs.verify_tag.outputs.version }} steps: - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - fetch-tags: true - - uses: actions/github-script@v7 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 with: - script: | - const script = require('./.github/wait-for-checks.js'); - await script({ github, context, core }); + persist-credentials: false + + # cache: false so modules restored from another workflow's cache can't end up in the release binary - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: go-version: "1.26.9" + cache: false + - name: Build binary env: CGO_ENABLED: 0 GOOS: linux GOARCH: amd64 + GOFLAGS: -mod=readonly run: | - set -e + set -euo pipefail + BUILD_TIME="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" go build \ -tags nofido \ -buildvcs=false \ - -ldflags "-s -w" \ + -trimpath \ + -ldflags "-s -w -X main.version=${VERSION} -X main.buildTime=${BUILD_TIME}" \ -o rack-gateway-linux-amd64 \ ./cmd/rack-gateway/ - - name: Create archive + ./rack-gateway-linux-amd64 version | grep -F "client: ${VERSION}" + + - name: Create archive and checksum run: | - set -e - tar czf rack-gateway-linux-amd64.tar.gz rack-gateway-linux-amd64 - echo "ASSET_PATH=rack-gateway-linux-amd64.tar.gz" >> "$GITHUB_ENV" - - uses: actions/upload-artifact@v4 + set -euo pipefail + mkdir -p dist + tar czf dist/rack-gateway-linux-amd64.tar.gz rack-gateway-linux-amd64 + (cd dist && sha256sum rack-gateway-linux-amd64.tar.gz > rack-gateway-linux-amd64.tar.gz.sha256) + + - name: Attest binary build provenance + uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3.2.0 + with: + subject-path: dist/rack-gateway-linux-amd64.tar.gz + + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: - path: ${{ env.ASSET_PATH }} name: rack-gateway-linux-amd64 + path: dist/ release_create: runs-on: ubuntu-latest needs: + - verify_tag + - docker_build - release_build + permissions: + contents: write # create the GitHub release + env: + RELEASE_TAG: ${{ needs.verify_tag.outputs.tag }} + RELEASE_VERSION: ${{ needs.verify_tag.outputs.version }} + REPOSITORY: ${{ github.repository }} + IMAGE_DIGEST: ${{ needs.docker_build.outputs.digest }} steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - fetch-tags: true - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: rack-gateway-linux-amd64 - path: artifacts/rack-gateway-linux-amd64 - - run: | - if [ "${{ github.event_name }}" = "push" ]; then - TAG="${GITHUB_REF#refs/tags/}" - if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+ ]]; then - echo "Error: Invalid tag format $TAG (expected v*.*.* semver)" >&2 - exit 1 - fi - echo "RELEASE_TAG=$TAG" >> "$GITHUB_ENV" - VERSION="${TAG#v}" - echo "RELEASE_VERSION=$VERSION" >> "$GITHUB_ENV" - else - # For workflow_dispatch, use latest tag - TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") - if [ -z "$TAG" ]; then - echo "Error: No tags found. Cannot create release without a tag." >&2 - exit 1 - fi - echo "RELEASE_TAG=$TAG" >> "$GITHUB_ENV" - VERSION="${TAG#v}" - echo "RELEASE_VERSION=$VERSION" >> "$GITHUB_ENV" - fi - - name: Generate checksums + path: dist + + - name: Verify checksum run: | - set -e - cd artifacts - for dir in */; do - cd "$dir" - for file in *; do - case "$file" in - *.tar.gz|*.zip) - if [ -f "$file" ]; then - sha256sum "$file" > "${file}.sha256" || shasum -a 256 "$file" | awk '{print $1}' > "${file}.sha256" - fi - ;; - esac - done - cd .. - done - cd .. + set -euo pipefail + cd dist + sha256sum --check --strict rack-gateway-linux-amd64.tar.gz.sha256 + - name: Generate changelog run: | - cat > changelog.md < changelog.md + + - uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 with: files: | - artifacts/**/*.tar.gz - artifacts/**/*.sha256 + dist/rack-gateway-linux-amd64.tar.gz + dist/rack-gateway-linux-amd64.tar.gz.sha256 prerelease: ${{ contains(env.RELEASE_TAG, '-') }} body_path: changelog.md name: rack-gateway v${{ env.RELEASE_VERSION }} draft: false tag_name: ${{ env.RELEASE_TAG }} + fail_on_unmatched_files: true diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml new file mode 100644 index 00000000..82d6e165 --- /dev/null +++ b/.github/workflows/security-scan.yml @@ -0,0 +1,68 @@ +name: Security Scan + +# Daily scan so newly disclosed vulnerabilities show up even when nobody pushes. +# GitHub emails the workflow's last editor when a scheduled run fails. +on: + schedule: + - cron: "17 18 * * *" # daily, 06:17 NZST + workflow_dispatch: {} + +permissions: + contents: read + +jobs: + govulncheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false + + - name: Setup Go + uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 + with: + go-version: "1.26.9" + cache: false + + - name: Install libfido2 dependencies + run: | + sudo apt-get update + sudo apt-get install -y libfido2-dev libudev-dev pkg-config + + - name: Install govulncheck + run: go install golang.org/x/vuln/cmd/govulncheck@v1.8.0 + + - name: Check Go vulnerabilities + run: govulncheck ./... + + web-audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + persist-credentials: false + + - name: Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 + with: + bun-version: "1.3.1" + + - name: Install web packages + working-directory: web + run: bun install --frozen-lockfile + + - name: Audit web dependencies (high and critical) + working-directory: web + run: bun audit --audit-level=high + + image-scan: + runs-on: ubuntu-latest + steps: + - name: Scan the published gateway image + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 + with: + version: v0.74.0 + image-ref: docker.io/docspringcom/rack-gateway:latest + severity: HIGH,CRITICAL + ignore-unfixed: true + exit-code: "1" diff --git a/CLAUDE.md b/CLAUDE.md index 819c2153..59573aa1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -525,59 +525,48 @@ See [docs/CONFIGURATION.md](docs/CONFIGURATION.md) for complete environment vari ## Version Management and Deployment -**IMPORTANT: Deploying to production requires a new Docker image, which is only built when you push a git tag.** +**IMPORTANT: Deploying to production requires a new Docker image, which is only built when you push a `v*` git tag.** -There is no way to deploy code changes without: -1. Creating a version tag (e.g., `v0.0.19`) -2. Pushing the tag to trigger the GitHub Actions release workflow -3. Waiting for the Docker image to build and push +**Single Source of Truth**: The project version is stored in `web/package.json`. `scripts/bump-version.sh` also pins +both `convox.yml` services to the matching immutable image tag (`docker.io/docspringcom/rack-gateway:vX.Y.Z`), so a +deploy never uses the mutable `:latest` tag. -**Single Source of Truth**: The project version is stored in `web/package.json`. +**Who can release:** a repository ruleset only lets repo admins create, move or delete `v*` tags, and `main` requires +a PR with green CI (admins can bypass). The Release workflow only runs on `v*` tags; it has no manual trigger. **Releasing a new version:** -1. Bump the version in `web/package.json`: +1. Bump the version (updates `web/package.json`, `web/bun.lock` and the image tag in `convox.yml`): ```bash ./scripts/bump-version.sh patch # or minor, major ``` -2. Commit the version bump: +2. Commit and push the version bump: ```bash git commit -am "chore: bump version to vX.Y.Z" - ``` - -3. Push the commit to main: - ```bash git push origin main ``` -4. Create and push a git tag to trigger the release: +3. Create and push the release tag (admins only): ```bash ./scripts/create-release-tags.sh - git push --tags + git push origin vX.Y.Z ``` -The GitHub Actions release workflow (`.github/workflows/release.yml`) is triggered by `v*` tags and: -- Builds the Docker image for linux/amd64 -- Pushes to `docker.io/docspringcom/rack-gateway` with both version tag and `latest` tags -- Creates a GitHub release with binaries and checksums - -**Deployment to Convox:** +The Release workflow (`.github/workflows/release.yml`): +- Checks the tag matches `web/package.json` and waits for CI + E2E to pass on the tagged commit +- Builds the Docker image without any build cache and pushes `:vX.Y.Z`, `:` and `:latest` +- Builds the CLI (`rack-gateway version` reports the release version) with checksums +- Publishes signed build provenance attestations for the image and the CLI archive +- Creates a GitHub release with the CLI archive and checksum -After the release workflow completes successfully: -1. The `convox.yml` uses `image: docker.io/docspringcom/rack-gateway:latest` (or a specific version tag) -2. Run `convox deploy` to deploy the new image to the rack +**Deployment to Convox:** once the Release workflow has published `:vX.Y.Z`, run `convox deploy` from the repo root. +`convox.yml` already points at that tag. -**Quick Release Workflow:** +**Verifying a release:** ```bash -# After your changes are merged to main: -./scripts/bump-version.sh patch -git commit -am "chore: bump version to v0.0.19" -git push origin main -./scripts/create-release-tags.sh -git push --tags -# Wait for GitHub Actions to complete, then deploy -convox deploy +gh attestation verify oci://docker.io/docspringcom/rack-gateway:vX.Y.Z --repo DocSpring/rack-gateway +gh attestation verify rack-gateway-linux-amd64.tar.gz --repo DocSpring/rack-gateway ``` ## Code Structure diff --git a/Dockerfile b/Dockerfile index efe2d0d5..01fad852 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -FROM oven/bun:1.3.2-alpine AS webbuild +FROM oven/bun:1.3.2-alpine@sha256:adda30fd4db7d8ef9a2113cb935c6f751de3daad39373713b56eefe49db78471 AS webbuild ARG COMMIT_SHA RUN test -n "$COMMIT_SHA" || (echo "COMMIT_SHA build arg is required" && exit 1) @@ -15,7 +15,7 @@ RUN bun install --frozen-lockfile COPY web/ ./ RUN bun run build -FROM golang:1.26.9-alpine AS builder +FROM golang:1.26.9-alpine@sha256:cdfd4fe2da6b225d8b40c6b7a105736e548e83ff56d5d8f9394446eeb5eb84e0 AS builder RUN apk add --no-cache git ca-certificates make gcc musl-dev nodejs npm @@ -33,24 +33,30 @@ COPY web/package.json ./web/package.json COPY internal ./internal COPY cmd/gateway ./cmd/gateway -# Build the gateway binary with version info -ARG COMMIT_HASH=unknown +# Build the gateway binary with version info (COMMIT_SHA is the same build arg the web stage requires) +ARG COMMIT_SHA +RUN test -n "$COMMIT_SHA" || (echo "COMMIT_SHA build arg is required" && exit 1) RUN VERSION=$(node -p "require('./web/package.json').version") && \ CGO_ENABLED=0 go build \ - -ldflags "-X github.com/DocSpring/rack-gateway/internal/gateway/version.Version=${VERSION} -X github.com/DocSpring/rack-gateway/internal/gateway/version.CommitHash=${COMMIT_HASH}" \ + -ldflags "-X github.com/DocSpring/rack-gateway/internal/gateway/version.Version=${VERSION} -X github.com/DocSpring/rack-gateway/internal/gateway/version.CommitHash=${COMMIT_SHA}" \ -o /out/rack-gateway-api ./cmd/gateway \ && /out/rack-gateway-api help -FROM alpine:latest +FROM alpine:3.24.2@sha256:294b683cb724975bec92580e1e685676bd4b50bda910ddb8c51d4cabeaec77e6 -RUN apk --no-cache add ca-certificates curl +# ca-certificates for outbound TLS. No curl: the compose healthcheck uses busybox wget. +RUN apk --no-cache add ca-certificates \ + && addgroup -S -g 10001 gateway \ + && adduser -S -D -H -u 10001 -G gateway -s /sbin/nologin gateway WORKDIR /app +# Files stay root-owned and read-only to the runtime user. COPY --from=builder /out/rack-gateway-api ./ COPY --from=webbuild /app/web/dist ./web/dist -COPY scripts/start-gateway.sh ./scripts/start-gateway.sh -RUN chmod +x ./scripts/start-gateway.sh +COPY --chmod=0755 scripts/start-gateway.sh ./scripts/start-gateway.sh + +USER 10001:10001 EXPOSE 8080 diff --git a/Dockerfile.gateway-dev b/Dockerfile.gateway-dev index 963b6a02..db7737a2 100644 --- a/Dockerfile.gateway-dev +++ b/Dockerfile.gateway-dev @@ -1,4 +1,4 @@ -FROM golang:1.26.9-alpine AS builder +FROM golang:1.26.9-alpine@sha256:cdfd4fe2da6b225d8b40c6b7a105736e548e83ff56d5d8f9394446eeb5eb84e0 AS builder RUN apk add --no-cache git ca-certificates make gcc musl-dev @@ -21,9 +21,9 @@ RUN --mount=type=cache,target=/go/pkg/mod,sharing=locked \ CGO_ENABLED=0 go build -o /out/rack-gateway-api ./cmd/gateway \ && /out/rack-gateway-api help -FROM alpine:latest +FROM alpine:3.24.2@sha256:294b683cb724975bec92580e1e685676bd4b50bda910ddb8c51d4cabeaec77e6 -RUN apk --no-cache add ca-certificates curl +RUN apk --no-cache add ca-certificates WORKDIR /root/ diff --git a/Dockerfile.mock-convox b/Dockerfile.mock-convox index 0831c183..27d79607 100644 --- a/Dockerfile.mock-convox +++ b/Dockerfile.mock-convox @@ -1,7 +1,7 @@ # Build stage # syntax=docker/dockerfile:1.5 -FROM golang:1.26.9-alpine AS builder +FROM golang:1.26.9-alpine@sha256:cdfd4fe2da6b225d8b40c6b7a105736e548e83ff56d5d8f9394446eeb5eb84e0 AS builder RUN apk add --no-cache git make @@ -25,7 +25,7 @@ RUN --mount=type=cache,target=/go/pkg/mod,sharing=locked \ && /out/mock-convox help # Final stage -FROM alpine:latest +FROM alpine:3.24.2@sha256:294b683cb724975bec92580e1e685676bd4b50bda910ddb8c51d4cabeaec77e6 RUN apk --no-cache add ca-certificates diff --git a/README.md b/README.md index 71d139d8..67ec9292 100644 --- a/README.md +++ b/README.md @@ -458,32 +458,38 @@ If your support needs are more complex, please consider using the official Convo To create a new release: ```bash -# 1. Bump the version +# 1. Bump the version (also pins convox.yml to docker.io/docspringcom/rack-gateway:v1.0.1) ./scripts/bump-version.sh patch # or minor, major -# 2. Commit the version bump +# 2. Commit and push the version bump git commit -am "chore: bump version to v1.0.1" +git push origin main -# 3. Create and push the release tag +# 3. Create and push the release tag (only repository admins can push v* tags) ./scripts/create-release-tags.sh -git push origin v1.0.1 # or: git push --tags +git push origin v1.0.1 ``` -The GitHub Actions release workflow automatically: +The GitHub Actions release workflow (triggered only by `v*` tags): -- Builds the Docker image for linux/amd64 -- Pushes to `docker.io/docspringcom/rack-gateway` with commit SHA and `latest` tags -- Creates a GitHub release with binaries and checksums +- Checks the tag matches `web/package.json` and waits for CI and E2E to pass on the tagged commit +- Builds the Docker image for linux/amd64 without a build cache +- Pushes `docker.io/docspringcom/rack-gateway` with the version (`v1.0.1`), short commit SHA and `latest` tags +- Publishes signed build provenance attestations for the image and the CLI archive +- Creates a GitHub release with the CLI archive and its checksum -After the release completes, update your deployment: +After the release completes, deploy. `convox.yml` already references the new version tag: ```bash -# Update convox.yml to use the new image tag -# image: docker.io/docspringcom/rack-gateway:${COMMIT_SHA} - convox deploy ``` +Verify what you deployed: + +```bash +gh attestation verify oci://docker.io/docspringcom/rack-gateway:v1.0.1 --repo DocSpring/rack-gateway +``` + ## Deployment See [DEPLOY.md](./docs/DEPLOY.md) for a production-ready deployment guide, environment configuration, persistence, and a minimal `convox.yml` example. diff --git a/convox.yml b/convox.yml index 42101bf3..70e69f2d 100644 --- a/convox.yml +++ b/convox.yml @@ -28,9 +28,10 @@ environment: services: gateway: - # To deploy: Build locally and push to Docker Hub using scripts/build-and-push.sh - # Then update the image tag below to the new version - image: docker.io/docspringcom/rack-gateway:latest + # Pinned to an immutable release tag. scripts/bump-version.sh sets it to the new + # version (:vX.Y.Z); the release workflow publishes that tag when the v* git tag is pushed. + # :e327add is the v0.1.1 release (identical to :latest when this was pinned). + image: docker.io/docspringcom/rack-gateway:e327add command: ./scripts/start-gateway.sh environment: - PORT=8080 @@ -51,8 +52,8 @@ services: - eks.amazonaws.com/role-arn: "${IAM_ROLE_ARN}" admin: - # Uses same image as gateway service - image: docker.io/docspringcom/rack-gateway:latest + # Uses same image as gateway service (kept in sync by scripts/bump-version.sh) + image: docker.io/docspringcom/rack-gateway:e327add command: echo "Use this service to run migrations, database admin tasks, etc." environment: - PORT=8080 diff --git a/docker-compose.yml b/docker-compose.yml index f8d32e9a..d67f8958 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,7 +18,7 @@ x-gateway-env: &gateway_common_env x-gateway-health: &gateway_healthcheck test: - ["CMD-SHELL", "curl -fsS http://localhost:$$PORT/api/v1/health || exit 1"] + ["CMD-SHELL", "wget -q -O /dev/null http://localhost:$$PORT/api/v1/health || exit 1"] interval: 2s timeout: 5s retries: 3 diff --git a/docs/legacy/DEPLOY.md b/docs/legacy/DEPLOY.md index 2427514a..4e1462f6 100644 --- a/docs/legacy/DEPLOY.md +++ b/docs/legacy/DEPLOY.md @@ -2,6 +2,11 @@ Deploy the gateway and UI using the `convox.yml` in this repo — no separate manifest needed. +> `convox.yml` deploys a released image pinned to an immutable version tag +> (`docker.io/docspringcom/rack-gateway:vX.Y.Z`). `scripts/bump-version.sh` updates that tag, and the Release +> workflow publishes it when a repository admin pushes the matching `v*` git tag. Verify a release with +> `gh attestation verify oci://docker.io/docspringcom/rack-gateway:vX.Y.Z --repo DocSpring/rack-gateway`. + ## Prerequisites - Convox CLI, authenticated against your rack (e.g., `staging`) diff --git a/docs/src/content/docs/deployment/docker.mdx b/docs/src/content/docs/deployment/docker.mdx index bd2a229c..4f8c9790 100644 --- a/docs/src/content/docs/deployment/docker.mdx +++ b/docs/src/content/docs/deployment/docker.mdx @@ -19,8 +19,18 @@ docker pull docker.io/docspringcom/rack-gateway:latest | Tag | Description | |-----|-------------| -| `latest` | Most recent release | -| `v0.x.x` | Specific version (recommended for production) | +| `v0.x.x` | Specific release (use this in production) | +| `` | The commit a release was built from | +| `latest` | Most recent release (mutable, avoid in production) | + +### Verifying an Image + +Every release image has a signed build provenance attestation generated by GitHub Actions. Verify it before +deploying: + +```bash +gh attestation verify oci://docker.io/docspringcom/rack-gateway:v0.x.x --repo DocSpring/rack-gateway +``` ## Quick Start diff --git a/mock-oauth/Dockerfile b/mock-oauth/Dockerfile index 0f56aa66..7076e3fa 100644 --- a/mock-oauth/Dockerfile +++ b/mock-oauth/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1.6 -FROM oven/bun:1-alpine AS base +FROM oven/bun:1.3.2-alpine@sha256:adda30fd4db7d8ef9a2113cb935c6f751de3daad39373713b56eefe49db78471 AS base RUN apk add --no-cache curl diff --git a/scripts/build-and-push.sh b/scripts/build-and-push.sh deleted file mode 100755 index 46c59371..00000000 --- a/scripts/build-and-push.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -set -e - -# Docker Hub image name -IMAGE_NAME="docker.io/docspringcom/rack-gateway" - -# Get commit SHA from git -COMMIT_SHA=$(git rev-parse --short HEAD) - -echo "Building rack-gateway for Docker Hub..." -echo "Image: ${IMAGE_NAME}" -echo "Commit: ${COMMIT_SHA}" - -# Build for amd64 (linux/amd64) -# Use DOCKER_DEFAULT_PLATFORM to ensure amd64 build -DOCKER_DEFAULT_PLATFORM=linux/amd64 docker build \ - --tag "${IMAGE_NAME}:${COMMIT_SHA}" \ - --tag "${IMAGE_NAME}:latest" \ - . - -echo "" -echo "Build complete! Images tagged:" -echo " - ${IMAGE_NAME}:${COMMIT_SHA}" -echo " - ${IMAGE_NAME}:latest" - -echo "" -echo "Pushing to Docker Hub..." -docker push "${IMAGE_NAME}:${COMMIT_SHA}" -docker push "${IMAGE_NAME}:latest" - -echo "" -echo "Push complete!" -echo "" -echo "To deploy, update convox.yml to use: image: ${IMAGE_NAME}:${COMMIT_SHA}" -echo "Then run: convox deploy" diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh index 802fb8d6..0bdd3b25 100755 --- a/scripts/bump-version.sh +++ b/scripts/bump-version.sh @@ -67,6 +67,22 @@ update_version() { echo -e "${GREEN}✓ Version updated to v${new_version}${NC}" } +# Function to pin convox.yml to the new release image tag +update_convox_image() { + local new_version=$1 + echo -e "${BLUE}Pinning convox.yml images to v${new_version}...${NC}" + + sed -E -i.bak "s#(image: docker\.io/docspringcom/rack-gateway:)[^[:space:]]+#\1v${new_version}#" convox.yml + rm -f convox.yml.bak + + if ! grep -q "image: docker.io/docspringcom/rack-gateway:v${new_version}" convox.yml; then + echo -e "${RED}Error: failed to update the image tag in convox.yml${NC}" + exit 1 + fi + + echo -e "${GREEN}✓ convox.yml now deploys docker.io/docspringcom/rack-gateway:v${new_version}${NC}" +} + # Check arguments if [ $# -ne 1 ]; then usage @@ -86,6 +102,7 @@ new_version=$(bump_version "$current_version" "$BUMP_TYPE") echo -e "${YELLOW}Version: ${current_version} -> ${new_version}${NC}" update_version "$new_version" +update_convox_image "$new_version" echo "" echo -e "${GREEN}Version bump complete!${NC}" @@ -93,5 +110,6 @@ echo "" echo "Next steps:" echo "1. Review the changes: git diff" echo "2. Commit: git commit -am \"chore: bump version to v${new_version}\"" -echo "3. Create release tag: ./scripts/create-release-tags.sh" -echo "4. Push: git push && git push --tags" +echo "3. Create release tag: ./scripts/create-release-tags.sh (v* tags can only be pushed by repo admins)" +echo "4. Push: git push && git push origin v${new_version}" +echo "5. After the Release workflow publishes docker.io/docspringcom/rack-gateway:v${new_version}, run: convox deploy" diff --git a/scripts/install.sh b/scripts/install.sh index 27c9e502..0dfc3db3 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -81,7 +81,7 @@ go mod download # Embed version and build time into the binary VERSION="$(git describe --tags --always --dirty=-modified 2>/dev/null || echo dev)" BUILDTIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" -LDFLAGS="-s -w -X main.Version=${VERSION} -X main.BuildTime=${BUILDTIME}" +LDFLAGS="-s -w -X main.version=${VERSION} -X main.buildTime=${BUILDTIME}" echo "Building CLI (version: $VERSION)..." GOFLAGS="${GOFLAGS:-}" diff --git a/taskfiles/Taskfile.go.yml b/taskfiles/Taskfile.go.yml index 453bb310..c7f83178 100644 --- a/taskfiles/Taskfile.go.yml +++ b/taskfiles/Taskfile.go.yml @@ -12,13 +12,13 @@ tasks: - go mod tidy tools: - desc: Install Go tooling + desc: Install Go tooling (pinned versions; bump deliberately) cmds: - - go install honnef.co/go/tools/cmd/staticcheck@latest - - go install gotest.tools/gotestsum@latest - - go install github.com/tkrajina/typescriptify-golang-structs/tscriptify@latest - - go install golang.org/x/tools/cmd/goimports@latest - - go install mvdan.cc/gofumpt@latest + - go install honnef.co/go/tools/cmd/staticcheck@v0.8.1 + - go install gotest.tools/gotestsum@v1.13.0 + - go install github.com/tkrajina/typescriptify-golang-structs/tscriptify@v0.2.0 + - go install golang.org/x/tools/cmd/goimports@v0.50.0 + - go install mvdan.cc/gofumpt@v0.12.0 install: aliases: [":install"] @@ -113,10 +113,14 @@ tasks: - Taskfile.go.yml - cmd/rack-gateway/**/*.go - internal/**/*.go + - web/package.json generates: - bin/rack-gateway + vars: + VERSION: + sh: node -p "require('./web/package.json').version" cmds: - - go build -buildvcs=false -ldflags "-X main.Version=1.0.0 -X main.BuildTime=$(date -u '+%Y-%m-%d_%H:%M:%S')" -o bin/rack-gateway ./cmd/rack-gateway/ + - go build -buildvcs=false -ldflags "-X main.version={{.VERSION}} -X main.buildTime=$(date -u '+%Y-%m-%dT%H:%M:%SZ')" -o bin/rack-gateway ./cmd/rack-gateway/ build:cli:nofido: desc: Build gateway CLI without libfido2 support (for CI) -> bin/rack-gateway-nofido @@ -128,10 +132,14 @@ tasks: - Taskfile.go.yml - cmd/rack-gateway/**/*.go - internal/**/*.go + - web/package.json generates: - bin/rack-gateway-nofido + vars: + VERSION: + sh: node -p "require('./web/package.json').version" cmds: - - go build -tags nofido -buildvcs=false -ldflags "-X main.Version=1.0.0 -X main.BuildTime=$(date -u '+%Y-%m-%d_%H:%M:%S')" -o bin/rack-gateway-nofido ./cmd/rack-gateway/ + - go build -tags nofido -buildvcs=false -ldflags "-X main.version={{.VERSION}} -X main.buildTime=$(date -u '+%Y-%m-%dT%H:%M:%SZ')" -o bin/rack-gateway-nofido ./cmd/rack-gateway/ build:mock: desc: Build mock Convox server -> bin/mock-convox @@ -244,7 +252,7 @@ tasks: sec:secrets: desc: Scan for secrets with TruffleHog cmds: - - trufflehog git file://. --results verified --fail + - trufflehog git file://. --results verified --fail --no-update mod:tidy: desc: Tidy go modules