feat: add security scanning on CI workflow #385
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: CI | |
on: | |
pull_request: | |
permissions: | |
contents: read | |
jobs: | |
orchestrator: | |
name: Orchestrator | |
runs-on: ubuntu-latest | |
outputs: | |
# Docs | |
should-build-docs: ${{ steps.changed-website-files.outputs.any_changed == 'true' || null }} | |
# App | |
should-build-app: ${{ steps.changed-api-files.outputs.any_changed == 'true' || steps.changed-selfserve-files.outputs.any_changed == 'true' || steps.changed-internal-files.outputs.any_changed == 'true' || null }} | |
should-build-api: ${{ steps.changed-api-files.outputs.any_changed == 'true' || null }} | |
should-build-selfserve: ${{ steps.changed-selfserve-files.outputs.any_changed == 'true' || null }} | |
should-build-internal: ${{ steps.changed-internal-files.outputs.any_changed == 'true' || null }} | |
# Assets | |
should-build-assets: ${{ steps.changed-assets-files.outputs.any_changed == 'true' || null }} | |
# Docker | |
should-build-docker: ${{ steps.changed-api-docker-files.outputs.any_changed == 'true' || steps.changed-selfserve-docker-files.outputs.any_changed == 'true' || steps.changed-internal-docker-files.outputs.any_changed == 'true' || null }} | |
should-build-api-docker: ${{ steps.changed-api-docker-files.outputs.any_changed == 'true' || steps.changed-api-files.outputs.any_changed == 'true' || null }} | |
should-build-selfserve-docker: ${{ steps.changed-selfserve-docker-files.outputs.any_changed == 'true' || steps.changed-selfserve-files.outputs.any_changed == 'true' || null }} | |
should-build-internal-docker: ${{ steps.changed-internal-docker-files.outputs.any_changed == 'true' || steps.changed-internal-files.outputs.any_changed == 'true' || null }} | |
# Terraform accounts | |
should-plan-terraform-accounts: ${{ steps.changed-accounts-terraform-files.outputs.any_changed == 'true' || null }} | |
should-plan-nonprod-account-terraform: ${{ contains(steps.changed-accounts-terraform-files.outputs.all_changed_files, 'infra/terraform/modules') || contains(steps.changed-accounts-terraform-files.outputs.all_changed_files, 'infra/terraform/accounts/nonprod') || null }} | |
should-plan-prod-account-terraform: ${{ contains(steps.changed-accounts-terraform-files.outputs.all_changed_files, 'infra/terraform/modules') || contains(steps.changed-accounts-terraform-files.outputs.all_changed_files, 'infra/terraform/accounts/prod') || null }} | |
# Terraform environments | |
should-plan-terraform-environments: ${{ steps.changed-environments-terraform-files.outputs.any_changed == 'true' || null }} | |
should-plan-dev-environment-terraform: ${{ contains(steps.changed-environments-terraform-files.outputs.all_changed_files, 'infra/terraform/modules') || contains(steps.changed-environments-terraform-files.outputs.all_changed_files, 'infra/terraform/environments/dev') || null }} | |
should-plan-int-environment-terraform: ${{ contains(steps.changed-environments-terraform-files.outputs.all_changed_files, 'infra/terraform/modules') || contains(steps.changed-environments-terraform-files.outputs.all_changed_files, 'infra/terraform/environments/int') || null }} | |
should-plan-prep-environment-terraform: ${{ contains(steps.changed-environments-terraform-files.outputs.all_changed_files, 'infra/terraform/modules') || contains(steps.changed-environments-terraform-files.outputs.all_changed_files, 'infra/terraform/environments/prep') || null }} | |
should-plan-prod-environment-terraform: ${{ contains(steps.changed-environments-terraform-files.outputs.all_changed_files, 'infra/terraform/modules') || contains(steps.changed-environments-terraform-files.outputs.all_changed_files, 'infra/terraform/environments/prod') || null }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- uses: tj-actions/changed-files@v44 | |
id: changed-api-files | |
with: | |
files: | | |
app/api/** | |
# since_last_remote_commit: true | |
- uses: tj-actions/changed-files@v44 | |
id: changed-selfserve-files | |
with: | |
files: | | |
app/selfserve/** | |
# since_last_remote_commit: true | |
- uses: tj-actions/changed-files@v44 | |
id: changed-internal-files | |
with: | |
files: | | |
app/internal/** | |
- uses: tj-actions/changed-files@v44 | |
id: changed-assets-files | |
with: | |
files: | | |
app/cdn/** | |
# since_last_remote_commit: true | |
- uses: tj-actions/changed-files@v44 | |
id: changed-api-docker-files | |
with: | |
files: | | |
infra/docker/api/** | |
# since_last_remote_commit: true | |
- uses: tj-actions/changed-files@v44 | |
id: changed-selfserve-docker-files | |
with: | |
files: | | |
infra/docker/selfserve/** | |
# since_last_remote_commit: true | |
- uses: tj-actions/changed-files@v44 | |
id: changed-internal-docker-files | |
with: | |
files: | | |
infra/docker/internal/** | |
# since_last_remote_commit: true | |
- uses: tj-actions/changed-files@v44 | |
id: changed-accounts-terraform-files | |
with: | |
files: | | |
infra/terraform/accounts/** | |
infra/terraform/modules/** | |
files_ignore: | | |
infra/terraform/modules/service/** | |
# since_last_remote_commit: true | |
- uses: tj-actions/changed-files@v44 | |
id: changed-environments-terraform-files | |
with: | |
files: | | |
infra/terraform/environments/{dev,int,prep,prod}/** | |
infra/terraform/modules/** | |
files_ignore: | | |
infra/terraform/modules/account/** | |
infra/terraform/modules/github/** | |
infra/terraform/modules/remote-state/** | |
# since_last_remote_commit: true | |
- uses: tj-actions/changed-files@v44 | |
id: changed-website-files | |
with: | |
files: | | |
website/** | |
docs/** | |
since_last_remote_commit: true | |
docs: | |
name: Documentation | |
if: ${{ needs.orchestrator.outputs.should-build-docs }} | |
needs: | |
- orchestrator | |
uses: ./.github/workflows/deploy-documentation.yaml | |
with: | |
deploy: false | |
permissions: | |
contents: read | |
pages: write | |
id-token: write | |
get-version: | |
name: Get latest app versions | |
if: ${{ needs.orchestrator.outputs.should-build-assets || needs.orchestrator.outputs.should-build-app || needs.orchestrator.outputs.should-build-docker || needs.orchestrator.outputs.should-plan-terraform-environments }} | |
needs: | |
- orchestrator | |
runs-on: ubuntu-latest | |
outputs: | |
api: ${{ steps.api-version.outputs.version }} | |
selfserve: ${{ steps.selfserve-version.outputs.version }} | |
internal: ${{ steps.internal-version.outputs.version }} | |
assets: ${{ steps.assets-version.outputs.version }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
ref: ${{ github.event.pull_request.head.sha }} | |
fetch-depth: 0 | |
- id: api-version | |
uses: ./.github/actions/get-app-version | |
with: | |
project-path: app/api infra/docker/api | |
- id: selfserve-version | |
uses: ./.github/actions/get-app-version | |
with: | |
project-path: app/selfserve infra/docker/selfserve | |
- id: internal-version | |
uses: ./.github/actions/get-app-version | |
with: | |
project-path: app/internal infra/docker/internal | |
- id: assets-version | |
uses: ./.github/actions/get-app-version | |
with: | |
project-path: app/cdn | |
- name: Add to summary | |
run: | | |
echo "#### App versions:" >> $GITHUB_STEP_SUMMARY | |
echo "**API**: \`${{ steps.api-version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY | |
echo "**Selfserve**: \`${{ steps.selfserve-version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY | |
echo "**Internal**: \`${{ steps.internal-version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY | |
echo "**Assets**: \`${{ steps.assets-version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY | |
cdn: | |
name: CDN | |
if: ${{ needs.orchestrator.outputs.should-build-assets }} | |
needs: | |
- orchestrator | |
- get-version | |
uses: ./.github/workflows/assets.yaml | |
with: | |
version: ${{ needs.get-version.outputs.assets }} | |
permissions: | |
contents: read | |
id-token: write | |
app: | |
name: App | |
if: ${{ needs.orchestrator.outputs.should-build-app || needs.orchestrator.outputs.should-build-docker }} | |
concurrency: | |
group: app-${{ matrix.project }}-${{ needs.get-version.outputs[matrix.project] }} | |
needs: | |
- orchestrator | |
- get-version | |
strategy: | |
fail-fast: false | |
matrix: | |
project: | |
- api | |
- selfserve | |
- internal | |
exclude: | |
- project: ${{ (needs.orchestrator.outputs.should-build-api || needs.orchestrator.outputs.should-build-api-docker) && 'ignored' || 'api' }} | |
- project: ${{ (needs.orchestrator.outputs.should-build-selfserve || needs.orchestrator.outputs.should-build-selfserve-docker) && 'ignored' || 'selfserve' }} | |
- project: ${{ (needs.orchestrator.outputs.should-build-internal || needs.orchestrator.outputs.should-build-internal-docker) && 'ignored' || 'internal' }} | |
uses: ./.github/workflows/php.yaml | |
with: | |
project: ${{ matrix.project }} | |
should-upload-artefact: ${{ !!needs.orchestrator.outputs[format('should-build-{0}-docker', matrix.project)] }} | |
artefact-name: ${{ matrix.project}} | |
retention-days: 1 | |
permissions: | |
contents: read | |
secrets: inherit | |
docker: | |
name: Docker | |
if: ${{ always() && !cancelled() && !failure() && needs.orchestrator.outputs.should-build-docker }} | |
concurrency: | |
group: docker-${{ matrix.project }}-${{ needs.get-version.outputs[matrix.project] }} | |
needs: | |
- orchestrator | |
- get-version | |
- app | |
strategy: | |
fail-fast: false | |
matrix: | |
project: | |
- api | |
- selfserve | |
- internal | |
exclude: | |
- project: ${{ needs.orchestrator.outputs.should-build-api-docker && 'ignored' || 'api' }} | |
- project: ${{ needs.orchestrator.outputs.should-build-selfserve-docker && 'ignored' || 'selfserve' }} | |
- project: ${{ needs.orchestrator.outputs.should-build-internal-docker && 'ignored' || 'internal' }} | |
uses: ./.github/workflows/docker.yaml | |
with: | |
project: ${{ matrix.project }} | |
version: ${{ needs.get-version.outputs[matrix.project] }} | |
app-artefact-name: ${{ matrix.project}} | |
push: false | |
permissions: | |
contents: read | |
id-token: write | |
terraform-lint: | |
name: Lint Terraform | |
if: ${{ needs.orchestrator.outputs.should-plan-terraform-accounts || needs.orchestrator.outputs.should-plan-terraform-environments }} | |
needs: | |
- orchestrator | |
runs-on: ubuntu-latest | |
defaults: | |
run: | |
working-directory: infra/terraform | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
sparse-checkout: infra/terraform | |
- run: terraform fmt -check -no-color -recursive | |
- uses: actions/cache@v4 | |
name: Cache plugin dir | |
with: | |
path: ~/.tflint.d/plugins | |
key: tflint-${{ hashFiles('infra/terraform/.tflint.hcl') }} | |
- uses: terraform-linters/setup-tflint@v4 | |
- run: tflint --init --recursive --config=$(realpath .tflint.hcl) | |
- run: tflint --recursive --config=$(realpath .tflint.hcl) -f compact | |
terraform-account: | |
name: Terraform Account | |
if: ${{ needs.orchestrator.outputs.should-plan-terraform-accounts }} | |
concurrency: | |
group: terraform-account-${{ matrix.account }} | |
needs: | |
- orchestrator | |
strategy: | |
fail-fast: false | |
matrix: | |
account: | |
- nonprod | |
#- prod | |
exclude: | |
- account: ${{ needs.orchestrator.outputs.should-plan-nonprod-account-terraform && 'ignored' || 'nonprod' }} | |
- account: ${{ needs.orchestrator.outputs.should-plan-prod-account-terraform && 'ignored' || 'prod' }} | |
uses: ./.github/workflows/deploy-account.yaml | |
with: | |
account: ${{ matrix.account }} | |
permissions: | |
contents: read | |
id-token: write | |
pull-requests: write | |
secrets: inherit | |
terraform-env: | |
name: Terraform Environment | |
if: ${{ needs.orchestrator.outputs.should-plan-terraform-environments }} | |
concurrency: | |
group: terraform-environment-${{ matrix.environment }} | |
needs: | |
- get-version | |
- orchestrator | |
strategy: | |
fail-fast: false | |
matrix: | |
environment: | |
- dev | |
- int | |
#- prep | |
#- prod | |
exclude: | |
- environment: ${{ needs.orchestrator.outputs.should-plan-dev-environment-terraform && 'ignored' || 'dev' }} | |
- environment: ${{ needs.orchestrator.outputs.should-plan-int-environment-terraform && 'ignored' || 'int' }} | |
- environment: ${{ needs.orchestrator.outputs.should-plan-prep-environment-terraform && 'ignored' || 'prep' }} | |
- environment: ${{ needs.orchestrator.outputs.should-plan-prod-environment-terraform && 'ignored' || 'prod' }} | |
uses: ./.github/workflows/deploy-environment.yaml | |
with: | |
environment: ${{ matrix.environment }} | |
api-image-tag: ${{ needs.get-version.outputs.api }} | |
selfserve-image-tag: ${{ needs.get-version.outputs.selfserve }} | |
internal-image-tag: ${{ needs.get-version.outputs.internal }} | |
assets-version: ${{ needs.get-version.outputs.assets }} | |
permissions: | |
contents: read | |
id-token: write | |
pull-requests: write | |
secrets: inherit | |
security: | |
name: security | |
needs: | |
- app | |
- orchestrator | |
strategy: | |
matrix: | |
project: | |
- api | |
- selfserve | |
- internal | |
exclude: | |
- project: ${{ (needs.orchestrator.outputs.should-build-api || needs.orchestrator.outputs.should-build-api-docker) && 'ignored' || 'api' }} | |
- project: ${{ (needs.orchestrator.outputs.should-build-selfserve || needs.orchestrator.outputs.should-build-selfserve-docker) && 'ignored' || 'selfserve' }} | |
- project: ${{ (needs.orchestrator.outputs.should-build-internal || needs.orchestrator.outputs.should-build-internal-docker) && 'ignored' || 'internal' }} | |
uses: ./.github/workflows/security.yaml | |
with: | |
project: ${{ matrix.project }} | |
permissions: | |
contents: read | |
secrets: inherit |