Skip to content

Rename to make simple ci.yml #686

Rename to make simple ci.yml

Rename to make simple ci.yml #686

Workflow file for this run

---
name: CI
# Build and run tests in containers
# Store test and prod images to GitHub Container Registry (GHCR)
# Build prod image and push to AWS ECR
# Run tests and quality checks on test image
# Run security scans on code and prod images
# Run tasks in parallel
# Use GHA caching
on: push
# on:
# push:
# branches: [main]
# paths-ignore:
# - 'README.md'
# - '.github/**'
# - '.vscode'
# - '.gitignore'
# pull_request:
# # branches: [main]
# types: [opened,synchronize,reopened,labeled,unlabeled]
env:
IMAGE_NAME: foo-app
IMAGE_OWNER: ${{ github.repository_owner }}
# Tag for release images
# IMAGE_TAG: ${{ (github.ref == 'refs/heads/main' && 'staging') || (github.ref == 'refs/heads/qa' && 'qa') }}
IMAGE_TAG: latest
IMAGE_VER: ${{ github.sha }}
ELIXIR_VER: 1.14-3
OTP_VER: 25.2.3
BUILD_OS_VER: bullseye-20230202-slim
PROD_OS_VER: bullseye-slim
BASE_OS="debian"

Check failure on line 33 in .github/workflows/ci.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/ci.yml

Invalid workflow file

