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
34 changes: 34 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
version: 2
updates:
# npm workspace — covers all packages/* and apps/* dependencies in one pass.
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
day: monday
time: "08:00"
timezone: "America/Edmonton"
open-pull-requests-limit: 5
labels:
- dependencies
- security
# Group non-major updates together so the PR queue doesn't flood.
groups:
minor-and-patch:
update-types:
- minor
- patch

# Rust / Cargo — covers the Tauri desktop app dependencies.
- package-ecosystem: cargo
directory: /apps/desktop/src-tauri
schedule:
interval: weekly
day: monday
time: "08:00"
timezone: "America/Edmonton"
open-pull-requests-limit: 3
labels:
- dependencies
- security
- rust
58 changes: 58 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: CodeQL Analysis

# CodeQL is NOT a PR gate — it is too slow (5–15 min) to block developer feedback.
# Findings appear in the GitHub Security tab automatically.
# Runs:
# - Every push to main (catches anything that slipped through PR checks)
# - Weekly on Monday at 02:00 UTC (baseline drift detection)

on:
push:
branches: [main]
schedule:
- cron: '0 2 * * 1'

permissions:
contents: read
security-events: write
actions: read

jobs:
analyze:
name: CodeQL — JavaScript / TypeScript
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
# No cache: npm — package-lock.json is gitignored in this project.

# CodeQL needs installed dependencies to resolve imports properly.
- name: Install dependencies
run: npm install --ignore-scripts

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
# "javascript" covers both JS and TS — no need to list both.
languages: javascript
# security-and-quality includes OWASP Top 10 patterns.
queries: security-and-quality

# Let CodeQL auto-detect the build (TypeScript projects typically need no explicit step).
- name: Autobuild
uses: github/codeql-action/autobuild@v3

# continue-on-error: SARIF upload requires GitHub Advanced Security on private repos.
# The analysis itself still runs; findings are logged in the job output.
- name: Run CodeQL analysis
continue-on-error: true
uses: github/codeql-action/analyze@v3
with:
category: /language:javascript
upload: true
104 changes: 104 additions & 0 deletions .github/workflows/dependency-security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: Dependency Security

# Runs on every PR and every push to main.
# Hard-blocks on Critical npm vulnerabilities.
# Hard-blocks on any Rust advisory (cargo audit).
# Warns on High npm vulnerabilities (non-blocking — devDep false positives are common).

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

jobs:
# ── npm audit ──────────────────────────────────────────────────────────────
npm-audit:
name: npm audit
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
# No cache: npm — package-lock.json is gitignored in this project.

# Generate lockfile on the fly so npm audit has a full dependency graph.
# Consider committing package-lock.json for faster, deterministic CI.
- name: Generate lockfile
run: npm install --package-lock-only --ignore-scripts

# Hard block — Critical vulns in production dependencies.
- name: Fail on Critical vulnerabilities
run: npm audit --audit-level=critical --omit=dev

# Soft check — High vulns across all deps (informational; common in devDeps).
- name: Warn on High vulnerabilities
run: npm audit --audit-level=high || echo "⚠️ High-severity advisories found — review npm-audit-full.json"

# Upload full JSON report as a build artifact for manual review.
- name: Save full audit report
if: always()
run: npm audit --json > npm-audit-full.json || true

- name: Upload audit report
if: always()
uses: actions/upload-artifact@v4
with:
name: npm-audit-report
path: npm-audit-full.json
retention-days: 30

# ── ESLint security rules ──────────────────────────────────────────────────
eslint-security:
name: ESLint security
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

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

- name: Install dependencies
run: npm install --ignore-scripts

# Errors (inject/eval/ReDoS) cause non-zero exit and block the PR.
# Warnings (detect-non-literal-fs-filename) are informational — legitimate
# server/CLI filesystem operations use variable paths by design.
- name: Run ESLint security rules
run: npx eslint .

# ── Rust / cargo audit ─────────────────────────────────────────────────────
cargo-audit:
name: cargo audit
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

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

- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: cargo-audit-${{ hashFiles('apps/desktop/src-tauri/Cargo.lock') }}
restore-keys: cargo-audit-

- name: Install cargo-audit
run: cargo install cargo-audit --locked --quiet

- name: Run cargo audit
working-directory: apps/desktop/src-tauri
run: cargo audit
134 changes: 134 additions & 0 deletions .github/workflows/release-gate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
name: Release Gate

# Triggered by a version tag push (e.g. v0.0.12).
# All security checks must pass before a GitHub Release draft is created.
# To release: push a tag matching v* — this workflow does the rest.
#
# Usage:
# git tag v0.0.12
# git push origin v0.0.12

on:
push:
tags:
- 'v*'

permissions:
contents: write # needed to create a GitHub Release
security-events: write

jobs:
# ── Gate: unit tests ────────────────────────────────────────────────────────
unit-tests:
name: Unit tests
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm install --ignore-scripts
- run: npx vitest run

# ── Gate: ESLint security ───────────────────────────────────────────────────
eslint-security:
name: ESLint security
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm install --ignore-scripts
- run: npx eslint .

# ── Gate: npm audit ─────────────────────────────────────────────────────────
npm-audit:
name: npm audit
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm install --package-lock-only --ignore-scripts
- run: npm audit --audit-level=critical --omit=dev

# ── Gate: Gitleaks ──────────────────────────────────────────────────────────
gitleaks:
name: Gitleaks
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Gitleaks
env:
GITLEAKS_VERSION: "8.21.2"
run: |
curl -sSfL \
"https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
| tar -xz -C /usr/local/bin gitleaks
- run: gitleaks detect --source . --config .gitleaks.toml --redact

# ── Gate: cargo audit ───────────────────────────────────────────────────────
cargo-audit:
name: cargo audit
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: cargo-audit-${{ hashFiles('apps/desktop/src-tauri/Cargo.lock') }}
- run: cargo install cargo-audit --locked --quiet
- run: cargo audit
working-directory: apps/desktop/src-tauri

# ── Publish: create GitHub Release draft ────────────────────────────────────
# Only runs if ALL gate jobs succeed.
create-release:
name: Create Release Draft
needs: [unit-tests, eslint-security, npm-audit, gitleaks, cargo-audit]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Extract version from tag
id: tag
run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"

- name: Create GitHub Release draft
uses: softprops/action-gh-release@v2
with:
draft: true
generate_release_notes: true
name: "FoxSchema ${{ github.ref_name }}"
body: |
## FoxSchema ${{ github.ref_name }}

All security gates passed:
- ✅ Unit tests
- ✅ ESLint security rules
- ✅ npm audit (no Critical vulnerabilities)
- ✅ Gitleaks (no secrets detected)
- ✅ cargo audit (no Rust advisories)

> **Review this draft before publishing.** Edit the release notes above, then click "Publish release."
Loading
Loading