Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions .github/workflows/license-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Fail PRs that introduce production dependencies under disallowed licenses.
name: license-check

on:
pull_request:
workflow_dispatch:

permissions: {}

env:
# Safe-chain enforces its own minimum-package-age check independently;
# mirror both the age (72 h) and the exclusion here. This job installs every
# in-scope package, including confidential-wrapper's @zama-fhe/relayer-sdk.
SAFE_CHAIN_MINIMUM_PACKAGE_AGE_HOURS: "72"
SAFE_CHAIN_MINIMUM_PACKAGE_AGE_EXCLUSIONS: "@zama-fhe/relayer-sdk"

concurrency:
group: ci-license-check-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

jobs:
check-licenses:
name: license-check/check-licenses (bpr)
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
steps:
# TODO: remove once GitHub runner images ship the CVE-2026-31431 kernel fix
- name: Workaround CVE-2026-31431 (copy.fail)
run: |
echo "install algif_aead /bin/false" | sudo tee /etc/modprobe.d/disable-algif-aead.conf
if lsmod | grep -q algif_aead; then
sudo rmmod algif_aead || echo "WARNING: rmmod failed - module may be in use"
elif modinfo algif_aead 2>/dev/null | grep -q builtin; then
echo "WARNING: algif_aead built-in - modprobe.d blacklist has no effect"
fi

- name: Checkout project
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: 'false'

- name: Install pnpm
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
with:
version: 9

- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[AUTOMATED]

Bug: --failOn uses exact string matching — copyleft licenses will slip through

license-checker's --failOn compares the full license string against each entry using literal equality (source). The values "GPL", "AGPL", and "LGPL" do not match real-world SPDX identifiers like GPL-2.0-only, GPL-3.0-only, AGPL-3.0-only, LGPL-2.1-only, etc.

As a result, every copyleft-licensed package will silently pass this check, defeating the purpose of the workflow.

