diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0e9a8283..3a9e12f1 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,47 +5,67 @@ updates: schedule: interval: daily open-pull-requests-limit: 10 + cooldown: + default-days: 7 - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" + cooldown: + default-days: 7 - package-ecosystem: mix directory: "/apps/api_accounts" schedule: interval: daily open-pull-requests-limit: 10 + cooldown: + default-days: 7 - package-ecosystem: mix directory: "/apps/api_web" schedule: interval: daily open-pull-requests-limit: 10 + cooldown: + default-days: 7 - package-ecosystem: mix directory: "/apps/events" schedule: interval: daily open-pull-requests-limit: 10 + cooldown: + default-days: 7 - package-ecosystem: mix directory: "/apps/fetch" schedule: interval: daily open-pull-requests-limit: 10 + cooldown: + default-days: 7 - package-ecosystem: mix directory: "/apps/health" schedule: interval: daily open-pull-requests-limit: 10 + cooldown: + default-days: 7 - package-ecosystem: mix directory: "/apps/model" schedule: interval: daily open-pull-requests-limit: 10 + cooldown: + default-days: 7 - package-ecosystem: mix directory: "/apps/state" schedule: interval: daily open-pull-requests-limit: 10 + cooldown: + default-days: 7 - package-ecosystem: mix directory: "/apps/state_mediator" schedule: interval: daily open-pull-requests-limit: 10 + cooldown: + default-days: 7 diff --git a/.github/workflows/asana.yml b/.github/workflows/asana.yml index a5c77656..5824c764 100644 --- a/.github/workflows/asana.yml +++ b/.github/workflows/asana.yml @@ -2,13 +2,25 @@ name: Asana integration for GitHub PRs on: workflow_dispatch: pull_request: - types: [review_requested, closed, opened, reopened, converted_to_draft, edited, ready_for_review] + types: + [ + review_requested, + closed, + opened, + reopened, + converted_to_draft, + edited, + ready_for_review, + ] pull_request_review: types: [submitted] +permissions: + pull-requests: read # Needed to read Asana ticket info from PR description + jobs: call-workflow: - uses: mbta/workflows/.github/workflows/asana.yml@main + uses: mbta/workflows/.github/workflows/asana.yml@c76e5ccd9556fbea52bc41548f7ceed5985ad775 # v5.1.0 with: development-section: "In Development" review-section: "Pending Review" diff --git a/.github/workflows/deploy-dev-blue.yml b/.github/workflows/deploy-dev-blue.yml index 01c7be61..8fa18c78 100644 --- a/.github/workflows/deploy-dev-blue.yml +++ b/.github/workflows/deploy-dev-blue.yml @@ -2,16 +2,22 @@ name: Deploy to Dev-blue (ECS) on: schedule: - - cron: '0 5 * * *' + - cron: "0 5 * * *" workflow_dispatch: +permissions: {} + +concurrency: + group: deploy-dev-blue + cancel-in-progress: true + jobs: deploy: name: Deploy runs-on: ubuntu-latest permissions: - id-token: write - contents: read + id-token: write # Needed to communicate with AWS + contents: read # Needed to check out code environment: dev-blue concurrency: dev-blue if: github.repository_owner == 'mbta' @@ -20,20 +26,22 @@ jobs: ECS_SERVICE: api-dev-blue steps: - - uses: actions/checkout@v2 - - uses: mbta/actions/build-push-ecr@v2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + - uses: mbta/actions/build-push-ecr@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 id: build-push with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} docker-repo: ${{ secrets.DOCKER_REPO }} docker-additional-tags: dev-blue - - uses: mbta/actions/deploy-ecs@v2 + - uses: mbta/actions/deploy-ecs@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} ecs-cluster: ${{ env.ECS_CLUSTER }} ecs-service: ${{ env.ECS_SERVICE }} docker-tag: ${{ steps.build-push.outputs.docker-tag }} - - uses: mbta/actions/notify-slack-deploy@v1 + - uses: mbta/actions/notify-slack-deploy@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 if: ${{ !cancelled() }} with: webhook-url: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/deploy-dev-green.yml b/.github/workflows/deploy-dev-green.yml index 346bc026..60ae27cf 100644 --- a/.github/workflows/deploy-dev-green.yml +++ b/.github/workflows/deploy-dev-green.yml @@ -2,13 +2,19 @@ name: Deploy to Dev-green (ECS) on: workflow_dispatch +permissions: {} + +concurrency: + group: deploy-dev-green + cancel-in-progress: true + jobs: deploy: name: Deploy runs-on: ubuntu-latest permissions: - id-token: write - contents: read + id-token: write # Needed to communicate with AWS + contents: read # Needed to check out code environment: dev-green concurrency: dev-green env: @@ -16,20 +22,22 @@ jobs: ECS_SERVICE: api-dev-green steps: - - uses: actions/checkout@v2 - - uses: mbta/actions/build-push-ecr@v2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + - uses: mbta/actions/build-push-ecr@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 id: build-push with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} docker-repo: ${{ secrets.DOCKER_REPO }} docker-additional-tags: dev-green - - uses: mbta/actions/deploy-ecs@v2 + - uses: mbta/actions/deploy-ecs@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} ecs-cluster: ${{ env.ECS_CLUSTER }} ecs-service: ${{ env.ECS_SERVICE }} docker-tag: ${{ steps.build-push.outputs.docker-tag }} - - uses: mbta/actions/notify-slack-deploy@v1 + - uses: mbta/actions/notify-slack-deploy@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 if: ${{ !cancelled() }} with: webhook-url: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index 4a915c5f..808b2342 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -5,13 +5,19 @@ on: push: branches: [master] +permissions: {} + +concurrency: + group: deploy-dev + cancel-in-progress: true + jobs: deploy: name: Deploy runs-on: ubuntu-latest permissions: - id-token: write - contents: read + id-token: write # Needed to communicate with AWS + contents: read # Needed to check out code environment: dev concurrency: dev env: @@ -19,20 +25,22 @@ jobs: ECS_SERVICE: api-dev steps: - - uses: actions/checkout@v2 - - uses: mbta/actions/build-push-ecr@v2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + - uses: mbta/actions/build-push-ecr@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 id: build-push with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} docker-repo: ${{ secrets.DOCKER_REPO }} docker-additional-tags: dev - - uses: mbta/actions/deploy-ecs@v2 + - uses: mbta/actions/deploy-ecs@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} ecs-cluster: ${{ env.ECS_CLUSTER }} ecs-service: ${{ env.ECS_SERVICE }} docker-tag: ${{ steps.build-push.outputs.docker-tag }} - - uses: mbta/actions/notify-slack-deploy@v1 + - uses: mbta/actions/notify-slack-deploy@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 if: ${{ !cancelled() }} with: webhook-url: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index ce84a262..deb1351f 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -2,13 +2,19 @@ name: Deploy to Prod (ECS) on: workflow_dispatch +permissions: {} + +concurrency: + group: deploy-prod + cancel-in-progress: true + jobs: deploy: name: Deploy runs-on: ubuntu-latest permissions: - id-token: write - contents: read + id-token: write # Needed to communicate with AWS + contents: read # Needed to check out code environment: prod concurrency: prod env: @@ -16,21 +22,23 @@ jobs: ECS_SERVICE: api-prod steps: - - uses: actions/checkout@v2 - - uses: mbta/actions/build-push-ecr@v2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + - uses: mbta/actions/build-push-ecr@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 id: build-push with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} docker-repo: ${{ secrets.DOCKER_REPO }} docker-additional-tags: prod - name: Deploy to ECS - uses: mbta/actions/deploy-ecs@v2 + uses: mbta/actions/deploy-ecs@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} ecs-cluster: ${{ env.ECS_CLUSTER }} ecs-service: ${{ env.ECS_SERVICE }} docker-tag: ${{ steps.build-push.outputs.docker-tag }} - - uses: mbta/actions/notify-slack-deploy@v1 + - uses: mbta/actions/notify-slack-deploy@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 if: ${{ !cancelled() }} with: webhook-url: ${{ secrets.SLACK_WEBHOOK }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index b9aef6ec..eafd8057 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -2,10 +2,20 @@ name: Docker on: [push] +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: docker: name: Build Docker image runs-on: ubuntu-22.04 + permissions: + contents: read # Needed to check out code steps: - - uses: actions/checkout@v3 - - run: docker build . + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + - run: docker build . diff --git a/.github/workflows/elixir.yml b/.github/workflows/elixir.yml index b8c5f409..59dd5aec 100644 --- a/.github/workflows/elixir.yml +++ b/.github/workflows/elixir.yml @@ -8,6 +8,9 @@ on: pull_request: workflow_dispatch: +permissions: + contents: read # Needed to check out code + concurrency: group: ci-${{ github.ref }} cancel-in-progress: true @@ -17,16 +20,18 @@ jobs: name: ASDF runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false # Cache the ASDF directory, using the values from .tool-versions. - name: ASDF cache - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.asdf key: ${{ runner.os }}-asdf-v3-${{ hashFiles('.tool-versions') }} id: asdf-cache # Only run `asdf install` if we didn't hit the cache. - - uses: asdf-vm/actions/install@b7bcd026f18772e44fe1026d729e1611cc435d47 # a.k.a. @4.0.1 + - uses: asdf-vm/actions/install@b7bcd026f18772e44fe1026d729e1611cc435d47 # v4.0.1 if: steps.asdf-cache.outputs.cache-hit != 'true' - run: | mix local.rebar --force @@ -39,20 +44,22 @@ jobs: needs: asdf steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: Restore dependencies cache id: deps-cache - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: deps key: ${{ runner.os }}-mix-v2-${{ hashFiles('**/mix.lock') }} - name: ASDF cache - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.asdf key: ${{ runner.os }}-asdf-v3-${{ hashFiles('.tool-versions') }} if: steps.deps-cache.outputs.cache-hit != 'true' - - uses: mbta/actions/reshim-asdf@v1 + - uses: mbta/actions/reshim-asdf@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 if: steps.deps-cache.outputs.cache-hit != 'true' - name: Install dependencies run: mix deps.get @@ -64,21 +71,23 @@ jobs: needs: deps steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: ASDF cache - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.asdf key: ${{ runner.os }}-asdf-v3-${{ hashFiles('.tool-versions') }} - - uses: mbta/actions/reshim-asdf@v1 + - uses: mbta/actions/reshim-asdf@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 - name: Restore dependencies cache id: deps-cache - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: deps key: ${{ runner.os }}-mix-v2-${{ hashFiles('**/mix.lock') }} - name: Restore dev build cache - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: _build/dev key: ${{ runner.os }}-mix-dev-${{ hashFiles('**/mix.lock') }} @@ -110,20 +119,22 @@ jobs: needs: deps steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: ASDF cache - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.asdf key: ${{ runner.os }}-asdf-v3-${{ hashFiles('.tool-versions') }} - - uses: mbta/actions/reshim-asdf@v1 + - uses: mbta/actions/reshim-asdf@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 - name: Restore dependencies cache id: deps-cache - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: deps key: ${{ runner.os }}-mix-v2-${{ hashFiles('**/mix.lock') }} - - uses: mbta/actions/dialyzer@v2 + - uses: mbta/actions/dialyzer@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 test: name: Test Tasks @@ -132,11 +143,11 @@ jobs: services: dynamodb: - image: amazon/dynamodb-local:2.0.0 + image: amazon/dynamodb-local@sha256:c8702bde709520b90930c20ee430d4123cd731da8e544cc4ccae0e2a78ee4fce # 2.0.0 ports: - 8000:8000 mosquitto: - image: eclipse-mosquitto:2.0 + image: eclipse-mosquitto@sha256:212f89e1eaeb2c322d6441b64396e3346026674db8fa9c27beac293405c32b3c # 2.0.22 ports: - 1883:1883 volumes: @@ -144,23 +155,25 @@ jobs: options: --name mqtt steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false - name: Restart MQTT to load mosquitto/mosquitto.conf from checkout run: docker restart mqtt - name: ASDF cache - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.asdf key: ${{ runner.os }}-asdf-v3-${{ hashFiles('.tool-versions') }} - - uses: mbta/actions/reshim-asdf@v1 + - uses: mbta/actions/reshim-asdf@62db3e5c547c3c7f439c4a7fb98e69fc79c1a9cc # v2.21 - name: Restore dependencies cache id: deps-cache - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: deps key: ${{ runner.os }}-mix-v2-${{ hashFiles('**/mix.lock') }} - name: Restore test build cache - uses: actions/cache@v6 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: _build/test key: ${{ runner.os }}-mix-test-${{ hashFiles('**/mix.lock') }} @@ -172,11 +185,28 @@ jobs: - name: Save PR information run: | mkdir -p cover - echo "${{ github.event.pull_request.number }}" > cover/PR_NUMBER - echo "${{ github.event.pull_request.head.sha }}" > cover/PR_SHA + echo "${PR_NUMBER}" > cover/PR_NUMBER + echo "${PR_SHA}" > cover/PR_SHA + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + PR_SHA: ${{ github.event.pull_request.head.sha }} if: github.event.pull_request - name: Upload coverage artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: elixir-lcov path: cover/ + + zizmor: + name: Run zizmor 🌈 + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + - name: Run zizmor 🌈 + uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7 + with: + persona: pedantic + advanced-security: false diff --git a/.github/workflows/report-coverage.yml b/.github/workflows/report-coverage.yml deleted file mode 100644 index 37981f1d..00000000 --- a/.github/workflows/report-coverage.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Report Elixir Coverage - -on: - workflow_run: - workflows: - - Elixir CI - types: - - completed - -permissions: - pull-requests: write - -jobs: - report-coverage: - if: ${{ github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' }} - runs-on: ubuntu-latest - - steps: - - run: mkdir -p ${{ runner.temp }}/cover - - run: echo Fetching artifacts for ${{ github.event.workflow_run.id }}, event name ${{ github.event_name }}, triggered by ${{ github.event.workflow_run.event }} - - name: Download artifact - uses: actions/github-script@v3.1.0 - with: - script: | - var artifacts = await github.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: ${{github.event.workflow_run.id }}, - }); - var matchArtifact = artifacts.data.artifacts.filter((artifact) => { - return artifact.name == "elixir-lcov" - })[0]; - var download = await github.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: matchArtifact.id, - archive_format: 'zip', - }); - var fs = require('fs'); - fs.writeFileSync('${{ runner.temp }}/cover/elixir-lcov.zip', Buffer.from(download.data)); - - working-directory: ${{ runner.temp }}/cover - run: | - unzip elixir-lcov.zip - echo "PR_SHA=$(cat PR_SHA)" >> $GITHUB_ENV - echo "PR_NUMBER=$(cat PR_NUMBER)" >> $GITHUB_ENV - - uses: actions/checkout@v2 # UNTRUSTED CODE - do not run scripts from it - with: - ref: ${{ env.PR_SHA }} - - name: Upload coverage artifact and post comment - uses: mbta/github-actions-report-lcov@v1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - coverage-files: ${{ runner.temp }}/cover/lcov*.info - artifact-name: elixir-code-coverage