chore: minor updates for encrypted data exchange feature #5413
Workflow file for this run
This file contains hidden or 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: Node Build | |
| on: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: "0 21 * * *" | |
| pull_request: | |
| branches: | |
| - "**" | |
| push: | |
| branches: | |
| - main | |
| - release/v* | |
| jobs: | |
| prerequisite: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: ./.github/workflows/rafiki/env-setup | |
| - run: pnpm checks | |
| - run: pnpm lint:docs | |
| backend: | |
| runs-on: ubuntu-latest | |
| needs: prerequisite | |
| timeout-minutes: 25 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| - uses: ./.github/workflows/rafiki/env-setup | |
| - run: pnpm --filter backend build:deps | |
| - run: NODE_OPTIONS="--max-old-space-size=4096" pnpm --filter backend test:ci | |
| - name: AsyncAPI extension | |
| run: | | |
| echo "{\"extends\":[\"spectral:oas\",\"spectral:asyncapi\"]}" >> .spectral.json | |
| - name: Validate Open API specs | |
| run: | | |
| npx @stoplight/spectral-cli lint ./packages/backend/src/openapi/specs/*.yaml | |
| frontend: | |
| runs-on: ubuntu-latest | |
| needs: prerequisite | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: ./.github/workflows/rafiki/env-setup | |
| - run: pnpm --filter frontend typecheck | |
| - run: pnpm --filter frontend build | |
| auth: | |
| runs-on: ubuntu-latest | |
| needs: prerequisite | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| - uses: ./.github/workflows/rafiki/env-setup | |
| - run: pnpm --filter auth build:deps | |
| - run: pnpm --filter auth test | |
| - name: AsyncAPI extension | |
| run: | | |
| echo "{\"extends\":[\"spectral:oas\",\"spectral:asyncapi\"]}" >> .spectral.json | |
| - name: Validate Open API specs | |
| run: | | |
| npx @stoplight/spectral-cli lint ./packages/auth/src/openapi/specs/*.yaml | |
| token-introspection: | |
| runs-on: ubuntu-latest | |
| needs: prerequisite | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: ./.github/workflows/rafiki/env-setup | |
| - run: pnpm --filter token-introspection test | |
| - name: AsyncAPI extension | |
| run: | | |
| echo "{\"extends\":[\"spectral:oas\",\"spectral:asyncapi\"]}" >> .spectral.json | |
| - name: Validate Open API specs | |
| run: | | |
| npx @stoplight/spectral-cli lint ./packages/token-introspection/src/openapi/specs/*.yaml | |
| card-service: | |
| runs-on: ubuntu-latest | |
| needs: prerequisite | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: ./.github/workflows/rafiki/env-setup | |
| - run: pnpm --filter card-service test:ci | |
| - run: pnpm --filter card-service build | |
| - name: AsyncAPI extension | |
| run: | | |
| echo "{\"extends\":[\"spectral:oas\",\"spectral:asyncapi\"]}" >> .spectral.json | |
| - name: Validate Open API specs | |
| run: | | |
| npx @stoplight/spectral-cli lint ./packages/card-service/src/openapi/specs/*.yaml | |
| point-of-sale: | |
| runs-on: ubuntu-latest | |
| needs: prerequisite | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: ./.github/workflows/rafiki/env-setup | |
| - run: pnpm --filter point-of-sale build | |
| - run: pnpm --filter point-of-sale test:ci | |
| mock-account-servicing-entity: | |
| runs-on: ubuntu-latest | |
| needs: prerequisite | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: ./.github/workflows/rafiki/env-setup | |
| - run: pnpm --filter mock-account-servicing-entity build | |
| - run: pnpm --filter mock-account-servicing-entity typecheck | |
| graphql: | |
| runs-on: ubuntu-latest | |
| needs: prerequisite | |
| strategy: | |
| matrix: | |
| package: [auth, backend] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: ./.github/workflows/rafiki/env-setup | |
| - name: generate ${{ matrix.package }} graphql | |
| run: pnpm --filter ${{ matrix.package }} generate | |
| - name: verify changed files | |
| uses: tj-actions/verify-changed-files@v19 | |
| id: verify-changed-files | |
| with: | |
| files: | | |
| **/generated/graphql.* | |
| - name: fail if GraphQL was generated | |
| if: steps.verify-changed-files.outputs.files_changed == 'true' | |
| run: exit 1 | |
| codeql-analyze: | |
| runs-on: ubuntu-latest | |
| needs: prerequisite | |
| timeout-minutes: 5 | |
| permissions: | |
| actions: read | |
| contents: read | |
| security-events: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| language: ["javascript"] | |
| config: | |
| - "./.github/codeql/source.yml" | |
| - "./.github/codeql/tests.yml" | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: ./.github/workflows/rafiki/env-setup | |
| - name: Initialize CodeQL | |
| uses: github/codeql-action/init@v3 | |
| with: | |
| languages: ${{ matrix.language }} | |
| config-file: ${{ matrix.config }} | |
| - name: Perform CodeQL Analysis | |
| uses: github/codeql-action/analyze@v3 | |
| integration-test: | |
| runs-on: ubuntu-22.04 | |
| needs: prerequisite | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| - name: Setup environment | |
| uses: ./.github/workflows/rafiki/env-setup | |
| - name: Setup hosts | |
| run: | | |
| echo "127.0.0.1 cloud-nine-wallet-test-backend" | sudo tee -a /etc/hosts | |
| echo "127.0.0.1 cloud-nine-wallet-test-auth" | sudo tee -a /etc/hosts | |
| echo "127.0.0.1 cloud-nine-wallet-test-card-service" | sudo tee -a /etc/hosts | |
| echo "127.0.0.1 happy-life-bank-test-backend" | sudo tee -a /etc/hosts | |
| echo "127.0.0.1 happy-life-bank-test-auth" | sudo tee -a /etc/hosts | |
| echo "127.0.0.1 happy-life-bank-test-point-of-sale" | sudo tee -a /etc/hosts | |
| - name: Build dependencies | |
| run: pnpm --filter integration build:deps | |
| - name: Run tests | |
| run: pnpm --filter integration run-tests | |
| performance-test: | |
| runs-on: ubuntu-22.04 | |
| needs: prerequisite | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| - name: Setup environment | |
| uses: ./.github/workflows/rafiki/env-setup | |
| - name: Set up k6 | |
| uses: grafana/setup-k6-action@v1 | |
| - name: Setup hosts | |
| run: | | |
| echo "127.0.0.1 cloud-nine-wallet-test-backend" | sudo tee -a /etc/hosts | |
| echo "127.0.0.1 cloud-nine-wallet-test-card-service" | sudo tee -a /etc/hosts | |
| echo "127.0.0.1 cloud-nine-wallet-test-auth" | sudo tee -a /etc/hosts | |
| echo "127.0.0.1 happy-life-bank-test-backend" | sudo tee -a /etc/hosts | |
| echo "127.0.0.1 happy-life-bank-test-auth" | sudo tee -a /etc/hosts | |
| echo "127.0.0.1 happy-life-bank-test-point-of-sale" | sudo tee -a /etc/hosts | |
| - name: Build dependencies | |
| run: pnpm --filter performance build:deps | |
| - name: Bundle | |
| run: pnpm --filter performance bundle | |
| - name: Start test environment | |
| run: pnpm --filter performance testenv:compose up --wait --build -d | |
| - name: Start Mock Account Entity Services | |
| run: | | |
| pnpm --filter performance start-mases > mases.log 2>&1 & | |
| MASES_PID=$! | |
| sleep 5 | |
| if ! ps -p $MASES_PID > /dev/null; then | |
| echo "Mock Account Entity Services failed to start. Check logs:" | |
| cat mases.log | |
| exit 1 | |
| fi | |
| - name: Run performance tests | |
| id: perf_test | |
| run: | | |
| pnpm --filter performance run-tests:testenv -k -q --vus 4 --duration 1m | tee performance.log | |
| - name: Post/Update Performance Test Results as PR Comment | |
| if: ${{ github.event_name == 'pull_request' }} | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const pr = context.payload.pull_request; | |
| if (!pr) { | |
| console.log("No PR detected, skipping comment."); | |
| return; | |
| } | |
| const sourceOwner = pr.head.repo.owner.login; | |
| const targetOwner = pr.base.repo.owner.login; | |
| if (sourceOwner !== targetOwner) { | |
| console.log("PR is from a fork, skipping automatic comment for security reasons."); | |
| return; | |
| } | |
| const fs = require('fs'); | |
| const summaryPath = './test/performance/k6-test-summary.txt'; | |
| const logPath = './performance.log'; | |
| let summaryContent = ''; | |
| let logContent = ''; | |
| // Read the k6 summary file | |
| if (fs.existsSync(summaryPath)) { | |
| summaryContent = fs.readFileSync(summaryPath, 'utf8'); | |
| } else { | |
| summaryContent = 'Performance test summary not found.'; | |
| } | |
| // Read the full logs | |
| if (fs.existsSync(logPath)) { | |
| logContent = fs.readFileSync(logPath, 'utf8'); | |
| } else { | |
| logContent = 'Performance log not found.'; | |
| } | |
| // Limit in case large file size to avoid error posting comment (65kb limit) | |
| // https://github.com/orgs/community/discussions/41331 | |
| const maxLogSize = 60000; | |
| const truncatedLogs = logContent.length > maxLogSize ? `...(truncated)...\n${logContent.slice(-maxLogSize)}` : logContent; | |
| const commentBody = ` | |
| ### 🚀 Performance Test Results | |
| ${summaryContent} | |
| <details> | |
| <summary>📜 Logs</summary> | |
| \`\`\` | |
| ${truncatedLogs} | |
| \`\`\` | |
| </details> | |
| `; | |
| const { owner, repo } = context.repo; | |
| const prNumber = context.payload.pull_request?.number; | |
| if (prNumber) { | |
| const comments = await github.rest.issues.listComments({ | |
| owner, | |
| repo, | |
| issue_number: prNumber | |
| }); | |
| // Identify existing comment via title | |
| const existingComment = comments.data.find(comment => comment.body.includes('🚀 Performance Test Results')); | |
| if (existingComment) { // upsert comment | |
| await github.rest.issues.updateComment({ | |
| owner, | |
| repo, | |
| comment_id: existingComment.id, | |
| body: commentBody | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner, | |
| repo, | |
| issue_number: prNumber, | |
| body: commentBody | |
| }); | |
| } | |
| } else { | |
| console.log("No PR detected, skipping comment."); | |
| } | |
| node-build: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| needs: | |
| [ | |
| auth, | |
| backend, | |
| frontend, | |
| token-introspection, | |
| card-service, | |
| point-of-sale, | |
| mock-account-servicing-entity, | |
| graphql, | |
| codeql-analyze, | |
| integration-test | |
| ] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: ./.github/workflows/rafiki/env-setup | |
| - run: pnpm build | |
| version-generator: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.version-generator.outputs.NEW_VERSION }} | |
| tagPushed: ${{ steps.version-generator.outputs.SHOULD_PUSH_TAG }} | |
| dockerPush: ${{ steps.version-generator.outputs.PUSH_DOCKER_IMAGE }} | |
| generateRelease: ${{ steps.version-generator.outputs.GENERATE_RELEASE }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| fetch-tags: true | |
| - name: Configure git | |
| run: | | |
| git config --global user.name "github-actions[bot]" | |
| git config --global user.email "github-actions[bot]@users.noreply.github.com" | |
| - id: version-generator | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| SHOULD_PUSH_TAG=false | |
| PUSH_DOCKER_IMAGE=false | |
| GENERATE_RELEASE=false | |
| if [ "${{ github.event_name == 'schedule' }}" = true ]; then | |
| PUSH_DOCKER_IMAGE=true | |
| NEW_VERSION="nightly" | |
| elif [ "${{ github.event_name == 'workflow_dispatch' }}" = true ]; then | |
| NEW_VERSION="$GITHUB_REF_NAME" | |
| if [[ "${{ github.ref_name }}" != "main" ]]; then | |
| PUSH_DOCKER_IMAGE="true" | |
| fi | |
| elif [ "${{ startsWith(github.ref_name, 'release/v')}}" = true ]; then | |
| PUSH_DOCKER_IMAGE=true | |
| SHOULD_PUSH_TAG=true | |
| GENERATE_RELEASE=true | |
| VERSION_PREFIX=$(echo "${{ github.ref_name }}" | sed 's|release/||') | |
| read major minor patch pre_release <<< $(echo "$VERSION_PREFIX" | awk -F'[.v-]' '{print $2, $3, $4, $5}') | |
| version_search="v$major.$minor.*" | |
| if [ -n "$pre_release" ]; then | |
| version_search="$version_search-$pre_release" | |
| fi | |
| echo "VERSION_SEARCH: $version_search" | |
| VERSION_PREFIX=$(git tag -l $version_search --sort=-taggerdate | head -n 1) | |
| if [ -n "$VERSION_PREFIX" ]; then | |
| read major minor patch pre_release <<< $(echo "$VERSION_PREFIX" | awk -F'[.v-]' '{print $2, $3, $4, $5}') | |
| patch=$((patch + 1)) | |
| fi | |
| NEW_VERSION="v${major}.${minor}.${patch}" | |
| if [ -n "$pre_release" ]; then | |
| NEW_VERSION="$NEW_VERSION-${pre_release}" | |
| fi | |
| else | |
| NEW_VERSION=$(echo "${{ github.ref_name }}" | sed 's/[^a-zA-Z0-9_.-]/_/g') | |
| if [[ ! "$NEW_VERSION" =~ ^[a-zA-Z0-9] ]]; then | |
| NEW_VERSION="tag_$NEW_VERSION" | |
| fi | |
| fi | |
| echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_OUTPUT | |
| echo "New version will be: $NEW_VERSION" | |
| echo "SHOULD_PUSH_TAG=$SHOULD_PUSH_TAG" >> $GITHUB_OUTPUT | |
| echo "Will tag be pushed? $SHOULD_PUSH_TAG" | |
| echo "PUSH_DOCKER_IMAGE=$PUSH_DOCKER_IMAGE" >> $GITHUB_OUTPUT | |
| echo "Will docker image be pushed? $PUSH_DOCKER_IMAGE" | |
| echo "GENERATE_RELEASE=$GENERATE_RELEASE" >> $GITHUB_OUTPUT | |
| echo "Will generate release noted? $GENERATE_RELEASE" | |
| if [ "$SHOULD_PUSH_TAG" = true ]; then | |
| git tag -fa $NEW_VERSION -m "$NEW_VERSION" | |
| git push -f origin $NEW_VERSION | |
| fi | |
| docker-build: | |
| runs-on: ${{ matrix.platform.name == 'arm64' && 'ubuntu-22.04-arm' || 'ubuntu-latest' }} | |
| needs: version-generator | |
| timeout-minutes: 10 | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| strategy: | |
| matrix: | |
| platform: | |
| - arch: linux/amd64 | |
| name: amd64 | |
| - arch: linux/arm64 | |
| name: arm64 | |
| package: | |
| - auth | |
| - backend | |
| - frontend | |
| - card-service | |
| - point-of-sale | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| with: | |
| platforms: ${{ matrix.platform.arch }} | |
| - name: Build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| push: false | |
| platforms: ${{ matrix.platform.arch }} | |
| file: packages/${{ matrix.package }}/Dockerfile.prod | |
| tags: ghcr.io/${{ github.repository_owner }}/rafiki-${{ matrix.package }}-${{ matrix.platform.name }}:${{ needs.version-generator.outputs.version }} | |
| outputs: type=docker,dest=/tmp/${{ github.sha }}-${{ matrix.package }}-${{ matrix.platform.name }}-${{ needs.version-generator.outputs.version }}.tar | |
| - name: Save docker image to cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: /tmp/${{ github.sha }}-${{ matrix.package }}-${{ matrix.platform.name }}-${{ needs.version-generator.outputs.version }}.tar | |
| key: ${{ github.sha }}-${{ matrix.package }}-${{ matrix.platform.name }}-${{ needs.version-generator.outputs.version }} | |
| docker-grype: | |
| name: Docker Grype Scan | |
| needs: [version-generator, docker-build] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| strategy: | |
| matrix: | |
| platform: | |
| - arch: linux/amd64 | |
| name: amd64 | |
| - arch: linux/arm64 | |
| name: arm64 | |
| package: | |
| - auth | |
| - backend | |
| - frontend | |
| - card-service | |
| - point-of-sale | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Fetch docker image from cache | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: /tmp/${{ github.sha }}-${{ matrix.package }}-${{ matrix.platform.name }}-${{ needs.version-generator.outputs.version }}.tar | |
| key: ${{ github.sha }}-${{ matrix.package }}-${{ matrix.platform.name }}-${{ needs.version-generator.outputs.version }} | |
| fail-on-cache-miss: true | |
| - name: Docker list | |
| run: | | |
| docker images | |
| - name: Scan docker image | |
| uses: anchore/scan-action@v7 | |
| with: | |
| image: /tmp/${{ github.sha }}-${{ matrix.package }}-${{ matrix.platform.name }}-${{ needs.version-generator.outputs.version }}.tar | |
| fail-build: true | |
| only-fixed: true | |
| severity-cutoff: high | |
| output-format: table | |
| docker-trivy: | |
| name: Docker Trivy Scan | |
| needs: [version-generator, docker-build] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| strategy: | |
| matrix: | |
| platform: | |
| - arch: linux/amd64 | |
| name: amd64 | |
| - arch: linux/arm64 | |
| name: arm64 | |
| package: | |
| - auth | |
| - backend | |
| - frontend | |
| - card-service | |
| - point-of-sale | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Fetch docker image from cache | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: /tmp/${{ github.sha }}-${{ matrix.package }}-${{ matrix.platform.name }}-${{ needs.version-generator.outputs.version }}.tar | |
| key: ${{ github.sha }}-${{ matrix.package }}-${{ matrix.platform.name }}-${{ needs.version-generator.outputs.version }} | |
| fail-on-cache-miss: true | |
| - name: Download Trivy | |
| run: | | |
| curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /tmp | |
| - name: Scan docker image | |
| run: | | |
| docker images | |
| /tmp/trivy image --db-repository ghcr.io/aquasecurity/trivy-db,public.ecr.aws/aquasecurity/trivy-db --java-db-repository ghcr.io/aquasecurity/trivy-java-db,public.ecr.aws/aquasecurity/trivy-java-db --ignore-unfixed --format table --vuln-type os,library --exit-code 1 --severity HIGH --input /tmp/${{ github.sha }}-${{ matrix.package }}-${{ matrix.platform.name }}-${{ needs.version-generator.outputs.version }}.tar | |
| push: | |
| name: Push to registry | |
| needs: [version-generator, docker-grype, docker-trivy, node-build] | |
| runs-on: ubuntu-latest | |
| if: needs.version-generator.outputs.dockerPush == 'true' | |
| strategy: | |
| matrix: | |
| platform: | |
| - arch: linux/amd64 | |
| name: amd64 | |
| - arch: linux/arm64 | |
| name: arm64 | |
| package: | |
| - auth | |
| - backend | |
| - frontend | |
| - card-service | |
| - point-of-sale | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: ./.github/actions/image-push | |
| with: | |
| app_name: rafiki | |
| package: ${{ matrix.package }} | |
| platform_name: ${{ matrix.platform.name }} | |
| version: ${{ needs.version-generator.outputs.version }} | |
| gh_token: ${{ secrets.GITHUB_TOKEN }} | |
| push-manifest: | |
| name: Push multi-arch manifest list | |
| needs: [version-generator, push] | |
| runs-on: ubuntu-latest | |
| if: needs.version-generator.outputs.dockerPush == 'true' | |
| strategy: | |
| matrix: | |
| package: | |
| - auth | |
| - backend | |
| - frontend | |
| - card-service | |
| - point-of-sale | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Push manifest list | |
| uses: ./.github/actions/manifest-push | |
| with: | |
| app_name: rafiki | |
| package: ${{ matrix.package }} | |
| gh_token: ${{ secrets.GITHUB_TOKEN }} | |
| version: ${{ needs.version-generator.outputs.version }} | |
| generate-release: | |
| runs-on: ubuntu-latest | |
| needs: [push-manifest, version-generator] | |
| if: needs.version-generator.outputs.generateRelease == 'true' | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v4 | |
| - name: Generate CHANGELOG data | |
| id: changelog | |
| uses: requarks/changelog-action@v1 | |
| with: | |
| token: ${{ github.token }} | |
| tag: ${{ needs.version-generator.outputs.version }} | |
| includeRefIssues: false | |
| - name: Create Release | |
| uses: ncipollo/release-action@v1.16.0 | |
| with: | |
| allowUpdates: true | |
| draft: false | |
| makeLatest: true | |
| prerelease: endsWith(needs.version-generator.outputs.version, '-alpha') | |
| name: ${{ needs.version-generator.outputs.version }} | |
| body: ${{ steps.changelog.outputs.changes }} | |
| tag: ${{ needs.version-generator.outputs.version }} | |
| token: ${{ github.token }} |