Skip to content

Add CI, tests, and architecture guardrails (GSSoC quality gates)#29

Merged
Venkat-Kolasani merged 5 commits into
mainfrom
ci/issue-28-quality-gates
Jun 8, 2026
Merged

Add CI, tests, and architecture guardrails (GSSoC quality gates)#29
Venkat-Kolasani merged 5 commits into
mainfrom
ci/issue-28-quality-gates

Conversation

@Venkat-Kolasani

@Venkat-Kolasani Venkat-Kolasani commented Jun 8, 2026

Copy link
Copy Markdown
Owner

PR Summary by Qodo

Add CI quality gates with frontend/backend tests and architecture guardrails
✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

Walkthroughs

User Description

Summary

  • Add GitHub Actions CI with parallel frontend, backend, architecture, and audit jobs
  • Split backend into app.js + server.js for Supertest; add 21 backend tests (validation, health, opportunities, documents)
  • Add frontend util tests + fix App.test.js for CI (14 tests total)
  • Add scripts/architecture-check.js to block frontend service-role keys and direct supabase.from() CRUD
  • Add docs/TESTING.md, docs/REVIEW_CHECKLIST.md, update CONTRIBUTING + PR template, and CODEOWNERS

Fixes #28

Test plan

  • npm run test:ci — 14 frontend tests pass
  • cd backend && npm test — 21 backend tests pass
  • npm run check:architecture — no violations
  • npm run build with CI env vars — succeeds
  • Verify GitHub Actions jobs are green on this PR
  • After merge: enable required status checks on main (see docs/TESTING.md)
