From 9c35c59948e18254c434bd496b9292a33606532f Mon Sep 17 00:00:00 2001 From: kundanr2 Date: Sun, 21 Sep 2025 11:46:58 +1000 Subject: [PATCH 1/6] rbac logging --- middleware/authorizeRoles.js | 41 ++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/middleware/authorizeRoles.js b/middleware/authorizeRoles.js index 0b578ff..c186e6b 100644 --- a/middleware/authorizeRoles.js +++ b/middleware/authorizeRoles.js @@ -1,13 +1,19 @@ /** - * Role-based access control (RBAC) middleware + * Role-based access control (RBAC) middleware with violation logging */ +const { createClient } = require('@supabase/supabase-js'); + +const supabase = createClient( + process.env.SUPABASE_URL, + process.env.SUPABASE_ANON_KEY // ✅ still using anon key +); + function authorizeRoles(...allowedRoles) { - return (req, res, next) => { - // Supabase JWTs: "role" is usually "authenticated" or "service_role" - // Custom JWTs: you explicitly set "role" in payload + return async (req, res, next) => { const userRole = req.user?.role || req.user?.user_roles || null; if (!userRole) { + await logViolation(req, userRole, "ROLE_MISSING"); return res.status(403).json({ success: false, error: "Role missing in token", @@ -15,13 +21,11 @@ function authorizeRoles(...allowedRoles) { }); } - // Normalize role value (lowercase string) const roleValue = String(userRole).toLowerCase(); - - // Normalize allowed roles too const normalizedAllowed = allowedRoles.map(r => r.toLowerCase()); if (!normalizedAllowed.includes(roleValue)) { + await logViolation(req, roleValue, "ACCESS_DENIED"); return res.status(403).json({ success: false, error: "Access denied: insufficient role", @@ -29,8 +33,31 @@ function authorizeRoles(...allowedRoles) { }); } + // ✅ If role is allowed, continue next(); }; } +async function logViolation(req, role, status) { + const payload = { + user_id: req.user?.userId || "unknown", + email: req.user?.email || "unknown", // ✅ added email + role: role || "unknown", + endpoint: req.originalUrl, + method: req.method, + status + }; + + try { + const { error } = await supabase.from("rbac_violation_logs").insert([payload]); + if (error) { + console.error("❌ Supabase insert error:", error.message); + } else { + console.log("✅ RBAC violation logged:", payload); + } + } catch (err) { + console.error("❌ RBAC log exception:", err.message); + } +} + module.exports = authorizeRoles; \ No newline at end of file From 6c26678c16abb0244c73647d1c1f981894e25e33 Mon Sep 17 00:00:00 2001 From: Tanya2209 Date: Fri, 26 Sep 2025 06:07:29 +1000 Subject: [PATCH 2/6] ci: add parallel lint/test/openapi jobs --- .github/workflows/security.yml | 27 +++++++++++++++------------ package-lock.json | 2 +- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index d823482..78c4f54 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -9,26 +9,29 @@ on: - '**' env: NODE_VERSION: "20" + OPENAPI_FILE: 'index.yaml' + PORT: '3000' jobs: - node-ci: + lint: runs-on: ubuntu-latest steps: - # 1. Checkout repository - - name: Checkout - uses: actions/checkout@v4 - - # 2. Setup Node.js with caching enabled - - name: Setup Node with cache - uses: actions/setup-node@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: ${{ env.NODE_VERSION }} + node-version: 20 cache: npm cache-dependency-path: package-lock.json + - run: npm ci --prefer-offline --no-audit --no-fund - # 3. Install dependencies (reproducible and cache-friendly) - - name: Install dependencies - run: npm ci + + - name: Ensure minimal ESLint config + run: | + node -e "const fs=require('fs');const has=['.eslintrc.json','.eslintrc.js','eslint.config.js'].some(f=>fs.existsSync(f));if(!has){fs.writeFileSync('.eslintrc.json',JSON.stringify({root:true,env:{es2021:true,node:true,browser:true},parserOptions:{ecmaVersion:2022,sourceType:'module'},ignorePatterns:['node_modules/','dist/','build/','coverage/'],rules:{curly:'off',eqeqeq:'off','no-undef':'off','no-unused-vars':'off'}},null,2));}" + + - name: Run ESLint (non-blocking) + run: npx -y eslint@8.57.0 . --no-error-on-unmatched-pattern --quiet || true + run-security-scan: runs-on: ubuntu-latest diff --git a/package-lock.json b/package-lock.json index 059759b..c33089a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7858,4 +7858,4 @@ } } } -} \ No newline at end of file +} From 5688f9bba476302e44ca5978c6187ffc477c47ab Mon Sep 17 00:00:00 2001 From: Tanya2209 Date: Fri, 26 Sep 2025 06:11:01 +1000 Subject: [PATCH 3/6] ci: add parallel lint/test/openapi jobs --- .github/workflows/security.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 78c4f54..25c0ae3 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -31,6 +31,31 @@ jobs: - name: Run ESLint (non-blocking) run: npx -y eslint@8.57.0 . --no-error-on-unmatched-pattern --quiet || true + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + cache-dependency-path: package-lock.json + - run: npm ci --prefer-offline --no-audit --no-fund + + + - name: Run fast tests (non-blocking) + shell: bash + run: | + set -e + if node -e "const s=(require('./package.json').scripts)||{};process.exit(s['test:unit']?0:1)"; then + npm run test:unit -- --ci || true + elif node -e "const p=require('./package.json');const hasJest=(p.devDependencies&&p.devDependencies.jest)||(p.dependencies&&p.dependencies.jest);process.exit(hasJest?0:1)"; then + npx jest --ci --passWithNoTests || true + else + npm test --silent || true + fi + run-security-scan: runs-on: ubuntu-latest From 9b51213cec36006fac92a4268c1bd2b6ecb1afe6 Mon Sep 17 00:00:00 2001 From: Tanya2209 Date: Fri, 26 Sep 2025 06:11:58 +1000 Subject: [PATCH 4/6] ci: add parallel lint/test/openapi jobs --- .github/workflows/security.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 25c0ae3..10e7da1 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -32,7 +32,7 @@ jobs: - name: Run ESLint (non-blocking) run: npx -y eslint@8.57.0 . --no-error-on-unmatched-pattern --quiet || true - test: + test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 From 80999050207f6cbe9a73810489a56e0945efec9a Mon Sep 17 00:00:00 2001 From: Tanya2209 Date: Fri, 26 Sep 2025 06:16:16 +1000 Subject: [PATCH 5/6] ci: add parallel lint/test/openapi jobs --- .github/workflows/security.yml | 65 ++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 10e7da1..810115a 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -55,6 +55,71 @@ jobs: else npm test --silent || true fi + + openapi-validate: + + runs-on: ubuntu-latest + + steps: + + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + + with: + + node-version: ${{ env.NODE_VERSION }} + + cache: npm + + cache-dependency-path: package-lock.json + + - run: npm ci + + - name: Install swagger-cli + + run: npx -y swagger-cli@4.0.4 --version + + + + - name: Validate OpenAPI (non-blocking) + + run: | + + REPORT=openapi-validate.log + + if [ ! -f "${{ env.OPENAPI_FILE }}" ]; then + + echo "::warning::OpenAPI file '${{ env.OPENAPI_FILE }}' not found at repo root. Skipping validation." | tee "$REPORT" + + exit 0 + + fi + + # Run validation, capture output; do not fail the step + + npx swagger-cli validate "${{ env.OPENAPI_FILE }}" >"$REPORT" 2>&1 || { + + echo "::warning::OpenAPI validation failed. See artifact '$REPORT' for details." + + } + + # Always succeed + + exit 0 + + - name: Upload OpenAPI validation report + + uses: actions/upload-artifact@v4 + + with: + + name: openapi-validate-report + + path: openapi-validate.log + + if-no-files-found: ignore + run-security-scan: From 22a8c4e9ef3b11cd67997bce4e169e3e24280538 Mon Sep 17 00:00:00 2001 From: Tanya2209 Date: Fri, 26 Sep 2025 06:16:54 +1000 Subject: [PATCH 6/6] ci: add parallel lint/test/openapi jobs --- .github/workflows/security.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 810115a..5ff6613 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -56,7 +56,7 @@ jobs: npm test --silent || true fi - openapi-validate: + openapi-validate: runs-on: ubuntu-latest