Files
firezone/.github/workflows/ci.yml
Jamil 70a9ed2714 feat(windows): code sign Windows client (#3891)
- Uses infra we [set up
previously](https://portal.azure.com/#@firezoneinc.onmicrosoft.com/resource/subscriptions/43767d16-5744-41af-ab38-6323d54b9b7d/resourceGroups/Default/providers/Microsoft.KeyVault/vaults/firezone-code-signing/overview)
in Azure for codesigning.
- Cert is currently expired so this is likely to fail. Currently pending
renewal with GlobalSign
- May need a few more pushes to `main` to troubleshoot issues since this
is run in CD

Fixes #3230
2024-03-06 01:58:43 +00:00

365 lines
12 KiB
YAML

name: Continuous Integration
on:
pull_request:
merge_group:
types: [checks_requested]
workflow_call:
# Cancel old workflow runs if new code is pushed
concurrency:
group: "ci-${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true
jobs:
elixir:
uses: ./.github/workflows/_elixir.yml
rust:
uses: ./.github/workflows/_rust.yml
secrets: inherit
kotlin:
uses: ./.github/workflows/_kotlin.yml
secrets: inherit
swift:
uses: ./.github/workflows/_swift.yml
secrets: inherit
static-analysis:
uses: ./.github/workflows/_static-analysis.yml
terraform:
uses: ./.github/workflows/_terraform.yml
secrets: inherit
codeql:
uses: ./.github/workflows/_codeql.yml
secrets: inherit
# We could build these in GCP with Cloud Build, but for now it's
# less overhead to keep things in GH actions. See work on building these
# in GCP with Cloud Build: https://github.com/firezone/firezone/pull/2234
build-images:
name: build-images-${{ matrix.image_name }}
runs-on: ubuntu-22.04
strategy:
matrix:
include:
- image_name: api
target: runtime
context: elixir
build-args: |
APPLICATION_NAME=api
- image_name: web
target: runtime
context: elixir
build-args: |
APPLICATION_NAME=web
- image_name: gateway
target: debug
context: rust
build-args: |
PACKAGE=firezone-gateway
- image_name: relay
target: debug
context: rust
build-args: |
PACKAGE=firezone-relay
- image_name: client
target: debug
context: rust
build-args: |
PACKAGE=firezone-linux-client
- image_name: snownet-tests
target: debug
context: rust
build-args: |
PACKAGE=snownet-tests
- image_name: elixir
target: compiler
context: elixir
build-args: |
APPLICATION_NAME=api
permissions:
contents: read
id-token: write
env:
# mark:automatic-version
VERSION: "1.0.0"
APPLICATION_NAME: ${{ matrix.image_name }}
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
# We are overriding the default buildkit version being used by Buildx. We need buildkit >= 12.0 and currently BuildX
# supports v0.11.6 https://github.com/docker/buildx/blob/b8739d74417f86aa8fc9aafb830a8ba656bdef0e/Dockerfile#L9.
# We should for any updates on buildx and on the setup-buildx-action itself.
driver-opts: |
image=moby/buildkit:v0.12.0
- uses: actions/checkout@v4
- name: Sanitize github.ref_name
run: |
# `ref_name` contains `/` which is not a valid docker image tag
REF="${{ github.ref_name }}"
CACHE_TAG="${REF//\//-}"
echo "CACHE_TAG=$CACHE_TAG" >> "$GITHUB_ENV"
echo "BRANCH_TAG=$CACHE_TAG" >> "$GITHUB_ENV"
- uses: ./.github/actions/gcp-docker-login
id: login
with:
project: firezone-staging
- name: Build Docker Tags
id: build_docker_tags
run: |
set -xe
TAGS=""
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
MAJOR_VERSION="${VERSION%%.*}"
MAJOR_MINOR_VERSION="${VERSION%.*}"
TAGS="${TAGS},${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_name }}:${MAJOR_VERSION}"
TAGS="${TAGS},${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_name }}:${MAJOR_MINOR_VERSION}"
TAGS="${TAGS},${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_name }}:${{ env.VERSION }}-${{ github.sha }}"
fi
TAGS="${TAGS},${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_name }}:${{ env.BRANCH_TAG }}"
TAGS="${TAGS},${{ steps.login.outputs.registry }}/firezone/${{ matrix.image_name }}:${{ github.sha }}"
echo "tags=$TAGS" >> "$GITHUB_OUTPUT"
- name: Build Docker images
uses: docker/build-push-action@v5
with:
platforms: linux/amd64
build-args: ${{ matrix.build-args }}
context: ${{ matrix.context }}/
cache-from: |
type=registry,ref=${{ steps.login.outputs.registry }}/cache/${{ matrix.image_name }}:${{ env.CACHE_TAG }}
type=registry,ref=${{ steps.login.outputs.registry }}/cache/${{ matrix.image_name }}:main
# This will write the cache on main even if integration tests fail,
# but it'll just be corrected on the next successful build.
cache-to: |
type=registry,ref=${{steps.login.outputs.registry}}/cache/${{ matrix.image_name}}:${{ env.CACHE_TAG }},mode=max
file: ${{ matrix.context }}/Dockerfile
push: true
target: ${{ matrix.target }}
tags: ${{ steps.build_docker_tags.outputs.tags }}
snownet-integration-tests:
name: snownet-integration-tests-${{ matrix.name }}
needs: build-images
runs-on: ubuntu-22.04
permissions:
contents: read
id-token: write
pull-requests: write
env:
VERSION: ${{ github.sha }}
strategy:
fail-fast: false
matrix:
include:
- file: docker-compose.lan.yml
name: lan
- file: docker-compose.wan-hp.yml
name: wan-hp
- file: docker-compose.wan-relay.yml
name: wan-relay
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/gcp-docker-login
id: login
with:
project: firezone-staging
- name: Run ${{ matrix.file }} test
run: |
sudo sysctl -w vm.overcommit_memory=1
timeout 600 docker compose -f rust/snownet-tests/${{ matrix.file }} up --exit-code-from dialer --abort-on-container-exit
integration-tests:
name: integration-tests-${{ matrix.test }}
needs: build-images
runs-on: ubuntu-22.04
permissions:
contents: read
id-token: write
pull-requests: write
env:
VERSION: ${{ github.sha }}
strategy:
fail-fast: false
matrix:
test: [
direct-curl-portal-restart,
relayed-curl-portal-restart,
relayed-curl-relay-restart,
direct-curl-portal-down,
relayed-curl-portal-down,
direct-curl-portal-relay-down,
dns-etc-resolvconf,
dns-nm,
systemd/dns-systemd-resolved,
]
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/gcp-docker-login
id: login
with:
project: firezone-staging
- name: Seed database
run: docker compose run elixir /bin/sh -c 'cd apps/domain && mix ecto.seed'
- name: Start docker compose in the background
run: |
# TODO: Order matters here, but it shouldn't. There seems to be some race
# condition involved in letting Docker deterime the start order here.
docker compose up -d dns.httpbin httpbin
docker compose up -d api web
docker compose up -d relay
docker compose up -d gateway
docker compose up -d client
- run: ./scripts/tests/${{ matrix.test }}.sh
- name: Show Client logs
if: "!cancelled()"
run: docker compose logs client
- name: Show Relay logs
if: "!cancelled()"
run: docker compose logs relay
- name: Show Gateway logs
if: "!cancelled()"
run: docker compose logs gateway
- name: Show API logs
if: "!cancelled()"
run: docker compose logs api
perf-tests:
name: perf-tests-${{ matrix.test_name }}
needs: build-images
runs-on: ubuntu-22.04
permissions:
contents: read
id-token: write
pull-requests: write
env:
VERSION: ${{ github.sha }}
strategy:
fail-fast: false
matrix:
test_name:
- direct-tcp-client2server
- direct-tcp-server2client
- direct-udp-client2server
- direct-udp-server2client
- relayed-tcp-client2server
- relayed-tcp-server2client
- relayed-udp-client2server
- relayed-udp-server2client
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/gcp-docker-login
id: login
with:
project: firezone-staging
- name: Seed database
run:
docker compose run elixir /bin/sh -c 'cd apps/domain && mix ecto.seed'
- name: Start docker compose in the background
run: |
# We need to increase the log level to make sure that they don't hold off storm of packets
# generated by UDP tests. Wire is especially chatty.
sed -i 's/^\(\s*\)RUST_LOG:.*$/\1RUST_LOG: wire=error,info/' docker-compose.yml
cat docker-compose.yml | grep RUST_LOG
# Start services in the same order each time for the tests
docker compose up -d iperf3
docker compose up -d api web
docker compose up -d relay
docker compose up -d gateway
docker compose up -d client
- name: 'Performance test: ${{ matrix.test_name }}'
timeout-minutes: 5
env:
TEST_NAME: ${{ matrix.test_name }}
run: ./scripts/tests/perf/${{ matrix.test_name }}.sh
- name: 'Save performance test results: ${{ matrix.test_name }}'
uses: actions/upload-artifact@v4
with:
overwrite: true
name: ${{ matrix.test_name }}-${{ github.ref_name == 'main' && 'main' || github.sha }}-iperf3results
path: ./${{ matrix.test_name }}.json
- name: Show Client logs
if: "!cancelled()"
run: docker compose logs client
- name: Show Client UDP stats
if: "!cancelled()"
run: docker compose exec client cat /proc/net/udp
- name: Show Relay logs
if: "!cancelled()"
run: docker compose logs relay
- name: Show Gateway logs
if: "!cancelled()"
run: docker compose logs gateway
- name: Show Gateway UDP stats
if: "!cancelled()"
run: docker compose exec gateway cat /proc/net/udp
- name: Show API logs
if: "!cancelled()"
run: docker compose logs api
- name: Show iperf3 logs
if: "!cancelled()"
run: docker compose logs iperf3
compare-results:
if: ${{ github.event_name == 'pull_request' }}
needs: perf-tests
runs-on: ubuntu-22.04
permissions:
contents: read
id-token: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Download PR performance test results
uses: actions/download-artifact@v4
with:
pattern: '*-${{ github.sha }}-iperf3results'
merge-multiple: true
path: ./
- name: Get last Continous Delivery workflow run Id
uses: actions/github-script@v7
id: get_last_cd_run
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { data } = await github.rest.actions.listWorkflowRuns({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: "cd.yml",
status: 'success',
per_page: 1
});
return data.workflow_runs[0].id;
- name: Download main branch performance test results
uses: actions/download-artifact@v4
with:
pattern: '*-main-iperf3results'
merge-multiple: true
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ steps.get_last_cd_run.outputs.result }}
path: ./main
- name: Update PR with results
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { script } = require('./scripts/tests/perf/results.js');
script(github, context, [
'direct-tcp-client2server',
'direct-tcp-server2client',
'direct-udp-client2server',
'direct-udp-server2client',
'relayed-tcp-client2server',
'relayed-tcp-server2client',
'relayed-udp-client2server',
'relayed-udp-server2client'
]);