diff --git a/.github/workflows/update-lavamoat-policies.yml b/.github/workflows/update-lavamoat-policies.yml new file mode 100644 index 000000000..ad43fb486 --- /dev/null +++ b/.github/workflows/update-lavamoat-policies.yml @@ -0,0 +1,172 @@ +name: Update LavaMoat policies + +on: + issue_comment: + types: created + +jobs: + is-fork-pull-request: + name: Determine whether this issue comment was on a pull request from a fork + if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '@metamaskbot update-policies') }} + runs-on: ubuntu-latest + outputs: + IS_FORK: ${{ steps.is-fork.outputs.IS_FORK }} + steps: + - uses: actions/checkout@v3 + - name: Determine whether this PR is from a fork + id: is-fork + run: echo "IS_FORK=$(gh pr view --json isCrossRepository --jq '.isCrossRepository' "${PR_NUMBER}" )" >> "$GITHUB_OUTPUT" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.issue.number }} + + prepare: + name: Prepare dependencies + runs-on: ubuntu-latest + needs: is-fork-pull-request + # Early exit if this is a fork, since later steps are skipped for forks + if: ${{ needs.is-fork-pull-request.outputs.IS_FORK == 'false' }} + steps: + - uses: actions/checkout@v3 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + - name: Install Yarn dependencies + run: yarn --immutable + + update-lavamoat-build-policy: + name: Update LavaMoat build policy + runs-on: ubuntu-latest + needs: + - prepare + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + - name: Install dependencies from cache + run: yarn --immutable --immutable-cache + - name: Update LavaMoat build policy + run: yarn lavamoat:build:auto + - name: Cache build policy + uses: actions/cache/save@v3 + with: + path: lavamoat/build-system + key: cache-build-${{ github.run_id }}-${{ github.run_attempt }} + + update-lavamoat-webapp-policy: + strategy: + matrix: + # Ensure this is synchronized with the list below in the "commit-updated-policies" job + # and with the build type list in `builds.yml` + build-type: [main, beta, flask, mmi, desktop] + name: Update LavaMoat ${{ matrix.build-type }} application policy + runs-on: ubuntu-latest + needs: + - prepare + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version-file: '.nvmrc' + cache: 'yarn' + - name: Install dependencies from cache + run: yarn --immutable --immutable-cache + - name: Update LavaMoat ${{ matrix.build-type }} policy + run: yarn lavamoat:webapp:auto:ci '--build-types=${{ matrix.build-type }}' + env: + INFURA_PROJECT_ID: 00000000000 + - name: Cache ${{ matrix.build-type }} application policy + uses: actions/cache/save@v3 + with: + path: lavamoat/browserify/${{ matrix.build-type }} + key: cache-${{ matrix.build-type }}-${{ github.run_id }}-${{ github.run_attempt }} + + commit-updated-policies: + name: Commit the updated LavaMoat policies + runs-on: ubuntu-latest + needs: + - is-fork-pull-request + - update-lavamoat-build-policy + - update-lavamoat-webapp-policy + # Ensure forks don't get access to the LavaMoat update token + if: ${{ needs.is-fork-pull-request.outputs.IS_FORK == 'false' }} + steps: + - uses: actions/checkout@v3 + with: + # Use PAT to ensure that the commit later can trigger status check workflows + token: ${{ secrets.LAVAMOAT_UPDATE_TOKEN }} + - name: Checkout pull request + run: gh pr checkout "${PR_NUMBER}" + env: + GITHUB_TOKEN: ${{ secrets.LAVAMOAT_UPDATE_TOKEN }} + PR_NUMBER: ${{ github.event.issue.number }} + - name: Restore build policy + uses: actions/cache/restore@v3 + with: + path: lavamoat/build-system + key: cache-build-${{ github.run_id }}-${{ github.run_attempt }} + # One restore step per build type: [main, beta, flask, mmi, desktop] + # Ensure this is synchronized with the list above in the "update-lavamoat-webapp-policy" job + # and with the build type list in `builds.yml` + - name: Restore main application policy + uses: actions/cache/restore@v3 + with: + path: lavamoat/browserify/main + key: cache-main-${{ github.run_id }}-${{ github.run_attempt }} + - name: Restore beta application policy + uses: actions/cache/restore@v3 + with: + path: lavamoat/browserify/beta + key: cache-beta-${{ github.run_id }}-${{ github.run_attempt }} + - name: Restore flask application policy + uses: actions/cache/restore@v3 + with: + path: lavamoat/browserify/flask + key: cache-flask-${{ github.run_id }}-${{ github.run_attempt }} + - name: Restore mmi application policy + uses: actions/cache/restore@v3 + with: + path: lavamoat/browserify/mmi + key: cache-mmi-${{ github.run_id }}-${{ github.run_attempt }} + - name: Restore desktop application policy + uses: actions/cache/restore@v3 + with: + path: lavamoat/browserify/desktop + key: cache-desktop-${{ github.run_id }}-${{ github.run_attempt }} + + - name: Check whether there are policy changes + id: policy-changes + run: | + if git diff --exit-code + then + echo "HAS_CHANGES=false" >> "$GITHUB_OUTPUT" + else + echo "HAS_CHANGES=true" >> "$GITHUB_OUTPUT" + fi + - name: Commit the updated policies + if: steps.policy-changes.outputs.HAS_CHANGES == 'true' + run: | + git config --global user.name 'MetaMask Bot' + git config --global user.email 'metamaskbot@users.noreply.github.com' + git commit -am "Update LavaMoat policies" + git push + - name: Post comment + run: | + if [[ $HAS_CHANGES == 'true' ]] + then + gh pr comment "${PR_NUMBER}" --body 'Policies updated' + else + gh pr comment "${PR_NUMBER}" --body 'No policy changes' + fi + env: + HAS_CHANGES: ${{ steps.policy-changes.outputs.HAS_CHANGES }} + GITHUB_TOKEN: ${{ secrets.LAVAMOAT_UPDATE_TOKEN }} + PR_NUMBER: ${{ github.event.issue.number }} diff --git a/README.md b/README.md index 579b81c6c..38d94d726 100644 --- a/README.md +++ b/README.md @@ -112,19 +112,22 @@ Whenever you change dependencies (adding, removing, or updating, either in `pack - The `allow-scripts` configuration in `package.json` - Run `yarn allow-scripts auto` to update the `allow-scripts` configuration automatically. This config determines whether the package's install/postinstall scripts are allowed to run. Review each new package to determine whether the install script needs to run or not, testing if necessary. - Unfortunately, `yarn allow-scripts auto` will behave inconsistently on different platforms. macOS and Windows users may see extraneous changes relating to optional dependencies. -- The LavaMoat policy files. The _tl;dr_ is to run `yarn lavamoat:auto` to update these files, but there can be devils in the details: - - There are two sets of LavaMoat policy files: - - The production LavaMoat policy files (`lavamoat/browserify/*/policy.json`), which are re-generated using `yarn lavamoat:background:auto`. Add `--help` for usage. - - These should be regenerated whenever the production dependencies for the background change. - - The build system LavaMoat policy file (`lavamoat/build-system/policy.json`), which is re-generated using `yarn lavamoat:build:auto`. - - This should be regenerated whenever the dependencies used by the build system itself change. - - Whenever you regenerate a policy file, review the changes to determine whether the access granted to each package seems appropriate. - - Unfortunately, `yarn lavamoat:auto` will behave inconsistently on different platforms. - macOS and Windows users may see extraneous changes relating to optional dependencies. - - If you keep getting policy failures even after regenerating the policy files, try regenerating the policies after a clean install by doing: - - `rm -rf node_modules/ && yarn && yarn lavamoat:auto` - - Keep in mind that any kind of dynamic import or dynamic use of globals may elude LavaMoat's static analysis. - Refer to the LavaMoat documentation or ask for help if you run into any issues. +- The LavaMoat policy files + - If you are a MetaMask team member and your PR is on a repository branch, you can use the bot command `@metamaskbot update-policies` to ask the MetaMask bot to automatically update the policies for you. + - If your PR is from a fork, you can ask a MetaMask team member to help with updating the policy files. + - Manual update instructions: The _tl;dr_ is to run `yarn lavamoat:auto` to update these files, but there can be devils in the details: + - There are two sets of LavaMoat policy files: + - The production LavaMoat policy files (`lavamoat/browserify/*/policy.json`), which are re-generated using `yarn lavamoat:background:auto`. Add `--help` for usage. + - These should be regenerated whenever the production dependencies for the background change. + - The build system LavaMoat policy file (`lavamoat/build-system/policy.json`), which is re-generated using `yarn lavamoat:build:auto`. + - This should be regenerated whenever the dependencies used by the build system itself change. + - Whenever you regenerate a policy file, review the changes to determine whether the access granted to each package seems appropriate. + - Unfortunately, `yarn lavamoat:auto` will behave inconsistently on different platforms. + macOS and Windows users may see extraneous changes relating to optional dependencies. + - If you keep getting policy failures even after regenerating the policy files, try regenerating the policies after a clean install by doing: + - `rm -rf node_modules/ && yarn && yarn lavamoat:auto` + - Keep in mind that any kind of dynamic import or dynamic use of globals may elude LavaMoat's static analysis. + Refer to the LavaMoat documentation or ask for help if you run into any issues. ## Architecture diff --git a/builds.yml b/builds.yml index 954ddd7f3..3ca68bd59 100644 --- a/builds.yml +++ b/builds.yml @@ -11,6 +11,7 @@ default: &default main # Declaration of build types # Each build type is composed of features, env variables and assets. # Also known as productFlavors in Android lingo +# Note: These build types should be kept in sync with the list in `.github/workflows/update-lavamoat-policies.yml` buildTypes: main: features: