Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ci): carve out storage layout CI #127

Merged

Conversation

MaxMustermann2
Copy link
Collaborator

@MaxMustermann2 MaxMustermann2 commented Nov 27, 2024

Since the storage layout CI needs the API keys to run, it does not work in PRs originating from forked repos. To avoid those unnecessary errors, this PR splits the workflow into two parts: the first that generates the compiled layouts and the second that fetches the deployed layouts and compares them.

Such a split is possible because the second type of workflow runs in a trusted context, and hence, the API key is accessible to it.

How does this CI work?

  1. The Forge CI workflow runs and generates the compiled.json layout files.
  2. Once the Forge CI workflow is completed, it triggers the Compare Storage Layouts workflow.
  3. That workflow executes in a private context and hence has access to the repository secrets. It is able to pull the deployed layouts using cast storage.
  4. The JSON files are then compared using OpenZeppelin's compare layouts script.

In addition, this PR now makes it such that the status of all CIs is posted to the PR: started / successful / failed. For the Compare Storage Layouts workflow, it also features posting a status manually since Github doesn't automatically generate one for workflows triggered by workflow_run.

Do note that these workflows need to go into main first, for things to successfully work. Hence it might not be immediately possible to see their results until the PR is merged. However, they can be seen in action here: MaxMustermann2#1 and MaxMustermann2#2.

The advantages of this rework are:

  1. Removal of custom Python scripts and move to standardised OpenZeppelin scripts
  2. Comparison of storage layout from forked repos
  3. Comment editing (instead of adding a new comment) after each workflow re-run
  4. Status update for Compare Storage Layouts as pending / successful / failed is available to make it a required status check

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced a new workflow for comparing storage layouts.
    • Added a new workflow to automate commenting on pull request statuses.
    • New script for comparing deployed and compiled JSON files related to smart contracts.
  • Bug Fixes

    • Adjusted the storage gap size in the ClientChainGatewayStorage contract for optimized storage allocation.
  • Chores

    • Updated dependencies in the project configuration.
    • Renamed and streamlined various workflow jobs for clarity and efficiency.
    • Revised the Forge CI workflow for enhanced clarity and efficiency.
    • Enhanced the Foundry setup workflow with new input parameters.
    • Added timeout settings to the Slither Analysis workflow.
    • Updated the Solhint linter workflow configuration for improved performance.

Since the storage layout CI needs the API keys to run, it does not work
in PRs originating from forked repos. To avoid those unnecessary errors,
this PR splits the workflow into two parts: the first that generates the
compiled layouts and the second that fetches the deployed layouts and
compares them.

Such a split is possible because the second type of workflow runs in a
trusted context, and hence, the API key is accessible to it.
Since the storage layout CI needs the API keys to run, it does not work
in PRs originating from forked repos. To avoid those unnecessary errors,
this PR splits the workflow into two parts: the first that generates the
compiled layouts and the second that fetches the deployed layouts and
compares them.

Such a split is possible because the second type of workflow runs in a
trusted context, and hence, the API key is accessible to it.
Copy link
Contributor

coderabbitai bot commented Nov 27, 2024

Walkthrough

This pull request introduces a new GitHub Actions workflow for comparing storage layouts of smart contracts, triggered by the completion of the "Forge CI" workflow. It includes jobs for setting commit statuses, environment setup, and layout comparison. Several existing scripts related to layout comparison have been deleted, and a new script has been added to automate the comparison of deployed and compiled JSON files. Additionally, modifications have been made to existing workflows for clarity and efficiency, including renaming jobs and updating Node.js versions.

Changes

File Path Change Summary
.github/workflows/compare-layouts.yml New workflow for comparing storage layouts added.
.github/workflows/compare_deployed_storage_layout.py Deleted script for comparing deployed storage layouts.
.github/workflows/compare_storage_layout.py Deleted script for comparing storage layouts of contracts.
.github/workflows/forge-ci.yml Workflow name simplified; job renamed and restructured for clarity; caching strategy updated.
.github/workflows/lint.yml Workflow name and job name updated; Node.js version changed; error handling removed.
.github/workflows/reusable-foundry-setup.yml Job renamed from setup to install; cache key management simplified.
.github/workflows/status-comment.yml New workflow added to automate commenting on PR status based on workflow completion.
package.json New dependency @openzeppelin/upgrades-core added.
script/compareLayouts.js New script for comparing deployed and compiled JSON files related to smart contracts added.
src/storage/ClientChainGatewayStorage.sol Storage gap size updated from 40 to 39 elements in ClientChainGatewayStorage contract.
.github/workflows/slither.yml Timeout setting added for the Slither analysis job.

Possibly related issues

Possibly related PRs

Suggested reviewers

  • cloud8little
  • adu-web3
  • bwhour
  • TimmyExogenous
  • leonz789
  • magj2006

🐰 "In the land of code, where changes bloom,
A workflow grows, dispelling the gloom.
With layouts compared and statuses bright,
We hop through the tasks, all day and night!
So gather your scripts, let’s dance and play,
For in this PR, we find our way!" 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Outside diff range and nitpick comments (15)
.github/workflows/lint.yml (2)

Line range hint 19-34: Update action versions and improve workflow efficiency

Several improvements can be made to enhance stability and performance:

  1. The actions/setup-node action is outdated (v2). Update to the latest version.
  2. Node.js 22 is currently unstable. Consider using LTS version 20.
  3. Add npm dependency caching to improve workflow speed.

Apply these changes:

       - uses: actions/checkout@v4

       - name: Set up Node.js
-        uses: actions/setup-node@v2
+        uses: actions/setup-node@v4
         with:
-          node-version: '22'
+          node-version: '20'
+          cache: 'npm'

       - name: Clear npm cache
         run: npm cache clean --force

Note: With caching enabled, you might want to remove the "Clear npm cache" step unless it's specifically needed for troubleshooting.

🧰 Tools
🪛 actionlint (1.7.4)

23-23: the runner of "actions/setup-node@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


Line range hint 1-34: Consider workflow ordering in the CI pipeline

Since this PR introduces new storage layout comparison workflows, consider adding this lint workflow as a required check before running the storage layout comparisons. This ensures code quality before performing more complex operations.

You can achieve this by:

  1. Adding this workflow as a required status check in branch protection rules
  2. Making the storage layout workflow depend on this one using needs in the workflow configuration
🧰 Tools
🪛 actionlint (1.7.4)

23-23: the runner of "actions/setup-node@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

script/compareLayouts.js (4)

33-33: Document the usage of unsafeAllowCustomTypes option

The unsafeAllowCustomTypes: true option might have security implications. Please document why this option is necessary and what types of custom storage layouts are expected.


29-30: Add JSON structure validation before comparison

The script parses JSON but doesn't validate if the files have the expected structure for storage layout comparison. This could lead to unclear errors if the JSON structure is invalid.

-    const deployedData = JSON.parse(fs.readFileSync(before, 'utf8'));
-    const compiledData = JSON.parse(fs.readFileSync(after, 'utf8'));
+    const deployedData = JSON.parse(fs.readFileSync(before, 'utf8'));
+    const compiledData = JSON.parse(fs.readFileSync(after, 'utf8'));
+    
+    // Validate expected structure
+    if (!deployedData.storage || !compiledData.storage) {
+      throw new Error('Invalid storage layout format: missing storage field');
+    }

43-46: Enhance error handling with specific error types

The current error handling catches all errors generically. Consider handling specific error types (e.g., FileNotFoundError, JSONParseError) differently to provide more helpful error messages.

