CodeQL has started scanning GitHub Actions workflows as well. It's not a major issue, but it's good to follow best practices. https://github.com/ubicloud/ubicloud/security/code-scanning/11 Workflow does not contain permissions If a GitHub Actions job or workflow has no explicit permissions set, then the repository permissions are used. Repositories created under organizations inherit the organization permissions. The organizations or repositories created before February 2023 have the default permissions set to read-write. Often these permissions do not adhere to the principle of least privilege and can be reduced to read-only, leaving the write permission only to a specific types as issues: write or pull-requests: write.
166 lines
6.7 KiB
YAML
166 lines
6.7 KiB
YAML
name: E2E CI
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
test_cases:
|
|
description: 'Comma-separated list of test cases (vm)'
|
|
required: true
|
|
default: 'vm,github_runner_ubuntu_2404,github_runner_ubuntu_2204,github_runner_ubuntu_2004,postgres_standard,postgres_ha'
|
|
type: string
|
|
|
|
schedule:
|
|
- cron: '0 */2 * * *'
|
|
|
|
jobs:
|
|
run-ci:
|
|
if: vars.RUN_E2E == 'true'
|
|
runs-on: ubicloud
|
|
environment: E2E-CI
|
|
timeout-minutes: 55
|
|
concurrency: e2e_environment
|
|
|
|
env:
|
|
DB_USER: clover
|
|
DB_PASSWORD: nonempty
|
|
DB_NAME: clover_test
|
|
|
|
services:
|
|
postgres:
|
|
image: postgres:15.4
|
|
env:
|
|
POSTGRES_USER: ${{ env.DB_USER }}
|
|
POSTGRES_PASSWORD: ${{ env.DB_PASSWORD }}
|
|
POSTGRES_DB: ${{ env.DB_NAME }}
|
|
ports:
|
|
- 5432:5432
|
|
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
|
|
|
|
steps:
|
|
- name: Perform superuser-only actions, then remove superuser
|
|
run: |
|
|
psql "postgres://${{ env.DB_USER }}:${{ env.DB_PASSWORD }}@localhost:5432/${{ env.DB_NAME }}" \
|
|
-c "CREATE EXTENSION citext; CREATE EXTENSION btree_gist; CREATE ROLE clover_password PASSWORD '${{ env.DB_PASSWORD }}' LOGIN; ALTER ROLE ${{ env.DB_USER }} NOSUPERUSER"
|
|
|
|
- name: Check out code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Ruby
|
|
uses: ruby/setup-ruby@v1
|
|
with:
|
|
ruby-version: .tool-versions
|
|
bundler-cache: true
|
|
|
|
- name: Apply migrations
|
|
env:
|
|
CLOVER_DATABASE_URL: postgres://${{ env.DB_USER }}:${{ env.DB_PASSWORD }}@localhost:5432/${{ env.DB_NAME }}
|
|
run: bundle exec rake _test_up
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version-file: "package.json"
|
|
cache: "npm"
|
|
|
|
- name: Install node packages
|
|
run: npm ci
|
|
|
|
- name: Build assets
|
|
run: npm run prod
|
|
|
|
- name: Install cloudflared
|
|
run: curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb && sudo dpkg -i cloudflared.deb
|
|
|
|
- name: Set cloudflared token
|
|
run: sudo cloudflared service install ${{ secrets.CLOUDFLARED_TOKEN }}
|
|
|
|
- name: Install foreman
|
|
run: gem install foreman
|
|
|
|
- name: Modify Procfile to add retry logic
|
|
run: |
|
|
sed -i "s/^\([^:]*\): \(.*\)/\1: bash -c 'for i in {1..4}; do \2 \&\& break || echo \"Attempt \$i failed, retrying...\"; sleep 1; done'/" Procfile
|
|
|
|
- name: Add e2e script to Procfile
|
|
run: |
|
|
test_cases="$(yq -r '[.[].name] | join(",")' config/e2e_test_cases.yml)"
|
|
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
|
test_cases="${{ inputs.test_cases }}"
|
|
fi
|
|
echo "Running e2e test cases: $test_cases"
|
|
echo "e2e: bin/ci --test-cases=$test_cases" >> Procfile
|
|
|
|
- name: Run tests
|
|
env:
|
|
BASE_URL: https://${{ secrets.CLOUDFLARED_ADDRESS }}
|
|
RACK_ENV: production
|
|
IS_E2E: "true"
|
|
CLOVER_DATABASE_URL: postgres://${{ env.DB_USER }}:${{ env.DB_PASSWORD }}@localhost:5432/${{ env.DB_NAME }}
|
|
CLOVER_SESSION_SECRET: kbaf1V3biZ+R2QqFahgDLB5/lSomwxQusA4PwROUkFS1srn0xM/I47IdLW7HjbQoxWri6/aVgtkqTLFiP65h9g==
|
|
CLOVER_RUNTIME_TOKEN_SECRET: r3rV5RzYVpDMlXxY1VnrHlmoMnXdUVt5ABec/TWXnmO7Ok/riFRDNATAMmDWTvtH+cSyXAniH3hHL6EetHj/FA==
|
|
CLOVER_COLUMN_ENCRYPTION_KEY: TtlY0+hd4lvedPkNbu5qsj5H7giPKJSRX9KDBrvid7c=
|
|
CI_HETZNER_SACRIFICIAL_SERVER_ID: ${{ secrets.CI_HETZNER_SACRIFICIAL_SERVER_ID }}
|
|
HETZNER_USER: ${{ secrets.HETZNER_USER }}
|
|
HETZNER_PASSWORD: ${{ secrets.HETZNER_PASSWORD }}
|
|
UBICLOUD_IMAGES_BLOB_STORAGE_ENDPOINT: ${{ secrets.UBICLOUD_IMAGES_BLOB_STORAGE_ENDPOINT }}
|
|
UBICLOUD_IMAGES_BLOB_STORAGE_ACCESS_KEY: ${{ secrets.UBICLOUD_IMAGES_BLOB_STORAGE_ACCESS_KEY }}
|
|
UBICLOUD_IMAGES_BLOB_STORAGE_SECRET_KEY: ${{ secrets.UBICLOUD_IMAGES_BLOB_STORAGE_SECRET_KEY }}
|
|
UBICLOUD_IMAGES_BLOB_STORAGE_CERTS: ${{ secrets.UBICLOUD_IMAGES_BLOB_STORAGE_CERTS }}
|
|
GITHUB_APP_NAME: ${{ secrets.GH_APP_NAME }}
|
|
GITHUB_APP_ID: ${{ secrets.GH_APP_ID }}
|
|
GITHUB_APP_CLIENT_ID: ${{ secrets.GH_APP_CLIENT_ID }}
|
|
GITHUB_APP_CLIENT_SECRET: ${{ secrets.GH_APP_CLIENT_SECRET }}
|
|
GITHUB_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
|
GITHUB_APP_WEBHOOK_SECRET: ${{ secrets.GH_APP_WEBHOOK_SECRET }}
|
|
GITHUB_RUNNER_SERVICE_PROJECT_ID: ${{ secrets.GH_RUNNER_SERVICE_PROJECT_ID }}
|
|
GITHUB_CACHE_BLOB_STORAGE_ENDPOINT: ${{ secrets.GH_CACHE_BLOB_STORAGE_ENDPOINT }}
|
|
GITHUB_CACHE_BLOB_STORAGE_REGION: ${{ secrets.GH_CACHE_BLOB_STORAGE_REGION }}
|
|
GITHUB_CACHE_BLOB_STORAGE_ACCESS_KEY: ${{ secrets.GH_CACHE_BLOB_STORAGE_ACCESS_KEY }}
|
|
GITHUB_CACHE_BLOB_STORAGE_SECRET_KEY: ${{ secrets.GH_CACHE_BLOB_STORAGE_SECRET_KEY }}
|
|
GITHUB_CACHE_BLOB_STORAGE_ACCOUNT_ID: ${{ secrets.GH_CACHE_BLOB_STORAGE_ACCOUNT_ID }}
|
|
GITHUB_CACHE_BLOB_STORAGE_API_KEY: ${{ secrets.GH_CACHE_BLOB_STORAGE_API_KEY }}
|
|
POSTGRES_SERVICE_PROJECT_ID: "546a1ed8-53e5-86d2-966c-fb782d2ae5ab"
|
|
MINIO_SERVICE_PROJECT_ID: "37ad2a8d-0220-4e8b-a67f-38db95d6c657"
|
|
VM_POOL_PROJECT_ID: ${{ secrets.VM_POOL_PROJECT_ID }}
|
|
E2E_GITHUB_INSTALLATION_ID: ${{ secrets.E2E_GH_INSTALLATION_ID }}
|
|
HETZNER_SSH_PUBLIC_KEY: ${{ secrets.HETZNER_SSH_PUBLIC_KEY }}
|
|
HETZNER_SSH_PRIVATE_KEY: ${{ secrets.HETZNER_SSH_PRIVATE_KEY }}
|
|
run: |
|
|
set -o pipefail
|
|
timeout 50m foreman start | tee foreman.log | grep "e2e.1"
|
|
|
|
- name: Print logs
|
|
if: always()
|
|
run: grep -h -v -E "sleep_duration_sec|monitor.1" foreman.log
|
|
|
|
- name: Upload logs
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: e2e-${{ github.run_id }}-logs
|
|
path: foreman.log
|
|
|
|
- name: Send notification if failed
|
|
if: ${{ failure() && github.ref_name == 'main' }}
|
|
uses: slackapi/slack-github-action@v2.0.0
|
|
with:
|
|
webhook: ${{ secrets.SLACK_WEBHOOK_PAGER_URL }}
|
|
webhook-type: incoming-webhook
|
|
payload: |
|
|
text: "*E2E Tests Failed* :this-is-fine-fire:"
|
|
attachments:
|
|
- color: "E33122"
|
|
fields:
|
|
- title: "Event"
|
|
short: true
|
|
value: "${{ github.event_name }}"
|
|
- title: "Reference"
|
|
short: true
|
|
value: "<${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}|${{ github.ref_name }}>"
|
|
- title: "Action"
|
|
short: false
|
|
value: "<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ github.workflow }}>"
|