diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml deleted file mode 100644 index 6f689301a4..0000000000 --- a/.github/workflows/docker.yml +++ /dev/null @@ -1,60 +0,0 @@ -on: - push: - branches: - - '**' - tags: - - '*' - -name: Build / Release Docker Images - -jobs: - build: - runs-on: ubuntu-22.04 - if: ${{ github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags/') }} - strategy: - matrix: - package: [auth, backend, frontend] - steps: - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Build - uses: docker/build-push-action@v5 - with: - push: false - file: packages/${{ matrix.package }}/Dockerfile - cache-from: type=gha - cache-to: type=gha,mode=max - - build-and-push: - runs-on: ubuntu-22.04 - if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') }} - strategy: - matrix: - package: [auth, backend, frontend] - steps: - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - images: ghcr.io/${{ github.repository_owner }}/rafiki-${{ matrix.package }} - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Login to GHCR - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push - uses: docker/build-push-action@v5 - with: - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - file: packages/${{ matrix.package }}/Dockerfile - platforms: linux/amd64,linux/arm64 - cache-from: type=gha - cache-to: type=gha,mode=max - diff --git a/.github/workflows/lint_test_build.yml b/.github/workflows/lint_test_build.yml deleted file mode 100644 index f67949a766..0000000000 --- a/.github/workflows/lint_test_build.yml +++ /dev/null @@ -1,155 +0,0 @@ -on: - push: - branches: - - '!main' - pull_request: - types: - - opened - - synchronize - -name: PR Checks - -jobs: - checkout: - runs-on: ubuntu-22.04 - timeout-minutes: 3 - steps: - - uses: actions/checkout@v4 - - uses: ./.github/workflows/rafiki/env-setup - - run: pnpm checks - - graphql: - runs-on: ubuntu-22.04 - needs: checkout - steps: - - uses: actions/checkout@v4 - - uses: ./.github/workflows/rafiki/env-setup - - - name: generate backend graphql - run: pnpm --filter backend generate - - name: generate auth graphql - run: pnpm --filter auth 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 - - backend: - runs-on: ubuntu-22.04 - needs: [checkout] - timeout-minutes: 25 - steps: - - uses: actions/checkout@v4 - - 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/openapi/specs/webhooks.yaml - - frontend: - runs-on: ubuntu-22.04 - needs: checkout - 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-22.04 - needs: [checkout] - timeout-minutes: 5 - steps: - - uses: actions/checkout@v4 - - 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/openapi/specs/id-provider.yaml - - mock-account-servicing-entity: - runs-on: ubuntu-22.04 - needs: checkout - 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 - - token-introspection: - runs-on: ubuntu-22.04 - needs: checkout - 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/openapi/specs/token-introspection.yaml - - integration-test: - runs-on: ubuntu-22.04 - needs: checkout - timeout-minutes: 5 - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - 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 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 - - - name: Build dependencies - run: pnpm --filter integration build:deps - - - name: Run tests - run: pnpm --filter integration run-tests - - build: - runs-on: ubuntu-22.04 - timeout-minutes: 5 - needs: - - backend - - frontend - - auth - - mock-account-servicing-entity - - token-introspection - steps: - - uses: actions/checkout@v4 - - uses: ./.github/workflows/rafiki/env-setup - - run: pnpm build - - all_pr_checks_passed: - runs-on: ubuntu-22.04 - needs: - - build - - integration-test - steps: - - run: echo 'PR Checks Passed' diff --git a/.github/workflows/node-build.yml b/.github/workflows/node-build.yml new file mode 100644 index 0000000000..be9a4e7ce2 --- /dev/null +++ b/.github/workflows/node-build.yml @@ -0,0 +1,367 @@ +name: Node Build + +on: + workflow_dispatch: + pull_request: + branches: + - '**' + push: + branches: + - main + - release/v* + +jobs: + prerequisite: + runs-on: ubuntu-latest + timeout-minutes: 1 + steps: + - uses: actions/checkout@v4 + - uses: ./.github/workflows/rafiki/env-setup + - run: pnpm checks + + backend: + runs-on: ubuntu-latest + needs: prerequisite + timeout-minutes: 25 + steps: + - uses: actions/checkout@v4 + - 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 + - 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 + + 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 + + - 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 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 + - name: Build dependencies + run: pnpm --filter integration build:deps + + - name: Run tests + run: pnpm --filter integration run-tests + + node-build: + runs-on: ubuntu-latest + timeout-minutes: 5 + needs: [auth, backend, frontend, token-introspection, 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 + if: startsWith(github.ref_name, 'release/v') + outputs: + version: ${{ steps.version-generator.outputs.NEW_VERSION }} + 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: | + 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 + + echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "New version will be: $NEW_VERSION" + + git tag -a $NEW_VERSION -m "$NEW_VERSION" + git push origin $NEW_VERSION + + docker-build-branch: + runs-on: ubuntu-latest + needs: prerequisite + if: ${{ !startsWith(github.ref_name, 'release/v') }} + timeout-minutes: 5 + strategy: + matrix: + package: [auth, backend, frontend] + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build linux/amd64 + uses: docker/build-push-action@v5 + with: + push: false + platforms: linux/amd64 + file: packages/${{ matrix.package }}/Dockerfile + tags: ghcr.io/${{ github.repository_owner }}/rafiki-${{ matrix.package }}:${{ github.workflow_sha }} + + docker-build: + runs-on: ubuntu-latest + needs: version-generator + timeout-minutes: 5 + strategy: + matrix: + package: [auth, backend, frontend] + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build linux/amd64 + if: ${{ !startsWith(github.ref_name, 'release/v') }} + uses: docker/build-push-action@v5 + with: + push: false + platforms: linux/amd64 + file: packages/${{ matrix.package }}/Dockerfile + tags: ghcr.io/${{ github.repository_owner }}/rafiki-${{ matrix.package }}:${{ needs.version-generator.outputs.version }} + outputs: type=docker,dest=/tmp/${{ matrix.package }}.tar + - name: Build linux/amd64 & linux/arm64 + uses: docker/build-push-action@v5 + with: + push: false + platforms: linux/amd64,linux/arm64 + file: packages/${{ matrix.package }}/Dockerfile + tags: ghcr.io/${{ github.repository_owner }}/rafiki-${{ matrix.package }}:${{ needs.version-generator.outputs.version }} + outputs: type=docker,dest=/tmp/${{ matrix.package }}.tar + - name: Save docker image to cache + uses: actions/cache@v4 + with: + path: /tmp/${{ matrix.package }}.tar + key: ${{ github.sha }} + + docker-grype: + name: Docker Grype Scan + needs: docker-build + runs-on: ubuntu-latest + timeout-minutes: 5 + strategy: + matrix: + package: [auth, backend, frontend] + steps: + - name: Fetch docker image from cache + uses: actions/cache/restore@v4 + with: + path: /tmp/${{ matrix.package }}.tar + key: ${{ github.sha }} + - name: Scan docker image + uses: anchore/scan-action@v3 + with: + image: /tmp/${{ matrix.package }}.tar + fail-build: true + only-fixed: true + severity-cutoff: high + output-format: table + + docker-trivy: + name: Docker Trivy Scan + needs: [docker-build] + runs-on: ubuntu-latest + timeout-minutes: 5 + strategy: + matrix: + package: [auth, backend, frontend] + steps: + - name: Fetch docker image from cache + uses: actions/cache/restore@v4 + with: + path: /tmp/${{ matrix.package }}.tar + key: ${{ github.sha }} + - 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: | + /tmp/trivy image --ignore-unfixed --format table --vuln-type os,library --exit-code 1 --severity HIGH --input /tmp/${{ matrix.package }}.tar + + push: + name: Push to registry + needs: [docker-grype, docker-trivy, version-generator, node-build] + runs-on: ubuntu-latest + + strategy: + matrix: + package: [auth, backend, frontend] + + steps: + - name: Fetch docker image from cache + uses: actions/cache/restore@v4 + with: + path: /tmp/${{ matrix.package }}.tar + key: ${{ github.sha }} + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Load image into Docker + run: | + docker load --input /tmp/${{ matrix.package }}.tar + - name: List docker images + run: docker images + - name: Push to registry + run: | + docker push ghcr.io/${{ github.repository_owner }}/rafiki-${{ matrix.package }}:${{ needs.version-generator.outputs.version }} + + generate-release: + runs-on: ubuntu-latest + needs: [push, version-generator] + 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 }} + - name: Create Release + uses: ncipollo/release-action@v1.14.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 }} diff --git a/.github/workflows/pr_title_check.yml b/.github/workflows/pr_title_check.yml index 94ec0501f4..c0766ba74e 100644 --- a/.github/workflows/pr_title_check.yml +++ b/.github/workflows/pr_title_check.yml @@ -2,7 +2,9 @@ name: Check PR title on: pull_request: - branches: ["**"] + branches: + - '**' + - '!release/v*' jobs: check-pr-title: diff --git a/.github/workflows/rafiki/env-setup/action.yml b/.github/workflows/rafiki/env-setup/action.yml index ff784ca7ec..bc4a77cb77 100644 --- a/.github/workflows/rafiki/env-setup/action.yml +++ b/.github/workflows/rafiki/env-setup/action.yml @@ -4,10 +4,10 @@ description: "Sets node version, init pnpm, restore cache" runs: using: "composite" steps: - - uses: pnpm/action-setup@v2 + - uses: pnpm/action-setup@v3 - uses: actions/setup-node@v4 with: - node-version: '18' + node-version: '20' cache: 'pnpm' - name: Install dependencies shell: bash diff --git a/README.md b/README.md index e074b8b83d..9f6036a364 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,9 @@ Never heard of Interledger before? Or would you like to learn more? Here are som Please read the [contribution guidelines](.github/contributing.md) before submitting contributions. All contributions must adhere to our [code of conduct](.github/code_of_conduct.md). -## Planning Calls +## Community Calls -Our planning calls are open to our community. We have them every Tuesday at 14:30 GMT, via Google Meet. +Our Rafiki community calls are open to our community members. We have them every Tuesday at 14:30 GMT, via Google Meet. **Google Meet joining info** diff --git a/localenv/mock-account-servicing-entity/Dockerfile b/localenv/mock-account-servicing-entity/Dockerfile index 4288fbb900..e0d4b95497 100644 --- a/localenv/mock-account-servicing-entity/Dockerfile +++ b/localenv/mock-account-servicing-entity/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18-alpine3.18 AS base +FROM node:20-alpine3.18 AS base WORKDIR /home/rafiki @@ -42,7 +42,7 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store \ --frozen-lockfile RUN pnpm --filter mock-account-servicing-entity build -FROM node:18-alpine3.18 AS runner +FROM node:20-alpine3.18 AS runner WORKDIR /home/rafiki diff --git a/localenv/mock-account-servicing-entity/package.json b/localenv/mock-account-servicing-entity/package.json index 001d92a63c..c052f2d83d 100644 --- a/localenv/mock-account-servicing-entity/package.json +++ b/localenv/mock-account-servicing-entity/package.json @@ -30,6 +30,6 @@ "@types/react-dom": "^18.2.22" }, "engines": { - "node": "18" + "node": "20" } } diff --git a/package.json b/package.json index fecb0765e6..0593a8de79 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "license": "Apache-2.0", "repository": "https://github.com/interledger/rafiki", "engines": { - "pnpm": "^8.15.5", - "node": "18" + "pnpm": "^8.15.4", + "node": "20" }, "packageManager": "pnpm@8.15.5", "scripts": { diff --git a/packages/auth/Dockerfile b/packages/auth/Dockerfile index 867cf8d38c..0d1bad0089 100644 --- a/packages/auth/Dockerfile +++ b/packages/auth/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18-alpine3.18 AS base +FROM node:20-alpine3.18 AS base WORKDIR /home/rafiki @@ -43,7 +43,7 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store \ --frozen-lockfile RUN pnpm --filter auth build -FROM node:18-alpine3.18 AS runner +FROM node:20-alpine3.18 AS runner WORKDIR /home/rafiki diff --git a/packages/backend/Dockerfile b/packages/backend/Dockerfile index b236417d10..8547a723ea 100644 --- a/packages/backend/Dockerfile +++ b/packages/backend/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18-alpine3.18 AS base +FROM node:20-alpine3.18 AS base WORKDIR /home/rafiki @@ -43,7 +43,7 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store \ --frozen-lockfile RUN pnpm --filter backend build -FROM node:18-alpine3.18 AS runner +FROM node:20-alpine3.18 AS runner WORKDIR /home/rafiki diff --git a/packages/frontend/Dockerfile b/packages/frontend/Dockerfile index 15679eae4f..90331dbe40 100644 --- a/packages/frontend/Dockerfile +++ b/packages/frontend/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18-alpine3.18 AS base +FROM node:20-alpine3.18 AS base WORKDIR /home/rafiki @@ -40,7 +40,7 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store \ --frozen-lockfile RUN pnpm --filter frontend build -FROM node:18-alpine3.18 AS runner +FROM node:20-alpine3.18 AS runner WORKDIR /home/rafiki diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 416aebfd85..ca81b979d4 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -40,6 +40,6 @@ "tailwindcss": "^3.4.1" }, "engines": { - "node": "18" + "node": "20" } } diff --git a/renovate.json b/renovate.json index e54f6ab95e..e0377abd3b 100644 --- a/renovate.json +++ b/renovate.json @@ -16,7 +16,7 @@ "packageRules": [ { "matchPackageNames": ["@types/node", "node"], - "allowedVersions": "<17.0.0" + "allowedVersions": "<21.0.0" } ] }