Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
149 changes: 128 additions & 21 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ jobs:
contracts: ${{ steps.filter.outputs.contracts }}
shared: ${{ steps.filter.outputs.shared }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2

- uses: dorny/paths-filter@v3
- uses: dorny/paths-filter@b41dfa943b1939b9b646f67753bfe35cf6e4de03 # v3.0.2
id: filter
with:
# On push events, compare against the previous commit so the first
Expand Down Expand Up @@ -62,11 +62,11 @@ jobs:
if: needs.changes.outputs.website == 'true' || needs.changes.outputs.shared == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2

- uses: pnpm/action-setup@v4
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v4.1.0

- uses: actions/setup-node@v4
- uses: actions/setup-node@e51e5fe84fc33b4c73ebe40526b2694712b5b858 # v4.3.0
with:
node-version: 20
cache: pnpm
Expand All @@ -90,9 +90,9 @@ jobs:
run:
working-directory: apps/intelligence
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2

- uses: actions/setup-python@v5
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v5.5.0
with:
python-version: "3.12"

Expand All @@ -117,11 +117,11 @@ jobs:
if: needs.changes.outputs.dapp == 'true' || needs.changes.outputs.shared == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2

- uses: pnpm/action-setup@v4
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v4.1.0

- uses: actions/setup-node@v4
- uses: actions/setup-node@e51e5fe84fc33b4c73ebe40526b2694712b5b858 # v4.3.0
with:
node-version: 22
cache: pnpm
Expand All @@ -148,7 +148,7 @@ jobs:
needs: changes
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2
with:
fetch-depth: 0

Expand All @@ -161,7 +161,7 @@ jobs:
- name: Run gitleaks
run: gitleaks detect --source . --no-git --redact --no-banner --config .gitleaks.toml

- uses: dtolnay/rust-toolchain@stable
- uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c # stable
if: needs.changes.outputs.contracts == 'true' || needs.changes.outputs.shared == 'true'

- name: Install cargo-audit
Expand All @@ -174,7 +174,7 @@ jobs:
working-directory: packages/contracts
continue-on-error: true

- uses: actions/setup-go@v5
- uses: actions/setup-go@5064d95ba18d4a9dda7c4cc67adeb03aea1a2a14 # v5.3.0
if: needs.changes.outputs.api == 'true' || needs.changes.outputs.shared == 'true'
with:
go-version-file: apps/api/go.mod
Expand Down Expand Up @@ -219,10 +219,10 @@ jobs:
working-directory: apps/api
continue-on-error: true

- uses: pnpm/action-setup@v4
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v4.1.0
if: needs.changes.outputs.dapp == 'true' || needs.changes.outputs.shared == 'true'

- uses: actions/setup-node@v4
- uses: actions/setup-node@e51e5fe84fc33b4c73ebe40526b2694712b5b858 # v4.3.0
if: needs.changes.outputs.dapp == 'true' || needs.changes.outputs.shared == 'true'
with:
node-version: 22
Expand All @@ -238,7 +238,7 @@ jobs:
working-directory: apps/dapp/frontend
continue-on-error: true

- uses: actions/setup-python@v5
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v5.5.0
if: needs.changes.outputs.intelligence == 'true' || needs.changes.outputs.shared == 'true'
with:
python-version: "3.12"
Expand All @@ -261,7 +261,7 @@ jobs:

- name: Semgrep SAST (TypeScript/Next.js)
if: needs.changes.outputs.dapp == 'true' || needs.changes.outputs.shared == 'true'
uses: semgrep/semgrep-action@v1
uses: semgrep/semgrep-action@713efdd345f3035192eaa63f56867b88e63e4e5d # v1
with:
config: >-
p/typescript
Expand All @@ -271,6 +271,66 @@ jobs:
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}

- name: Typosquat detection (new npm dependencies)
if: needs.changes.outputs.dapp == 'true' || needs.changes.outputs.shared == 'true'
run: |
# Check for typosquatting patterns in package.json dependencies
# Uses npm package name similarity to detect potential typosquats
python3 -c "

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This block breaks the entire workflow file, not just this step.

run: | on line 276 opens a block scalar, but the Python starting here sits at column 0 — outside the scalar's indentation. YAML therefore ends the scalar at line 279 and tries to parse import json, sys, re as a new top-level mapping key:

yaml.scanner.ScannerError: while scanning a simple key
  in "ci.yml", line 280, column 1
could not find expected ':'

GitHub Actions rejects a workflow it cannot parse, so merging this disables every job in ci.yml repo-wide — website, intelligence, dapp, api, contracts, security, all of it.

The 12 green checks on this PR are misleading: they ran against the merge-base ci.yml from dev, not this version. The step is also gated on needs.changes.outputs.dapp, which was false for this PR's own file set, so it never executed even locally.

Two ways to fix it. Either indent the whole heredoc to sit inside the block scalar, or — better, and what #968 already does — move the script to scripts/typosquat_check.py and invoke it as a file. A committed script is testable and lintable; an inlined one is neither.