Options to fix:

  1. Enumerate the specific SPDX identifiers (and common non-SPDX variants reported by npm):

    npx --yes license-checker --production --failOn \
      "GPL-1.0-only;GPL-1.0-or-later;GPL-2.0-only;GPL-2.0-or-later;GPL-3.0-only;GPL-3.0-or-later;AGPL-1.0-only;AGPL-1.0-or-later;AGPL-3.0-only;AGPL-3.0-or-later;LGPL-2.0-only;LGPL-2.0-or-later;LGPL-2.1-only;LGPL-2.1-or-later;LGPL-3.0-only;LGPL-3.0-or-later"
  2. Use --onlyAllow instead (allowlist approach — --onlyAllow does substring matching, so it's safer):

    npx --yes license-checker --production --onlyAllow \
      "MIT;ISC;Apache-2.0;BSD-2-Clause;BSD-3-Clause;0BSD;CC0-1.0;Unlicense;CC-BY-3.0;CC-BY-4.0;Python-2.0;BlueOak-1.0.0"
  3. Switch to a fork with SPDX-aware matching, e.g. license-checker-rseidelsohn (actively maintained) or @onebeyond/license-checker (enforces valid SPDX).

Confidence: 95/100

- name: Cache node_modules
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: |
contracts/confidential-batcher/node_modules
contracts/confidential-token-wrappers-registry/node_modules
contracts/confidential-wrapper/node_modules
contracts/governance/node_modules
contracts/safe/node_modules
contracts/solanaOFT/node_modules
contracts/staking/node_modules
contracts/token/node_modules
scripts/fhevm-cli/node_modules
scripts/governance-proposal-builder/node_modules
key: license-check-node-modules-${{ hashFiles('contracts/*/package-lock.json', 'contracts/*/pnpm-lock.yaml', 'scripts/*/package-lock.json', 'scripts/*/pnpm-lock.yaml') }}

- name: Install safe-chain (Aikido malicious-package guard)
shell: bash
run: curl -fsSL https://github.com/AikidoSec/safe-chain/releases/download/1.5.8/install-safe-chain.sh | sh -s -- --ci

- name: Verify safe-chain package manager shims
run: |
npm safe-chain-verify
pnpm safe-chain-verify

- name: Check licenses
run: make check-licenses
75 changes: 75 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Protocol Apps Makefile
#
# Full list of SPDX identifiers can be found here: https://spdx.org/licenses/
#
# Scope is what we distribute: contracts/* ship bytecode, scripts/* ship source
# (public repo) and fhevm-cli also ships bytecode. Tooling and test dependencies
# stay in devDependencies and are excluded by --production.
# scripts/chains-config-checker is omitted: read-only view tooling.
# Deprecated packages omitted from license checks (see .github/dependabot.yml exclude-paths).
LICENSE_SKIP_PACKAGES := contracts/feesBurner contracts/pauserSetWrapper
# solanaOFT: production deliverable is the Anchor program (Cargo), not EVM bytecode.
# ZamaOFTAdapter.sol is a wiring-tooling ABI mirror only (deployed from contracts/token).
DEPLOY_SKIP_PACKAGES := contracts/solanaOFT
LICENSE_PACKAGES := $(filter-out $(LICENSE_SKIP_PACKAGES),$(patsubst %/package.json,%,$(wildcard contracts/*/package.json))) scripts/fhevm-cli scripts/governance-proposal-builder
DEPLOY_PACKAGES := $(filter-out $(LICENSE_SKIP_PACKAGES) $(DEPLOY_SKIP_PACKAGES),$(patsubst %/package.json,%,$(wildcard contracts/*/package.json))) scripts/fhevm-cli

# Excluded from --onlyAllow (exact name@version; bumps re-trigger review):
#
# In deployed bytecode (LZBL-1.2, PENDING):
# - lz-evm-protocol-v2@{3.0.141,3.0.142,3.0.156}
# - lz-evm-messagelib-v2@{3.0.141,3.0.142,3.0.156} (ExecutorOptions/DVNOptions via OptionsBuilder)
#
# Cleared external use:
# - @safe-global/safe-contracts@1.4.1-2 (LGPL-3.0)
#
# Peer-install noise only — in node_modules via pnpm autoInstallPeers, not in our Solidity imports:
# - lz-evm-v1-0.7@{3.0.141,3.0.142,3.0.156} (BUSL-1.1; legacy V1 peer of messagelib-v2)
# - @chainlink/contracts-ccip@0.7.6 (BUSL-1.1; CCIP DVN peer of messagelib-v2)
# - @layerzerolabs/lz-v2-utilities@3.0.168 (BUSL-1.1; governance-proposal-builder script only)
#
# Keep on one line: license-checker splits --excludePackages on ';' without trimming.
EXCLUDE_PACKAGES := @safe-global/safe-contracts@1.4.1-2;@layerzerolabs/lz-evm-protocol-v2@3.0.141;@layerzerolabs/lz-evm-protocol-v2@3.0.142;@layerzerolabs/lz-evm-protocol-v2@3.0.156;@layerzerolabs/lz-evm-messagelib-v2@3.0.141;@layerzerolabs/lz-evm-messagelib-v2@3.0.142;@layerzerolabs/lz-evm-messagelib-v2@3.0.156;@layerzerolabs/lz-evm-v1-0.7@3.0.141;@layerzerolabs/lz-evm-v1-0.7@3.0.142;@layerzerolabs/lz-evm-v1-0.7@3.0.156;@layerzerolabs/lz-v2-utilities@3.0.168;@chainlink/contracts-ccip@0.7.6

ALLOWED_LICENSES := 0BSD;Apache-2.0;BSD-2-Clause;BSD-3-Clause;BSD-3-Clause-Clear;CC-BY-3.0;CC0-1.0;ISC;MIT;MPL-2.0;Python-2.0;WTFPL;PSF

.PHONY: help check-licenses

help:
@echo "Protocol Apps Makefile"
@echo ""
@echo "Available targets:"
@echo " check-licenses - Check dependency licenses for all distributed packages"
@echo ""
@echo "Packages: $(LICENSE_PACKAGES)"

# --excludePrivatePackages drops each package itself: license-checker reports any
# `"private": true` package as UNLICENSED regardless of its license field.
check-licenses:
@failed=""; \
for pkg in $(LICENSE_PACKAGES); do \
echo "Checking licenses in $$pkg..."; \
( \
cd $$pkg && \
if [ -f pnpm-lock.yaml ]; then \
pnpm install --frozen-lockfile --ignore-scripts --config.node-linker=hoisted --prod >/dev/null; \
else \
npm install --ignore-scripts --no-audit --no-fund --omit=dev >/dev/null; \
fi && \
if echo " $(DEPLOY_PACKAGES) " | grep -q " $$pkg " && \
[ "$$(node -p "Object.keys(require('./package.json').dependencies||{}).length")" = "0" ]; then \
echo " ships Solidity but declares no production dependencies; move them out of devDependencies"; \
exit 1; \
fi && \
npx --yes license-checker --production --excludePrivatePackages \
--onlyAllow '$(ALLOWED_LICENSES)' \
--excludePackages '$(EXCLUDE_PACKAGES)' \
> /dev/null \
) || failed="$$failed $$pkg"; \
done; \
if [ -n "$$failed" ]; then \
echo ""; \
echo "License check failed for:$$failed"; \
exit 1; \
fi; \
echo "All license checks passed!"

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"name": "confidential-token-wrappers-registry",
"description": "Confidential Token Wrappers Registry",
"version": "0.1.0",
"license": "BSD-3-Clause-Clear",
"keywords": [
"fhevm",
"zama",
Expand Down
8 changes: 4 additions & 4 deletions contracts/governance/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,18 @@
"@layerzerolabs/io-devtools": "~0.3.0",
"@layerzerolabs/lz-definitions": "^3.0.147",
"@layerzerolabs/lz-evm-messagelib-v2": "^3.0.75",
"@layerzerolabs/lz-evm-protocol-v2": "^3.0.75",
"@layerzerolabs/lz-evm-sdk-v2": "^3.0.147",
"@layerzerolabs/lz-evm-v1-0.7": "^3.0.75",
"@layerzerolabs/lz-v2-utilities": "^3.0.75",
"@layerzerolabs/metadata-tools": "^3.0.0",
"@layerzerolabs/oapp-evm": "^0.3.2",
"@layerzerolabs/prettier-config-next": "^2.3.39",
"@layerzerolabs/solhint-config": "^3.0.12",
"@layerzerolabs/toolbox-hardhat": "~0.6.12",
"@nomicfoundation/hardhat-ethers": "^3.0.5",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@openzeppelin/contracts": "^5.0.2",
"@openzeppelin/contracts-upgradeable": "^5.0.2",
"@rushstack/eslint-patch": "^1.7.0",
"@safe-global/safe-contracts": "1.4.1-2",
"@types/chai": "^4.3.11",
"@types/mocha": "^10.0.6",
"@types/node": "~18.18.14",
Expand Down Expand Up @@ -107,6 +105,8 @@
}
},
"dependencies": {
"@safe-global/safe-contracts": "1.4.1-2"
"@layerzerolabs/lz-evm-protocol-v2": "^3.0.75",
"@layerzerolabs/oapp-evm": "^0.3.2",
"@openzeppelin/contracts": "^5.0.2"
}
}
24 changes: 12 additions & 12 deletions contracts/governance/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 3 additions & 11 deletions contracts/safe/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion contracts/safe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@
"qs": "^6.15.2",
"glob": "^10.5.0"
},
"dependencies": {
"@safe-global/safe-contracts": "^1.4.1-2"
},
"devDependencies": {
"@nomicfoundation/hardhat-toolbox": "^6.1.0",
"@openzeppelin/contracts": "^5.4.0",
"@safe-global/protocol-kit": "^6.1.1",
"@safe-global/safe-contracts": "^1.4.1-2",
"hardhat": "^2.26.3",
"hardhat-dependency-compiler": "^1.2.1",
"hardhat-deploy": "^0.12.1",
Expand Down
Loading
Loading