| 1 | # Interoperability Tests |
| 2 | # |
| 3 | # This workflow ensures Kubo remains compatible with the broader IPFS ecosystem. |
| 4 | # It builds Kubo from source, then runs: |
| 5 | # |
| 6 | # 1. helia-interop: Tests compatibility with Helia (JavaScript IPFS implementation) |
| 7 | # using Playwright-based tests from @helia/interop package. |
| 8 | # |
| 9 | # 2. ipfs-webui: Runs E2E tests from ipfs/ipfs-webui repository to verify |
| 10 | # the web interface works correctly with the locally built Kubo binary. |
| 11 | # |
| 12 | # Both jobs use caching to speed up repeated runs (npm dependencies, Playwright |
| 13 | # browsers, and webui build artifacts). |
| 14 | |
| 15 | name: Interop |
| 16 | |
| 17 | on: |
| 18 | workflow_dispatch: |
| 19 | pull_request: |
| 20 | paths-ignore: |
| 21 | - '**/*.md' |
| 22 | push: |
| 23 | branches: |
| 24 | - 'master' |
| 25 | |
| 26 | concurrency: |
| 27 | group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }} |
| 28 | cancel-in-progress: true |
| 29 | |
| 30 | defaults: |
| 31 | run: |
| 32 | shell: bash |
| 33 | |
| 34 | jobs: |
| 35 | interop-prep: |
| 36 | if: github.repository == 'ipfs/kubo' || github.event_name == 'workflow_dispatch' |
| 37 | runs-on: ubuntu-latest |
| 38 | timeout-minutes: 5 |
| 39 | env: |
| 40 | TEST_DOCKER: 0 |
| 41 | TEST_FUSE: 0 |
| 42 | TEST_VERBOSE: 1 |
| 43 | GIT_PAGER: cat |
| 44 | IPFS_CHECK_RCMGR_DEFAULTS: 1 |
| 45 | defaults: |
| 46 | run: |
| 47 | shell: bash |
| 48 | steps: |
| 49 | - uses: actions/checkout@v6 |
| 50 | - uses: actions/setup-go@v6 |
| 51 | with: |
| 52 | go-version-file: 'go.mod' |
| 53 | - run: make build |
| 54 | - uses: actions/upload-artifact@v7 |
| 55 | with: |
| 56 | name: kubo |
| 57 | path: cmd/ipfs/ipfs |
| 58 | helia-interop: |
| 59 | needs: [interop-prep] |
| 60 | runs-on: ${{ fromJSON(github.repository == 'ipfs/kubo' && '["self-hosted", "linux", "x64", "2xlarge"]' || '"ubuntu-latest"') }} |
| 61 | timeout-minutes: 20 |
| 62 | defaults: |
| 63 | run: |
| 64 | shell: bash |
| 65 | steps: |
| 66 | - uses: actions/setup-node@v6 |
| 67 | with: |
| 68 | node-version: lts/* |
| 69 | - uses: actions/download-artifact@v8 |
| 70 | with: |
| 71 | name: kubo |
| 72 | path: cmd/ipfs |
| 73 | - run: chmod +x cmd/ipfs/ipfs |
| 74 | - run: sudo apt update |
| 75 | - run: sudo apt install -y libxkbcommon0 libxdamage1 libgbm1 libpango-1.0-0 libcairo2 # dependencies for playwright |
| 76 | # Cache node_modules based on latest @helia/interop version from npm registry. |
| 77 | # This ensures we always test against the latest release while still benefiting |
| 78 | # from caching when the version hasn't changed. |
| 79 | - name: Get latest @helia/interop version |
| 80 | id: helia-version |
| 81 | run: echo "version=$(npm view @helia/interop version)" >> $GITHUB_OUTPUT |
| 82 | - name: Cache helia-interop node_modules |
| 83 | uses: actions/cache@v5 |
| 84 | id: helia-cache |
| 85 | with: |
| 86 | path: node_modules |
| 87 | key: ${{ runner.os }}-helia-interop-${{ steps.helia-version.outputs.version }} |
| 88 | - name: Install @helia/interop |
| 89 | if: steps.helia-cache.outputs.cache-hit != 'true' |
| 90 | run: npm install @helia/interop |
| 91 | # TODO(IPIP-499): Remove --grep --invert workaround once helia implements IPIP-499 |
| 92 | # Tracking issue: https://github.com/ipfs/helia/issues/941 |
| 93 | # |
| 94 | # PROVISIONAL HACK: Skip '@helia/mfs - should have the same CID after |
| 95 | # creating a file' test due to IPIP-499 changes in kubo. |
| 96 | # |
| 97 | # WHY IT FAILS: The test creates a 5-byte file in MFS on both kubo and helia, |
| 98 | # then compares the root directory CID. With kubo PR #11148, `ipfs files write` |
| 99 | # now produces raw CIDs for single-block files (matching `ipfs add --raw-leaves`), |
| 100 | # while helia uses `reduceSingleLeafToSelf: false` which keeps the dag-pb wrapper. |
| 101 | # Different file CIDs lead to different directory CIDs. |
| 102 | # |
| 103 | # We run aegir directly (instead of helia-interop binary) because only aegir |
| 104 | # supports the --grep/--invert flags needed to exclude specific tests. |
| 105 | - name: Run helia-interop tests (excluding IPIP-499 incompatible test) |
| 106 | run: npx aegir test -t node --bail -- --grep 'should have the same CID after creating a file' --invert |
| 107 | env: |
| 108 | KUBO_BINARY: ${{ github.workspace }}/cmd/ipfs/ipfs |
| 109 | working-directory: node_modules/@helia/interop |
| 110 | ipfs-webui: |
| 111 | needs: [interop-prep] |
| 112 | runs-on: ${{ fromJSON(github.repository == 'ipfs/kubo' && '["self-hosted", "linux", "x64", "2xlarge"]' || '"ubuntu-latest"') }} |
| 113 | timeout-minutes: 20 |
| 114 | env: |
| 115 | NO_SANDBOX: true |
| 116 | LIBP2P_TCP_REUSEPORT: false |
| 117 | LIBP2P_ALLOW_WEAK_RSA_KEYS: 1 |
| 118 | E2E_IPFSD_TYPE: go |
| 119 | GIT_PAGER: cat |
| 120 | IPFS_CHECK_RCMGR_DEFAULTS: 1 |
| 121 | defaults: |
| 122 | run: |
| 123 | shell: bash |
| 124 | steps: |
| 125 | - uses: actions/download-artifact@v8 |
| 126 | with: |
| 127 | name: kubo |
| 128 | path: cmd/ipfs |
| 129 | - run: chmod +x cmd/ipfs/ipfs |
| 130 | - uses: actions/checkout@v6 |
| 131 | with: |
| 132 | repository: ipfs/ipfs-webui |
| 133 | path: ipfs-webui |
| 134 | - uses: actions/setup-node@v6 |
| 135 | with: |
| 136 | node-version-file: 'ipfs-webui/.tool-versions' |
| 137 | - id: webui-ref |
| 138 | run: echo "ref=$(git rev-parse --short HEAD)" | tee -a $GITHUB_OUTPUT |
| 139 | working-directory: ipfs-webui |
| 140 | - id: webui-state |
| 141 | env: |
| 142 | GITHUB_TOKEN: ${{ github.token }} |
| 143 | ENDPOINT: repos/ipfs/ipfs-webui/commits/${{ steps.webui-ref.outputs.ref }}/status |
| 144 | SELECTOR: .state |
| 145 | KEY: state |
| 146 | run: gh api "$ENDPOINT" --jq "$SELECTOR" | xargs -I{} echo "$KEY={}" | tee -a $GITHUB_OUTPUT |
| 147 | # Cache node_modules based on package-lock.json |
| 148 | - name: Cache node_modules |
| 149 | uses: actions/cache@v5 |
| 150 | id: node-modules-cache |
| 151 | with: |
| 152 | path: ipfs-webui/node_modules |
| 153 | key: ${{ runner.os }}-webui-node-modules-${{ hashFiles('ipfs-webui/package-lock.json') }} |
| 154 | restore-keys: | |
| 155 | ${{ runner.os }}-webui-node-modules- |
| 156 | - name: Install dependencies |
| 157 | if: steps.node-modules-cache.outputs.cache-hit != 'true' |
| 158 | run: npm ci --prefer-offline --no-audit --progress=false |
| 159 | working-directory: ipfs-webui |
| 160 | # Cache Playwright browsers |
| 161 | - name: Cache Playwright browsers |
| 162 | uses: actions/cache@v5 |
| 163 | id: playwright-cache |
| 164 | with: |
| 165 | path: ~/.cache/ms-playwright |
| 166 | key: ${{ runner.os }}-playwright-${{ hashFiles('ipfs-webui/package-lock.json') }} |
| 167 | restore-keys: | |
| 168 | ${{ runner.os }}-playwright- |
| 169 | # On cache miss: download browsers and install OS dependencies |
| 170 | - name: Install Playwright with dependencies |
| 171 | if: steps.playwright-cache.outputs.cache-hit != 'true' |
| 172 | run: npx playwright install --with-deps |
| 173 | working-directory: ipfs-webui |
| 174 | # On cache hit: only ensure OS dependencies are present (fast, idempotent) |
| 175 | - name: Install Playwright OS dependencies |
| 176 | if: steps.playwright-cache.outputs.cache-hit == 'true' |
| 177 | run: npx playwright install-deps |
| 178 | working-directory: ipfs-webui |
| 179 | # Cache test build output |
| 180 | - name: Cache test build |
| 181 | uses: actions/cache@v5 |
| 182 | id: test-build-cache |
| 183 | with: |
| 184 | path: ipfs-webui/build |
| 185 | key: ${{ runner.os }}-webui-build-${{ hashFiles('ipfs-webui/package-lock.json', 'ipfs-webui/src/**', 'ipfs-webui/public/**') }} |
| 186 | restore-keys: | |
| 187 | ${{ runner.os }}-webui-build- |
| 188 | - name: Build ipfs-webui@${{ steps.webui-ref.outputs.ref }} (state=${{ steps.webui-state.outputs.state }}) |
| 189 | if: steps.test-build-cache.outputs.cache-hit != 'true' |
| 190 | run: npm run test:build |
| 191 | working-directory: ipfs-webui |
| 192 | - name: Test ipfs-webui@${{ steps.webui-ref.outputs.ref }} (state=${{ steps.webui-state.outputs.state }}) E2E against the locally built Kubo binary |
| 193 | run: npm run test:e2e |
| 194 | env: |
| 195 | IPFS_GO_EXEC: ${{ github.workspace }}/cmd/ipfs/ipfs |
| 196 | working-directory: ipfs-webui |
| 197 | - name: Upload test artifacts on failure |
| 198 | if: failure() |
| 199 | uses: actions/upload-artifact@v7 |
| 200 | with: |
| 201 | name: webui-test-results |
| 202 | path: ipfs-webui/test-results/ |
| 203 | retention-days: 7 |