From fe140206a9791e4d237460a9a02af50f08687ceb Mon Sep 17 00:00:00 2001 From: TuDo1403 Date: Tue, 22 Oct 2024 18:40:33 +0700 Subject: [PATCH] ci: add ci for slither-analyze, storage-layout-check, unit-test and rework git hook --- .github/scripts/comment.js | 24 ++++ .github/workflows/compare-storage-layout.yml | 128 +++++++++++++++++++ .github/workflows/slither-analyze.yml | 46 +++---- .github/workflows/test.yml | 13 +- .husky/post-commit | 17 ++- foundry.toml | 3 +- install.sh | 19 +-- remappings.txt | 2 +- soldeer.lock | 9 +- 9 files changed, 210 insertions(+), 51 deletions(-) create mode 100755 .github/scripts/comment.js create mode 100644 .github/workflows/compare-storage-layout.yml diff --git a/.github/scripts/comment.js b/.github/scripts/comment.js new file mode 100755 index 00000000..bb9d9ec7 --- /dev/null +++ b/.github/scripts/comment.js @@ -0,0 +1,24 @@ +module.exports = async ({ github, context, header, body }) => { + const comment = [header, body].join("\n"); + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.number, + }); + + const botComment = comments.find( + (comment) => + // github-actions bot user + comment.user.id === 41898282 && comment.body.startsWith(header) + ); + + const commentFn = botComment ? "updateComment" : "createComment"; + + await github.rest.issues[commentFn]({ + owner: context.repo.owner, + repo: context.repo.repo, + body: comment, + ...(botComment ? { comment_id: botComment.id } : { issue_number: context.payload.number }), + }); +}; diff --git a/.github/workflows/compare-storage-layout.yml b/.github/workflows/compare-storage-layout.yml new file mode 100644 index 00000000..ecb69af4 --- /dev/null +++ b/.github/workflows/compare-storage-layout.yml @@ -0,0 +1,128 @@ +name: Check Storage Layout Changes + +on: + pull_request: + branches: + - mainnet + - testnet + - "release/*" + - "feature/*" + - "features/*" + +env: + FOUNDRY_PROFILE: ci + +jobs: + check: + strategy: + fail-fast: true + + name: Foundry project + runs-on: [self-hosted, dockerize] + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Install package with soldeer + run: forge soldeer install + + - name: "Setup Node" + uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 #v3.4.1 + with: + node-version: v16.16.0 + + - name: Run Forge build + run: | + forge --version + forge build + id: build + + - name: Run Storage Layout Check + id: storage-layout-check + run: | + sudo apt-get update + sudo apt-get install -y wget + sudo apt-get install bc + sudo wget https://github.com/mikefarah/yq/releases/download/v4.44.3/yq_linux_amd64 -O /usr/bin/yq + sudo chmod +x /usr/bin/yq + + src_root='src' + dst_root='src' + + echo "Current directory: $(pwd)" + echo "ls: $(ls)" + + src_root=$(yq eval '.profile.default.src' ./foundry.toml) + echo "Contract source root: $src_root" + + git fetch --unshallow || git fetch --all + # Checkout to the base branch + git checkout ${{ github.event.pull_request.base.sha }} + dst_root=$(yq eval '.profile.default.src' ./foundry.toml) + echo "Destination contract source root: $dst_root" + # Return to the current branch + git checkout ${{ github.sha }} + + echo "Checking storage layout..." + echo "Current branch: ${{ github.head_ref || github.ref_name }}" + echo "BASE_BRANCH: ${{ github.event.pull_request.base.ref }}" + echo "CURRENT_COMMIT_HASH: ${{ github.sha }}" + dependencies/storage-delta-0.3.2/run.sh ${{ github.event.pull_request.base.sha }} --omit new --dst-root $dst_root --src-root $src_root + + - name: Check for storage_delta folder + id: check-folder + run: | + if [ -d "storage_delta" ]; then + # Query all the subdirectories in the storage_delta folder to check any `.diff` files + # Echo the contents of the `.diff` files to the output with wrapped ```diff {content} ``` + find storage_delta -type f -name "*.diff" + for file in $(find storage_delta -type f -name "*.diff"); do + echo "## Layout Changes for $(basename "${file%.*}")" >>storage_delta_report.md + echo '```diff' >>storage_delta_report.md + # Remove \ No newline at end of file from the diff file + grep -v '\\ No newline at end of file' $file >>storage_delta_report.md + echo '```' >>storage_delta_report.md + done + # Check if .removed files exist, if yes, add header `Removed Storage Layouts` and append the contents of the file to storage_delta_report.md + if [ -f "storage_delta/.removed" ]; then + echo "## Removed Storage Layouts" >>storage_delta_report.md + echo '```' >>storage_delta_report.md + cat storage_delta/.removed >>storage_delta_report.md + echo '```' >>storage_delta_report.md + fi + + # Check if the storage_delta_report.md file exists + if [ -f "storage_delta_report.md" ]; then + # Output the contents of the storage_delta_report.md file to the output + cat storage_delta_report.md + echo "storage_delta_exists=true" >>$GITHUB_OUTPUT + else + echo "No storage layout changes detected." + fi + fi + env: + GITHUB_OUTPUT: ${{ steps.check-folder.outputs.storage_delta_exists }} + shell: bash + + - name: Set storage delta report output + if: ${{ steps.check-folder.outputs.storage_delta_exists == 'true' }} + id: set-report + run: | + REPORT=$(cat storage_delta_report.md) + echo "REPORT<> $GITHUB_ENV + echo "$REPORT" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - name: Create/update checklist as PR comment + uses: actions/github-script@v7 + if: github.event_name == 'pull_request' && steps.check-folder.outputs.storage_delta_exists == 'true' + with: + script: | + const script = require('.github/scripts/comment'); + const header = '# Storage Layout Change Report'; + const body = process.env.REPORT; + await script({ github, context, header, body }); diff --git a/.github/workflows/slither-analyze.yml b/.github/workflows/slither-analyze.yml index 7651faff..8e0e3ba5 100644 --- a/.github/workflows/slither-analyze.yml +++ b/.github/workflows/slither-analyze.yml @@ -1,14 +1,6 @@ name: Slither Analyze on: - push: - branches: - - mainnet - - testnet - - "feature/*" - - "features/*" - - "feat/*" - - "feats/*" pull_request: branches: - mainnet @@ -39,30 +31,28 @@ jobs: with: submodules: recursive - - name: Set up Go 1.19 - uses: actions/setup-go@v4 - with: - go-version: "1.19" - - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 - name: Install package with soldeer run: forge soldeer install - - name: Setup repo - run: | - chmod +x ./install.sh - ./install.sh - id: setup-repo - - - name: Install Slither for security analysis - run: | - sudo apt-get update - sudo apt-get install -y python3-pip - python3 -m pip install slither-analyzer - - - name: Run Slither analysis - run: | - slither ./ --exclude-optimization --exclude-low --exclude-medium --exclude-informational --exclude-dependencies --filter-paths "dependencies/|script/|test/foundry/" + - name: Run Slither + uses: crytic/slither-action@v0.4.0 id: slither + with: + node-version: 18 + fail-on: none + slither-args: --exclude-optimization --exclude-low --exclude-medium --exclude-informational --exclude-dependencies --filter-paths "dependencies/|script/|test/foundry/" --checklist --markdown-root ${{ github.server_url }}/${{ github.repository }}/blob/${{ github.sha }}/ + + - name: Create/update checklist as PR comment + uses: actions/github-script@v7 + if: github.event_name == 'pull_request' + env: + REPORT: ${{ steps.slither.outputs.stdout }} + with: + script: | + const script = require('.github/scripts/comment') + const header = '# Slither report' + const body = process.env.REPORT + await script({ github, context, header, body }) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 45a4bb3d..fbd4412d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,19 +36,12 @@ jobs: with: go-version: "1.19" - - name: Install jq - run: sudo apt-get install -y jq - - - name: Update apt-get and Install GCC + - name: Setup external packages run: | sudo apt-get update + sudo apt-get install -y jq sudo apt-get install -y gcc - - - name: Install wget - run: sudo apt-get install -y wget - - - name: Install yq - run: | + sudo apt-get install -y wget sudo wget https://github.com/mikefarah/yq/releases/download/v4.34.1/yq_linux_amd64 -O /usr/local/bin/yq sudo chmod +x /usr/local/bin/yq diff --git a/.husky/post-commit b/.husky/post-commit index 9ddba35c..41611313 100755 --- a/.husky/post-commit +++ b/.husky/post-commit @@ -1,5 +1,14 @@ #!/bin/bash echo "Running post-commit hook" + +HAS_PENDING_CHANGES=false +# If there are any changes in the working directory, stash them +if [[ $(git status -s) ]]; then + HAS_PENDING_CHANGES=true + echo "\033[33m[post-commit] Stashing pending changes\033[0m" + git stash push -m "post-commit: Stash changes" +fi + GIT_BLAME_IGNORE_REVS_FILE=".git-blame-ignore-revs" # If `.git-blame-ignore-revs` does not exist, create it @@ -34,4 +43,10 @@ if [[ $(git status -s $GIT_BLAME_IGNORE_REVS_FILE) ]]; then echo "\033[33m[post-commit] .git-blame-ignore-revs changes detected\033[0m" git add $GIT_BLAME_IGNORE_REVS_FILE HUSKY=0 git commit -m "chore(automated): post-commit update .git-blame-ignore-revs" -n -fi \ No newline at end of file +fi + +# If there were any pending changes, unstash them +if [ "$HAS_PENDING_CHANGES" = true ]; then + echo "\033[33m[post-commit] Unstashing pending changes\033[0m" + git stash pop +fi diff --git a/foundry.toml b/foundry.toml index f5a025b6..f4022826 100644 --- a/foundry.toml +++ b/foundry.toml @@ -43,9 +43,10 @@ ronin-mainnet-shadow = "${RONIN_MAINNET_SHADOW}" "openzeppelin-v4" = { version = "4.7.3", url = "https://github.com/OpenZeppelin/openzeppelin-contracts/archive/refs/tags/v4.7.3.zip" } "openzeppelin-v5" = { version = "5.0.2", url = "https://github.com/OpenZeppelin/openzeppelin-contracts/archive/refs/tags/v5.0.2.zip" } "chainlink" = { version = "1.6.0", url = "https://github.com/smartcontractkit/chainlink/archive/refs/tags/v1.6.0.zip" } -"safe-smart-account" = { version = "1.4.1", url = "https://github.com/safe-global/safe-smart-account/archive/refs/tags/v1.4.1.zip" } +"safe" = { version = "1.4.1", url = "https://github.com/safe-global/safe-smart-account/archive/refs/tags/v1.4.1.zip" } "prb-test" = { version = "0.6.4", url = "https://github.com/PaulRBerg/prb-test/archive/refs/tags/v0.6.4.zip" } "prb-math" = { version = "4.0.1", url = "https://github.com/PaulRBerg/prb-math/archive/refs/tags/v4.0.1.zip" } +storage-delta = { version = "0.3.2", url = "https://github.com/TuDo1403/storage-delta/archive/refs/tags/0.3.2.zip" } [soldeer] # whether soldeer manages remappings diff --git a/install.sh b/install.sh index 4e282523..b3378788 100755 --- a/install.sh +++ b/install.sh @@ -15,32 +15,31 @@ fi # Check if jq is installed if ! command -v jq &>/dev/null; then # Install jq - sudo apt-get install jq + brew install jq fi # Check if yq is installed if ! command -v yq &>/dev/null; then - curl -L https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -o /usr/bin/yq && - sudo chmod +x /usr/bin/yq + brew install -y wget + sudo wget https://github.com/mikefarah/yq/releases/download/v4.34.1/yq_linux_amd64 -O /usr/local/bin/yq + sudo chmod +x /usr/local/bin/yq fi # Check if gvm is installed -if ! command -v go &>/dev/null; then +if ! command -v gvm &>/dev/null; then # Install bison - sudo apt-get install bison + brew install bison # Install gvm bash < <(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer) # Source gvm script source $HOME/.gvm/scripts/gvm - sudo apt-get install bsdmainutils + brew install bsdmainutils # Install go1.19 gvm install go1.19 -B fi -rm -rf temp && mkdir temp && cd temp - -git clone https://github.com/ronin-chain/ronin-random-beacon.git && cd ronin-random-beacon +rm -rf temp && mkdir temp && cd temp && git clone https://github.com/ronin-chain/ronin-random-beacon.git && cd ronin-random-beacon # Check if installed gvm if ! command -v gvm &>/dev/null; then @@ -48,3 +47,5 @@ if ! command -v gvm &>/dev/null; then fi go build -o ronin-random-beacon && cp ronin-random-beacon ../../bin/ && cd ../../ && rm -rf temp + +echo "Installed successfully!" diff --git a/remappings.txt b/remappings.txt index a53a594a..e62f8130 100644 --- a/remappings.txt +++ b/remappings.txt @@ -4,4 +4,4 @@ forge-std/=dependencies/fdk-0.3.5-beta/dependencies/forge-std-1.9.3/src/ @solady/=dependencies/fdk-0.3.5-beta/dependencies/solady-0.0.228/src/ @fdk/=dependencies/fdk-0.3.5-beta/script/ @chainlink/contracts/=dependencies/chainlink-1.6.0/contracts/ -@safe/contracts/=dependencies/safe-smart-account-1.4.1/contracts/ \ No newline at end of file +@safe/contracts/=dependencies/safe-1.4.1/contracts/ \ No newline at end of file diff --git a/soldeer.lock b/soldeer.lock index f2fd51c6..8462e22b 100644 --- a/soldeer.lock +++ b/soldeer.lock @@ -41,8 +41,15 @@ checksum = "1458dc3760d4fa5ad2ecd778d04d61143785d0a10c1674aed29a69210ac4e072" integrity = "e61d2d4974d6461b650445295fa55b8065a802878c80672214762630339e2bac" [[dependencies]] -name = "safe-smart-account" +name = "safe" version = "1.4.1" url = "https://github.com/safe-global/safe-smart-account/archive/refs/tags/v1.4.1.zip" checksum = "84348d4a1cf975f5d013cf8bdb74b8713bcccb40fceb5a1e7fc9debd27489e99" integrity = "65ed08a525b96c6b4d8316f827fcd799ff831e1a3b4e56bc55fbf200d27c372d" + +[[dependencies]] +name = "storage-delta" +version = "0.3.2" +url = "https://github.com/TuDo1403/storage-delta/archive/refs/tags/0.3.2.zip" +checksum = "de492d28d1f1367a7b984669758a708da8c25e3ef63d9d0150cfee07db72d1aa" +integrity = "70acc46d57376ee3ff000fe511d44174f5ae838786b8fc4b4d7f9e9b385baa5c"