Skip to content
harshaR-ctrlPublic

About

amulti layered proctoring system built to ensure fairness and prevent cheating during interviews

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Interview Integrity Extension — Complete Build

A production-grade, privacy-first browser extension for verifying technical-interview integrity through behavioral, environmental, and system-level signals.

Features

  • Layer 1: Behavioral — Focus changes, paste events, typing cadence, mouse presence
  • Layer 2: Environmental — Cell phone detection, multi-person detection (camera-based object detection, no facial analysis)
  • Layer 3: System — Optional process blacklist monitoring (opt-in native companion app)
  • Risk Engine — Correlated scoring with GREEN/YELLOW/RED classification (RED requires ≥2 independent layer signals)
  • Recruiter Dashboard — React-based timeline view of flagged events and risk assessments

Privacy-First Design

  • ✅ No gaze tracking, facial emotion analysis, or general behavior judgment
  • ✅ No code content capture; metadata only (timestamps, lengths, event types)
  • ✅ All ML inference client-side; no raw media leaves the browser
  • ✅ Camera snapshots sent only when detection threshold is breached
  • ✅ No automated session termination; flags are for human review only
  • ✅ Minimal permissions; each justified in code comments

Architecture

interview-extension/
├── extension/          # Layer 1 & 2, manifest.json, content-script, service-worker
├── backend/            # Ingestion API, Risk Engine, Supabase integration
├── dashboard/          # React recruiter UI
├── native-host/        # Layer 3 (optional): process monitoring
├── docker-compose.yml  # Local Docker deployment entrypoint
├── k8s/                # Kubernetes manifests
└── shared/             # TypeScript data contracts

Build & Deploy

Prerequisites

  • Node.js 18+
  • Supabase project with a service role key
  • Docker Desktop (optional, for local container runs)
  • Chrome 120+ (for MV3)

1. Extension (Layers 1 & 2)

cd extension

# Compile TypeScript
npm install -g typescript
tsc content-script.ts --outDir .
tsc background.ts --outDir .

# Load unpacked extension in Chrome:
# 1. chrome://extensions/
# 2. Enable "Developer mode" (top right)
# 3. "Load unpacked"
# 4. Select ./extension folder

Key Files:

  • manifest.json — MV3 permissions (activeTab, camera optional)
  • content-script.ts — Layer 1 event capture
  • background.ts — Batching + API calls
  • layer2.html — Camera + TensorFlow.js for Layer 2
  • popup.html — Extension popup UI
  • onboarding.html — First-run consent flow
  • settings.html — User-configurable settings

2. Backend API

cd backend

# Install dependencies
npm install

# Configure backend/.env with your Supabase values
# The service will create its required tables automatically on startup

# Start server (development)
npm run dev

# Server listens on http://localhost:3000
# POST  /api/ingest       — accept event batches from extension
# GET   /api/sessions     — list sessions
# GET   /api/session/:id  — get session details + events

Service Setup:

  • Put your Supabase values in backend/.env
  • The backend uses SUPABASE_DIRECT_CONNECTION_STRING for the database connection
  • The startup flow creates the required tables automatically, so there is no manual DB setup step

Database Schema:

  • Session — interview metadata + aggregated risk state
  • RiskEvent — individual events (Layer 1, 2, or 3)
  • SessionRiskState — cached risk classification for fast queries

Risk Engine Logic:

  • Scores events individually per layer
  • Correlates events across layers within a 30s window
  • RED = ≥2 independent layer signals correlated (constraint C6)
  • YELLOW = single minor signal
  • GREEN = no material anomalies

3. Recruiter Dashboard

cd dashboard

# Install & start dev server
npm install
npm run dev

# Runs on http://localhost:5173
# Displays: session list, timeline, risk levels, contributing events

# Build for production
npm run build
# Output: dist/

Pages:

  • Home: Session list with filter (RED/YELLOW/GREEN)
  • Detail: Full timeline with event metadata and snapshots

4. Native Host (Layer 3, Optional)

cd native-host

# Build
npm install
npm run build

# Register with Chrome (platform-specific):