Please validate before re-requesting review:

python -c "import yaml; yaml.safe_load(open('.github/workflows/ci.yml'))"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@0xDeon thanks for the thorough review — both points are addressed. The YAML block-scalar indentation is fixed (the Python now sits inside the run: | block, and yaml.safe_load passes), and the missing ) SyntaxError is fixed. Per your suggestion, the logic was also extracted into a committed, testable scripts/typosquat_check.py (invoked as a file, with regression tests in scripts/test_typosquat_check.py), and the step now has continue-on-error: true so the fuzzy heuristic can never block an unrelated PR. Full scoped names are compared and only newly-added deps (incl. optionalDependencies) are checked.

import json, sys, re
from pathlib import Path

pkg = json.loads(Path('apps/dapp/frontend/package.json').read_text())
known_packages = {'react', 'react-dom', 'next', 'next/router', 'next/navigation',
'@tanstack/react-query', 'framer-motion', 'recharts', 'zod', 'react-hook-form',
'zustand', 'uuid', 'date-fns', 'ethers', 'viem', 'wagmi', 'axios', 'lodash',
'@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu', '@radix-ui/react-tabs',
'@radix-ui/react-tooltip', '@radix-ui/react-popover', '@radix-ui/react-select',
'tailwindcss', 'postcss', 'autoprefixer', 'typescript', 'vitest', 'eslint',
'@typescript-eslint/eslint-plugin', '@typescript-eslint/parser', 'prettier',
'clsx', 'tailwind-merge', 'lucide-react', 'class-variance-authority',
'@hookform/resolvers', 'sonner', 'react-hot-toast', 'next-themes',
'@starknet-react/core', '@starknet-react/chains', 'starknet',
'@stellar/stellar-sdk', '@blend-capital/blend-sdk'}

def levenshtein(a, b):
m, n = len(a), len(b)
dp = [[0]*(n+1) for _ in range(m+1)]
for i in range(m+1): dp[i][0] = i
for j in range(n+1): dp[0][j] = j
for i in range(1, m+1):
for j in range(1, n+1):
dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1,
dp[i-1][j-1] + (a[i-1] != b[j-1]))
return dp[m][n]

suspicious = []
for dep in pkg.get('dependencies', {}):
name = dep.split('/')[-1] if '/' in dep else dep
for known in known_packages:
kname = known.split('/')[-1] if '/' in known else known
if name != kname and len(name) > 3 and len(kname) > 3:
d = levenshtein(name.lower(), kname.lower())
if d <= 2 and d > 0:
suspicious.append((dep, known, d))

for dep in pkg.get('devDependencies', {}):
name = dep.split('/')[-1] if '/' in dep else dep
for known in known_packages:
kname = known.split('/')[-1] if '/' in known else known
if name != kname and len(name) > 3 and len(kname) > 3:
d = levenshtein(name.lower(), kname.lower())
if d <= 2 and d > 0:
suspicious.append((dep, known, d))
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

if suspicious:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Separate from the YAML problem above, this Python does not compile.

The print(...) call is missing its closing paren immediately before else::