-  } catch (error) {
-    console.error(`❌ Error processing ${before} or ${after}: ${error.message}`);
-    process.exitCode = 1;
+  } catch (error) {
+    if (error instanceof SyntaxError) {
+      console.error(`❌ Invalid JSON in ${before} or ${after}: ${error.message}`);
+    } else if (error.code === 'ENOENT') {
+      console.error(`❌ File not found: ${error.path}`);
+    } else {
+      console.error(`❌ Error processing ${before} or ${after}: ${error.message}`);
+    }
+    process.exitCode = 1;

16-47: Consider parallel processing for better performance

The script processes comparisons sequentially. For better performance, especially in CI environments, consider using Promise.all to process comparisons concurrently.

-fileMappings.forEach(({ before, after }) => {
+Promise.all(fileMappings.map(async ({ before, after }) => {
   console.log(`🔍 Comparing ${before} and ${after}...`);
   try {
     // ... existing comparison logic ...
   } catch (error) {
     // ... error handling ...
   }
-});
+})).then(() => {
+  if (process.exitCode === 1) {
+    console.log('❌ One or more comparisons failed');
+  } else {
+    console.log('✅ All comparisons completed successfully');
+  }
+});
.github/workflows/status-comment.yml (2)

9-11: Consider alternative approach for Compare Storage Layout status updates

The comment correctly notes that nested workflow_run triggers aren't supported. However, this means we won't get status updates for the Compare Storage Layout workflow in the same format as other workflows. Consider documenting this limitation in the PR description or implementing a consistent status update mechanism across all workflows.


51-72: Enhance message construction robustness

The message construction could be more robust with input validation and proper shell quoting.

 run: |
+  # Validate required environment variables
+  : "${WORKFLOW_NAME:?Required environment variable not set}"
+  : "${WORKFLOW_URL:?Required environment variable not set}"
+  : "${SHA:?Required environment variable not set}"
+
   if [ "${{ github.event.action }}" == "requested" ]; then
     message="🚀 The $WORKFLOW_NAME workflow has started."
   elif [ "${{ github.event.workflow_run.conclusion }}" == "success" ]; then
     message="✅ The $WORKFLOW_NAME workflow has completed successfully."
   elif [ "${{ github.event.workflow_run.conclusion }}" == "failure" ]; then
     message="❌ The $WORKFLOW_NAME workflow has failed!"
   elif [ "${{ github.event.workflow_run.conclusion }}" == "cancelled" ]; then
     message="⏹️ The $WORKFLOW_NAME workflow was cancelled."
   else
     message="❓ The $WORKFLOW_NAME workflow has completed with an unknown status."
   fi
-  echo "message=$message Check the [workflow run]($WORKFLOW_URL) for details. ($SHA)" >> "${GITHUB_OUTPUT}"
+  # Properly escape the message for GitHub Actions output
+  message="${message} Check the [workflow run](${WORKFLOW_URL}) for details. (${SHA})"
+  message="${message//'%'/'%25'}"
+  message="${message//$'\n'/'%0A'}"
+  message="${message//$'\r'/'%0D'}"
+  echo "message=${message}" >> "${GITHUB_OUTPUT}"
.github/workflows/forge-ci.yml (4)

Line range hint 22-55: Consider enhancing the caching strategy

Two suggestions to improve the caching mechanism:

  1. Add restore-keys fallback to the Foundry toolchain cache restore step for better cache hits
  2. Include a hash of relevant files (e.g., forge config, dependencies) in the build artifacts cache key for more precise caching
       uses: actions/cache/restore@v3
       with:
         path: ${{ needs.setup.outputs.installation-dir }}
         key: ${{ needs.setup.outputs.cache-key }}
+        restore-keys: |
+          foundry-

       uses: actions/cache/save@v3
       with:
         path: |
           ./lib
           ./out
           ./cache
           ./broadcast
-        key: build-${{ github.event.pull_request.head.sha || github.event.after || github.sha }}
+        key: build-${{ hashFiles('foundry.toml', 'lib/**/*.json') }}-${{ github.event.pull_request.head.sha || github.event.after || github.sha }}
🧰 Tools
🪛 actionlint (1.7.4)

40-40: shellcheck reported issue in this script: SC2086:info:1:55: Double quote to prevent globbing and word splitting

(shellcheck)


Line range hint 57-82: Consider reducing test verbosity

The -vvv flag generates very verbose output which might make it harder to identify important information in CI logs. Consider using -v or -vv unless the extra verbosity is specifically needed.

-      run: forge test -vvv
+      run: forge test -vv
🧰 Tools
🪛 actionlint (1.7.4)

67-67: shellcheck reported issue in this script: SC2086:info:1:55: Double quote to prevent globbing and word splitting

(shellcheck)


160-162: Consider making the file list dynamic

The hardcoded list of files to generate layouts for could become outdated as new contracts are added or removed. Consider making this list dynamic by finding all contract files in the src/core directory.

-      for file in Bootstrap ClientChainGateway RewardVault Vault ExocoreGateway ExoCapsule; do
-        forge inspect src/core/${file}.sol:${file} storage-layout > ${file}.compiled.json;
-      done
+      # Find all .sol files in src/core and generate layouts
+      for filepath in src/core/*.sol; do
+        filename=$(basename "$filepath" .sol)
+        if grep -q "^contract ${filename}" "$filepath"; then
+          forge inspect "$filepath:${filename}" storage-layout > "${filename}.compiled.json"
+        fi
+      done

133-135: Simplify base branch layout file handling

The current approach of copying files back and forth between /tmp seems unnecessary. Consider simplifying this process.

-      run: |
-        forge inspect src/core/ExocoreGateway.sol:ExocoreGateway storage-layout > ExocoreGateway.base.json
-      - name: Copy base branch layout file
-        run: cp ExocoreGateway.base.json /tmp/
+      run: |
+        forge inspect src/core/ExocoreGateway.sol:ExocoreGateway storage-layout > ExocoreGateway.base.json.tmp
+        mv ExocoreGateway.base.json.tmp ExocoreGateway.base.json
-      - name: Copy back base branch layout file
-        run: cp /tmp/ExocoreGateway.base.json ./ExocoreGateway.base.json

Also applies to: 163-164

package.json (1)

12-12: Consider adding npm scripts for layout comparison workflow.

To streamline the CI process and make it easier to run locally, consider adding dedicated npm scripts for the storage layout comparison functionality.

Add these scripts to the scripts section:

  "scripts": {
    "test": "mocha",
+   "compile-layouts": "YOUR_COMPILE_COMMAND",
+   "compare-layouts": "node script/compareLayouts.js"
  },
.github/workflows/compare-layouts.yml (2)

17-73: Consider extracting status context as environment variable.

The status context "Compare Storage Layouts" is used in multiple places. Consider extracting it to an environment variable to maintain consistency and ease updates.

 jobs:
+  env:
+    STATUS_CONTEXT: "Compare Storage Layouts"
   set-commit-status:
     # ... existing code ...
             -d '{
               "state": "pending",
-              "context": "Compare Storage Layouts",
+              "context": "${{ env.STATUS_CONTEXT }}",

185-197: Simplify conditional logic for better readability.

The current shell logic using && and || is hard to read and potentially error-prone. Consider using a more explicit if-then-else structure.

-          outcome=$(
-            [[ "${{ steps.compare-layouts.outcome }}" == "success" ]] &&
-            echo "success" ||
-            echo "failure"
-          )
-          description=$(
-            [[ "${{ steps.compare-layouts.outcome }}" == "success" ]] &&
-            echo "Storage layouts match" ||
-            ([[ "${{ steps.compare-layouts.outcome }}" == "failure" ]] &&
-            echo "Storage layouts do not match" ||
-            echo "Job skipped since ${{ github.event.workflow_run.name }} failed.")
-          )
+          if [[ "${{ steps.compare-layouts.outcome }}" == "success" ]]; then
+            outcome="success"
+            description="Storage layouts match"
+          elif [[ "${{ steps.compare-layouts.outcome }}" == "failure" ]]; then
+            outcome="failure"
+            description="Storage layouts do not match"
+          else
+            outcome="failure"
+            description="Job skipped since ${{ github.event.workflow_run.name }} failed."
+          fi
🧰 Tools
🪛 actionlint (1.7.4)

185-185: shellcheck reported issue in this script: SC2015:info:7:61: Note that A && B || C is not if-then-else. C may run when A is true

(shellcheck)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 46f9927 and 7d5a4b4.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • .github/workflows/compare-layouts.yml (1 hunks)
  • .github/workflows/compare_deployed_storage_layout.py (0 hunks)
  • .github/workflows/compare_storage_layout.py (0 hunks)
  • .github/workflows/forge-ci.yml (5 hunks)
  • .github/workflows/lint.yml (2 hunks)
  • .github/workflows/reusable-foundry-setup.yml (2 hunks)
  • .github/workflows/status-comment.yml (1 hunks)
  • package.json (1 hunks)
  • script/compareLayouts.js (1 hunks)
  • src/storage/ClientChainGatewayStorage.sol (1 hunks)
💤 Files with no reviewable changes (2)
  • .github/workflows/compare_deployed_storage_layout.py
  • .github/workflows/compare_storage_layout.py
🧰 Additional context used
🪛 actionlint (1.7.4)
.github/workflows/compare-layouts.yml

120-120: shellcheck reported issue in this script: SC2086:info:1:55: Double quote to prevent globbing and word splitting

(shellcheck)


166-166: the runner of "actions/setup-node@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


185-185: shellcheck reported issue in this script: SC2015:info:7:61: Note that A && B || C is not if-then-else. C may run when A is true

(shellcheck)

.github/workflows/forge-ci.yml

40-40: shellcheck reported issue in this script: SC2086:info:1:55: Double quote to prevent globbing and word splitting

(shellcheck)


67-67: shellcheck reported issue in this script: SC2086:info:1:55: Double quote to prevent globbing and word splitting

(shellcheck)


82-82: shellcheck reported issue in this script: SC2086:info:1:30: Double quote to prevent globbing and word splitting

(shellcheck)


94-94: shellcheck reported issue in this script: SC2086:info:1:55: Double quote to prevent globbing and word splitting

(shellcheck)


119-119: shellcheck reported issue in this script: SC2086:info:1:55: Double quote to prevent globbing and word splitting

(shellcheck)


166-166: shellcheck reported issue in this script: SC2035:info:1:25: Use ./glob or -- glob so names with dashes won't become options

(shellcheck)

.github/workflows/lint.yml

23-23: the runner of "actions/setup-node@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🪛 yamllint (1.35.1)
.github/workflows/status-comment.yml

[error] 80-80: no new line character at the end of file

(new-line-at-end-of-file)

🔇 Additional comments (14)
.github/workflows/lint.yml (2)

Line range hint 1-13: LGTM! Well-configured workflow triggers

The workflow triggers are comprehensive, covering all necessary events (PRs, merges, and specific branch/tag pushes).


14-18: LGTM! Clear job naming and appropriate strategy

The job name "lint" clearly describes its purpose, and the fail-fast strategy is appropriate for linting tasks.

.github/workflows/reusable-foundry-setup.yml (3)

13-13: LGTM: Output references correctly updated

The output references have been properly updated to reflect the job rename from 'setup' to 'install', maintaining workflow consistency.

Also applies to: 16-16


Line range hint 19-24: LGTM: Job name change improves clarity

Renaming from 'setup' to 'install' better reflects the job's primary purpose of installing the Foundry toolchain. The outputs remain properly configured.


43-43: Verify the impact of removing OS-specific cache keys

The removal of ${{ runner.os }} from cache keys means all operating systems will share the same cache key. Since Foundry binaries are typically OS-specific, this could potentially cause issues.

Let's verify if this workflow is only used with Ubuntu runners:

If this workflow is used with multiple OS types, consider keeping the OS-specific cache keys to prevent potential issues with binary compatibility.

Also applies to: 47-47

✅ Verification successful

Cache key simplification is safe - workflow only runs on Ubuntu

The verification shows that:

  • The reusable workflow is only used by forge-ci.yml and compare-layouts.yml
  • All workflows in the repository, including the reusable workflow itself and its callers, exclusively use ubuntu-latest runners

Since the workflow and its dependencies are strictly Ubuntu-based, removing the OS-specific cache prefix is safe and won't cause any binary compatibility issues.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the workflow is only used with Ubuntu runners
# Expected: Only find references to ubuntu-latest as the runner

# Search for workflow files that reference this reusable workflow
echo "Searching for workflows using reusable-foundry-setup.yml..."
rg -l "uses: .*workflows/reusable-foundry-setup.yml" .github/workflows/

# Search for different runner types in those files
echo "Checking runner types in those workflows..."
rg "runs-on:" .github/workflows/ -A 1

Length of output: 1509

src/storage/ClientChainGatewayStorage.sol (2)

44-44: Ensure storage layout compatibility through new CI workflow

Since this PR introduces a new storage layout comparison workflow, please ensure that:

  1. This change passes the new storage layout comparison checks
  2. The reduction in storage gap doesn't create incompatibilities with deployed contracts

Let's verify the existence and configuration of the new workflow:


44-44: Verify the storage gap reduction and its implications

The storage gap has been reduced from 40 to 39 slots. While this might be intentional to accommodate new state variables, reducing the gap without clear documentation could limit future upgradability.

Let's verify the storage layout changes and their documentation:

Consider:

  1. Adding inline documentation explaining why the gap was reduced
  2. Updating storage layout documentation if it exists
  3. Ensuring this change is compatible with any deployed instances of this contract
.github/workflows/status-comment.yml (1)

16-19: LGTM! Well-scoped permissions

The permissions are appropriately minimal, following security best practices by only granting necessary access.

.github/workflows/forge-ci.yml (3)

Line range hint 1-11: LGTM! Well-structured workflow triggers

The workflow triggers are properly configured to run on necessary events while maintaining efficiency by limiting push events to relevant branches and tags.


15-21: LGTM! Good use of reusable workflow and version management

Excellent practice using a reusable workflow and maintaining foundry-version as a single source of truth.


Line range hint 84-107: LGTM! Consistent formatting check implementation

The format job follows the established pattern and correctly implements the formatting check.

🧰 Tools
🪛 actionlint (1.7.4)

82-82: shellcheck reported issue in this script: SC2086:info:1:30: Double quote to prevent globbing and word splitting

(shellcheck)


94-94: shellcheck reported issue in this script: SC2086:info:1:55: Double quote to prevent globbing and word splitting

(shellcheck)

package.json (1)

12-12: Verify OpenZeppelin package version security.

The addition of @openzeppelin/upgrades-core is appropriate for the storage layout comparison functionality. Let's verify the version for known vulnerabilities.

✅ Verification successful

@openzeppelin/upgrades-core v1.40.0 is secure and up-to-date

The version 1.40.0 is very close to the latest version (1.41.0) and there are no known security vulnerabilities reported for this package. The latest version was published recently (November 25, 2024), indicating active maintenance.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for known vulnerabilities in @openzeppelin/upgrades-core

# Get latest version and release date
echo "Checking latest version information..."
curl -s https://registry.npmjs.org/@openzeppelin/upgrades-core | jq -r '.["dist-tags"].latest, .time.modified'

# Check for security advisories
echo "Checking for security advisories..."
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: NPM, package: "@openzeppelin/upgrades-core") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Length of output: 673

.github/workflows/compare-layouts.yml (2)

1-13: LGTM! Well-configured workflow trigger and permissions.

The workflow trigger and permissions are properly configured following security best practices with the principle of least privilege.


74-82: Consider using a stable version instead of nightly.

Using the "nightly" version in a production workflow could lead to unexpected behavior if breaking changes are introduced. Consider pinning to a specific stable version for better reliability.

script/compareLayouts.js Outdated Show resolved Hide resolved
script/compareLayouts.js Outdated Show resolved Hide resolved
.github/workflows/status-comment.yml Outdated Show resolved Hide resolved
.github/workflows/status-comment.yml Outdated Show resolved Hide resolved
.github/workflows/forge-ci.yml Outdated Show resolved Hide resolved
.github/workflows/compare-layouts.yml Outdated Show resolved Hide resolved
.github/workflows/compare-layouts.yml Outdated Show resolved Hide resolved
.github/workflows/compare-layouts.yml Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Outside diff range and nitpick comments (6)
script/compareLayouts.js (3)

4-13: Document the special mapping between Bootstrap and ClientChainGateway

While most mappings compare deployed vs. compiled versions of the same contract, the last mapping compares Bootstrap with ClientChainGateway. Although this is intentional (as Bootstrap upgrades to ClientChainGateway), it would be helpful to document this special case.

Add a comment explaining the special case:

 const fileMappings = [
   { before: 'Bootstrap.deployed.json', after: 'Bootstrap.compiled.json' },
   { before: 'ClientChainGateway.deployed.json', after: 'ClientChainGateway.compiled.json' },
   { before: 'Vault.deployed.json', after: 'Vault.compiled.json' },
   { before: 'RewardVault.deployed.json', after: 'RewardVault.compiled.json' },
   { before: 'ExoCapsule.deployed.json', after: 'ExoCapsule.compiled.json' },
   { before: 'ExocoreGateway.base.json', after: 'ExocoreGateway.compiled.json' },
+  // Special case: Compare Bootstrap with ClientChainGateway as Bootstrap upgrades to it
   { before: 'Bootstrap.compiled.json', after: 'ClientChainGateway.compiled.json' },
 ];

19-27: Consider using async/await for file operations

The synchronous file operations (fs.existsSync, fs.readFileSync) could block the event loop. Consider using async versions for better performance.

Example refactor:

-    if (!fs.existsSync(before)) {
-      console.log(`⚠️ Skipping: ${before} does not exist.`);
-      return;
-    }
-    if (!fs.existsSync(after)) {
-      console.log(`⚠️ Skipping: ${after} does not exist.`);
-      return;
-    }
+    await Promise.all([
+      fs.promises.access(before).catch(() => {
+        console.log(`⚠️ Skipping: ${before} does not exist.`);
+        return Promise.reject();
+      }),
+      fs.promises.access(after).catch(() => {
+        console.log(`⚠️ Skipping: ${after} does not exist.`);
+        return Promise.reject();
+      })
+    ]);

15-47: Consider making file paths configurable

The script assumes JSON files are in the current directory. Consider making the base directory configurable through environment variables or command-line arguments.

Example improvement:

const baseDir = process.env.LAYOUTS_DIR || '.';
const getFilePath = (filename) => path.join(baseDir, filename);

fileMappings.forEach(({ before, after }) => {
  const beforePath = getFilePath(before);
  const afterPath = getFilePath(after);
  // ... use these paths instead of raw filenames
});
.github/workflows/forge-ci.yml (3)

15-21: Consider pinning to a specific nightly version

While using nightly ensures you get the latest features, it could lead to unexpected behavior if breaking changes are introduced. Consider pinning to a specific nightly version for better reproducibility.

-      foundry-version: nightly
+      foundry-version: nightly-87c4cef3f88920c42fb12956b0c291049ca8d609

55-55: Enhance build artifacts cache key

The current cache key only uses the commit SHA. Consider adding the runner OS and Foundry version to prevent potential cache conflicts:

-          key: build-${{ github.event.pull_request.head.sha || github.event.after || github.sha }}
+          key: build-${{ runner.os }}-foundry-${{ needs.setup.outputs.cache-key }}-${{ github.event.pull_request.head.sha || github.event.after || github.sha }}

82-82: Quote forge test arguments

To prevent potential issues with argument handling:

-        run: forge test -vvv
+        run: forge test "-vvv"
🧰 Tools
🪛 actionlint (1.7.4)

82-82: shellcheck reported issue in this script: SC2086:info:1:30: Double quote to prevent globbing and word splitting

(shellcheck)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 7d5a4b4 and c05fca0.

📒 Files selected for processing (4)
  • .github/workflows/compare-layouts.yml (1 hunks)
  • .github/workflows/forge-ci.yml (5 hunks)
  • .github/workflows/status-comment.yml (1 hunks)
  • script/compareLayouts.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/status-comment.yml
🧰 Additional context used
📓 Learnings (2)
.github/workflows/compare-layouts.yml (1)
Learnt from: MaxMustermann2
PR: ExocoreNetwork/exocore-contracts#127
File: .github/workflows/compare-layouts.yml:122-154
Timestamp: 2024-11-27T05:03:53.004Z
Learning: The `compareLayouts.js` script is responsible for error handling related to JSON parsing and field extraction, so additional error handling in the GitHub Actions workflow is unnecessary.
script/compareLayouts.js (1)
Learnt from: MaxMustermann2
PR: ExocoreNetwork/exocore-contracts#127
File: script/compareLayouts.js:12-12
Timestamp: 2024-11-27T04:58:50.251Z
Learning: In `script/compareLayouts.js`, the mapping comparing `Bootstrap.compiled.json` to `ClientChainGateway.compiled.json` is intentional because `Bootstrap` upgrades to `ClientChainGateway`.
🪛 actionlint (1.7.4)
.github/workflows/compare-layouts.yml

189-189: shellcheck reported issue in this script: SC2015:info:7:61: Note that A && B || C is not if-then-else. C may run when A is true

(shellcheck)

.github/workflows/forge-ci.yml

82-82: shellcheck reported issue in this script: SC2086:info:1:30: Double quote to prevent globbing and word splitting

(shellcheck)

🔇 Additional comments (9)
script/compareLayouts.js (2)

1-2: ⚠️ Potential issue

Avoid importing from internal package paths

Importing from the package's dist directory makes the code fragile as it depends on the internal structure of the package.

Apply this diff to import from the package's main entry point:

-const { getStorageUpgradeReport } = require('@openzeppelin/upgrades-core/dist/storage');
+const { getStorageUpgradeReport } = require('@openzeppelin/upgrades-core');

33-33: Verify the usage of unsafeAllowCustomTypes

The unsafeAllowCustomTypes flag is being used in the storage comparison. This flag might bypass important type safety checks.

Let's check if any custom types are used in the contracts:

✅ Verification successful

The use of unsafeAllowCustomTypes is justified in this context

The codebase contains multiple contracts with custom structs and enums, particularly in storage contracts like ExoCapsuleStorage.sol and GatewayStorage.sol. The unsafeAllowCustomTypes flag is necessary here to properly compare storage layouts that include these custom types. The script is using this flag as part of OpenZeppelin's upgrade validation process, which is a standard practice when dealing with custom types in upgradeable contracts.

  • The flag is used in a controlled environment (deployment script) for storage layout comparison
  • The script properly handles and reports any storage incompatibilities (report.ok check)
  • Multiple contracts in the codebase use legitimate custom types that require this flag
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for custom types in contract files
rg -l "struct\s+\w+\s*{" .

Length of output: 124


Script:

#!/bin/bash
# Search for custom types in contract files with fixed regex
rg -l "struct\s+\w+" .

# Also search for custom enum definitions
rg -l "enum\s+\w+" .

# Check the context of getStorageUpgradeReport usage
rg -A 5 "getStorageUpgradeReport" .

Length of output: 1710

.github/workflows/forge-ci.yml (3)

Line range hint 1-11: LGTM! Well-structured workflow triggers

The workflow configuration properly handles all necessary events including pull requests from forks, which aligns with the PR objectives.


Line range hint 84-107: LGTM! Well-structured format job

The formatting check is properly configured and maintains consistency with other jobs.

🧰 Tools
🪛 actionlint (1.7.4)

82-82: shellcheck reported issue in this script: SC2086:info:1:30: Double quote to prevent globbing and word splitting

(shellcheck)


166-166: Fix glob pattern in zip command

The zip command uses unquoted glob patterns which could cause issues with filenames containing special characters.

-        run: zip "storage-layouts.zip" "./*.compiled.json" "./ExocoreGateway.base.json"
+        run: zip storage-layouts.zip ./*.compiled.json ./ExocoreGateway.base.json
.github/workflows/compare-layouts.yml (4)

1-13: LGTM! Well-configured workflow trigger and permissions.

The workflow is properly configured with:

  • Clear trigger conditions based on the "Forge CI" workflow completion
  • Minimal required permissions following security best practices

40-60: LGTM! Robust PR number extraction logic.

The PR number extraction logic correctly handles:

  • Cross-repository PRs
  • Error cases with appropriate messaging
  • Output variable setting

236-244: LGTM! Proper exit code handling.

The final exit code handling ensures that the workflow fails appropriately when the comparison fails or when the parent job fails.


78-86: Consider using a stable Foundry version.

Using the nightly version in CI could lead to unexpected failures if breaking changes are introduced. Consider pinning to a stable version unless nightly features are specifically required.

script/compareLayouts.js Outdated Show resolved Hide resolved
.github/workflows/forge-ci.yml Outdated Show resolved Hide resolved
.github/workflows/forge-ci.yml Outdated Show resolved Hide resolved
.github/workflows/compare-layouts.yml Outdated Show resolved Hide resolved
.github/workflows/compare-layouts.yml Outdated Show resolved Hide resolved
.github/workflows/compare-layouts.yml Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (7)
.github/workflows/forge-ci.yml (4)

15-21: Well-structured reusable workflow implementation

Good practice using a reusable workflow and centralizing the Foundry version. This improves maintainability and reduces version inconsistencies across the CI pipeline.

Consider documenting the version selection criteria in the repository's contributing guidelines to help maintainers understand when and why to update the Foundry version.


46-47: Add error handling to the build step

Consider adding error handling and build status reporting:

-      - name: Build
-        run: forge build
+      - name: Build
+        id: build
+        run: |
+          if ! forge build; then
+            echo "::error::Build failed"
+            exit 1
+          fi
+          echo "Build completed successfully"

81-83: Consider preserving test results as artifacts

While the test summary is helpful, consider also uploading test results as artifacts for historical comparison and debugging:

       - name: Test
-        run: forge test -vvv
+        run: |
+          mkdir -p test-results
+          forge test -vvv --json > test-results/results.json
       - name: Set test snapshot as summary
         run: NO_COLOR=1 forge snapshot >> $GITHUB_STEP_SUMMARY
+      - name: Upload test results
+        uses: actions/upload-artifact@v4
+        with:
+          name: test-results-${{ github.event.pull_request.head.sha || github.event.after || github.sha }}
+          path: test-results/
🧰 Tools
🪛 actionlint (1.7.4)

82-82: shellcheck reported issue in this script: SC2086:info:1:30: Double quote to prevent globbing and word splitting

(shellcheck)


109-164: Well-structured storage layout extraction process

The job effectively implements the storage layout comparison workflow:

  • Proper handling of base branch and PR layouts
  • Efficient use of temporary storage
  • Comprehensive artifact preservation

This implementation aligns well with the PR objective of carving out storage layout CI, allowing the comparison workflow to run in a trusted context with API access.

.github/workflows/compare-layouts.yml (3)

38-56: Consider enhancing error message for PR lookup failures.

The error handling for PR lookup could be more informative by including the actual API response.

-          if [ -z "$pr_number" ]; then
-            echo "Error: PR number not found for branch '${PR_BRANCH}' in repository '${PR_TARGET_REPO}'" >&2
+          pr_response=$(gh pr view --repo "${PR_TARGET_REPO}" "${PR_BRANCH}" 2>&1)
+          if [ $? -ne 0 ]; then
+            echo "Error: Failed to find PR for branch '${PR_BRANCH}' in repository '${PR_TARGET_REPO}'" >&2
+            echo "API Response: ${pr_response}" >&2
             exit 1
           fi

122-154: Consider improving the contract processing logic.

The contract processing could be enhanced for better maintainability and error handling.

-          declare -A contracts=(
-            ["Bootstrap"]="$bootstrap"
-            ["ClientChainGateway"]="$clientGateway"
-            ["Vault"]="$vault"
-            ["RewardVault"]="$rewardVault"
-            ["ExoCapsule"]="$capsule"
-          )
+          # Define contracts configuration in a more structured way
+          config_file=$(mktemp)
+          cat > "$config_file" << EOF
+          {
+            "Bootstrap": "$bootstrap",
+            "ClientChainGateway": "$clientGateway",
+            "Vault": "$vault",
+            "RewardVault": "$rewardVault",
+            "ExoCapsule": "$capsule"
+          }
+          EOF
+
+          # Process contracts using jq
+          jq -r 'to_entries[] | select(.value != null) | [.key, .value] | @tsv' "$config_file" |
+          while IFS=$'\t' read -r contract address; do
+            echo "Processing $contract at address $address"
+            cast storage --json "$address" --rpc-url "$RPC_URL" \
+              --etherscan-api-key "$ETHERSCAN_API_KEY" > "$contract.deployed.json" || {
+                echo "Failed to fetch storage for $contract" >&2
+                exit 1
+              }
+            mv "$contract.deployed.json" "$pwd"
+          done

213-220: Consider using a case statement for better readability.

The message setting logic could be more readable using a case statement.

-          if [ ${{ steps.compare-layouts.outcome }} == "success" ]; then
-            message="✅ The $WORKFLOW_NAME workflow has completed successfully."
-          elif [ ${{ steps.compare-layouts.outcome }} == "failure" ]; then
-            message="❌ The $WORKFLOW_NAME workflow has failed!"
-          else
-            message="⏭ The $WORKFLOW_NAME workflow was skipped."
-          fi
+          case "${{ steps.compare-layouts.outcome }}" in
+            "success")
+              message="✅ The $WORKFLOW_NAME workflow has completed successfully."
+              ;;
+            "failure")
+              message="❌ The $WORKFLOW_NAME workflow has failed!"
+              ;;
+            *)
+              message="⏭ The $WORKFLOW_NAME workflow was skipped."
+              ;;
+          esac
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c05fca0 and dd628db.

📒 Files selected for processing (2)
  • .github/workflows/compare-layouts.yml (1 hunks)
  • .github/workflows/forge-ci.yml (5 hunks)
🧰 Additional context used
📓 Learnings (2)
.github/workflows/compare-layouts.yml (1)
Learnt from: MaxMustermann2
PR: ExocoreNetwork/exocore-contracts#127
File: .github/workflows/compare-layouts.yml:122-154
Timestamp: 2024-11-27T05:03:53.004Z
Learning: The `compareLayouts.js` script is responsible for error handling related to JSON parsing and field extraction, so additional error handling in the GitHub Actions workflow is unnecessary.
.github/workflows/forge-ci.yml (1)
Learnt from: MaxMustermann2
PR: ExocoreNetwork/exocore-contracts#127
File: .github/workflows/forge-ci.yml:160-162
Timestamp: 2024-11-27T05:11:26.802Z
Learning: In CI scripts, it's acceptable to assume that required files exist and commands succeed; failures should be addressed by modifying the CI in the PR.
🪛 actionlint (1.7.4)
.github/workflows/compare-layouts.yml

29-29: receiver of object dereference "name" must be type of object but got "string"

(expression)


188-188: receiver of object dereference "name" must be type of object but got "string"

(expression)

.github/workflows/forge-ci.yml

82-82: shellcheck reported issue in this script: SC2086:info:1:30: Double quote to prevent globbing and word splitting

(shellcheck)

🔇 Additional comments (6)
.github/workflows/forge-ci.yml (3)

Line range hint 1-11: LGTM! Well-structured workflow triggers

The workflow triggers are properly configured with clear and specific event types and branch patterns.


107-108: LGTM! Format check is properly configured

The formatting check is appropriately set up using forge fmt --check.


159-159: Fix glob pattern in zip command

The zip command uses an unquoted glob pattern which could cause issues with filenames containing special characters.

-        run: zip storage-layouts.zip ./*.compiled.json ./ExocoreGateway.base.json
+        run: zip storage-layouts.zip -- ./*.compiled.json ./ExocoreGateway.base.json
.github/workflows/compare-layouts.yml (3)

1-13: LGTM! Well-configured workflow permissions.

The workflow configuration follows security best practices by:

  • Using workflow_run trigger for better security with forked repositories
  • Explicitly defining minimal required permissions

91-94: LGTM! Proper secret handling.

The workflow correctly uses repository secrets for API keys.


75-83: Consider using a stable Foundry version.

Using nightly builds in CI can lead to unexpected failures if breaking changes are introduced. Consider pinning to a stable version unless there's a specific need for nightly features.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (3)
.github/workflows/reusable-foundry-setup.yml (1)

19-22: Consider enhancing the cache-key output description.

While the output references are correctly updated, the description for cache-key could be more specific about its format (e.g., "Cache key in format 'foundry-{version}' for Foundry toolchain").

script/compareLayouts.js (2)

9-10: Track the RewardVault deployment status

The TODO comment indicates that RewardVault.deployed.json will be required after deployment. This should be tracked to ensure the flag is updated post-deployment.

Would you like me to create a GitHub issue to track this TODO?


38-38: Document the usage of unsafeAllowCustomTypes

The unsafeAllowCustomTypes flag is used without explanation. Consider adding a comment explaining why this flag is necessary and any potential risks.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between dd628db and 65a4656.

📒 Files selected for processing (4)
  • .github/workflows/compare-layouts.yml (1 hunks)
  • .github/workflows/reusable-foundry-setup.yml (2 hunks)
  • .github/workflows/status-comment.yml (1 hunks)
  • script/compareLayouts.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/compare-layouts.yml
  • .github/workflows/status-comment.yml
🧰 Additional context used
📓 Learnings (1)
script/compareLayouts.js (2)
Learnt from: MaxMustermann2
PR: ExocoreNetwork/exocore-contracts#127
File: script/compareLayouts.js:43-46
Timestamp: 2024-11-27T05:09:46.690Z
Learning: In `script/compareLayouts.js`, for the CI process, the existing error logging is sufficient, and adding more granular error handling is not required.
Learnt from: MaxMustermann2
PR: ExocoreNetwork/exocore-contracts#127
File: script/compareLayouts.js:12-12
Timestamp: 2024-11-27T04:58:50.251Z
Learning: In `script/compareLayouts.js`, the mapping comparing `Bootstrap.compiled.json` to `ClientChainGateway.compiled.json` is intentional because `Bootstrap` upgrades to `ClientChainGateway`.
🔇 Additional comments (7)
.github/workflows/reusable-foundry-setup.yml (4)

9-15: LGTM! Well-documented input parameters.

The new skip-install parameter is well-documented and serves its purpose in allowing the workflow to run without installation, which aligns with the PR's objective of supporting forked repository PRs.


25-30: LGTM! Job name better reflects its purpose.

The rename from setup to install improves clarity by better describing the job's primary function while maintaining the same output structure.


54-55: LGTM! Improved cache key format.

The simplified cache key format foundry-${{ inputs.foundry-version }} is more predictable and appropriate since the job only runs on ubuntu-latest.


Line range hint 1-63: Verify workflow integration with storage layout comparison.

Since this workflow is part of the storage layout CI restructuring, ensure it properly integrates with the new Compare Storage Layouts workflow, particularly when:

  1. Running with skip-install: true in the forked PR context
  2. Running with skip-install: false in the trusted context
✅ Verification successful

Integration with storage layout comparison workflow verified successfully

The workflow properly integrates with both the forge-ci and compare-layouts workflows:

  • In forge-ci.yml: Used with default skip-install: false for trusted context
  • In compare-layouts.yml: Correctly implements skip-install based on the parent workflow's success status
  • Both workflows consistently use the same Foundry version (nightly)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check how this workflow is called from other workflows
rg "uses: .*reusable-foundry-setup" .github/workflows/

Length of output: 239


Script:

#!/bin/bash
# Check how the workflow is called in forge-ci.yml
rg -A 10 "uses: .*reusable-foundry-setup" .github/workflows/forge-ci.yml

# Check how the workflow is called in compare-layouts.yml
rg -A 10 "uses: .*reusable-foundry-setup" .github/workflows/compare-layouts.yml

Length of output: 1077

script/compareLayouts.js (3)

1-2: Avoid importing from the 'dist' directory

Importing directly from the dist directory is fragile as it depends on the internal structure of the package. Consider importing from the package's main entry point instead.

-const { getStorageUpgradeReport } = require('@openzeppelin/upgrades-core/dist/storage');
+const { getStorageUpgradeReport } = require('@openzeppelin/upgrades-core');

5-14: LGTM! Well-structured configuration

The file mappings configuration is clear and well-organized:

  • Each mapping clearly defines the files to compare
  • The mustExist flag provides flexibility for handling optional files
  • The mapping between Bootstrap and ClientChainGateway is intentionally included for upgrade verification

16-52: LGTM! Well-implemented comparison logic

The implementation is robust and well-suited for CI:

  • Proper file existence checks with clear error messages
  • Effective JSON parsing and comparison using OpenZeppelin's tools
  • Clear output formatting for CI logs
  • Appropriate error handling and exit code management

.github/workflows/reusable-foundry-setup.yml Outdated Show resolved Hide resolved
@MaxMustermann2 MaxMustermann2 linked an issue Nov 27, 2024 that may be closed by this pull request
Copy link
Collaborator

@adu-web3 adu-web3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

impressive! this would certainly improve the CI workflow

src/storage/ClientChainGatewayStorage.sol Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (7)
.github/workflows/slither.yml (1)

15-16: Document timeout rationale in workflow.

Consider adding more context in the comment about why 10 minutes was chosen as the timeout value.

-    # Takes about 2 minutes
+    # Default timeout set to 10 minutes (typical run: 2 minutes)
+    # Increased buffer accounts for larger PRs and potential CI load
     timeout-minutes: 10
.github/workflows/lint.yml (1)

Line range hint 34-37: Consider adding error notifications.

The removal of the failure comment mechanism means developers won't be notified of linting failures. Consider adding GitHub status checks or annotations for better visibility.

      - name: Run Solhint
        run: |
          npx solhint 'src/**/*.sol' -c ./src/.solhint.json
+         if [ $? -ne 0 ]; then
+           echo "::error::Solhint found issues. Please check the logs above."
+           exit 1
+         fi
.github/workflows/reusable-foundry-setup.yml (1)

18-22: Improve output descriptions to indicate optional availability

The output descriptions should clarify that these values might not be available when skip-install is true.

     outputs:
       installation-dir:
-        description: "The installation directory of Foundry toolchain"
+        description: "The installation directory of Foundry toolchain. Empty when skip-install is true."
         value: ${{ jobs.install.outputs.installation-dir }}
       cache-key:
-        description: "The cache key for Foundry toolchain"
+        description: "The cache key for Foundry toolchain. Empty when skip-install is true."
         value: ${{ jobs.install.outputs.cache-key }}
.github/workflows/forge-ci.yml (4)

15-21: Good use of reusable workflow pattern

The setup leverages GitHub Actions' reusable workflows feature, which promotes maintainability and consistency. The comment about foundry-version being the single source of truth is valuable documentation.

Consider documenting the version selection criteria (why nightly?) in the repository's contributing guidelines or CI documentation.


48-49: Add error handling and build verification

The build step could benefit from additional error handling and verification.

-      - name: Build
-        run: forge build
+      - name: Build
+        run: |
+          forge build
+          # Verify build artifacts exist
+          if [ ! -d "out" ] || [ -z "$(ls -A out)" ]; then
+            echo "::error::Build failed - no artifacts generated"
+            exit 1
+          fi

84-87: Consider preserving test results as artifacts

While the test snapshot is added to the workflow summary, preserving detailed test results as artifacts would be valuable for debugging failures.

       - name: Test
-        run: forge test -vvv
+        run: |
+          mkdir -p test-results
+          forge test -vvv --json > test-results/forge-test.json || { exit_code=$?; cp test-results/forge-test.json test-results/forge-test-failed.json; exit $exit_code; }
+      - name: Upload test results
+        if: always()
+        uses: actions/upload-artifact@v4
+        with:
+          name: forge-test-results
+          path: test-results/
🧰 Tools
🪛 actionlint (1.7.4)

86-86: shellcheck reported issue in this script: SC2086:info:1:30: Double quote to prevent globbing and word splitting

(shellcheck)


161-163: Consider making the contract list configurable

The list of contracts is currently hardcoded in the script. Consider moving it to a configuration file for better maintainability.

+      - name: Create contract list
+        run: |
+          cat > contracts.txt << EOL
+          Bootstrap
+          ClientChainGateway
+          RewardVault
+          Vault
+          ExocoreGateway
+          ExoCapsule
+          EOL
       - name: Generate storage layout files for the PR
         run: |
-          for file in Bootstrap ClientChainGateway RewardVault Vault ExocoreGateway ExoCapsule; do
+          while IFS= read -r file; do
             forge inspect src/core/${file}.sol:${file} storage-layout > ${file}.compiled.json;
-          done
+          done < contracts.txt
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 1b9c587 and aadac30.

📒 Files selected for processing (6)
  • .github/workflows/compare-layouts.yml (1 hunks)
  • .github/workflows/forge-ci.yml (5 hunks)
  • .github/workflows/lint.yml (2 hunks)
  • .github/workflows/reusable-foundry-setup.yml (2 hunks)
  • .github/workflows/slither.yml (1 hunks)
  • .github/workflows/status-comment.yml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/compare-layouts.yml
  • .github/workflows/status-comment.yml
🧰 Additional context used
📓 Learnings (2)
.github/workflows/forge-ci.yml (1)
Learnt from: MaxMustermann2
PR: ExocoreNetwork/exocore-contracts#127
File: .github/workflows/forge-ci.yml:160-162
Timestamp: 2024-11-27T05:11:26.802Z
Learning: In CI scripts, it's acceptable to assume that required files exist and commands succeed; failures should be addressed by modifying the CI in the PR.
.github/workflows/reusable-foundry-setup.yml (1)
Learnt from: MaxMustermann2
PR: ExocoreNetwork/exocore-contracts#127
File: .github/workflows/reusable-foundry-setup.yml:57-63
Timestamp: 2024-11-27T06:17:09.257Z
Learning: In `reusable-foundry-setup.yml`, when `skip-install` is true, the cache key may not be set, and the input description doesn't indicate that the cache key will always be available.
🪛 actionlint (1.7.4)
.github/workflows/forge-ci.yml

86-86: shellcheck reported issue in this script: SC2086:info:1:30: Double quote to prevent globbing and word splitting

(shellcheck)

.github/workflows/lint.yml

25-25: the runner of "actions/setup-node@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🔇 Additional comments (8)
.github/workflows/lint.yml (2)

Line range hint 1-12: LGTM! Clear and well-structured workflow configuration.

The workflow triggers are comprehensive, covering all necessary events (PRs, merges, and releases).


14-20: Verify if the 5-minute timeout is sufficient.

While adding a timeout is good practice, please verify that 5 minutes is enough for your codebase size.

✅ Verification successful

5-minute timeout is more than sufficient for this linting workflow

Based on the historical runs data, the linting workflow consistently completes in less than 1 minute (around 30-40 seconds). The codebase is relatively small with Solidity files, and the workflow only runs Solhint linting. The current 5-minute timeout provides ample buffer for potential variations in execution time.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check historical run times of the linting workflow to ensure 5 minutes is sufficient

# Get the last 10 workflow runs and their duration
gh run list --workflow=lint.yml --limit 10 --json durationInMinutes \
  | jq -r '.[] | .durationInMinutes'

Length of output: 347


Script:

#!/bin/bash
# Let's try a different approach to check the workflow execution times
# Get the last 10 workflow runs with their start and completion times
gh run list --workflow=lint.yml --limit 10 --json startedAt,updatedAt \
  | jq -r '.[] | (.startedAt + " to " + .updatedAt)'

# Also, let's check the size of the codebase to estimate potential lint time
find . -type f -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" | wc -l

# And check what linting tasks are configured
cat .github/workflows/lint.yml

Length of output: 1355

.github/workflows/reusable-foundry-setup.yml (2)

25-27: LGTM! Job configuration is well structured.

The timeout of 15 minutes provides sufficient buffer for the 3-minute caching operation.


57-58: Verify the impact of simplified cache key format

The cache key format has been simplified to exclude the runner's OS. Please verify that this doesn't cause issues with cross-platform builds.

Also applies to: 62-63

✅ Verification successful

Cache key format change is safe to proceed

The simplified cache key format is acceptable because:

  1. This is the only workflow file using Foundry-related caching
  2. The cache is version-specific through inputs.foundry-version, which is sufficient for isolation
  3. Foundry toolchain is platform-independent, so OS-specific caching is unnecessary
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are any other workflows that might depend on OS-specific cache keys
rg -l "runner.os.*foundry" .github/workflows/

Length of output: 47


Script:

#!/bin/bash
# Let's check for any cache key patterns in workflow files
rg -A 2 "key:.*foundry" .github/workflows/

# Also check for any cache restore/save actions with foundry
rg -A 2 "actions/cache@.*foundry" .github/workflows/

Length of output: 355

.github/workflows/forge-ci.yml (4)

Line range hint 1-11: LGTM! Well-structured workflow configuration

The workflow triggers and branch filters are appropriately configured for the CI pipeline.


Line range hint 89-113: LGTM! Clean formatting check implementation

The formatting check is appropriately configured with proper artifact restoration.

🧰 Tools
🪛 actionlint (1.7.4)

86-86: shellcheck reported issue in this script: SC2086:info:1:30: Double quote to prevent globbing and word splitting

(shellcheck)


166-167: Fix glob pattern in zip command

The zip command uses an unquoted glob pattern which could cause issues with filenames containing special characters.

-      - name: Zip storage layout files
-        run: zip storage-layouts.zip ./*.compiled.json ./ExocoreGateway.base.json
+      - name: Zip storage layout files
+        run: zip storage-layouts.zip -- ./*.compiled.json ./ExocoreGateway.base.json

168-172: LGTM! Well-structured artifact upload

The artifact upload is properly configured with a unique name based on the commit SHA.

.github/workflows/slither.yml Show resolved Hide resolved
.github/workflows/lint.yml Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (7)
.github/workflows/lint.yml (1)

1-1: Consider reducing the timeout duration.

The configuration looks good, but since the job usually completes in 30 seconds, consider reducing the timeout from 5 minutes to 2 minutes to fail faster in case of issues.

-    timeout-minutes: 5
+    timeout-minutes: 2

Also applies to: 14-16

.github/workflows/forge-ci.yml (3)

Line range hint 23-57: Consider adding error handling for the build step

While the build configuration is good, the build step could benefit from error handling and logging.

-      - name: Build
-        run: forge build
+      - name: Build
+        run: |
+          echo "Starting build process..."
+          if ! forge build; then
+            echo "::error::Build failed"
+            exit 1
+          fi
+          echo "Build completed successfully"

86-87: Quote the command output redirection

The snapshot command should have quoted redirection to handle special characters safely.

-        run: NO_COLOR=1 forge snapshot >> $GITHUB_STEP_SUMMARY
+        run: NO_COLOR=1 forge snapshot >> "$GITHUB_STEP_SUMMARY"
🧰 Tools
🪛 actionlint (1.7.4)

86-86: shellcheck reported issue in this script: SC2086:info:1:30: Double quote to prevent globbing and word splitting

(shellcheck)


Line range hint 1-204: Consider adding workflow status checks

Based on the PR objectives mentioning the need for status posting, consider adding status check steps at key points in the workflow.

Example implementation:

      - name: Set workflow status
        if: always()
        uses: actions/github-script@v7
        with:
          script: |
            const status = ${{ job.status }} === 'success' ? 'success' : 'failure';
            await github.rest.repos.createCommitStatus({
              owner: context.repo.owner,
              repo: context.repo.repo,
              sha: context.sha,
              state: status,
              context: 'Forge CI',
              description: 'Forge CI workflow completed'
            });
.github/workflows/compare-layouts.yml (3)

61-67: Enhance error handling for PR number retrieval.

While the current implementation checks if the PR number is empty, it would be beneficial to add more specific error handling for different failure scenarios.

 pr_number=$(gh pr view --repo "${PR_TARGET_REPO}" "${PR_BRANCH}" \
       --json 'number' --jq '.number')
+if [ $? -ne 0 ]; then
+  echo "Error: Failed to retrieve PR information. Command exited with status $?" >&2
+  exit 1
+fi
 if [ -z "$pr_number" ]; then
   echo "Error: PR number not found for branch '${PR_BRANCH}' in repository '${PR_TARGET_REPO}'" >&2
   exit 1
 fi

161-172: Optimize layout fetching with parallel processing.

Following up on @bwhour's suggestion, we can optimize the layout fetching process using GNU parallel.

+fetch_layout() {
+  local name=$1
+  local address=$2
+  local rpc_url=$3
+  local etherscan_key=$4
+  
+  echo "Processing $name at address $address"
+  cast storage --json "$address" \
+    --rpc-url "$rpc_url" \
+    --etherscan-api-key "$etherscan_key" > "$name.deployed.json"
+}
+
+export -f fetch_layout
+
 echo "Processing ${{ matrix.contract.name }} at address ${{ matrix.contract.address }}"
 RPC_URL="https://eth-sepolia.g.alchemy.com/v2/$ALCHEMY_API_KEY"
-cast storage --json "${{ matrix.contract.address }}" \
-  --rpc-url "$RPC_URL" \
-  --etherscan-api-key "$ETHERSCAN_API_KEY" > "${{ matrix.contract.name }}.deployed.json"
+parallel --jobs 3 fetch_layout {1} {2} "$RPC_URL" "$ETHERSCAN_API_KEY" ::: \
+  "${{ matrix.contract.name }}" ::: "${{ matrix.contract.address }}"

236-246: Add caching for npm dependencies.

Consider caching the npm dependencies to speed up the workflow execution.

 - name: Set up Node.js
   if: ${{ github.event.workflow_run.conclusion == 'success' }}
   uses: actions/setup-node@v4
   with:
     node-version: '18'
+    cache: 'npm'
+    cache-dependency-path: 'package-lock.json'
 - name: Clear npm cache
   if: ${{ github.event.workflow_run.conclusion == 'success' }}
   run: npm cache clean --force
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between aadac30 and 491ecba.

📒 Files selected for processing (3)
  • .github/workflows/compare-layouts.yml (1 hunks)
  • .github/workflows/forge-ci.yml (6 hunks)
  • .github/workflows/lint.yml (2 hunks)
🧰 Additional context used
📓 Learnings (2)
.github/workflows/compare-layouts.yml (1)
Learnt from: MaxMustermann2
PR: ExocoreNetwork/exocore-contracts#127
File: .github/workflows/compare-layouts.yml:122-154
Timestamp: 2024-11-27T05:03:53.004Z
Learning: The `compareLayouts.js` script is responsible for error handling related to JSON parsing and field extraction, so additional error handling in the GitHub Actions workflow is unnecessary.
.github/workflows/forge-ci.yml (1)
Learnt from: MaxMustermann2
PR: ExocoreNetwork/exocore-contracts#127
File: .github/workflows/forge-ci.yml:160-162
Timestamp: 2024-11-27T05:11:26.802Z
Learning: In CI scripts, it's acceptable to assume that required files exist and commands succeed; failures should be addressed by modifying the CI in the PR.
🪛 actionlint (1.7.4)
.github/workflows/compare-layouts.yml

112-112: shellcheck reported issue in this script: SC2086:info:24:21: Double quote to prevent globbing and word splitting

(shellcheck)

.github/workflows/forge-ci.yml

86-86: shellcheck reported issue in this script: SC2086:info:1:30: Double quote to prevent globbing and word splitting

(shellcheck)

🔇 Additional comments (4)
.github/workflows/forge-ci.yml (2)

15-21: LGTM! Well-structured setup using reusable workflow pattern.

The setup job is well-organized and documented, with clear explanations for design decisions.


199-199: ⚠️ Potential issue

Fix zip command to handle special characters

The zip command should use proper path handling to avoid issues with special characters in filenames.

-        run: zip -j compiled-layouts.zip combined/*/*.json
+        run: zip -j compiled-layouts.zip ./combined/*/*.json
.github/workflows/compare-layouts.yml (2)

1-13: LGTM! Well-structured workflow configuration with proper permissions.

The workflow configuration follows security best practices by explicitly defining minimum required permissions.


179-201: LGTM! Well-structured artifact handling.

The job effectively combines the deployed layouts and uses the latest version of the download-artifact action.

.github/workflows/lint.yml Outdated Show resolved Hide resolved
.github/workflows/compare-layouts.yml Outdated Show resolved Hide resolved
.github/workflows/compare-layouts.yml Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
.github/workflows/lint.yml (1)

14-16: LGTM! Good job configuration with timeout.

The job name is clear, and the timeout addition is a good practice. The comment about typical duration helps justify the timeout value.

Consider adding a comment explaining why 5 minutes was chosen as the timeout value, especially since it's 10x the typical duration:

    # Usually done in 30 seconds
-    timeout-minutes: 5
+    timeout-minutes: 5 # 5min timeout to account for potential npm registry delays
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 491ecba and 99bb116.

📒 Files selected for processing (2)
  • .github/workflows/compare-layouts.yml (1 hunks)
  • .github/workflows/lint.yml (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/compare-layouts.yml
🔇 Additional comments (3)
.github/workflows/lint.yml (3)

1-1: LGTM! Clear and concise workflow name.

The simplified name "Solhint" effectively communicates the workflow's purpose.


25-27: Changes already addressed in previous reviews.


Line range hint 35-36: Verify the Solhint configuration file location.

The Solhint configuration file is located at ./src/.solhint.json, which is non-standard. Consider moving it to the repository root for better visibility and maintainability.

@MaxMustermann2 MaxMustermann2 added this pull request to the merge queue Nov 27, 2024
Merged via the queue into ExocoreNetwork:main with commit 4a2c8ee Nov 27, 2024
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[CI] Layout CI does not work from forked repos
4 participants