# === Windows ===
# 1. Create manifest.json in:
#    C:\Users\<USER>\AppData\Local\Google\Chrome\NativeMessagingHosts\
# 2. Manifest contents:
#{
#  "name": "com.interviewintegrity.layer3",
#  "description": "Layer 3 process monitoring",
#  "path": "C:\\path\\to\\native-host\\dist\\index.js",
#  "type": "stdio",
#  "allowed_origins": [
#    "chrome-extension://YOUR_EXTENSION_ID/"
#  ]
#}

# === macOS/Linux ===
# 1. Create manifest in ~/.config/google-chrome/NativeMessagingHosts/
# 2. Same format, adjust path to your system

# === Test ===
node dist/index.js
# Send JSON messages via stdin; receive responses via stdout

Process Blacklist:

  • Screen-share tools (Zoom, Skype, TeamViewer, etc.)
  • Remote desktop (RDP, TeamViewer, VNC, Chrome Remote Desktop)
  • AI assistants (Copilot, Codeium, TabNine)
  • Suspicious debuggers

Privacy Note: Reports only matched category tags (e.g., ["screen-share-tool-detected"]), never a full process list (constraint C8).

Configuration

Extension Settings (popup.html → localStorage)

{
  layer1Enabled: true,
  typingBurstThreshold: 150,          // chars/sec
  pasteLengthThreshold: 500,          // bytes
  layer2Enabled: false,               // requires camera permission
  confidenceThreshold: 0.7,           // 0–1, for COCO-SSD
  sampleInterval: 2.5,                // seconds between camera frames
  layer3Enabled: false,               // requires native host
  apiUrl: "http://localhost:3000/api",
  batchInterval: 4,                   // seconds
  correlationWindow: 30,              // seconds (C6)
}

Backend Environment (.env)

Create backend/.env with:

SUPABASE_URL=https://<project-ref>.supabase.co
SUPABASE_SERVICE_ROLE_KEY=<service-role-key>
SUPABASE_DIRECT_CONNECTION_STRING=postgresql://postgres:<password>@db.<project-ref>.supabase.co:5432/postgres
PORT=3000
NODE_ENV=development

The backend reads these values automatically at startup.

Risk Scoring

Default weights (configurable in Risk Engine):

  • Layer 1 Focus Change: 0.1 (common, low weight)
  • Layer 1 Paste: 0.15 (size-dependent)
  • Layer 1 Typing Burst: 0.05 (not suspicious alone)
  • Layer 2 Phone: 0.5 (strong signal, needs corroboration)
  • Layer 2 Multi-Person: 0.4 (strong signal)
  • Layer 3 Process Match: 0.6 (very strong, especially with Layer 2)

Correlation (C6): Two events from different layers within 30s → escalate to RED.

Docker and Kubernetes

Docker

docker compose up --build

This starts the backend service on port 3000 using the environment variables from your shell or Docker environment.

Kubernetes

kubectl apply -f k8s/

Make sure the interview-secrets secret exists with the same Supabase environment variables.

###Render

Render can host the backend as a web service.

  1. Create a new Web Service in Render and point it to this repository.
  2. Set the build command to:
    npm --prefix backend install && npm --prefix backend run build
  3. Set the start command to:
    npm --prefix backend start
  4. Add these environment variables in Render:
    SUPABASE_URL=https://<project-ref>.supabase.co
    SUPABASE_SERVICE_ROLE_KEY=<service-role-key>
    SUPABASE_DIRECT_CONNECTION_STRING=postgresql://postgres:<password>@db.<project-ref>.supabase.co:5432/postgres
    PORT=10000
    NODE_ENV=production
  5. Render will expose the service on its generated URL.

Update the extension and dashboard API URLs to the Render-hosted backend URL when you deploy.

Testing

Layer 1 (Behavioral)

// content-script.ts tests:
// T2: Single focus_change → YELLOW
// T3: Organic typing burst (plausible human cadence) → no flag
// T4: paste event → logged with length, never content

Layer 2 (Environmental)

// layer2.html + COCO-SSD tests:
// T5: Cell phone in frame (confidence > 0.7) → phone_detected + snapshot
// T6: Normal scene (one person, no phone) → no flag

Risk Engine