You have an error in your yaml syntax on line 33
# Variant if test matrix is not used
VAR: ${{ env.ELIXIR_VER }}-erlang-${{ env.OTP_VER }}-${{ env.BASE_OS }}-${{ matrix.build_os_ver }}
# Variant that is deployed
PROD_VAR: ${{ env.VAR }}
# Registry for test images
REGISTRY: ghcr.io/
# Registry for public images, default is docker.io
PUBLIC_REGISTRY: ""
# Give GitHub Actions access to AWS
AWS_ACCOUNT_ID: "770916339360"
AWS_ROLE_TO_ASSUME: arn:aws:iam::770916339360:role/foo-dev-ecr-github-action-role
AWS_REGION: ap-northeast-1
# Health check port for app
APP_PORT: 4000
# Datadog
# DD_API_KEY: ${{ secrets.ACTIONS_DD_API_KEY }}
# DD_ENV: ci
# DD_TAGS: "environment:ci"
# Docker
DOCKER_BUILDKIT: '1'
COMPOSE_DOCKER_CLI_BUILD: '1'
COMPOSE_FILE: docker-compose.gha.yml
DOCKER_FILE: deploy/debian.Dockerfile
TASKDEF=ecs/taskdef-otel.json
jobs:
build-test:
name: Build test image
runs-on: ubuntu-latest
permissions:
# Push to ghcr.io repository
packages: write
# Cancel previous runs
actions: write
steps:
- name: Dump event
run: cat "$GITHUB_EVENT_PATH"
- name: Cancel previous runs in progress
uses: styfle/[email protected]
with:
access_token: ${{ github.token }}
- name: Check out source
uses: actions/checkout@v3
- name: Set variables
run: |
echo "GITHUB_SHA_SHORT=$(echo $GITHUB_SHA | cut -c 1-7)" >> $GITHUB_ENV
echo "run_id=${GITHUB_RUN_ID}" >> $GITHUB_OUTPUT
echo "run_num=${GITHUB_RUN_NUMBER}" >> $GITHUB_OUTPUT
- name: Get branch name for main
if: github.event_name != 'pull_request'
run: echo "BRANCH=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV
- name: Get branch name for pull_request
if: github.event_name == 'pull_request'
run: echo "BRANCH=$(echo $GITHUB_HEAD_REF | tr '//\\' '.' | cut -c -55)" >> $GITHUB_ENV
- name: Log in to GHCR
uses: docker/login-action@v2
# https://github.com/marketplace/actions/docker-login
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Pull public images without rate limits
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# - name: Configure ssh keys
# uses: webfactory/[email protected]
# # Configure machine key or deploy keys to access private repos from build
# # https://github.com/marketplace/actions/webfactory-ssh-agent
# # https://docs.github.com/en/developers/overview/managing-deploy-keys#deploy-keys
# # ssh-keygen -t ed25519 -m pem -C "[email protected]:reachfh/api-utils.git" -f api-utils
# with:
# ssh-private-key: |
# ${{ secrets.SSH_PRIVATE_KEY }}
- name: Set env vars for builds
run: |
echo 'DATABASE_HOST=postgres' >> ./.env.test
# - name: Set up QEMU for multi-platform builds
# id: qemu
# uses: docker/setup-qemu-action@v2
# with:
# platforms: linux/amd64,linux/arm64
# - name: Display available platforms
# run: echo "${{ steps.qemu.outputs.platforms }}"
- name: Set up Docker buildx
id: buildx
uses: docker/setup-buildx-action@v2
with:
driver-opts: network=host
- name: Build test image and push to GHCR
uses: docker/build-push-action@v3
# https://github.com/docker/build-push-action
with:
file: ${{ env.DOCKER_FILE }}
target: test-image
build-args: |
ELIXIR_VER=${{ env.ELIXIR_VER }}
OTP_VER=${{ env.OTP_VER }}
BUILD_OS_VER=${{ env.BUILD_OS_VER }}
PROD_OS_VER=${{ env.PROD_OS_VER }}
context: .
builder: ${{ steps.buildx.outputs.name }}
push: true
# https://github.com/moby/buildkit#export-cache
cache-from: type=gha,scope=${{ github.workflow }}-test-${{ env.VAR }}
cache-to: type=gha,scope=${{ github.workflow }}-test-${{ env.VAR }},mode=max
# ssh: default
tags: |
ghcr.io/${{ env.IMAGE_OWNER }}/${{ env.IMAGE_NAME }}:test${{ env.VAR }}${{ env.IMAGE_VER }}
# secrets: |
# "access_token=${{ secrets.DEVOPS_ACCESS_TOKEN }}"
# "oban_key_fingerprint=${{ secrets.OBAN_KEY_FINGERPRINT }}"
# "oban_license_key=${{ secrets.OBAN_LICENSE_KEY }}"
test:
name: Run tests
runs-on: ubuntu-latest
# permissions: write-all
permissions:
# Read from ghcr.io repository
packages: read
# Upload JUnit report files
# https://github.com/EnricoMi/publish-unit-test-result-action#permissions
contents: read
checks: write
pull-requests: write
issues: read
needs: [build-test]
steps:
- name: Log in to GHCR
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Check out source
uses: actions/checkout@v3
- name: Pull repos
run: |
docker compose pull --quiet --include-deps test
docker images --no-trunc
- name: Start services
run: docker compose up --detach test
- name: Show docker logs
if: failure()
run: |
docker compose logs --timestamps postgres
docker compose logs --timestamps test
docker compose ps --format json | jq .
- name: Display health check results
if: failure()
run: |
echo postgres
docker inspect --format "{{json .State.Health }}" $(docker compose ps -q postgres) | jq
echo redis
docker inspect --format "{{json .State.Health }}" $(docker compose ps -q redis) | jq
- name: Debug env
if: failure()
run: |
docker compose run test env
# docker compose run test env PGPASSWORD=postgres /usr/bin/psql -w -h postgres -U postgres -d postgres -c "SELECT 1"
# docker compose run test env PGPASSWORD=postgres /usr/lib/postgresql/13/bin/pg_isready -h postgres -p 5432 -d postgres -U postgres
- name: Initialize test database
run: docker compose run test mix do ecto.create, ecto.migrate
- name: Run tests
# run: docker compose run test mix test --cover
# run: docker compose run test env MIX_TEST_PARTITION=${{ matrix.ci_node_index }} mix test --partitions ${{ matrix.ci_node_total }}
run: docker compose run test mix test
- name: Run quality checks
run: docker compose run test mix do format --check-formatted, deps.unlock --check-unused, credo --all, hex.audit, deps.audit, sobelow
- name: Publish unit test results to GitHub
uses: EnricoMi/publish-unit-test-result-action@v2
# Run even if tests fail
if: always()
with:
# Volume mounted from local filesystem into build by docker compose
junit_files: junit-reports/*.xml
# - name: Upload test results to Datadog
# if: always()
# continue-on-error: true
# run: |
# npm install -g @datadog/datadog-ci
# datadog-ci junit upload --service api-graphql junit-reports/
test-dialyzer:
name: Run dialyzer
runs-on: ubuntu-latest
needs: [build-test]
permissions:
# Read from ghcr.io repository
packages: read
# Upload JUnit report files
# https://github.com/EnricoMi/publish-unit-test-result-action#permissions
checks: write
pull-requests: write
issues: read
steps:
- name: Log in to GHCR
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Check out source
uses: actions/checkout@v3
- name: Pull repos
run: |
docker compose pull --quiet test
# docker images --no-trunc
- name: Run dialyzer
run: docker compose run test mix dialyzer --no-check --format github
test-scan:
name: Security scan code
runs-on: ubuntu-latest
needs: [build-test]
permissions:
# Read from ghcr.io repository
packages: read
# Upload JUnit report files
# https://github.com/EnricoMi/publish-unit-test-result-action#permissions
checks: write
pull-requests: write
issues: read
# Upload SARIF report files
security-events: write
steps:
- name: Log in to GHCR
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Checkout source
uses: actions/checkout@v3
- name: Scan code with trivy
uses: aquasecurity/trivy-action@master
# https://github.com/marketplace/actions/aqua-security-trivy
with:
scan-type: 'fs'
scan-ref: '.'
# ignore-unfixed: true
# severity: 'CRITICAL'
# trivy-config: trivy.yaml
# format: 'table'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Display scan results
run: cat trivy-results.sarif | jq .
- name: Upload trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
# Requires GitHub Advanced Security
# https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security
# https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning
# https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github
if: always()
with:
sarif_file: 'trivy-results.sarif'
category: trivy
- name: Scan code with grype
uses: anchore/scan-action@v3
# https://github.com/marketplace/actions/anchore-container-scan
id: scan-grype
with:
path: .
# output-format: table
output-format: 'sarif'
fail-build: false
# severity-cutoff: critical
- name: Display scan results
run: cat ${{ steps.scan-grype.outputs.sarif }} | jq .
- name: Upload grype scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: ${{ steps.scan-grype.outputs.sarif }}
category: grype
build-prod:
name: Build prod image
runs-on: ubuntu-latest
permissions:
# Interact with GitHub OIDC Token endpoint for AWS
id-token: write
contents: read
# Push to ghcr.io repository
packages: write
# Cancel previous runs
actions: write
steps:
- name: Cancel previous runs in progress
uses: styfle/[email protected]
with:
access_token: ${{ github.token }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
# https://github.com/aws-actions/configure-aws-credentials
# https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services
with:
role-to-assume: ${{ env.AWS_ROLE_TO_ASSUME }}
aws-region: ${{ env.AWS_REGION }}
- name: Log in to Amazon ECR
id: ecr-login
uses: aws-actions/amazon-ecr-login@v1
- name: Set vars
run: echo "ECR_REGISTRY=${{ steps.ecr-login.outputs.registry }}" >> $GITHUB_ENV
# - name: Log in to ECR
# uses: docker/login-action@v2
# with:
# registry: ${{ env.ECR_REGISTRY }}
# username: ${{ secrets.AWS_ACCESS_KEY_ID }}
# password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Log in to GHCR
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Check out source
uses: actions/checkout@v3
- name: Set variables
id: vars
run: |
echo "GITHUB_SHA_SHORT=$(echo $GITHUB_SHA | cut -c 1-7)" >> $GITHUB_ENV
echo "run_id=${GITHUB_RUN_ID}" >> $GITHUB_OUTPUT
echo "run_num=${GITHUB_RUN_NUMBER}" >> $GITHUB_OUTPUT
- name: Get branch name for push
if: github.event_name != 'pull_request'
run: echo "BRANCH=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV
- name: Get branch name for pull_request
if: github.event_name == 'pull_request'
run: echo "BRANCH=$(echo $GITHUB_HEAD_REF | tr '//\\' '.' | cut -c -55)" >> $GITHUB_ENV
# - name: Configure ssh keys
# uses: webfactory/[email protected]
# # https://github.com/marketplace/actions/webfactory-ssh-agent
# # https://docs.github.com/en/developers/overview/managing-deploy-keys#deploy-keys
# # ssh-keygen -t ed25519 -m pem -C "[email protected]:reachfh/api-utils.git" -f api-utils
# with:
# ssh-private-key: |
# ${{ secrets.SSH_PRIVATE_KEY }}
- name: Set up Docker buildx
id: buildx
uses: docker/setup-buildx-action@v2
with:
driver-opts: network=host
- name: Build prod image and push to GHCR
uses: docker/build-push-action@v3
with:
file: ${{ env.DOCKER_FILE }}
target: prod
build-args: |
ELIXIR_VER=${{ matrix.elixir }}
OTP_VER=${{ matrix.otp }}
BUILD_OS_VER=${{ matrix.build_os_ver }}
PROD_OS_VER=${{ matrix.prod_os_ver }}
context: .
builder: ${{ steps.buildx.outputs.name }}
push: true
cache-from: type=gha,scope=${{ github.workflow }}-${{ env.VAR }}
cache-to: type=gha,scope=${{ github.workflow }}-${{ env.VAR }},mode=max
# ssh: default
tags: |
ghcr.io/${{ env.IMAGE_OWNER }}/${{ env.IMAGE_NAME }}:${{ env.VAR }}${{ env.IMAGE_VER }}
ghcr.io/${{ env.IMAGE_OWNER }}/${{ env.IMAGE_NAME }}:${{ env.BRANCH }}-${{ env.GITHUB_SHA_SHORT }}
# secrets: |
# "access_token=${{ secrets.DEVOPS_ACCESS_TOKEN }}"
# "oban_key_fingerprint=${{ secrets.OBAN_KEY_FINGERPRINT }}"
# "oban_license_key=${{ secrets.OBAN_LICENSE_KEY }}"
- name: Build prod image and push to Docker Hub
uses: docker/build-push-action@v3
with:
file: ${{ env.DOCKER_FILE }}
target: prod
context: .
builder: ${{ steps.buildx.outputs.name }}
push: true
cache-from: type=gha,scope=${{ github.workflow }}-${{ env.VAR }}
cache-to: type=gha,scope=${{ github.workflow }}-${{ env.VAR }},mode=max
# ssh: default
tags: |
docker.io/${{ env.IMAGE_OWNER }}/${{ env.IMAGE_NAME }}:${{ env.VAR }}${{ env.IMAGE_VER }}
docker.io/${{ env.IMAGE_OWNER }}/${{ env.IMAGE_NAME }}:${{ env.BRANCH }}-${{ env.GITHUB_SHA_SHORT }}
# secrets: |
# "access_token=${{ secrets.DEVOPS_ACCESS_TOKEN }}"
# "oban_key_fingerprint=${{ secrets.OBAN_KEY_FINGERPRINT }}"
# "oban_license_key=${{ secrets.OBAN_LICENSE_KEY }}"
- name: Build prod image and push to AWS ECR
uses: docker/build-push-action@v3
env:
REGISTRY: "${{ env.ECR_REGISTRY }}/"
with:
file: ${{ env.DOCKER_FILE }}
target: prod
context: .
builder: ${{ steps.buildx.outputs.name }}
push: true
cache-from: type=gha,scope=${{ github.workflow }}-${{ env.VAR }}
cache-to: type=gha,scope=${{ github.workflow }}-${{ env.VAR }},mode=max
# ssh: default
tags: |
${{ env.ECR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.VAR }}${{ env.IMAGE_VER }}
${{ env.ECR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.BRANCH }}-${{ env.GITHUB_SHA_SHORT }}
# secrets: |
# "access_token=${{ secrets.DEVOPS_ACCESS_TOKEN }}"
# "oban_key_fingerprint=${{ secrets.OBAN_KEY_FINGERPRINT }}"
# "oban_license_key=${{ secrets.OBAN_LICENSE_KEY }}"
# build-newman:
# name: Build newman image
# runs-on: ubuntu-latest
# permissions:
# # Push to ghcr.io repository
# packages: write
# # Cancel previous runs
# actions: write
# steps:
# - name: Cancel previous runs
# uses: styfle/[email protected]
# with:
# access_token: ${{ github.token }}
#
# - name: Check out source
# uses: actions/checkout@v3
#
# - name: Log in to GHCR
# uses: docker/login-action@v2
# with:
# registry: ghcr.io
# username: ${{ github.actor }}
# password: ${{ secrets.GITHUB_TOKEN }}
#
# # Pull public images without rate limits
# # - name: Log in to Docker Hub
# # uses: docker/login-action@v2
# # with:
# # username: ${{ secrets.DOCKERHUB_USERNAME }}
# # password: ${{ secrets.DOCKERHUB_TOKEN }}
#
# - name: Set up Docker buildx
# id: buildx
# uses: docker/setup-buildx-action@v2
# with:
# driver-opts: network=host
#
# - name: Build newman image
# uses: docker/build-push-action@v3
# with:
# file: deploy/newman.Dockerfile
# context: .
# builder: ${{ steps.buildx.outputs.name }}
# push: true
# cache-from: type=gha,scope=${{ github.workflow }}-newman
# cache-to: type=gha,scope=${{ github.workflow }}-newman,mode=max
# tags: |
# ghcr.io/${{ env.IMAGE_OWNER }}/newman:latest
test-prod:
name: Run external API tests
runs-on: ubuntu-latest
# needs: [build-prod, build-newman]
needs: [build-prod]
permissions:
# Read from ghcr.io repository
packages: read
# Upload JUnit report files
# https://github.com/EnricoMi/publish-unit-test-result-action#permissions
contents: read
issues: read
checks: write
pull-requests: write
steps:
- name: Log in to GHCR
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Check out source
uses: actions/checkout@v3
- name: Pull repos
# run: echo "newman postgres router prod" | xargs -n 1 -P 8 docker compose pull --quiet
# docker compose pull --quiet newman
# docker images --no-trunc
run: |
docker compose pull --quiet --include-deps prod
- name: Start services
run: docker compose up --wait --detach prod
- name: Display logs
if: failure()
run: |
docker compose logs --timestamps prod
docker compose logs --timestamps postgres
echo prod
docker inspect --format "{{json .State.Health }}" $(docker compose ps -q prod) | jq
echo postgres
docker inspect --format "{{json .State.Health }}" $(docker compose ps -q postgres) | jq
docker compose ps --format json | jq .
# - name: Debug env
# if: failure()
# run: |
# docker compose run --entrypoint /bin/bash prod env
# docker compose run --entrypoint /bin/bash prod env PGPASSWORD=postgres /usr/bin/psql -w -h postgres -U postgres -d postgres -c "SELECT 1"
# # docker compose run --entrypoint /bin/bash prod pg_isready -h postgres -p 5432 -d postgres -U postgres
- name: Initialize database
run: |
docker compose run prod eval 'PhoenixContainerExample.Release.create_repos()'
docker compose run prod eval 'PhoenixContainerExample.Release.migrate()'
docker compose run prod eval 'PhoenixContainerExample.Release.run_seeds()'
- name: Run health check
run: curl -v http://localhost:${{ env.APP_PORT }}/healthz
# - name: Run API tests
# env:
# NEWMAN_ARGS: "--verbose -r cli,junitfull --reporter-junitfull-export /junit-reports/newman.xml -e ci.json"
# # NEWMAN_ARGS: "--verbose -r cli,junit --reporter-junit-export /junit-reports/newman.xml -e ci.json"
# # https://hub.docker.com/r/postman/newman/
# run: docker compose run newman run ${{env.NEWMAN_ARGS}} Queries.postman_collection.json
- name: Display logs
if: failure()
run: |
docker compose logs --timestamps prod
# docker compose logs --timestamps newman
- name: Publish unit test results to GitHub
uses: EnricoMi/publish-unit-test-result-action@v2
# Run even if tests fail
if: always()
with:
# Volume mounted from local filesystem into build
junit_files: ./junit-reports/*.xml
check_name: "External API Tests"
scan:
name: Security scan prod image
runs-on: ubuntu-latest
needs: [build-prod]
permissions:
# Interact with GitHub OIDC Token endpoint for AWS
id-token: write
contents: read
# Read from ghcr.io repository
packages: read
# Upload JUnit report files
# https://github.com/EnricoMi/publish-unit-test-result-action#permissions
checks: write
pull-requests: write
issues: read
# Upload SARIF report files
security-events: write
steps:
- name: Log in to GHCR
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Pull image
run: docker pull ghcr.io/${{env.IMAGE_OWNER}}/${{env.IMAGE_NAME}}:${{ env.VAR }}${{ env.IMAGE_VER }}
- name: Scan image with Trivy
uses: aquasecurity/trivy-action@master
# https://github.com/aquasecurity/trivy-action
# https://github.com/marketplace/actions/aqua-security-trivy#inputs
with:
image-ref: ghcr.io/${{env.IMAGE_OWNER}}/${{env.IMAGE_NAME}}:${{ env.VAR }}${{ env.IMAGE_VER }}
# exit-code: '1' # fail build
# ignore-unfixed: true
# vuln-type: 'os,library'
# severity: 'CRITICAL,HIGH'
# cache-dir: /var/cache
format: 'sarif'
output: 'trivy.sarif'
- name: Display scan results
run: cat trivy.sarif | jq .
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
# Requires GitHub Advanced Security
# https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security
# https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning
# https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github
if: always()
with:
sarif_file: 'trivy.sarif'
category: trivy
- name: Scan image with Grype
uses: anchore/scan-action@v3
# https://github.com/marketplace/actions/anchore-container-scan
id: scan-grype
with:
image: ghcr.io/${{env.IMAGE_OWNER}}/${{env.IMAGE_NAME}}:${{ env.VAR }}${{ env.IMAGE_VER }}
# severity-cutoff: critical
fail-build: false
output-format: 'sarif'
# output-format: table
- name: Display scan results
run: cat ${{ steps.scan-grype.outputs.sarif }} | jq .
- name: Upload Grype scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: ${{ steps.scan-grype.outputs.sarif }}
category: grype
# - name: Scan image with snyk
# # if: github.event_name != 'pull_request'
# uses: snyk/actions/docker@master
# continue-on-error: true
# env:
# SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
# with:
# command: test
# image: ghcr.io/${{ env.IMAGE_OWNER }}/${{ env.IMAGE_NAME }}:${{ env.VAR }}${{ env.IMAGE_VER }}
# args: --file=${{ env.DOCKER_FILE }} --project-name=api
prod:
name: Deploy prod images
if: github.event_name != 'pull_request'
# if: contains(github.ref, 'refs/heads/main')
runs-on: ubuntu-latest
needs: [build-prod, test-prod, test]
permissions:
# Interact with GitHub OIDC Token endpoint for AWS
id-token: write
contents: read
# Push to ghcr.io repository
packages: write
# Upload JUnit report files
# https://github.com/EnricoMi/publish-unit-test-result-action#permissions
checks: write
pull-requests: write
issues: read
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1-node16
with:
role-to-assume: ${{ env.AWS_ROLE_TO_ASSUME }}
aws-region: ${{ env.AWS_REGION }}
- name: Log in to Amazon ECR
id: ecr-login
uses: aws-actions/amazon-ecr-login@v1
- name: Set vars
run: echo "ECR_REGISTRY=${{ steps.ecr-login.outputs.registry }}" >> $GITHUB_ENV
# - name: Log in to ECR
# uses: docker/login-action@v2
# with:
# registry: ${{ env.ECR_REGISTRY }}
# username: ${{ secrets.AWS_ACCESS_KEY_ID }}
# password: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Log in to GHCR
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Tag GHCR release as latest
run: |
docker buildx imagetools create \
--append ghcr.io/${{env.IMAGE_OWNER}}/${{env.IMAGE_NAME}}:${{env.PROD_VAR}}${{env.IMAGE_VER}} \
--tag ghcr.io/${{env.IMAGE_OWNER}}/${{env.IMAGE_NAME}}:${{env.IMAGE_TAG}}
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Check out source
uses: actions/checkout@v3
- name: Set up Docker buildx
id: buildx
uses: docker/setup-buildx-action@v2
with:
driver-opts: network=host
# - name: Build final prod image and push to GHCR as latest
# uses: docker/build-push-action@v3
# with:
# file: ${{ env.DOCKER_FILE }}
# target: prod
# context: .
# builder: ${{ steps.buildx.outputs.name }}
# push: true
# cache-from: type=gha,scope=${{ github.workflow }}-${{ env.PROD_VAR }}
# cache-to: type=gha,scope=${{ github.workflow }}-${{ env.PROD_VAR }},mode=max
# tags: |
# ghcr.io/${{env.IMAGE_OWNER}}/${{env.IMAGE_NAME}}:${{ env.IMAGE_VER }}
# ghcr.io/${{env.IMAGE_OWNER}}/${{env.IMAGE_NAME}}:${{ env.IMAGE_TAG }}
# - name: Tag ECR release as latest
# run: |
# export MANIFEST=$(aws ecr batch-get-image --repository-name ${{ env.IMAGE_NAME }} \
# --image-ids imageTag=${{ env.IMAGE_VER }} --output json | jq --raw-output --join-output '.images[0].imageManifest')
# aws ecr put-image --repository-name ${{ env.IMAGE_NAME }} \
# --image-tag ${{ env.IMAGE_TAG }} --image-manifest "$MANIFEST"
# aws ecr describe-images --repository-name ${{ env.IMAGE_NAME }}
- name: Build final prod image and push to Docker Hub as latest
uses: docker/build-push-action@v3
with:
file: ${{ env.DOCKER_FILE }}
target: prod
context: .
builder: ${{ steps.buildx.outputs.name }}
push: true
cache-from: type=gha,scope=${{ github.workflow }}-${{ env.PROD_VAR }}
cache-to: type=gha,scope=${{ github.workflow }}-${{ env.PROD_VAR }},mode=max
# ssh: default
tags: |
docker.io/${{ env.IMAGE_OWNER }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
docker.io/${{ env.IMAGE_OWNER }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_VER }}
# secrets: |
# "access_token=${{ secrets.DEVOPS_ACCESS_TOKEN }}"
# "oban_key_fingerprint=${{ secrets.OBAN_KEY_FINGERPRINT }}"
# "oban_license_key=${{ secrets.OBAN_LICENSE_KEY }}"
- name: Build final prod image and push to AWS ECR as latest
uses: docker/build-push-action@v3
env:
REGISTRY: "${{ env.ECR_REGISTRY }}/"
with:
file: ${{ env.DOCKER_FILE }}
target: prod
context: .
builder: ${{ steps.buildx.outputs.name }}
push: true
cache-from: type=gha,scope=${{ github.workflow }}-${{ env.PROD_VAR }}
cache-to: type=gha,scope=${{ github.workflow }}-${{ env.PROD_VAR }},mode=max
# ssh: default
tags: |
${{ env.ECR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
${{ env.ECR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_VER }}
# secrets: |
# "access_token=${{ secrets.DEVOPS_ACCESS_TOKEN }}"
# "oban_key_fingerprint=${{ secrets.OBAN_KEY_FINGERPRINT }}"
# "oban_license_key=${{ secrets.OBAN_LICENSE_KEY }}"
deploy:
name: Deploy using AWS CodeDeploy
needs: [prod]
permissions:
# Interact with GitHub OIDC Token endpoint for AWS
id-token: write
contents: read
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1-node16
with:
role-to-assume: ${{ env.AWS_ROLE_TO_ASSUME }}
aws-region: ${{ env.AWS_REGION }}
- name: Log in to Amazon ECR
id: ecr-login
uses: aws-actions/amazon-ecr-login@v1
- name: Set vars
run: echo "ECR_REGISTRY=${{ steps.ecr-login.outputs.registry }}" >> $GITHUB_ENV
- name: Check out source
uses: actions/checkout@v3
# https://docs.aws.amazon.com/codedeploy/latest/userguide/reference-appspec-file-structure-resources.html
- name: Generate appspec.yml
env:
CONTAINER_NAME: "foo-app"
PORT: "4000"
run: sed -i -e "s!<NAME>!${CONTAINER_NAME}!g" -e "s!<PORT>!${PORT}!g" ecs/appspec.yml
- name: Generate task-defintion.json
env:
CONTAINER_NAME: "foo-app"
PORT: "4000"
AWSLOGS_GROUP: "/ecs/foo-app"
AWSLOGS_STREAM_PREFIX: "foo-app"
CONFIG_S3_BUCKET: = dependency.s3.outputs.buckets["config"].id
CONFIG_S3_PREFIX: "app-ecs"
# FARGATE supported values
# CPU value Memory value (MiB)
# 256 (.25 vCPU) 512 (0.5 GB), 1024 (1 GB), 2048 (2 GB)
# 512 (.5 vCPU) 1024 (1 GB), 2048 (2 GB), 3072 (3 GB), 4096 (4 GB)
# 1024 (1 vCPU) 2048 (2 GB), 3072 (3 GB), 4096 (4 GB), 5120 (5 GB), 6144 (6 GB), 7168 (7 GB), 8192 (8 GB)
# 2048 (2 vCPU) Between 4096 (4 GB) and 16384 (16 GB) in increments of 1024 (1 GB)
# 4096 (4 vCPU) Between 8192 (8 GB) and 30720 (30 GB) in increments of 1024 (1 GB)
CPU: 256
MEMORY: 512
CPU_ARCH: ARM64
TASK_ROLE_ARN: "arn:aws:iam::770916339360:role/foo-app-20200227055150076000000001"
EXECUTUION_ROLE_ARN: "arn:aws:iam::770916339360:role/foo-ecs-task-execution-role"
CONFIG_S3_PREFIX: "app-ecs"
CONFIG_S3_BUCKET: "cogini-foo-dev-app-config"
run: |
sed -i -e "s!<AWS_ACCOUNT_ID>!${AWS_ACCOUNT_ID}!g" $TASKDEF
sed -i -e "s!<AWS_REGION>!${AWS_REGION}!g" $TASKDEF
sed -i -e "s!<AWSLOGS_GROUP>!${AWSLOGS_GROUP}!g" $TASKDEF
sed -i -e "s!<AWSLOGS_REGION>!${AWS_REGION}!g" $TASKDEF
sed -i -e "s!<AWSLOGS_STREAM_PREFIX>!${AWSLOGS_STREAM_PREFIX}!g" $TASKDEF
sed -i -e "s!<NAME>!${CONTAINER_NAME}!g" -e "s!<PORT>!${PORT}!g" $TASKDEF
sed -i -e "s!<CPU>!${CPU}!g" -e "s!<MEMORY>!${MEMORY}!g" $TASKDEF
sed -i -e "s!<CPU_ARCH>!${CPU_ARCH}!g" $TASKDEF
sed -i -e "s!<TASK_ROLE_ARN>!${TASK_ROLE_ARN}!g" $TASKDEF
sed -i -e "s!<EXECUTION_ROLE_ARN>!${EXECUTION_ROLE_ARN}!g" $TASKDEF
sed -i -e "s!<CONFIG_S3_BUCKET>!${CONFIG_S3_BUCKET}!g" -e "s!<CONFIG_S3_PREFIX>!${CONFIG_S3_PREFIX}!g" $TASKDEF
cat $TASKDEF
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: ${{ env.TASKDEF }}
container-name: "foo-app"
image: ${{ env.ECR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.PROD_VAR }}${{ env.IMAGE_VER }}
- name: Deploy to Amazon ECS
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: task-definition.json
service: foo-app
cluster: foo
wait-for-service-stability: true
codedeploy-appspec: ecs/appspec.yml
codedeploy-application: foo-app
codedeploy-deployment-group: foo-app