In workflow build image using makefile target #251
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: Main | |
on: | |
push: | |
env: | |
KOSLI_DRY_RUN: ${{ vars.KOSLI_DRY_RUN }} # false | |
KOSLI_HOST: ${{ vars.KOSLI_HOST }} # https://app.kosli.com | |
KOSLI_ORG: ${{ vars.KOSLI_ORG }} # cyber-dojo | |
KOSLI_FLOW: ${{ vars.KOSLI_FLOW }} # saver-ci | |
KOSLI_API_TOKEN: ${{ secrets.KOSLI_API_TOKEN }} | |
KOSLI_TRAIL: ${{ github.sha }} | |
SERVICE_NAME: ${{ github.event.repository.name }} # saver | |
AWS_ACCOUNT_ID: ${{ vars.AWS_ACCOUNT_ID }} | |
AWS_ECR_ID: ${{ vars.AWS_ECR_ID }} | |
AWS_REGION: ${{ vars.AWS_REGION }} | |
IMAGE_TAR_FILENAME: /tmp/${{ github.event.repository.name }}:${{ github.sha }}.tar | |
DOCKER_API_VERSION: ${{ vars.DOCKER_API_VERSION }} | |
jobs: | |
setup: | |
runs-on: ubuntu-latest | |
outputs: | |
aws_account_id: ${{ steps.vars.outputs.aws_account_id }} | |
ecr_registry: ${{ steps.vars.outputs.ecr_registry }} | |
aws_region: ${{ steps.vars.outputs.aws_region }} | |
gh_actions_iam_role_name: ${{ steps.vars.outputs.gh_actions_iam_role_name }} | |
service_name: ${{ steps.vars.outputs.service_name }} | |
image_tag: ${{ steps.vars.outputs.image_tag }} | |
image_name: ${{ steps.vars.outputs.image_name }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 2 | |
- name: Prepare outputs for workflow jobs | |
id: vars | |
run: | | |
IMAGE_TAG=${GITHUB_SHA:0:7} | |
ECR_REGISTRY="${AWS_ECR_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com" | |
IMAGE_NAME="${ECR_REGISTRY}/${{ env.SERVICE_NAME }}:${IMAGE_TAG}" | |
echo "aws_account_id=${AWS_ACCOUNT_ID}" >> ${GITHUB_OUTPUT} | |
echo "ecr_registry=${ECR_REGISTRY}" >> ${GITHUB_OUTPUT} | |
echo "aws_region=${AWS_REGION}" >> ${GITHUB_OUTPUT} | |
echo "gh_actions_iam_role_name=gh_actions_services" >> ${GITHUB_OUTPUT} | |
echo "service_name=${{ env.SERVICE_NAME }}" >> ${GITHUB_OUTPUT} | |
echo "image_tag=${IMAGE_TAG}" >> ${GITHUB_OUTPUT} | |
echo "image_name=${IMAGE_NAME}" >> ${GITHUB_OUTPUT} | |
- name: Setup Kosli CLI | |
uses: kosli-dev/setup-cli-action@v2 | |
with: | |
version: ${{ vars.KOSLI_CLI_VERSION }} | |
- name: Attest pull-request evidence to Kosli | |
if: ${{ github.ref == 'refs/heads/main' }} | |
run: | |
kosli begin trail "${{ env.KOSLI_TRAIL }}" | |
--flow="${{ env.KOSLI_FLOW }}" | |
--template-file=.kosli.yml | |
pull-request: | |
if: ${{ github.ref == 'refs/heads/main' }} | |
runs-on: ubuntu-latest | |
needs: [] | |
permissions: | |
id-token: write | |
contents: read | |
pull-requests: read | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 1 | |
- name: Setup Kosli CLI | |
uses: kosli-dev/setup-cli-action@v2 | |
with: | |
version: ${{ vars.KOSLI_CLI_VERSION }} | |
- name: Attest pull-request evidence to Kosli | |
run: | |
kosli attest pullrequest github | |
--github-token=${{ secrets.GITHUB_TOKEN }} | |
--name=pull-request | |
snyk-code-scan: | |
runs-on: ubuntu-latest | |
needs: [] | |
env: | |
SARIF_FILENAME: snyk.code.scan.json | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 1 | |
- name: Setup Snyk | |
uses: snyk/actions/setup@master | |
- name: Run Snyk code scan | |
env: | |
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} | |
run: | |
snyk code test | |
--policy-path=.snyk | |
--sarif | |
--sarif-file-output="${SARIF_FILENAME}" | |
- name: Setup Kosli CLI | |
if: ${{ github.ref == 'refs/heads/main' && (success() || failure()) }} | |
uses: kosli-dev/setup-cli-action@v2 | |
with: | |
version: ${{ vars.KOSLI_CLI_VERSION }} | |
- name: Attest evidence to Kosli | |
if: ${{ github.ref == 'refs/heads/main' && (success() || failure()) }} | |
run: | |
kosli attest snyk | |
--attachments=.snyk | |
--name=saver.snyk-code-scan | |
--scan-results="${SARIF_FILENAME}" | |
build-image: | |
needs: [setup] | |
runs-on: ubuntu-latest | |
env: | |
IMAGE_NAME: ${{ needs.setup.outputs.image_name }} | |
permissions: | |
id-token: write | |
contents: write | |
outputs: | |
artifact_digest: ${{ steps.variables.outputs.artifact_digest }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 1 | |
- name: Configure AWS credentials | |
uses: aws-actions/configure-aws-credentials@v4 | |
with: | |
aws-region: ${{ needs.setup.outputs.aws_region }} | |
role-duration-seconds: 900 | |
role-session-name: ${{ github.event.repository.name }} | |
role-to-assume: arn:aws:iam::${{ needs.setup.outputs.aws_account_id }}:role/${{ needs.setup.outputs.gh_actions_iam_role_name }} | |
mask-aws-account-id: no | |
- name: Login to Amazon ECR | |
id: login-ecr | |
uses: aws-actions/amazon-ecr-login@v2 | |
- name: Build and push Docker image to ECR | |
run: | | |
make image_server | |
docker push "${{ env.IMAGE_NAME }}" | |
- name: Tar Docker image | |
run: | |
docker image save ${{ env.IMAGE_NAME }} --output ${{ env.IMAGE_TAR_FILENAME }} | |
- name: Cache Docker image | |
uses: actions/cache@v4 | |
with: | |
path: ${{ env.IMAGE_TAR_FILENAME }} | |
key: ${{ env.IMAGE_NAME }} | |
- name: Setup Kosli CLI | |
if: ${{ github.ref == 'refs/heads/main' }} | |
uses: kosli-dev/setup-cli-action@v2 | |
with: | |
version: ${{ vars.KOSLI_CLI_VERSION }} | |
- name: Make Digest available to following jobs | |
id: variables | |
run: | | |
FINGERPRINT=$(kosli fingerprint "${IMAGE_NAME}" --artifact-type=docker) | |
echo "artifact_digest=${FINGERPRINT}" >> ${GITHUB_OUTPUT} | |
- name: Attest image evidence to Kosli | |
if: ${{ github.ref == 'refs/heads/main' }} | |
run: | |
kosli attest artifact "${IMAGE_NAME}" | |
--artifact-type=docker | |
--name=saver | |
unit-tests: | |
runs-on: ubuntu-latest | |
needs: [setup, build-image] | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 1 | |
- name: Retrieve Docker image from cache | |
uses: actions/cache@v4 | |
with: | |
path: ${{ env.IMAGE_TAR_FILENAME }} | |
key: ${{ needs.setup.outputs.image_name }} | |
- name: Load Docker image | |
run: | |
docker image load --input ${{ env.IMAGE_TAR_FILENAME }} | |
- name: Run unit tests with metrics | |
run: | |
make metrics_test_server metrics_coverage_server | |
- name: Setup Kosli CLI | |
if: ${{ github.ref == 'refs/heads/main' && (success() || failure()) }} | |
uses: kosli-dev/setup-cli-action@v2 | |
with: | |
version: ${{ vars.KOSLI_CLI_VERSION }} | |
- name: Attest JUnit test evidence to Kosli | |
if: ${{ github.ref == 'refs/heads/main' && (success() || failure()) }} | |
env: | |
KOSLI_FINGERPRINT: ${{ needs.build-image.outputs.artifact_digest }} | |
run: | |
kosli attest junit | |
--name=saver.unit-test | |
--results-dir=./reports/server/junit | |
- name: Attest test metrics to Kosli | |
if: ${{ github.ref == 'refs/heads/main' && (success() || failure()) }} | |
env: | |
KOSLI_FINGERPRINT: ${{ needs.build-image.outputs.artifact_digest }} | |
run: | |
kosli attest custom | |
--attestation-data=./reports/server/test_metrics.json | |
--name=saver.unit-test-metrics | |
--type=test-metrics | |
- name: Attest coverage metrics to Kosli | |
if: ${{ github.ref == 'refs/heads/main' && (success() || failure()) }} | |
env: | |
KOSLI_FINGERPRINT: ${{ needs.build-image.outputs.artifact_digest }} | |
run: | |
kosli attest custom | |
--attestation-data=./reports/server/coverage_metrics.json | |
--name=saver.unit-test-coverage-metrics | |
--type=coverage-metrics | |
integration-tests: | |
runs-on: ubuntu-latest | |
needs: [setup, build-image] | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 1 | |
- name: Retrieve Docker image from cache | |
uses: actions/cache@v4 | |
with: | |
path: ${{ env.IMAGE_TAR_FILENAME }} | |
key: ${{ needs.setup.outputs.image_name }} | |
- name: Load Docker image | |
run: | |
docker image load --input ${{ env.IMAGE_TAR_FILENAME }} | |
- name: Run integration tests with metrics | |
run: | |
make image_client test_client metrics_test_client metrics_coverage_client | |
- name: Setup Kosli CLI | |
if: ${{ github.ref == 'refs/heads/main' && (success() || failure()) }} | |
uses: kosli-dev/setup-cli-action@v2 | |
with: | |
version: ${{ vars.KOSLI_CLI_VERSION }} | |
- name: Attest junit test evidence to Kosli | |
if: ${{ github.ref == 'refs/heads/main' && (success() || failure()) }} | |
env: | |
KOSLI_FINGERPRINT: ${{ needs.build-image.outputs.artifact_digest }} | |
run: | |
kosli attest junit | |
--name=saver.integration-test | |
--results-dir=./reports/client/junit | |
- name: Attest test metrics to Kosli | |
if: ${{ github.ref == 'refs/heads/main' && (success() || failure()) }} | |
env: | |
KOSLI_FINGERPRINT: ${{ needs.build-image.outputs.artifact_digest }} | |
run: | |
kosli attest custom | |
--attestation-data=./reports/client/test_metrics.json | |
--name=saver.integration-test-metrics | |
--type=test-metrics | |
- name: Attest coverage metrics to Kosli | |
if: ${{ github.ref == 'refs/heads/main' && (success() || failure()) }} | |
env: | |
KOSLI_FINGERPRINT: ${{ needs.build-image.outputs.artifact_digest }} | |
run: | |
kosli attest custom | |
--attestation-data=./reports/client/coverage_metrics.json | |
--name=saver.integration-test-coverage-metrics | |
--type=coverage-metrics | |
snyk-container-scan: | |
runs-on: ubuntu-latest | |
needs: [setup, build-image] | |
env: | |
SARIF_FILENAME: snyk.container.scan.json | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 1 | |
- name: Retrieve Docker image from cache | |
uses: actions/cache@v4 | |
with: | |
path: ${{ env.IMAGE_TAR_FILENAME }} | |
key: ${{ needs.setup.outputs.image_name }} | |
- name: Load Docker image | |
run: | |
docker image load --input ${{ env.IMAGE_TAR_FILENAME }} | |
- name: Setup Snyk | |
uses: snyk/actions/setup@master | |
- name: Run Snyk container scan | |
env: | |
IMAGE_NAME: ${{ needs.setup.outputs.image_name }} | |
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} | |
run: | |
snyk container test ${IMAGE_NAME} | |
--file=Dockerfile | |
--policy-path=.snyk | |
--sarif | |
--sarif-file-output="${SARIF_FILENAME}" | |
- name: Setup Kosli CLI | |
if: ${{ github.ref == 'refs/heads/main' && (success() || failure()) }} | |
uses: kosli-dev/setup-cli-action@v2 | |
with: | |
version: ${{ vars.KOSLI_CLI_VERSION }} | |
- name: Attest evidence to Kosli | |
if: ${{ github.ref == 'refs/heads/main' && (success() || failure()) }} | |
env: | |
KOSLI_FINGERPRINT: ${{ needs.build-image.outputs.artifact_digest }} | |
run: | |
kosli attest snyk | |
--attachments=.snyk | |
--name=saver.snyk-container-scan | |
--scan-results="${SARIF_FILENAME}" | |
sdlc-control-gate: | |
if: ${{ github.ref == 'refs/heads/main' }} | |
runs-on: ubuntu-latest | |
needs: [setup, build-image, pull-request, unit-tests, integration-tests, snyk-container-scan, snyk-code-scan] | |
steps: | |
- name: Setup Kosli CLI | |
uses: kosli-dev/setup-cli-action@v2 | |
with: | |
version: ${{ vars.KOSLI_CLI_VERSION }} | |
- name: Kosli SDLC gate to short-circuit the workflow | |
env: | |
IMAGE_NAME: ${{ needs.setup.outputs.image_name }} | |
KOSLI_FINGERPRINT: ${{ needs.build-image.outputs.artifact_digest }} | |
run: | |
kosli assert artifact ${IMAGE_NAME} | |
approve-deployment-to-beta: | |
runs-on: ubuntu-latest | |
needs: [setup, build-image, sdlc-control-gate] | |
environment: | |
name: staging | |
url: https://beta.cyber-dojo.org | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Setup Kosli CLI | |
uses: kosli-dev/setup-cli-action@v2 | |
with: | |
version: ${{ vars.KOSLI_CLI_VERSION }} | |
- name: Attest approval of deployment to Kosli | |
env: | |
IMAGE_NAME: ${{ needs.setup.outputs.image_name }} | |
KOSLI_FINGERPRINT: ${{ needs.build-image.outputs.artifact_digest }} | |
KOSLI_ENVIRONMENT: aws-beta | |
run: | |
kosli report approval ${IMAGE_NAME} | |
--approver="${{ github.actor }}" | |
deploy-to-beta: | |
needs: [setup, approve-deployment-to-beta] | |
uses: ./.github/workflows/sub_deploy_to_beta.yml | |
with: | |
IMAGE_TAG: ${{ needs.setup.outputs.image_tag }} | |
secrets: | |
KOSLI_API_TOKEN: ${{ secrets.KOSLI_API_TOKEN }} | |
approve-deployment-to-prod: | |
runs-on: ubuntu-latest | |
needs: [setup, build-image, deploy-to-beta] | |
environment: | |
name: production | |
url: https://cyber-dojo.org | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Setup Kosli CLI | |
uses: kosli-dev/setup-cli-action@v2 | |
with: | |
version: ${{ vars.KOSLI_CLI_VERSION }} | |
- name: Attest approval of deployment to Kosli | |
env: | |
IMAGE_NAME: ${{ needs.setup.outputs.image_name }} | |
KOSLI_FINGERPRINT: ${{ needs.build-image.outputs.artifact_digest }} | |
KOSLI_ENVIRONMENT: aws-prod | |
run: | |
kosli report approval ${IMAGE_NAME} | |
--approver="${{ github.actor }}" | |
deploy-to-prod: | |
needs: [setup, approve-deployment-to-prod] | |
uses: ./.github/workflows/sub_deploy_to_prod.yml | |
with: | |
IMAGE_TAG: ${{ needs.setup.outputs.image_tag }} | |
secrets: | |
KOSLI_API_TOKEN: ${{ secrets.KOSLI_API_TOKEN }} | |
# The cyberdojo/versioner refresh-env.sh script | |
# https://github.com/cyber-dojo/versioner/blob/master/sh/refresh-env.sh | |
# relies on being able to: | |
# - get the :latest image from dockerhub | |
# - extract the SHA env-var embedded inside it | |
# - use the 1st 7 chars of the SHA as a latest-equivalent tag from dockerhub | |
push-latest: | |
needs: [setup, deploy-to-prod] | |
runs-on: ubuntu-latest | |
permissions: | |
id-token: write | |
contents: write | |
steps: | |
- name: Configure AWS credentials | |
uses: aws-actions/configure-aws-credentials@v4 | |
with: | |
aws-region: ${{ needs.setup.outputs.aws_region }} | |
role-duration-seconds: 900 | |
role-session-name: ${{ github.event.repository.name }} | |
role-to-assume: arn:aws:iam::${{ needs.setup.outputs.aws_account_id }}:role/${{ needs.setup.outputs.gh_actions_iam_role_name }} | |
mask-aws-account-id: 'no' | |
- name: Login to Amazon ECR | |
id: login-ecr | |
uses: aws-actions/amazon-ecr-login@v2 | |
- uses: docker/login-action@v3 | |
with: | |
username: ${{ secrets.DOCKER_USER }} | |
password: ${{ secrets.DOCKER_PASS }} | |
- name: Tag image to :latest and push to Dockerhub Registry | |
env: | |
IMAGE_NAME: ${{ needs.setup.outputs.image_name }} | |
IMAGE_TAG: ${{ needs.setup.outputs.image_tag }} | |
run: | | |
docker pull "${IMAGE_NAME}" | |
docker tag "${IMAGE_NAME}" cyberdojo/${{ env.SERVICE_NAME }}:${IMAGE_TAG} | |
docker tag "${IMAGE_NAME}" cyberdojo/${{ env.SERVICE_NAME }}:latest | |
docker push cyberdojo/${{ env.SERVICE_NAME }}:${IMAGE_TAG} | |
docker push cyberdojo/${{ env.SERVICE_NAME }}:latest |