print(f'  {dep} (edit distance {dist} from {known})'
else:

python3 -c compiles the whole string before executing, so this is a hard SyntaxError, not a runtime issue on an unusual path.

This step has no continue-on-error, so once the YAML is valid this would fail Security Scanning on every PR that touches dapp or shared. For an advisory heuristic like typosquat detection I'd suggest adding continue-on-error: true as well — a fuzzy name-similarity check shouldn't be able to block an unrelated PR from merging.

Worth noting the description also lists "Typosquat Detection" via scripts/typosquat_check.py, but that file isn't in this diff — it only exists in #968. Please align the description with what the branch actually contains.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@0xDeon fixed: the script now compiles (closing paren added) and has been extracted into scripts/typosquat_check.py with continue-on-error: true on the step, per your suggestion. Regression tests are added at scripts/test_typosquat_check.py.

print('::warning::Potential typosquatted dependencies detected:')
for dep, known, dist in suspicious:
print(f' {dep} (edit distance {dist} from {known})'
else:
print('No potential typosquats detected')
"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

api:
name: API (Go)
needs: changes
Expand Down Expand Up @@ -312,9 +372,9 @@ jobs:
# silently skips in CI even though the redis service below is running.
REDIS_ADDR: localhost:6379
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2

- uses: actions/setup-go@v5
- uses: actions/setup-go@5064d95ba18d4a9dda7c4cc67adeb03aea1a2a14 # v5.3.0
with:
go-version-file: apps/api/go.mod
cache: true
Expand Down Expand Up @@ -357,9 +417,9 @@ jobs:
run:
working-directory: packages/contracts
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2

- uses: dtolnay/rust-toolchain@stable
- uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c # stable
with:
targets: wasm32-unknown-unknown

Expand Down Expand Up @@ -406,3 +466,50 @@ jobs:
exit 1
fi

sbom:
name: SBOM Generation
needs: changes
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2

- name: Install cyclonedx-bom (Go)
run: go install github.com/CycloneDX/cyclonedx-gomod/cmd/cyclonedx-gomod@v1

- name: Install syft
run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin v1.19.0

- name: Generate Go API SBOM
if: needs.changes.outputs.api == 'true' || needs.changes.outputs.shared == 'true'
working-directory: apps/api
run: |
cyclonedx-gomod mod -json -output ../../sbom-api.json .
syft dir:. --output cyclonedx-json=sbom-api-syft.json 2>/dev/null || true
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

- name: Generate frontend SBOM (npm)
if: needs.changes.outputs.dapp == 'true' || needs.changes.outputs.shared == 'true'
working-directory: apps/dapp/frontend
run: |
npx @cyclonedx/cyclonedx-npm --output-file ../../../sbom-frontend.json --pnpm 2>/dev/null || \
npx @cyclonedx/cyclonedx-npm --output-file ../../../sbom-frontend.json 2>/dev/null || true
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

- name: Generate Python SBOM
if: needs.changes.outputs.intelligence == 'true' || needs.changes.outputs.shared == 'true'
working-directory: apps/intelligence
run: |
syft dir:. --output cyclonedx-json=../../sbom-intelligence.json 2>/dev/null || true

- name: Generate contracts SBOM (Rust)
if: needs.changes.outputs.contracts == 'true' || needs.changes.outputs.shared == 'true'
working-directory: packages/contracts
run: |
syft dir:. --output cyclonedx-json=../../sbom-contracts.json 2>/dev/null || true

- name: Upload SBOM artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v4
with:
name: sbom-artifacts
path: sbom-*.json
if-no-files-found: warn

6 changes: 3 additions & 3 deletions .github/workflows/contract-audit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
name: x402 Heuristic Contract Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2

- name: Make audit script executable
run: chmod +x scripts/contract-audit.sh
Expand Down Expand Up @@ -69,14 +69,14 @@ for pkg in meta['packages']:
cat ../../wasm-hashes/wasm-hashes.txt

- name: Upload WASM Hashes Artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v4
with:
name: contract-wasm-hashes
path: wasm-hashes/wasm-hashes.txt

- name: Upload audit reports
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v4
with:
name: contract-audit-reports
path: audit-report-*.json
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dependabot-auto-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
steps:
- name: Fetch Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v2
uses: dependabot/fetch-metadata@7a4b92f93a688100997537756415299e15fc2431 # v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/load-soak.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
if: ${{ secrets.STAGING_LOAD_API_BASE_URL != '' }}
environment: staging
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
- name: Run isolated staging soak
env:
API_BASE_URL: ${{ secrets.STAGING_LOAD_API_BASE_URL }}
Expand All @@ -30,7 +30,7 @@ jobs:
-e API_BASE_URL -e INTELLIGENCE_BASE_URL -e WS_URL -e VAULT_ID -e AUTH_TOKEN \
-v "$PWD:/work" -w /work grafana/k6:latest \
run --summary-export results/soak-summary.json tests/load/soak.js
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v4
if: always()
with:
name: k6-soak-summary-${{ github.run_id }}
Expand Down
26 changes: 13 additions & 13 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2
with:
fetch-depth: 0

Expand All @@ -49,10 +49,10 @@ jobs:
working-directory: ${{ matrix.directory }}
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2

- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@e51e5fe84fc33b4c73ebe40526b2694712b5b858 # v4.3.0
with:
node-version: 22

Expand All @@ -75,10 +75,10 @@ jobs:
working-directory: ${{ matrix.module }}
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2

- name: Setup Go
uses: actions/setup-go@v5
uses: actions/setup-go@5064d95ba18d4a9dda7c4cc67adeb03aea1a2a14 # v5.3.0
with:
go-version-file: ${{ matrix.module }}/go.mod
cache: true
Expand Down Expand Up @@ -123,10 +123,10 @@ jobs:
working-directory: packages/contracts
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2

- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c # stable

- name: Install cargo-audit
run: cargo install cargo-audit --locked
Expand All @@ -142,10 +142,10 @@ jobs:
working-directory: apps/intelligence
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2

- name: Setup Python
uses: actions/setup-python@v5
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v5.5.0
with:
python-version: "3.12"

Expand Down Expand Up @@ -231,15 +231,15 @@ jobs:
language: ["go", "javascript-typescript", "python"]
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v4.2.2

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@f02afd42b08e9c7fd2198fe321a96e6b3867a0fd # v3
with:
languages: ${{ matrix.language }}

- name: Autobuild
uses: github/codeql-action/autobuild@v3
uses: github/codeql-action/autobuild@f02afd42b08e9c7fd2198fe321a96e6b3867a0fd # v3

- name: Analyze
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@f02afd42b08e9c7fd2198fe321a96e6b3867a0fd # v3
Loading
Loading