// risk-engine.ts tests:
// T1: No events → GREEN
// T2: Single signal → YELLOW (not RED, per C6)
// T7: Phone detected (Layer 2) + blacklist match (Layer 3) within 30s → RED
// T8: Phone alone (no Layer 3 signal) → not RED (pending)

Deployment Checklist

Pre-Launch Legal

  • Candidate consent/disclosure copy reviewed
  • Data retention and deletion policy finalized
  • Regional law review (BIPA, GDPR, state wiretap laws)
  • Privacy policy published and linked in onboarding

Extension

  • All Layer 1 permissions justified in manifest comments
  • Layer 2 camera access only via dedicated extension page, not injected script
  • Layer 3 clearly optional; separate install with explicit consent
  • No test/debug code in production build

Backend

  • Supabase backup / retention policy in place
  • API authentication (JWT or OAuth) added for recruiter dashboard
  • Rate limiting and DDoS protection enabled
  • Logs redacted of sensitive data
  • CORS configured to allow dashboard origin only

Dashboard

  • No candidate data displayed in session list (only recruiter-facing)
  • Event timestamps in recruiter's timezone
  • Snapshots blurred or redacted before recruiter view (optional privacy layer)

Troubleshooting

Extension not capturing events

  1. Check chrome://extensions/ → Extension ID and version
  2. Verify interview page matches manifest.json matches patterns
  3. Open DevTools (F12) on interview page → Console for [Layer 1] logs
  4. Check background service worker logs: chrome://extensions → Inspect background page

Backend API not receiving events

  1. Verify background.ts is sending to correct API URL
  2. Check http://localhost:3000/health for API health
  3. Ensure your Supabase project is reachable and your service role key is configured
  4. Check backend logs for ingestion errors

Risk Engine not scoring correctly

  1. Review event weights in risk-engine.ts for your platform
  2. Adjust CORRELATION_WINDOW_MS if events are too far apart
  3. Increase YELLOW_THRESHOLD if you want fewer YELLOW flags
  4. Verify contributingEvents array in /api/session/:id to see which events triggered the score

Camera not working in Layer 2

  1. Check layer2.html in extension → Browser console for [Layer 2] logs
  2. Verify camera permission granted: chrome://settings/content/camera
  3. Ensure TensorFlow.js and COCO-SSD load from CDN (check network tab)
  4. Try in incognito mode to rule out conflicting extensions

Native host not connecting (Layer 3)

  1. Verify manifest registered correctly:
    • Windows: regedit → HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts
    • macOS: ls ~/.config/google-chrome/NativeMessagingHosts/
  2. Test native host standalone: node dist/index.js → send JSON to stdin
  3. Check extension error logs for native messaging failures
  4. Rebuild and re-register if you moved the native host binary

Architecture Decisions

Why TypeScript?

  • Type safety across extension, backend, and dashboard
  • Shared types.ts ensures data contract consistency
  • Better tooling for Chrome API types (DefinitelyTyped)

Why Supabase?

  • Managed Postgres under the hood
  • Type-safe SDK access
  • Easy schema evolution and deployment

Why React for Dashboard?

  • Real-time updates via polling (could add WebSocket later)
  • Component reusability (card, timeline, badge)
  • Large ecosystem for charts/visualization if needed

Why Native Host for Layer 3?

  • Browser extensions cannot enumerate OS-level processes
  • Node.js chosen for stack consistency (could switch to Rust for smaller binary)
  • Native messaging keeps Layer 3 optional (no dependency in extension code)

Privacy & Compliance Notes

  • C1 — No code content: only metadata (paste length, not pasted text)
  • C2 — No gaze/facial analysis: only phone and person count detection
  • C3 — One snapshot per flag: no video clips
  • C4 — No auto-termination: RED flags are for human review
  • C5 — Minimal permissions: only activeTab + camera (optional)
  • C6 — Multi-layer correlation: RED requires ≥2 independent signals within 30s
  • C7 — Layer 3 opt-in: separate install, disclosed to candidate
  • C8 — No process dump: only category tags
  • C9 — Client-side inference: no raw media to backend

License

Proprietary. Built with privacy and transparency as core values.


Questions or issues? Review the spec in interview-integrity-extension-prompt-optimized.md or contact the development team.

About

amulti layered proctoring system built to ensure fairness and prevent cheating during interviews

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages