Keycloak Password Policy #348
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: CICD | |
on: | |
workflow_dispatch: | |
inputs: | |
reset-deployments: | |
description: "Reset deployment: Clean start" | |
required: false | |
default: false | |
type: boolean | |
push: | |
branches: | |
- master | |
pull_request: | |
branches: | |
- master | |
release: | |
types: | |
- released | |
env: | |
REGISTRY: ghcr.io/${{ github.repository_owner }} | |
jobs: | |
lint: | |
name: Lint | |
permissions: | |
checks: write | |
contents: write | |
runs-on: ubuntu-latest | |
concurrency: | |
group: ${{ github.workflow }}-lint-${{ matrix.project }}-${{ github.ref }} | |
cancel-in-progress: true | |
strategy: | |
fail-fast: false | |
matrix: | |
project: | |
- api | |
- web | |
include: | |
- project: api | |
dir: ./src/api | |
lang: cs | |
config: | |
auto_fix: false | |
continue_on_error: false | |
check_name: "Dotnet Format (${dir})" | |
dotnet_format: true | |
dotnet_format_dir: ./src/api | |
env: {} | |
- project: web | |
dir: ./src/web | |
lang: js | |
config: | |
auto_fix: false | |
continue_on_error: false | |
check_name: "${linter} (${dir})" | |
# ESLint | |
eslint: true | |
eslint_dir: ./src/web | |
eslint_extensions: js,ts,tsx | |
eslint_args: --ignore-path ../../.gitignore --config .eslintrc.cjs | |
# Prettier | |
prettier: true | |
prettier_dir: ./src/web | |
prettier_extensions: js,ts,tsx | |
prettier_args: --ignore-path ../../.gitignore --config prettier.config.cjs | |
env: | |
SKIP_ENV_VALIDATION: true | |
# outputs: # https://github.com/actions/runner/pull/2477 | |
# ${{ matrix.project }}-changes: ${{ steps.filter.outputs.changes }} | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: dorny/paths-filter@v3 | |
id: filter | |
with: | |
base: master | |
filters: |- | |
changes: | |
- '${{ matrix.dir }}/**' | |
- uses: actions/setup-node@v4 | |
if: (steps.filter.outputs.changes == 'true' || github.event_name == 'workflow_dispatch') && matrix.lang == 'js' | |
with: | |
node-version: 18 | |
cache: yarn | |
cache-dependency-path: ${{ matrix.dir }}/yarn.lock | |
- uses: actions/cache@v4 | |
if: (steps.filter.outputs.changes == 'true' || github.event_name == 'workflow_dispatch') && matrix.lang == 'js' | |
with: | |
path: ${{ matrix.dir }}/node_modules | |
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} | |
- run: yarn install --frozen-lockfile | |
if: (steps.filter.outputs.changes == 'true' || github.event_name == 'workflow_dispatch') && matrix.lang == 'js' | |
working-directory: ${{ matrix.dir }} | |
- uses: actions/setup-dotnet@v4 | |
if: (steps.filter.outputs.changes == 'true' || github.event_name == 'workflow_dispatch') && matrix.lang == 'cs' | |
with: | |
dotnet-version: 8.x | |
- uses: wearerequired/lint-action@v2 | |
if: steps.filter.outputs.changes == 'true' || github.event_name == 'workflow_dispatch' | |
with: ${{ matrix.config }} | |
env: ${{ matrix.env }} | |
build: | |
name: Build and push | |
permissions: | |
contents: read | |
packages: write | |
runs-on: ubuntu-latest | |
concurrency: | |
group: ${{ github.workflow }}-build-${{ matrix.image }}-${{ github.ref }} | |
cancel-in-progress: true | |
needs: | |
- lint | |
outputs: | |
image_version: ${{ steps.meta.outputs.version }} | |
strategy: | |
matrix: | |
image: | |
- yoma-api | |
- yoma-web | |
include: | |
- image: yoma-api | |
context: ./src/api | |
helm: ./helm/yoma-api | |
file: ./src/api/Dockerfile | |
buildArgs: "" | |
- image: yoma-web | |
context: ./src/web | |
helm: ./helm/yoma-web | |
file: ./src/web/Dockerfile | |
buildArgs: |- | |
NEXT_PUBLIC_ENVIRONMENT=production | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: dorny/paths-filter@v3 # https://github.com/actions/runner/pull/2477 | |
id: filter | |
with: | |
base: master | |
filters: |- | |
changes: | |
- '${{ matrix.context }}/**' | |
- '${{ matrix.helm }}/**' | |
- name: Should build? | |
id: should-run | |
run: |- | |
if [ "${{ github.event_name }}" = "release" ] || \ | |
[ "${{ steps.filter.outputs.changes }}" = "true" ] || \ | |
[ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
echo run=true >> $GITHUB_OUTPUT | |
else | |
echo run=false >> $GITHUB_OUTPUT | |
fi | |
- uses: docker/setup-buildx-action@v3 | |
if: steps.should-run.outputs.run == 'true' | |
- uses: docker/login-action@v3 | |
if: steps.should-run.outputs.run == 'true' | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ github.token }} | |
- uses: docker/metadata-action@v5 | |
id: meta | |
with: | |
images: ${{ env.REGISTRY }}/${{ matrix.image }} | |
tags: | | |
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }} | |
type=sha,prefix=pr-${{ github.event.pull_request.number }}-,priority=601,enable=${{ github.event_name == 'pull_request' }} | |
type=sha,prefix={{branch}}-,priority=601,enable=${{ github.event_name != 'pull_request' && github.event_name != 'release' }} | |
type=ref,event=branch,priority=600 | |
type=ref,event=pr | |
type=semver,pattern={{version}} | |
type=semver,pattern={{major}}.{{minor}} | |
- uses: docker/build-push-action@v5 | |
if: steps.should-run.outputs.run == 'true' | |
with: | |
platforms: linux/amd64 # linux/arm64/v8 is a little too slow right now | |
context: ${{ matrix.context }} | |
file: ${{ matrix.file }} | |
push: true | |
tags: ${{ steps.meta.outputs.tags }} | |
labels: ${{ steps.meta.outputs.labels }} | |
cache-from: | | |
type=gha,scope=build-${{ matrix.image }} | |
type=registry,ref=${{ env.REGISTRY }}/${{ matrix.image }}:latest | |
cache-to: type=gha,mode=max,scope=build-${{ matrix.image }} | |
build-args: ${{ matrix.buildArgs }} | |
test-e2e: | |
name: Test (e2e) | |
permissions: | |
id-token: write | |
contents: read | |
packages: read | |
needs: build | |
runs-on: ubuntu-latest | |
env: | |
PUBLIC_S3_ACCESS_KEY: ${{ secrets.PUBLIC_S3_ACCESS_KEY }} | |
PUBLIC_S3_SECRET_KEY: ${{ secrets.PUBLIC_S3_SECRET_KEY }} | |
PRIVATE_S3_ACCESS_KEY: ${{ secrets.PRIVATE_S3_ACCESS_KEY }} | |
PRIVATE_S3_SECRET_KEY: ${{ secrets.PRIVATE_S3_SECRET_KEY }} | |
concurrency: | |
group: ${{ github.workflow }}-e2e-${{ github.ref }} | |
cancel-in-progress: true | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: dorny/paths-filter@v3 # https://github.com/actions/runner/pull/2477 | |
id: filter | |
with: | |
base: master | |
filters: |- | |
api: | |
- './src/api/**' | |
web: | |
- './src/web/**' | |
keycloak: | |
- './src/keycloak/**' | |
cypress: | |
- './cypress/**' | |
- name: Should e2e run? | |
id: should-run | |
run: |- | |
if [ "${{ github.event_name }}" = "release" ] || \ | |
[ "${{ steps.filter.outputs.api }}" = "true" ] || \ | |
[ "${{ steps.filter.outputs.web }}" = "true" ] || \ | |
[ "${{ steps.filter.outputs.keycloak }}" = "true" ] || \ | |
[ "${{ steps.filter.outputs.cypress }}" = "true" ] || \ | |
[ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
echo run=true >> $GITHUB_OUTPUT | |
else | |
echo run=false >> $GITHUB_OUTPUT | |
fi | |
- uses: docker/login-action@v3 | |
if: steps.should-run.outputs.run == 'true' | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ github.token }} | |
- name: Create env file | |
if: steps.should-run.outputs.run == 'true' | |
run: | | |
echo "AWSS3__Buckets__Public__AccessKey=${{ secrets.PUBLIC_S3_ACCESS_KEY }}" >> src/api/env.secrets | |
echo "AWSS3__Buckets__Public__SecretKey=${{ secrets.PUBLIC_S3_SECRET_KEY }}" >> src/api/env.secrets | |
echo "AWSS3__Buckets__Public__BucketName=yoma-v3-public-storage" >> src/api/env.secrets | |
echo "AWSS3__Buckets__Private__AccessKey=${{ secrets.PRIVATE_S3_ACCESS_KEY }}" >> src/api/env.secrets | |
echo "AWSS3__Buckets__Private__SecretKey=${{ secrets.PRIVATE_S3_SECRET_KEY }}" >> src/api/env.secrets | |
echo "AWSS3__Buckets__Private__BucketName=yoma-v3-private-storage" >> src/api/env.secrets | |
echo "AriesCloudAPI__BaseUri=${{ secrets.ARIESCLOUDAPI_BASEURI }}" >> src/api/env.secrets | |
echo "AriesCloudAPI__GroupId=${{ secrets.ARIESCLOUDAPI_GROUPID }}" >> src/api/env.secrets | |
echo "AriesCloudAPI__ProtocolVersion=v2" >> src/api/env.secrets | |
echo "AriesCloudAPI__GovernanceAdmin__ClientId=${{ secrets.ARIESCLOUDAPI_GOVERNANCEADMIN_CLIENTID }}" >> src/api/env.secrets | |
echo "AriesCloudAPI__GovernanceAdmin__ClientSecret=${{ secrets.ARIESCLOUDAPI_GOVERNANCEADMIN_CLIENTSECRET }}" >> src/api/env.secrets | |
echo "AriesCloudAPI__Customer__ClientId=${{ secrets.ARIESCLOUDAPI_CUSTOMER_CLIENTID }}" >> src/api/env.secrets | |
echo "AriesCloudAPI__Customer__ClientSecret=${{ secrets.ARIESCLOUDAPI_CUSTOMER_CLIENTSECRET }}" >> src/api/env.secrets | |
echo "Zlto__Username=${{ secrets.ZLTO_USERNAME }}" >> src/api/env.secrets | |
echo "Zlto__Password=${{ secrets.ZLTO_PASSWORD }}" >> src/api/env.secrets | |
echo "AppSettings__SSIIssuerNameYomaOrganization=${{ secrets.APPSETTINGS_SSIISSUERNAMEYOMAORGANIZATION }}" >> src/api/env.secrets | |
echo "AppSettings__SSISchemaFullNameYoID=${{ secrets.APPSETTINGS_SSISCHEMAFULLNAMEYOID }}" >> src/api/env.secrets | |
- name: Pre-pull images | |
if: steps.should-run.outputs.run == 'true' | |
run: |- | |
docker compose -f ./src/api/docker-compose.yml pull | |
docker compose -f ./src/web/docker-compose.yml pull | |
env: | |
API_TAG: ${{ steps.filter.outputs.api == 'true' && needs.build.outputs.image_version || 'latest' }} | |
YOUTH_TAG: ${{ steps.filter.outputs.web == 'true' && needs.build.outputs.image_version || 'latest' }} | |
continue-on-error: true | |
- name: Start services | |
if: steps.should-run.outputs.run == 'true' | |
run: |- | |
docker compose -f ./src/api/docker-compose.yml up -d | |
docker compose -f ./src/web/docker-compose.yml up -d | |
env: | |
API_TAG: ${{ steps.filter.outputs.api == 'true' && needs.build.outputs.image_version || 'latest' }} | |
YOUTH_TAG: ${{ steps.filter.outputs.web == 'true' && needs.build.outputs.image_version || 'latest' }} | |
- uses: actions/setup-node@v4 | |
if: steps.should-run.outputs.run == 'true' | |
with: | |
node-version: 18 | |
cache: yarn | |
- uses: cypress-io/github-action@v6 | |
if: steps.should-run.outputs.run == 'true' | |
- name: Upload Cypress Screenshots | |
uses: actions/upload-artifact@v4 | |
if: always() | |
with: | |
name: cypress-screenshots | |
path: cypress/screenshots | |
if-no-files-found: ignore | |
- name: Upload Cypress Recording | |
uses: actions/upload-artifact@v4 | |
if: always() | |
with: | |
name: cypress-videos | |
path: cypress/videos | |
if-no-files-found: ignore | |
- name: Keycloak Config logs | |
if: always() && steps.should-run.outputs.run == 'true' | |
run: docker logs keycloak-config | |
- name: Keycloak logs | |
if: always() && steps.should-run.outputs.run == 'true' | |
run: docker logs keycloak | |
- name: Yoma API logs | |
if: always() && steps.should-run.outputs.run == 'true' | |
run: docker logs yoma-api | |
- name: Yoma Web logs | |
if: always() && steps.should-run.outputs.run == 'true' | |
run: docker logs yoma-web | |
- run: docker compose down -v | |
deploy: | |
name: Deploy | |
permissions: | |
id-token: write | |
contents: read | |
packages: read | |
needs: [test-e2e, build] | |
runs-on: ubuntu-latest | |
env: | |
TAILSCALE_VERSION: 1.64.0 | |
HELMFILE_VERSION: v0.163.1 | |
HELM_VERSION: v3.14.4 | |
TAG: ${{ needs.build.outputs.image_version }} | |
concurrency: | |
group: ${{ github.workflow }}-deploy-${{ github.event_name == 'release' && 'prod' || (github.event_name == 'push' && github.event.repository.default_branch == github.ref_name) && 'stage' || 'dev' }} | |
cancel-in-progress: false | |
environment: | |
name: ${{ | |
github.event.inputs.reset-deployments == 'true' && 'dev' || | |
github.event_name == 'release' && 'prod' || | |
(github.event_name == 'push' && github.event.repository.default_branch == github.ref_name) && 'stage' || | |
'dev' | |
}} | |
url: ${{ vars.PUBLIC_URL }} | |
if: github.triggering_actor != 'dependabot[bot]' | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: dorny/paths-filter@v3 # https://github.com/actions/runner/pull/2477 | |
id: filter | |
with: | |
base: master | |
filters: |- | |
api: | |
- './src/api/**' | |
- './helm/yoma-api/**' | |
web: | |
- './src/web/**' | |
- './helm/yoma-web/**' | |
keycloak: | |
- './src/keycloak/**' | |
- './helm/keycloak/**' | |
- name: Should deploy? | |
id: should-run | |
run: |- | |
if [ "${{ github.event_name }}" = "release" ] || \ | |
[ "${{ steps.filter.outputs.api }}" = "true" ] || \ | |
[ "${{ steps.filter.outputs.web }}" = "true" ] || \ | |
[ "${{ steps.filter.outputs.keycloak }}" = "true" ] || \ | |
[ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
echo run=true >> $GITHUB_OUTPUT | |
else | |
echo run=false >> $GITHUB_OUTPUT | |
fi | |
- uses: unfor19/install-aws-cli-action@v1 | |
if: steps.should-run.outputs.run == 'true' | |
- name: SOPS Binary Installer | |
if: steps.should-run.outputs.run == 'true' | |
uses: mdgreenwald/mozilla-sops-action@v1.6.0 | |
- uses: aws-actions/configure-aws-credentials@v4 | |
if: steps.should-run.outputs.run == 'true' | |
with: | |
aws-region: ${{ secrets.AWS_REGION }} | |
role-to-assume: ${{ secrets.AWS_ROLE_ARN }} | |
role-session-name: github-cicd | |
- run: aws eks update-kubeconfig --name ${{ secrets.CLUSTER }} | |
if: steps.should-run.outputs.run == 'true' | |
- uses: tailscale/github-action@main | |
if: steps.should-run.outputs.run == 'true' | |
with: | |
authkey: ${{ secrets.TAILSCALE_AUTHKEY }} | |
version: ${{ env.TAILSCALE_VERSION }} | |
- name: Helmfile Destroy | |
if: github.event.inputs.reset-deployments == 'true' | |
uses: helmfile/helmfile-action@v1.9.0 | |
with: | |
helmfile-args: | | |
destroy \ | |
--environment dev | |
helm-plugins: | | |
https://github.com/databus23/helm-diff, | |
https://github.com/jkroepke/helm-secrets, | |
https://github.com/aslafy-z/helm-git | |
helmfile-version: ${{ env.HELMFILE_VERSION }} | |
helm-version: ${{ env.HELM_VERSION }} | |
- name: Delete Pods and PVCs | |
if: github.event.inputs.reset-deployments == 'true' | |
run: kubectl delete pods,pvc --all --namespace yoma-v3-dev | |
- name: Deploy fresh DBs | |
if: github.event.inputs.reset-deployments == 'true' | |
uses: helmfile/helmfile-action@v1.9.0 | |
with: | |
helmfile-args: | | |
apply \ | |
--environment dev \ | |
--selector=app=postgresql-keycloak \ | |
--selector=app=postgresql \ | |
--selector=app=redis | |
helm-plugins: | | |
https://github.com/databus23/helm-diff, | |
https://github.com/jkroepke/helm-secrets, | |
https://github.com/aslafy-z/helm-git | |
# Diff on PR draft, otherwise Apply | |
- name: Helmfile Apply/Diff Keycloak | |
if: ( | |
github.event_name == 'release' || | |
steps.filter.outputs.keycloak == 'true' || | |
github.event_name == 'workflow_dispatch' | |
) && steps.should-run.outputs.run == 'true' | |
uses: helmfile/helmfile-action@v1.9.0 | |
with: | |
helmfile-args: | | |
${{ (github.event_name == 'pull_request' && github.event.pull_request.draft) && 'diff' || 'apply' }} \ | |
--environment ${{ vars.ENVIRONMENT }} \ | |
--selector app=keycloak \ | |
--set config-cli.init.ref=${{ github.event_name == 'release' && github.ref_name || github.sha }} \ | |
--set keycloak.themes.ref=${{ github.event_name == 'release' && github.ref_name || github.sha }} \ | |
--set postInstallHook.ref=${{ github.event_name == 'release' && github.ref_name || github.sha }} | |
helmfile-version: ${{ env.HELMFILE_VERSION }} | |
helm-version: ${{ env.HELM_VERSION }} | |
helm-plugins: | | |
https://github.com/databus23/helm-diff, | |
https://github.com/jkroepke/helm-secrets, | |
https://github.com/aslafy-z/helm-git | |
- name: Helmfile Apply/Diff API | |
if: ( | |
github.event_name == 'release' || | |
steps.filter.outputs.api == 'true' || | |
github.event_name == 'workflow_dispatch' | |
) && steps.should-run.outputs.run == 'true' | |
uses: helmfile/helmfile-action@v1.9.0 | |
with: | |
helmfile-args: | | |
${{ (github.event_name == 'pull_request' && github.event.pull_request.draft) && 'diff' || 'apply' }} \ | |
--environment ${{ vars.ENVIRONMENT }} \ | |
--selector app=yoma-api \ | |
--set postInstallHook.ref=${{ github.event_name == 'release' && github.ref_name || github.sha }} | |
helmfile-version: ${{ env.HELMFILE_VERSION }} | |
helm-version: ${{ env.HELM_VERSION }} | |
helm-plugins: | | |
https://github.com/databus23/helm-diff, | |
https://github.com/jkroepke/helm-secrets, | |
https://github.com/aslafy-z/helm-git | |
- name: Helmfile Apply/Diff Web | |
if: ( | |
github.event_name == 'release' || | |
steps.filter.outputs.web == 'true' || | |
github.event_name == 'workflow_dispatch' | |
) && steps.should-run.outputs.run == 'true' | |
uses: helmfile/helmfile-action@v1.9.0 | |
with: | |
helmfile-args: | | |
${{ (github.event_name == 'pull_request' && github.event.pull_request.draft) && 'diff' || 'apply' }} \ | |
--environment ${{ vars.ENVIRONMENT }} \ | |
--selector app=yoma-web | |
helmfile-version: ${{ env.HELMFILE_VERSION }} | |
helm-version: ${{ env.HELM_VERSION }} | |
helm-plugins: | | |
https://github.com/databus23/helm-diff, | |
https://github.com/jkroepke/helm-secrets, | |
https://github.com/aslafy-z/helm-git |