Skip to content
Merged
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
77 changes: 77 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Dependabot config. Update PRs are grouped by ecosystem to cut noise;
# remediation SLAs for any alert this doesn't auto-fix are documented
# in docs/vulnerability-management.md (Dependabot has no SLA field).
version: 2

updates:
# --- npm: root workspace (sdk + frontend) -------------------------
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 10
labels: ["dependencies", "npm", "security"]
groups:
npm-minor-patch:
update-types: ["minor", "patch"]
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-major"]

# --- npm: frontend --------------------------------------------------
- package-ecosystem: "npm"
directory: "/frontend"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 10
labels: ["dependencies", "npm", "frontend", "security"]
groups:
frontend-minor-patch:
update-types: ["minor", "patch"]

# --- npm: sdk ---------------------------------------------------
- package-ecosystem: "npm"
directory: "/sdk"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 5
labels: ["dependencies", "npm", "sdk", "security"]
groups:
sdk-minor-patch:
update-types: ["minor", "patch"]

# --- npm/pnpm: backend (package-lock.json + pnpm-lock.yaml) --------
- package-ecosystem: "npm"
directory: "/backend"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 10
labels: ["dependencies", "npm", "backend", "security"]
groups:
backend-minor-patch:
update-types: ["minor", "patch"]

# --- Cargo: Stellar contract workspace ------------------------------
- package-ecosystem: "cargo"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 5
labels: ["dependencies", "cargo", "contract", "security"]
groups:
cargo-minor-patch:
update-types: ["minor", "patch"]

# --- GitHub Actions: pin/patch the CI supply chain itself -----------
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
open-pull-requests-limit: 5
labels: ["dependencies", "github-actions", "security"]
97 changes: 97 additions & 0 deletions .github/workflows/osv-scanner.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# PR-time dependency vulnerability gate. Scans every npm/pnpm/Cargo
# lockfile in the repo against the OSV/GHSA database (the same source
# Dependabot alerts use) and fails the build on High/Critical findings.
name: OSV Dependency Scan

on:
pull_request:
branches: [main]
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read

# OSV-Scanner CLI release to use. Bump deliberately after checking the
# release notes: https://github.com/google/osv-scanner/releases
env:
OSV_SCANNER_VERSION: "v2.5.0"

jobs:
osv-scan:
name: OSV-Scanner (High/Critical gate)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

# Pinned to a tagged release (not "latest") so a compromised or
# regressed upstream build can't silently change what CI trusts.
- name: Install OSV-Scanner
run: |
curl -sSfL -o /usr/local/bin/osv-scanner \
"https://github.com/google/osv-scanner/releases/download/${OSV_SCANNER_VERSION}/osv-scanner_linux_amd64"
chmod +x /usr/local/bin/osv-scanner
osv-scanner --version

# Every real lockfile in the repo. Each one drives an actual
# `npm ci`/`pnpm install --frozen-lockfile` somewhere (Docker
# build or CI job), so drift here means a real, installable
# vulnerability - not a false positive from an unused file.
- name: Scan lockfiles
id: scan
run: |
set -o pipefail
mkdir -p osv-results
LOCKFILES=(
"package-lock.json"
"frontend/package-lock.json"
"backend/package-lock.json"
"backend/pnpm-lock.yaml"
"Cargo.lock"
)
FOUND_HIGH_CRIT=0
for lock in "${LOCKFILES[@]}"; do
[ -f "$lock" ] || continue
out="osv-results/$(echo "$lock" | tr '/' '_').json"
echo "::group::Scanning $lock"
osv-scanner scan source --lockfile="$lock" \
--format=json --output-file="$out" || true
# Human-readable table for the log, and its summary line
# is also our severity source of truth (see below).
TABLE_OUT=$(osv-scanner scan source --lockfile="$lock" || true)
echo "$TABLE_OUT"
echo "::endgroup::"

# osv-scanner itself buckets each finding into Critical/
# High/Medium/Low/Unknown via its own CVSS parsing and
# prints the totals in one summary line, e.g.:
# Total 1 package affected by 2 known vulnerabilities
# (0 Critical, 2 High, 0 Medium, 0 Low, 0 Unknown) ...
# Reusing that count avoids re-parsing raw CVSS vectors
# ourselves, which the JSON output does not pre-compute.
SUMMARY=$(echo "$TABLE_OUT" | grep -oE '\([0-9]+ Critical, [0-9]+ High,' || true)
CRIT=$(echo "$SUMMARY" | grep -oE '^[(][0-9]+' | tr -d '(')
HIGH=$(echo "$SUMMARY" | grep -oE '[0-9]+ High' | grep -oE '^[0-9]+')
CRIT="${CRIT:-0}"
HIGH="${HIGH:-0}"
echo "$lock: $CRIT Critical, $HIGH High"
if [ "$CRIT" -gt 0 ] || [ "$HIGH" -gt 0 ]; then
FOUND_HIGH_CRIT=1
fi
done
echo "found_high_crit=$FOUND_HIGH_CRIT" >> "$GITHUB_OUTPUT"

- name: Upload scan results
if: always()
uses: actions/upload-artifact@v4
with:
name: osv-scan-results
path: osv-results/
retention-days: 30

- name: Fail on High/Critical findings
if: steps.scan.outputs.found_high_crit == '1'
run: |
echo "::error::High/Critical severity vulnerabilities found. See the 'osv-scan-results' artifact for details, or run 'osv-scanner scan --lockfile=<path>' locally."
exit 1
10 changes: 10 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@
"web-push": "^3.6.7",
"zod": "^3.23.8"
},
"pnpm": {
"overrides": {
"brace-expansion@1": "1.1.18",
"brace-expansion@2": "2.1.4",
"brace-expansion@5": "5.0.9",
"fast-uri": "3.1.5",
"js-yaml@3": "3.15.1",
"js-yaml@4": "4.3.1"
}
},
"devDependencies": {
"eslint": "^8.57.0",
"eslint-config-prettier": "9.1.0",
Expand Down
Loading
Loading