diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..8e5296dbd8 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default-days: 7 + groups: + github-actions: + patterns: + - "*" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3690949bbe..c82a85a8f4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,6 +5,7 @@ on: inputs: tag: default: '' + type: string push: branches: - master @@ -12,6 +13,12 @@ on: release: types: [published] # releases and pre-releases (release candidates) +permissions: + contents: read + +env: + PYTHON_VERSION: "3.12" + defaults: run: shell: bash @@ -19,6 +26,7 @@ defaults: jobs: unix-build: runs-on: ${{ matrix.os }} + timeout-minutes: 45 strategy: matrix: os: @@ -29,22 +37,22 @@ jobs: - macos-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: # grab the commit passed in via `tag`, if any ref: ${{ github.event.inputs.tag }} # need to fetch unshallow so that setuptools_scm can infer the version fetch-depth: 0 + persist-credentials: false # debug - name: Git shorthash run: git rev-parse --short HEAD - name: Python - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: - python-version: "3.11" - cache: "pip" + python-version: ${{ env.PYTHON_VERSION }} - name: Generate Binary run: | @@ -58,31 +66,32 @@ jobs: - name: Upload Artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: vyper-${{ runner.os }} path: dist/vyper.* windows-build: runs-on: windows-latest + timeout-minutes: 45 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: # grab the commit passed in via `tag`, if any ref: ${{ github.event.inputs.tag }} # need to fetch unshallow so that setuptools_scm can infer the version fetch-depth: 0 + persist-credentials: false # debug - name: Git shorthash run: git rev-parse --short HEAD - name: Python - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: - python-version: "3.11" - cache: "pip" + python-version: ${{ env.PYTHON_VERSION }} - name: Generate Binary run: >- @@ -91,7 +100,7 @@ jobs: ./make.cmd freeze - name: Upload Artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: vyper-${{ runner.os }} path: dist/vyper.* @@ -100,26 +109,36 @@ jobs: needs: [windows-build, unix-build] if: ${{ github.event_name == 'release' }} runs-on: ubuntu-latest + timeout-minutes: 45 + permissions: + # Upload generated binaries to the GitHub release. + contents: write steps: - - uses: actions/checkout@v6 - - uses: actions/download-artifact@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: artifacts/ merge-multiple: true - name: Upload assets working-directory: artifacts + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPOSITORY: ${{ github.repository }} + RELEASE_ID: ${{ github.event.release.id }} run: | - set -Eeuxo pipefail + set -Eeuo pipefail for BIN_NAME in $(ls) do curl -L \ --no-progress-meter \ -X POST \ - -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"\ + -H "Authorization: Bearer ${GH_TOKEN}"\ -H "Content-Type: application/octet-stream" \ - "https://uploads.github.com/repos/${{ github.repository }}/releases/${{ github.event.release.id }}/assets?name=${BIN_NAME/+/%2B}" \ + "https://uploads.github.com/repos/${REPOSITORY}/releases/${RELEASE_ID}/assets?name=${BIN_NAME/+/%2B}" \ --data-binary "@${BIN_NAME}" done @@ -127,7 +146,9 @@ jobs: build-success: if: always() runs-on: ubuntu-latest + timeout-minutes: 45 needs: [windows-build, unix-build] + permissions: {} steps: - name: check that all builds succeeded if: ${{ contains(needs.*.result, 'failure') }} diff --git a/.github/workflows/bytecode-size-comment.yml b/.github/workflows/bytecode-size-comment.yml new file mode 100644 index 0000000000..bbb869f324 --- /dev/null +++ b/.github/workflows/bytecode-size-comment.yml @@ -0,0 +1,82 @@ +name: Bytecode Size PR Comment + +on: + workflow_run: # zizmor: ignore[dangerous-triggers] Comment-only follow-up; never checks out or executes PR code. + workflows: ["Bytecode Size Report"] + types: [completed] + +permissions: {} + +jobs: + comment: + if: > + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'pull_request' + runs-on: ubuntu-latest + timeout-minutes: 45 + permissions: + # Download the report artifact from the completed measurement run. + actions: read + # Required by artifact download and workflow run metadata reads. + contents: read + # Update only the benchmark report comment on the pull request. + pull-requests: write + steps: + - name: Download report + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: bytecode-size-report + path: report + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Post or update PR comment + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + with: + script: | + const fs = require('fs'); + const marker = ''; + const report = fs.readFileSync('report/report.md', 'utf8'); + const body = marker + '\n\n' + report; + const workflowRun = context.payload.workflow_run; + let issue_number = (workflowRun.pull_requests || []).find(pr => pr.number)?.number; + if (!issue_number) { + const headOwner = workflowRun.head_repository?.owner?.login; + const headBranch = workflowRun.head_branch; + if (!headOwner || !headBranch) { + core.info('Could not resolve pull request for workflow run.'); + return; + } + const { data: pulls } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + head: `${headOwner}:${headBranch}` + }); + const pull = pulls.find(pr => pr.head.sha === workflowRun.head_sha) || pulls[0]; + if (!pull) { + core.info(`No open pull request found for ${headOwner}:${headBranch}.`); + return; + } + issue_number = pull.number; + } + const comments = await github.paginate(github.rest.issues.listComments, { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number + }); + const existing = comments.find(c => c.body.includes(marker)); + if (existing) { + return github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body + }); + } + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number, + body + }); diff --git a/.github/workflows/bytecode-size.yml b/.github/workflows/bytecode-size.yml index 6ae309d1e7..2da2bbacd0 100644 --- a/.github/workflows/bytecode-size.yml +++ b/.github/workflows/bytecode-size.yml @@ -3,65 +3,43 @@ name: Bytecode Size Report on: pull_request: branches: [master] - pull_request_target: - branches: [master] permissions: contents: read - pull-requests: write + +env: + PYTHON_VERSION: "3.12" jobs: bytecode-size: - # pull_request: untrusted contributors only (step summary, no comment) - # pull_request_target: trusted contributors only (step summary + comment) - if: | - (github.event_name == 'pull_request' && !contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.pull_request.author_association)) || - (github.event_name == 'pull_request_target' && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.pull_request.author_association)) runs-on: ubuntu-latest + timeout-minutes: 45 steps: - - name: Invalidate existing comment - if: github.event_name == 'pull_request_target' - uses: actions/github-script@v7 - with: - script: | - const marker = ''; - const comments = await github.paginate(github.rest.issues.listComments, { - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number - }); - const existing = comments.find(c => c.body.includes(marker)); - if (!existing) return; - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: existing.id, - body: marker + '\n\n⏳ **Recalculating bytecode sizes...**' - }); - - name: Checkout merge commit - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: refs/pull/${{ github.event.pull_request.number }}/merge path: head fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Checkout base - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ github.base_ref }} path: base fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Copy scripts to base run: cp -r head/.github/scripts base/.github/ - - name: Set up Python - uses: actions/setup-python@v6 + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: - python-version: "3.12" + python-version: ${{ env.PYTHON_VERSION }} - name: Install vyper (base) working-directory: base @@ -80,50 +58,15 @@ jobs: run: python .github/scripts/measure_bytecode.py > ../head-sizes.json - name: Generate report - id: report run: | python3 head/.github/scripts/compare_bytecode.py base-sizes.json head-sizes.json > report.md cat report.md >> "$GITHUB_STEP_SUMMARY" - { - echo 'REPORT<> "$GITHUB_OUTPUT" - - - name: Post or update PR comment - if: github.event_name == 'pull_request_target' - uses: actions/github-script@v7 - with: - script: | - const marker = ''; - const body = marker + '\n\n' + process.env.REPORT; - const comments = await github.paginate(github.rest.issues.listComments, { - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number - }); - const existing = comments.find(c => c.body.includes(marker)); - if (existing) { - return github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: existing.id, - body: body - }); - } - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number, - body: body - }); - env: - REPORT: ${{ steps.report.outputs.REPORT }} - name: Upload size data - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: bytecode-sizes + name: bytecode-size-report path: | base-sizes.json head-sizes.json + report.md diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 29d8999dd2..1277ee1983 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -6,29 +6,37 @@ on: pull_request: branches: [ "master" ] +permissions: {} + jobs: analyze: name: Analyze runs-on: ubuntu-latest + timeout-minutes: 45 permissions: + # Required for CodeQL to read workflow metadata. actions: read + # Required to checkout and analyze repository contents. contents: read + # Required to upload CodeQL analysis results. security-events: write steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 with: languages: python queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@v3 + uses: github/codeql-action/autobuild@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5 with: category: "/language:python" diff --git a/.github/workflows/era-tester.yml b/.github/workflows/era-tester.yml index 63a7371101..fb6bad0bf4 100644 --- a/.github/workflows/era-tester.yml +++ b/.github/workflows/era-tester.yml @@ -9,6 +9,13 @@ name: Era compiler tester on: [push, pull_request] +permissions: + contents: read + +env: + ERA_HASH: 943fcc39d1173409fb4a3f53029b170fb7cb4e60 + PYTHON_VERSION: "3.12" + concurrency: # cancel older, in-progress jobs from the same PR, same workflow. # use run_id if the job is triggered by a push to ensure @@ -19,30 +26,28 @@ concurrency: jobs: era-compiler-tester: runs-on: ubuntu-latest - - steps: - - name: Get latest commit hash - run: | - echo "ERA_HASH=$( curl -u "u:${{ github.token }}" https://api.github.com/repos/matter-labs/era-compiler-tester/git/ref/heads/main | jq .object.sha | tr -d '"' )" >> $GITHUB_ENV - echo "ERA_VYPER_HASH=$( curl -u "u:${{ github.token }}" https://api.github.com/repos/matter-labs/era-compiler-vyper/git/ref/heads/main | jq .object.sha | tr -d '"' )" >> $GITHUB_ENV + timeout-minutes: 120 + steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Rust setup - uses: actions-rust-lang/setup-rust-toolchain@v1 + uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1 with: toolchain: nightly-2022-11-03 - - name: Set up Python ${{ matrix.python-version[0] }} - uses: actions/setup-python@v6 + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: - python-version: ${{ matrix.python-version[0] }} + python-version: ${{ env.PYTHON_VERSION }} cache: "pip" - name: Get cache id: get-cache - uses: actions/cache@v4 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: | ~/.cargo/bin/ @@ -54,13 +59,14 @@ jobs: **/compiler_tester **/llvm **/era-compiler-tester - key: ${{ runner.os }}-${{ env.ERA_HASH }}-${{ env.ERA_VYPER_HASH }} + key: ${{ runner.os }}-${{ env.ERA_HASH }} - name: Initialize repository and install dependencies if: steps.get-cache.outputs.cache-hit != 'true' run: | - git clone --depth 1 https://github.com/matter-labs/era-compiler-tester.git + git clone https://github.com/matter-labs/era-compiler-tester.git cd era-compiler-tester + git -c advice.detachedHead=false checkout --detach "$ERA_HASH" sed -i 's/ssh:\/\/git@/https:\/\//g' .gitmodules git submodule init git submodule update @@ -71,7 +77,7 @@ jobs: cargo build --release - name: Save cache - uses: actions/cache/save@v4 + uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 if: steps.get-cache.outputs.cache-hit != 'true' with: path: | @@ -84,7 +90,7 @@ jobs: **/compiler_tester **/llvm **/era-compiler-tester - key: ${{ runner.os }}-${{ env.ERA_HASH }}-${{ env.ERA_VYPER_HASH }} + key: ${{ runner.os }}-${{ env.ERA_HASH }} - name: Build Vyper run: | @@ -95,7 +101,7 @@ jobs: - name: Install Vyper run: | mkdir era-compiler-tester/vyper-bin - cp $(which vyper) era-compiler-tester/vyper-bin/vyper-${{ env.VYPER_VERSION }} + cp "$(which vyper)" "era-compiler-tester/vyper-bin/vyper-${VYPER_VERSION}" - name: Run tester (fast) # Run era tester with no LLVM optimizations @@ -103,7 +109,7 @@ jobs: if: ${{ github.ref != 'refs/heads/master' }} run: | cd era-compiler-tester - cargo run --release --bin compiler-tester -- --path=tests/vyper/ --mode="M0B0 ${{ env.VYPER_VERSION }}" + cargo run --release --bin compiler-tester -- --path=tests/vyper/ --mode="M0B0 ${VYPER_VERSION}" - name: Run tester (slow) # Run era tester across the LLVM optimization matrix @@ -111,7 +117,7 @@ jobs: if: ${{ github.ref == 'refs/heads/master' }} run: | cd era-compiler-tester - cargo run --release --bin compiler-tester -- --path=tests/vyper/ --mode="M*B* ${{ env.VYPER_VERSION }}" + cargo run --release --bin compiler-tester -- --path=tests/vyper/ --mode="M*B* ${VYPER_VERSION}" - name: Mark as success run: | diff --git a/.github/workflows/gas-bench-comment.yml b/.github/workflows/gas-bench-comment.yml new file mode 100644 index 0000000000..728544c8b0 --- /dev/null +++ b/.github/workflows/gas-bench-comment.yml @@ -0,0 +1,82 @@ +name: Gas Benchmark PR Comment + +on: + workflow_run: # zizmor: ignore[dangerous-triggers] Comment-only follow-up; never checks out or executes PR code. + workflows: ["Gas Benchmark Report"] + types: [completed] + +permissions: {} + +jobs: + comment: + if: > + github.event.workflow_run.conclusion == 'success' && + github.event.workflow_run.event == 'pull_request' + runs-on: ubuntu-latest + timeout-minutes: 45 + permissions: + # Download the report artifact from the completed measurement run. + actions: read + # Required by artifact download and workflow run metadata reads. + contents: read + # Update only the benchmark report comment on the pull request. + pull-requests: write + steps: + - name: Download report + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: gas-bench-report + path: report + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Post or update PR comment + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 + with: + script: | + const fs = require('fs'); + const marker = ''; + const report = fs.readFileSync('report/report.md', 'utf8'); + const body = marker + '\n\n' + report; + const workflowRun = context.payload.workflow_run; + let issue_number = (workflowRun.pull_requests || []).find(pr => pr.number)?.number; + if (!issue_number) { + const headOwner = workflowRun.head_repository?.owner?.login; + const headBranch = workflowRun.head_branch; + if (!headOwner || !headBranch) { + core.info('Could not resolve pull request for workflow run.'); + return; + } + const { data: pulls } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + head: `${headOwner}:${headBranch}` + }); + const pull = pulls.find(pr => pr.head.sha === workflowRun.head_sha) || pulls[0]; + if (!pull) { + core.info(`No open pull request found for ${headOwner}:${headBranch}.`); + return; + } + issue_number = pull.number; + } + const comments = await github.paginate(github.rest.issues.listComments, { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number + }); + const existing = comments.find(c => c.body.includes(marker)); + if (existing) { + return github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body + }); + } + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number, + body + }); diff --git a/.github/workflows/gas-bench.yml b/.github/workflows/gas-bench.yml index 0a87a3c7f9..95f4b9c63d 100644 --- a/.github/workflows/gas-bench.yml +++ b/.github/workflows/gas-bench.yml @@ -3,78 +3,57 @@ name: Gas Benchmark Report on: pull_request: branches: [master] - pull_request_target: - branches: [master] permissions: contents: read - pull-requests: write + +env: + PYTHON_VERSION: "3.12" jobs: gas-bench: - # pull_request: untrusted contributors only (step summary, no comment) - # pull_request_target: trusted contributors only (step summary + comment) - if: | - (github.event_name == 'pull_request' && !contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.pull_request.author_association)) || - (github.event_name == 'pull_request_target' && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.pull_request.author_association)) runs-on: ubuntu-latest + timeout-minutes: 45 steps: - - name: Invalidate existing comment - if: github.event_name == 'pull_request_target' - uses: actions/github-script@v9 - with: - script: | - const marker = ''; - const comments = await github.paginate(github.rest.issues.listComments, { - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number - }); - const existing = comments.find(c => c.body.includes(marker)); - if (!existing) return; - await github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: existing.id, - body: marker + '\n\n⏳ **Recalculating gas benchmark...**' - }); - - name: Checkout merge commit - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: refs/pull/${{ github.event.pull_request.number }}/merge path: head fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Checkout base - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ github.base_ref }} path: base fetch-depth: 0 fetch-tags: true + persist-credentials: false - name: Copy scripts to base run: cp -r head/.github/scripts base/.github/ - - name: Set up Python - uses: actions/setup-python@v6 + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: - python-version: "3.12" + python-version: ${{ env.PYTHON_VERSION }} - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 + uses: foundry-rs/foundry-toolchain@c7450ba673e133f5ee30098b3b54f444d3a2ca2d # v1 with: - version: nightly + version: nightly-407994620c0e7a6a66d2b7b03c53e2c8bf873fca - name: Checkout snekmate - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: repository: pcaversaccio/snekmate - ref: main + ref: 400f6b4f2288635aff5861aa95f5e99c5f451d54 submodules: recursive path: snekmate + persist-credentials: false - name: Install vyper (base) working-directory: base @@ -93,50 +72,15 @@ jobs: run: python .github/scripts/measure_gas.py --snekmate-dir ../snekmate > ../head-gas.json - name: Generate report - id: report run: | python3 head/.github/scripts/compare_gas.py base-gas.json head-gas.json > report.md cat report.md >> "$GITHUB_STEP_SUMMARY" - { - echo 'REPORT<> "$GITHUB_OUTPUT" - - - name: Post or update PR comment - if: github.event_name == 'pull_request_target' - uses: actions/github-script@v9 - with: - script: | - const marker = ''; - const body = marker + '\n\n' + process.env.REPORT; - const comments = await github.paginate(github.rest.issues.listComments, { - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number - }); - const existing = comments.find(c => c.body.includes(marker)); - if (existing) { - return github.rest.issues.updateComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: existing.id, - body: body - }); - } - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number, - body: body - }); - env: - REPORT: ${{ steps.report.outputs.REPORT }} - name: Upload gas data - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: gas-results + name: gas-bench-report path: | base-gas.json head-gas.json + report.md diff --git a/.github/workflows/ghcr.yml b/.github/workflows/ghcr.yml index 9c1a5fb96e..12dd225e55 100644 --- a/.github/workflows/ghcr.yml +++ b/.github/workflows/ghcr.yml @@ -13,30 +13,35 @@ on: release: types: [released] +permissions: {} + env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} + PYTHON_VERSION: "3.12" jobs: deploy-ghcr: runs-on: ubuntu-latest + timeout-minutes: 45 permissions: contents: read + # Push built images to GitHub Container Registry. packages: write steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: # need to fetch unshallow so that setuptools_scm can infer the version fetch-depth: 0 + persist-credentials: false - - uses: actions/setup-python@v6 - name: Install python + - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 + name: Install Python ${{ env.PYTHON_VERSION }} with: - python-version: "3.11" - cache: "pip" + python-version: ${{ env.PYTHON_VERSION }} - name: Generate vyper/version.py run: | @@ -49,7 +54,7 @@ jobs: - name: Docker meta id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | @@ -60,14 +65,14 @@ jobs: - name: Login to ghcr.io - uses: docker/login-action@v3 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v5 + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 with: context: . push: true diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index 3879e26dc6..324bf3f815 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -15,8 +15,9 @@ permissions: jobs: validate-pr: runs-on: ubuntu-latest + timeout-minutes: 45 steps: - - uses: amannn/action-semantic-pull-request@v5 + - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1 name: Run conventional commit checker env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-pypi.yml b/.github/workflows/release-pypi.yml index 585674a24e..d4cfb06041 100644 --- a/.github/workflows/release-pypi.yml +++ b/.github/workflows/release-pypi.yml @@ -7,32 +7,39 @@ on: release: types: [published] # releases and pre-releases (release candidates) +permissions: {} + +env: + PYTHON_VERSION: "3.12" + jobs: publish-pypi: runs-on: ubuntu-latest + timeout-minutes: 45 # https://docs.pypi.org/trusted-publishers/using-a-publisher/ permissions: - # IMPORTANT: this permission is mandatory for trusted publishing - id-token: write + contents: read + id-token: write # Required for PyPI trusted publishing. # Specifying a GitHub environment is optional, but strongly encouraged environment: release steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: # fetch unshallow so commit hash matches github release. # see https://github.com/vyperlang/vyper/blob/8f9a8cac49aafb3fbc9dde78f0f6125c390c32f0/.github/workflows/build.yml#L27-L32 fetch-depth: 0 + persist-credentials: false # debug - name: Git shorthash run: git rev-parse --short HEAD - name: Python - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: - python-version: "3.11" + python-version: ${{ env.PYTHON_VERSION }} - name: Install dependencies run: | @@ -43,4 +50,4 @@ jobs: run: python setup.py sdist bdist_wheel - name: Publish - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0a7eca6f55..25d1e1bb2a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,6 +7,12 @@ on: pull_request: merge_group: +permissions: + contents: read + +env: + PYTHON_VERSION: "3.12" + concurrency: # cancel older, in-progress jobs from the same PR, same workflow. # use run_id if the job is triggered by a push to ensure @@ -18,14 +24,17 @@ jobs: lint: runs-on: ubuntu-latest + timeout-minutes: 45 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - - name: Set up Python 3.11 - uses: actions/setup-python@v6 + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: - python-version: "3.11" + python-version: ${{ env.PYTHON_VERSION }} cache: "pip" - name: Install Dependencies @@ -48,14 +57,17 @@ jobs: docs: runs-on: ubuntu-latest + timeout-minutes: 45 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - - name: Set up Python 3.11 - uses: actions/setup-python@v6 + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: - python-version: "3.11" + python-version: ${{ env.PYTHON_VERSION }} cache: "pip" - name: Install deps @@ -67,15 +79,18 @@ jobs: # Symbolic tests symbolic-tests: runs-on: "ubuntu-latest" + timeout-minutes: 45 name: symbolic-tests steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - - name: Set up Python 3.11 - uses: actions/setup-python@v6 + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: - python-version: "3.11" + python-version: ${{ env.PYTHON_VERSION }} cache: "pip" - name: Install dependencies @@ -106,11 +121,12 @@ jobs: # "Regular"/core tests. tests: runs-on: ${{ matrix.os || 'ubuntu' }}-latest + timeout-minutes: 45 # IMPORTANT: Test defaults are duplicated in the "Run tests" step below! # it is annoying that we need to duplicate them, but it is necessary # to avoid repeating defaults for every "include" in the matrix. name: "${{ matrix.os && matrix.os != 'ubuntu' && format('{0}-', matrix.os) || '' }}\ - py${{ matrix.python-version[1] || '311' }}\ + py${{ matrix.python-version[1] || '312' }}\ -opt-${{ matrix.opt-mode || 'gas' }}\ ${{ matrix.debug && '-debug' || '' }}\ ${{ matrix.experimental-codegen && '-experimental' || '' }}\ @@ -120,7 +136,7 @@ jobs: matrix: # declare all variables used in the "include" section here! Conflicting jobs get overwritten by GitHub actions. os: [ubuntu] - python-version: [["3.11", "311"]] # note: do not forget to replace 311 in the job names when upgrading! + python-version: [["3.12", "312"]] # note: do not forget to replace 312 in the job names when upgrading! opt-mode: [gas, none, codesize, O1, O2, O3] debug: [true, false] evm-version: [prague] # note: when upgrading, check the "include" section below for conflicting jobs @@ -129,7 +145,7 @@ jobs: # https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs#expanding-or-adding-matrix-configurations include: - # test default settings with 3.11 across all supported evm versions + # test default settings with 3.12 across all supported evm versions - evm-version: london - evm-version: paris - evm-version: shanghai @@ -167,7 +183,7 @@ jobs: # run across other python versions. we don't really need to run all # modes across all python versions - one is enough - - python-version: ["3.12", "312"] + - python-version: ["3.11", "311"] - python-version: ["3.13", "313"] # todo: add 3.14 when it is released on oct 7 2025 @@ -176,15 +192,16 @@ jobs: - os: macos steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: # need to fetch unshallow so that setuptools_scm can infer the version fetch-depth: 0 + persist-credentials: false - - name: Set up Python ${{ matrix.python-version[0] || '3.11' }} - uses: actions/setup-python@v6 + - name: Set up Python ${{ matrix.python-version[0] || env.PYTHON_VERSION }} + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: - python-version: ${{ matrix.python-version[0] || '3.11' }} + python-version: ${{ matrix.python-version[0] || env.PYTHON_VERSION }} cache: "pip" - name: Install dependencies @@ -207,7 +224,7 @@ jobs: tests/ - name: Upload coverage artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: coverage-files-${{ github.job }}-${{ strategy.job-index }} include-hidden-files: true @@ -219,7 +236,9 @@ jobs: # summary result from test matrix. # see https://github.community/t/status-check-for-a-matrix-jobs/127354/7 runs-on: ubuntu-latest + timeout-minutes: 45 needs: [tests, symbolic-tests] + permissions: {} steps: - name: Check tests tests all succeeded if: ${{ needs.tests.result != 'success' }} @@ -230,6 +249,7 @@ jobs: # the regular test suite) fuzzing: runs-on: ubuntu-latest + timeout-minutes: 45 strategy: matrix: @@ -239,12 +259,14 @@ jobs: group: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - - name: Set up Python 3.11 - uses: actions/setup-python@v6 + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: - python-version: "3.11" + python-version: ${{ env.PYTHON_VERSION }} cache: "pip" - name: Install dependencies @@ -268,7 +290,7 @@ jobs: tests/ - name: Upload coverage artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: coverage-files-${{ github.job }}-${{ strategy.job-index }} include-hidden-files: true @@ -280,7 +302,9 @@ jobs: # summary result from test matrix. # see https://github.community/t/status-check-for-a-matrix-jobs/127354/7 runs-on: ubuntu-latest + timeout-minutes: 45 needs: fuzzing + permissions: {} steps: - name: Check slow tests all succeeded @@ -291,22 +315,25 @@ jobs: # Consolidate code coverage using `coverage combine` and # call coverage report with fail-under=90 runs-on: ubuntu-latest + timeout-minutes: 45 needs: [tests, fuzzing] steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - - name: Set up Python 3.11 - uses: actions/setup-python@v6 + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6 with: - python-version: "3.11" + python-version: ${{ env.PYTHON_VERSION }} cache: "pip" - name: Install coverage run: pip install coverage - name: Download coverage artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: coverage-files-* path: coverage-files @@ -327,7 +354,7 @@ jobs: - name: Upload coverage artifacts # upload coverage sqlite db for debugging # upload coverage.xml artifact for downstream codecov upload action - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: coverage-artifacts include-hidden-files: true @@ -338,17 +365,23 @@ jobs: upload-coverage: # upload coverage to the codecov app + if: github.event_name == 'push' runs-on: ubuntu-latest + timeout-minutes: 45 needs: [coverage-report] + permissions: + contents: read steps: - - uses: actions/checkout@v6 - - uses: actions/download-artifact@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: coverage-artifacts - name: Upload Coverage - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 with: token: ${{ secrets.CODECOV_TOKEN }} files: coverage.xml