AI Description
• Add GitHub Actions CI with parallel frontend, backend, architecture, and audit jobs.
• Add Jest/Supertest backend tests and refactor Express boot to support testing.
• Add frontend Jest fixes, utility tests, and architecture guardrails plus contributor docs.
Diagram
graph TD
  PR["Pull request"] --> CI["GitHub Actions CI"]
  CI --> FE["Frontend build+tests"]
  CI --> BE["Backend tests"]
  CI --> ARCH["Architecture check"]
  CI --> AUD["npm audit (info)"]
  ARCH --> SCRIPT["architecture-check.js"] --> TARGETS["src/ + manifests"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. ESLint rule for Supabase-from restriction
  • ➕ AST-based (fewer false positives than string search)
  • ➕ Integrates into dev workflow/editor feedback
  • ➕ Can be extended to enforce import boundaries and secret patterns
  • ➖ More setup/maintenance (custom rule packaging)
  • ➖ Harder to include git-diff-based checks (e.g., “new console.log in routes”)
2. Semgrep-based architecture/security checks
  • ➕ Robust pattern matching across languages
  • ➕ Easy to add more security rules over time
  • ➕ Works well in CI with clear findings output
  • ➖ Adds a new tool dependency and rule management overhead
  • ➖ May require tuning to avoid noisy findings
3. Use a matrix CI job per workspace instead of separate jobs
  • ➕ Less duplication in workflow YAML
  • ➕ Easier to add more Node versions later
  • ➖ Harder to read status checks at a glance for required checks
  • ➖ Less flexible per-job settings (e.g., working-directory, caching)

Recommendation: Current approach is appropriate for near-term GSSoC guardrails: separate CI jobs create clear required checks, and the lightweight Node guardrail script is simple to run locally. Consider migrating the string-based frontend Supabase/secret detection to ESLint or Semgrep later to reduce brittleness and scale rules without adding custom parsing logic.

Grey Divider

File Changes

Refactor (2)
app.js Extract Express app initialization into standalone module +228/-0

Extract Express app initialization into standalone module

• Moves middleware, rate limiting, health endpoints, and protected route wiring into an exportable Express app to support Supertest integration tests.

backend/src/app.js


server.js Simplify server entrypoint to run exported app +1/-266

Simplify server entrypoint to run exported app

• Replaces inline Express setup with a thin startup wrapper that imports app.js and listens on PORT.

backend/src/server.js


Tests (13)
documents.test.js Add integration coverage for Documents API basics +98/-0

Add integration coverage for Documents API basics

• Adds Supertest tests for auth enforcement, validation failures, list retrieval, and creating an external-link document using mocked Supabase and auth.

backend/tests/integration/documents.test.js


health.test.js Add integration tests for health and dependency health endpoints +44/-0

Add integration tests for health and dependency health endpoints

• Covers /api/health and /api/health/deps for healthy and degraded Supabase scenarios using a mocked supabase client.

backend/tests/integration/health.test.js


opportunities.test.js Add integration coverage for Opportunities API basics +83/-0

Add integration coverage for Opportunities API basics

• Adds Supertest tests for auth requirement, create validation errors, successful creation, and not-found behavior on patch.

backend/tests/integration/opportunities.test.js


auth.js Provide mock requireAuth middleware for backend tests +24/-0

Provide mock requireAuth middleware for backend tests

• Implements a minimal auth mock that returns 401 without a Bearer token and injects a stable TEST_AUTH object when present.

backend/tests/mocks/auth.js


supabase.js Add chainable Supabase query mocks for tests +36/-0

Add chainable Supabase query mocks for tests

• Provides utilities to mock fluent Supabase query chains, including a count-capable chain used by document limit checks.

backend/tests/mocks/supabase.js


setup.js Add backend test env defaults (no secrets required) +5/-0

Add backend test env defaults (no secrets required)

• Sets NODE_ENV=test and supplies placeholder Supabase/CORS env vars so tests run without local .env setup.

backend/tests/setup.js


validate-middleware.test.js Add unit tests for Joi validate middleware behavior +41/-0

Add unit tests for Joi validate middleware behavior

• Verifies that valid input is sanitized and forwarded and invalid input returns 400 with structured field errors.

backend/tests/unit/validate-middleware.test.js


validation.test.js Add unit tests for opportunity and document Joi schemas +76/-0

Add unit tests for opportunity and document Joi schemas

• Covers acceptance/rejection of typical payloads (title, link scheme, category) and document type validation.

backend/tests/unit/validation.test.js


App.test.js Stabilize App test for CI by mocking router/auth/api wiring +10/-2

Stabilize App test for CI by mocking router/auth/api wiring

• Mocks react-router-dom, auth token hook, and api token setter to avoid runtime side effects; updates expected home-page heading text.

src/App.test.js


react-router-dom.js Add lightweight react-router-dom Jest mock +23/-0

Add lightweight react-router-dom Jest mock

• Provides minimal BrowserRouter/Routes behavior to render the '/' route during unit tests without full router setup.

src/mocks/react-router-dom.js


setupTests.js Add Jest test harness mocks for browser APIs and Clerk/analytics +43/-3

Add Jest test harness mocks for browser APIs and Clerk/analytics

• Mocks IntersectionObserver, supplies REACT_APP env defaults for CI, and stubs Clerk + analytics modules to make tests deterministic.

src/setupTests.js


dateHelpers.test.js Add deterministic unit tests for date helper utilities +48/-0

Add deterministic unit tests for date helper utilities

• Uses fake timers to validate day calculations, overdue detection, and formatting behavior including falsy inputs.

src/utils/dateHelpers.test.js


opportunityHelpers.test.js Add unit tests for opportunity document-support helpers +33/-0

Add unit tests for opportunity document-support helpers

• Verifies supported categories, exported constants, and user messaging for unsupported categories.

src/utils/opportunityHelpers.test.js


Documentation (4)
pull_request_template.md Update PR template with CI-aligned test checklist +5/-1

Update PR template with CI-aligned test checklist

• Replaces watch-mode frontend test command with CI command, adds backend test and architecture-check requirements, and links to the testing guide.

.github/pull_request_template.md


CONTRIBUTING.md Document required pre-review checks and architecture rules +12/-5

Document required pre-review checks and architecture rules

• Points contributors to the testing guide, lists required commands, and codifies rules like “no frontend Supabase CRUD” and “API changes require tests.”

CONTRIBUTING.md


REVIEW_CHECKLIST.md Add maintainer review checklist for GSSoC PRs +52/-0

Add maintainer review checklist for GSSoC PRs

• Introduces a structured checklist covering architecture rules, security/RLS, code quality patterns, and verification expectations.

docs/REVIEW_CHECKLIST.md


TESTING.md Add testing guide describing local workflow and CI expectations +100/-0

Add testing guide describing local workflow and CI expectations

• Documents required commands, when to add which tests, architecture constraints, and how to enable branch protection required checks.

docs/TESTING.md


Other (6)
CODEOWNERS Add CODEOWNERS for sensitive backend/docs paths +4/-0

Add CODEOWNERS for sensitive backend/docs paths

• Introduces automatic review requests for backend middleware/routes and migration SQL files to ensure owner oversight on high-risk changes.

.github/CODEOWNERS


ci.yml Add GitHub Actions CI workflow with four parallel jobs +90/-0

Add GitHub Actions CI workflow with four parallel jobs

• Adds frontend build+tests, backend Jest tests, architecture guardrails, and non-blocking npm audit jobs for PRs/pushes to main.

.github/workflows/ci.yml


jest.config.js Add backend Jest configuration and test discovery +7/-0

Add backend Jest configuration and test discovery

• Configures Node test environment, loads test setup defaults, and scopes test matching to backend/tests.

backend/jest.config.js


package.json Add backend test scripts and dev dependencies for Jest/Supertest +5/-1

Add backend test scripts and dev dependencies for Jest/Supertest

• Introduces jest-based test scripts (including coverage CI mode) and adds Jest/Supertest as dev dependencies.

backend/package.json


package.json Add root scripts for CI-mode tests and architecture check +2/-0

Add root scripts for CI-mode tests and architecture check

• Adds test:ci for non-watch React tests and check:architecture for the guardrail script.

package.json


architecture-check.js Introduce architecture guardrail script (frontend Supabase/secret bans) +156/-0

Introduce architecture guardrail script (frontend Supabase/secret bans)

• Scans frontend src for service-role leakage and disallowed supabase.from usage; warns on new console.log in backend routes and on new dependencies.

scripts/architecture-check.js


Grey Divider

Qodo Logo

Introduces GitHub Actions (frontend build/test, backend tests, architecture check), Jest coverage for API routes and utils, and contributor testing docs so PRs can be gated on green checks.

Fixes #28
Copilot AI review requested due to automatic review settings June 8, 2026 13:51
@vercel

vercel Bot commented Jun 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
future-stack Ready Ready Preview, Comment Jun 8, 2026 2:06pm

@qodo-code-review

qodo-code-review Bot commented Jun 8, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Context used

Grey Divider


Remediation recommended

1. Health skip never triggers 🐞 Bug ☼ Reliability
Description
generalLimiter is mounted at /api/, but the skip predicate compares req.path to /api/health,
so health checks can still be rate limited. This can cause monitoring/health probes to
intermittently fail with 429s under load.
Code

backend/src/app.js[R69-75]

+const generalLimiter = rateLimit({
+    windowMs: 15 * 60 * 1000,
+    max: 2000,
+    standardHeaders: true,
+    legacyHeaders: false,
+    skip: (req) => req.path === '/api/health',
+    handler: (req, res) => {
Evidence
The limiter is mounted at /api/ while the skip compares against a full /api/health path;
elsewhere in the same app, mounted routers define paths relative to their mount, which implies the
limiter’s req.path won’t include the /api prefix either.

backend/src/app.js[69-116]
backend/src/app.js[157-163]
backend/src/app.js[199-202]
backend/src/routes/opportunities.js[54-64]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`backend/src/app.js` mounts the general rate limiter at `/api/`, but the skip predicate checks `req.path === '/api/health'`. In Express, `req.path` in middleware mounted at `/api/` is typically relative to the mount (e.g. `/health`), so the skip does not apply.

### Issue Context
The codebase already relies on mount-path stripping for routers (e.g. `/api/opportunities` mounts a router that defines `router.get('/')`). The limiter is mounted similarly, so its path check should be consistent with that.

### Fix Focus Areas
- backend/src/app.js[69-116]

### Suggested fix
Update the skip logic to match the mounted path, or use `req.originalUrl`:
- Option A: `skip: (req) => req.path === '/health'`
- Option B (more robust): `skip: (req) => req.originalUrl.startsWith('/api/health')`

(Keep the mount at `/api/` unchanged.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Trust proxy always enabled 🐞 Bug ⛨ Security
Description
app.set('trust proxy', 1) is enabled unconditionally, so if the backend is reachable without a
trusted reverse proxy, clients can spoof X-Forwarded-For and affect IP-derived behavior (rate
limiting and audit IP logs). This undermines abuse controls and audit integrity in misconfigured
deployments.
Code

backend/src/app.js[R18-23]

+// =============================================================================
+// Trust Proxy Configuration
+// =============================================================================
+
+app.set('trust proxy', 1);
+
Evidence
The app enables proxy trust and later prefers req.ips[0] (derived from forwarding headers when
trust proxy is on) for request/response audit logs, so spoofed forwarding headers can affect the
logged/limited IP in direct-to-app deployments.

backend/src/app.js[18-23]
backend/src/app.js[124-146]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The backend enables `trust proxy` globally. When the service is directly reachable (or the proxy chain is not what you expect), `X-Forwarded-For` becomes user-controlled input and can influence `req.ip`/`req.ips`, which impacts rate limiting and IP logging.

### Issue Context
This repo uses IP-based rate limiting (`express-rate-limit`) and logs client IPs for write operations.

### Fix Focus Areas
- backend/src/app.js[18-23]
- backend/src/app.js[124-146]

### Suggested fix
Make `trust proxy` explicit and environment-controlled:
- Only enable it in production behind a known proxy, or
- Read from an env var like `TRUST_PROXY` and default to `false`.

Example:
```js
const trustProxy = process.env.TRUST_PROXY;
if (trustProxy) app.set('trust proxy', Number(trustProxy));
```
Also consider documenting the required deployment topology (reverse proxy/LB) alongside this setting.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. .env check unreachable ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
scripts/architecture-check.js filters scanned files to only js/jsx/ts/tsx, then checks for
basenames like .env, making that guardrail impossible to trigger. This weakens the intended
architecture/security enforcement by giving false confidence that .env files under src/ would be
caught.
Code

scripts/architecture-check.js[R52-63]

+function scanFrontendSrc() {
+    const srcDir = path.join(ROOT, 'src');
+    const files = walkDir(srcDir).filter((f) => /\.(js|jsx|ts|tsx)$/.test(f));
+
+    for (const file of files) {
+        const rel = relPath(file);
+        const content = fs.readFileSync(file, 'utf8');
+        const basename = path.basename(file);
+
+        if (basename === '.env' || basename.startsWith('.env.')) {
+            errors.push(`${rel}: .env files must not live in src/`);
+        }
Evidence
The code explicitly restricts scanned files to code extensions and only then checks whether the
basename is .env/.env.*, which cannot be true under that filter.

scripts/architecture-check.js[52-63]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The architecture checker intends to fail if `.env`-style files appear under `src/`, but it filters the file list to `.(js|jsx|ts|tsx)` before performing the `.env` basename check. As a result, `.env` files are never inspected and the rule is ineffective.

### Issue Context
The script is meant to enforce guardrails against secrets/unsafe patterns in the frontend.

### Fix Focus Areas
- scripts/architecture-check.js[52-79]

### Suggested fix
Split scanning into two passes:
1) Walk all files under `src/` and fail on basenames `.env` / `.env.*`.
2) For content scanning, restrict to `js/jsx/ts/tsx` and apply the existing string/regex checks.

This preserves performance while making the `.env` rule functional.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@Venkat-Kolasani Venkat-Kolasani left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment thread scripts/architecture-check.js Outdated

Copilot AI left a comment

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.

Pull request overview

Adds GSSoC “quality gates” to the repo by introducing GitHub Actions CI, expanding automated test coverage for both frontend and backend, and adding an architecture guardrail script + contributor docs so PRs can’t merge without meeting baseline checks.

Changes:

  • Added GitHub Actions CI workflow with separate frontend/backend/architecture/audit jobs.
  • Added Jest/Supertest backend test suite and refactored backend entrypoint into app.js (exportable for tests) + server.js (listen).
  • Added frontend util tests, fixed App.test.js wiring for CI, and introduced an architecture guardrail script + testing/review documentation.

Reviewed changes

Copilot reviewed 25 out of 26 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/utils/opportunityHelpers.test.js Adds unit tests for opportunity document-support helpers.
src/utils/dateHelpers.test.js Adds unit tests for date utility helpers.
src/setupTests.js Adds shared Jest test setup/mocks for browser APIs, Clerk, and analytics.
src/App.test.js Updates App smoke tests and adds mocks for CI stability.
src/mocks/react-router-dom.js Adds a local router mock implementation for tests.
scripts/architecture-check.js Adds guardrail script to detect frontend secret usage and disallowed Supabase CRUD patterns.
package.json Adds test:ci and check:architecture scripts.
docs/TESTING.md Documents local testing commands and what CI enforces.
docs/REVIEW_CHECKLIST.md Adds a maintainer review checklist for common PR red flags.
CONTRIBUTING.md Updates contributor guidance to align with new CI/test expectations.
backend/tests/unit/validation.test.js Adds unit tests for Joi validation schemas.
backend/tests/unit/validate-middleware.test.js Adds unit tests for request validation middleware behavior.
backend/tests/setup.js Adds backend Jest setup (test env defaults).
backend/tests/mocks/supabase.js Adds chainable Supabase client mocks for backend tests.
backend/tests/mocks/auth.js Adds auth middleware mock helpers for integration tests.
backend/tests/integration/opportunities.test.js Adds Supertest integration tests for opportunities routes.
backend/tests/integration/health.test.js Adds integration tests for health endpoints (including dependency health).
backend/tests/integration/documents.test.js Adds integration tests for documents routes.
backend/src/server.js Simplifies to a thin “listen” wrapper around the Express app.
backend/src/app.js Introduces exportable Express app for Supertest and production server reuse.
backend/package.json Adds Jest/Supertest and test scripts for backend CI.
backend/jest.config.js Adds backend Jest configuration (node env + setup files).
.github/workflows/ci.yml Adds CI workflow running frontend build/tests, backend tests, architecture checks, and audits.
.github/pull_request_template.md Updates PR template to reflect new commands and expectations.
.github/CODEOWNERS Adds CODEOWNERS entries for sensitive backend/docs paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/App.test.js Outdated
Comment thread scripts/architecture-check.js Outdated
Comment thread src/utils/dateHelpers.test.js
…ans all files in the src directory first, then filters for code files, ensuring .env files are correctly identified and reported. This enhances the clarity and efficiency of the architecture checks.
…ame mapping for react-router-dom to use a mock implementation, enhancing test isolation. Updated package.json to set the timezone for CI tests.
…to return a formatted string, added parseLocalDate for accurate date parsing, and set UTC timezone for consistent test results across environments.
…d formatDate for better string output, added parseLocalDate for precise parsing, and ensured UTC timezone is applied in tests for uniformity across environments.
@Venkat-Kolasani Venkat-Kolasani merged commit 4df4b0c into main Jun 8, 2026
7 checks passed
@Venkat-Kolasani Venkat-Kolasani deleted the ci/issue-28-quality-gates branch June 8, 2026 14:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GSSoC Quality Gates and Testing

2 participants