Continuous Integration Secure #737
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: Continuous Integration Secure | |
# Secure execution of continuous integration jobs | |
# which are performed upon completion of the | |
# "Continuous Integration" workflow | |
# https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ | |
on: | |
workflow_run: | |
workflows: ['Continuous Integration'] | |
types: [completed] | |
permissions: | |
deployments: write | |
packages: write | |
pull-requests: write | |
jobs: | |
preview-image: | |
runs-on: ubuntu-latest | |
if: > | |
github.event.workflow_run.conclusion == 'success' && ( | |
github.event.workflow_run.event == 'pull_request' || ( | |
github.event.workflow_run.event == 'push' && | |
github.event.workflow_run.head_branch == 'main' | |
) | |
) | |
env: | |
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0] != null && github.event.workflow_run.pull_requests[0].number || '' }} | |
IMAGE_REPO: ghcr.io/${{ github.repository }}-preview | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/download-artifact@v4 | |
with: | |
name: build | |
path: dist/netzgrafik-frontend/ | |
run-id: ${{ github.event.workflow_run.id }} | |
# TODO: Create GH_ACTIONS_ARTIFACT_DOWNLOAD secret | |
github-token: ${{ secrets.GH_ACTIONS_ARTIFACT_DOWNLOAD }} | |
- name: Remove files without allowed extensions | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
const fs = require('fs'), | |
path = require('path'), | |
allowedExtensions = | |
/^\.(s?css|html?|m?js|json|ts|map|ico|jpe?g|png|svg|woff2|txt|gitignore|gitkeep|stackblitzrc)$/, | |
distDir = path.resolve('dist/netzgrafik-frontend'); | |
// Removes all files not matching allowed extensions from given directory. | |
fs.readdirSync(distDir, { withFileTypes: true, recursive: true }) | |
.filter((d) => d.isFile() && !allowedExtensions.test(path.extname(d.name))) | |
.forEach((d) => { | |
console.log(`Removing ${path.join(d.path, d.name)}`); | |
fs.unlinkSync(path.join(d.path, d.name)); | |
}); | |
- name: Create GitHub Deployment | |
id: tag-name | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
const environment = process.env.PR_NUMBER ? `pr${process.env.PR_NUMBER}` : 'main'; | |
const payload = { owner: context.repo.owner, repo: context.repo.repo, environment }; | |
const { data: deployment } = await github.rest.repos.createDeployment({ | |
...payload, | |
ref: context.payload.workflow_run.head_sha, | |
auto_merge: false, | |
required_contexts: ['integrity', 'build', 'test', 'lint'] | |
}); | |
await github.rest.repos.createDeploymentStatus({ | |
...payload, | |
deployment_id: deployment.id, | |
state: 'in_progress', | |
environment_url: `https://${context.repo.repo}-${environment}.app.sbb.ch`, | |
}); | |
return environment; | |
result-encoding: string | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Login to GitHub Container Repository | |
uses: docker/login-action@v3 | |
with: | |
registry: ghcr.io | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Build and push | |
uses: docker/build-push-action@v5 | |
with: | |
push: true | |
tags: $IMAGE_REPO:${{ steps.tag-name.outputs.result }} | |
- name: "Add 'preview-available' label" | |
if: env.PR_NUMBER != '' | |
# This label is used for filtering deployments in ArgoCD | |
run: gh issue edit "$NUMBER" --add-label "preview-available" | |
env: | |
NUMBER: ${{ env.PR_NUMBER }} |