Skip to content

`feat(frontend): add wallet referral links and first-bet attribution … #459

`feat(frontend): add wallet referral links and first-bet attribution …

`feat(frontend): add wallet referral links and first-bet attribution … #459

name: Security Scanning (Semgrep + Secret Scanning)
on:
pull_request:
branches:
- Default
- main
- dev
- staging
push:
branches:
- Default
- main
# Cancel in-progress runs on the same PR to save CI minutes
concurrency:
group: security-${{ github.ref }}
cancel-in-progress: true
jobs:
# ── 1. Semgrep OSS static analysis ────────────────────────────────────────
semgrep:
name: Semgrep Static Analysis
runs-on: ubuntu-latest
# Required for the SARIF upload step
permissions:
security-events: write
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Run Semgrep
uses: semgrep/semgrep-action@v1
with:
# ── Rule-sets ──────────────────────────────────────────────────────
# p/secrets – hardcoded API keys, private keys, tokens
# p/javascript – JS/TS security anti-patterns (eval, prototype pollution…)
# p/nodejs – Node/Express specific issues
# p/rust – Rust memory-safety and logic checks
# p/owasp-top-ten – OWASP Top 10 coverage
# soroban-security – custom rule-set (see .semgrep/soroban.yml)
config: >-
p/secrets
p/javascript
p/nodejs
p/rust
p/owasp-top-ten
.semgrep/soroban.yml
# Block the merge on HIGH severity findings
# (MEDIUM/LOW are reported but non-blocking)
generateSarif: "1"
# Exit 1 on any HIGH or CRITICAL finding β†’ blocks merge
auditOn: findings
env:
# Optional: add your Semgrep token for the App dashboard
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
- name: Upload SARIF to GitHub Security tab
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: semgrep.sarif
category: semgrep
- name: Generate Semgrep Security Report Summary
if: always()
run: |
echo "### πŸ”’ Semgrep Security Report" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ -f semgrep.sarif ]; then
# Count findings by severity
CRITICAL=$(jq '[.runs[].results[] | select(.properties.severity == "CRITICAL")] | length' semgrep.sarif 2>/dev/null || echo "0")
HIGH=$(jq '[.runs[].results[] | select(.properties.severity == "HIGH")] | length' semgrep.sarif 2>/dev/null || echo "0")
MEDIUM=$(jq '[.runs[].results[] | select(.properties.severity == "MEDIUM")] | length' semgrep.sarif 2>/dev/null || echo "0")
LOW=$(jq '[.runs[].results[] | select(.properties.severity == "LOW")] | length' semgrep.sarif 2>/dev/null || echo "0")
TOTAL=$(jq '.runs[].results | length' semgrep.sarif 2>/dev/null || echo "0")
echo "| Severity | Count |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| πŸ”΄ Critical | $CRITICAL |" >> $GITHUB_STEP_SUMMARY
echo "| 🟠 High | $HIGH |" >> $GITHUB_STEP_SUMMARY
echo "| 🟑 Medium | $MEDIUM |" >> $GITHUB_STEP_SUMMARY
echo "| πŸ”΅ Low | $LOW |" >> $GITHUB_STEP_SUMMARY
echo "| **Total** | **$TOTAL** |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "$HIGH" -gt "0" ] || [ "$CRITICAL" -gt "0" ]; then
echo "❌ **Merge blocked** β€” $CRITICAL critical and $HIGH high severity findings must be resolved." >> $GITHUB_STEP_SUMMARY
else
echo "βœ… **No high/critical findings** β€” merge is unblocked by security scan." >> $GITHUB_STEP_SUMMARY
fi
else
echo "⚠️ SARIF file not found β€” Semgrep may have exited early." >> $GITHUB_STEP_SUMMARY
fi
# ── 2. Hardcoded secrets via git history ──────────────────────────────────
secret-scanning:
name: Secret Scanning (gitleaks)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
# Full history so gitleaks can scan all commits in the PR
fetch-depth: 0
- name: Run gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Exit 1 on any leak found β†’ blocks merge
GITLEAKS_ENABLE_COMMENTS: true
- name: Secret scan summary
if: always()
run: |
echo "### πŸ”‘ Secret Scanning Report" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ job.status }}" == "success" ]; then
echo "βœ… No secrets detected in commit history." >> $GITHUB_STEP_SUMMARY
else
echo "❌ **Secrets detected** β€” remove leaked credentials and rotate them immediately." >> $GITHUB_STEP_SUMMARY
fi
# ── 3. Rust-specific dependency audit ─────────────────────────────────────
cargo-audit:
name: Cargo Dependency Audit
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: "stable"
cache: true
- name: Install cargo-audit
run: cargo install cargo-audit --locked
- name: Run cargo audit
working-directory: ./contracts/prediction_market
run: |
echo "### πŸ“¦ Cargo Dependency Audit" >> $GITHUB_STEP_SUMMARY
cargo audit --json > audit-report.json 2>&1 || true
VULNS=$(jq '.vulnerabilities.count' audit-report.json 2>/dev/null || echo "0")
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Vulnerabilities found | $VULNS |" >> $GITHUB_STEP_SUMMARY
if [ "$VULNS" -gt "0" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "⚠️ Dependency vulnerabilities found β€” review audit-report.json" >> $GITHUB_STEP_SUMMARY
cargo audit # re-run for human-readable output in logs
else
echo "βœ… No known vulnerabilities in dependencies." >> $GITHUB_STEP_SUMMARY
fi
# ── 4. Gate: block merge on any HIGH/CRITICAL finding ─────────────────────
security-gate:
name: Security Gate
runs-on: ubuntu-latest
needs: [semgrep, secret-scanning, cargo-audit]
if: always()
steps:
- name: Evaluate gate
run: |
SEMGREP="${{ needs.semgrep.result }}"
SECRETS="${{ needs.secret-scanning.result }}"
AUDIT="${{ needs.cargo-audit.result }}"
echo "### 🚦 Security Gate" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Check | Result |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Semgrep | $SEMGREP |" >> $GITHUB_STEP_SUMMARY
echo "| Secret Scanning | $SECRETS |" >> $GITHUB_STEP_SUMMARY
echo "| Cargo Audit | $AUDIT |" >> $GITHUB_STEP_SUMMARY
if [ "$SEMGREP" != "success" ] || [ "$SECRETS" != "success" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "❌ **Merge is BLOCKED** β€” resolve all high/critical security findings before merging." >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "βœ… **All security checks passed β€” merge is unblocked.**" >> $GITHUB_STEP_SUMMARY