Skip to content
Open
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
2 changes: 1 addition & 1 deletion backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ click-didyoumean==0.3.1
click-plugins==1.1.1
click-repl==0.3.0
colorama==0.4.6
Django==5.2.15
Django==5.2.16
django-cors-headers==4.9.0
djangorestframework==3.17.1
djangorestframework_simplejwt==5.5.1
Expand Down
1,047 changes: 380 additions & 667 deletions frontend/webcoder_ui/package-lock.json

Large diffs are not rendered by default.

19 changes: 13 additions & 6 deletions frontend/webcoder_ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"react-dom": "^18.2.0",
"react-hot-toast": "^2.6.0",
"react-i18next": "^13.0.1",
"react-router-dom": "^6.23.0",
"react-router": "^7.18.0",
"react-scripts": "5.0.1",
"react-syntax-highlighter": "^15.5.0",
"stream-http": "^3.2.0",
Expand Down Expand Up @@ -57,17 +57,24 @@
},
"overrides": {
"nth-check": "^2.1.1",
"postcss": "^8.4.31",
"postcss": ">=8.5.18 <9",
"prismjs": "^1.30.0",
"serialize-javascript": "^7.0.5",
"ws": "^7.5.11",
"underscore": "^1.13.8",
"js-yaml": "^4.2.0",
"js-yaml": ">=4.3.0 <5",
"http-proxy-middleware": "^3.0.6",
"@tootallnate/once": "^2.0.1",
"webpack-dev-server": "^5.2.5",
"webpack-dev-server": ">=5.2.6 <6",
"uuid": "^11.1.1",
"storybook": "^8.6.17"
"storybook": "^8.6.17",
"websocket-driver": ">=0.7.5 <0.8",
"fast-xml-parser": ">=5.10.1 <6",
"body-parser": ">=1.20.6 <2",
"fast-uri": ">=3.1.4 <4",
"find-my-way": ">=9.7.0 <10",
"sharp": ">=0.35.0 <0.36",
"shell-quote": ">=1.9.0 <2",
"svgo": ">=2.8.3 <3"
},
"browserslist": {
"production": [
Expand Down
2 changes: 1 addition & 1 deletion frontend/webcoder_ui/src/App.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import { BrowserRouter } from 'react-router';
import App from './App';
import { AuthProvider } from './context/AuthContext';

Expand Down
2 changes: 1 addition & 1 deletion frontend/webcoder_ui/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react'; // Ensuring React is explicitly imported
import { Routes, Route } from 'react-router-dom';
import { Routes, Route } from 'react-router';
import { Toaster } from 'react-hot-toast';
import './App.css';
// import { useAuth } from './context/AuthContext'; // No longer needed directly in App for ProtectedRoute logic
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { MemoryRouter, Routes, Route } from 'react-router-dom';
import { MemoryRouter, Routes, Route } from 'react-router';
import ProtectedRoute from './ProtectedRoute';
import { AuthProvider } from '../../context/AuthContext';
import { seedAuthUser, makeUser } from '../../test-utils';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Navigate, useLocation } from 'react-router-dom';
import { Navigate, useLocation } from 'react-router';
import { useAuth } from '../../context/AuthContext';

export interface ProtectedRouteProps {
Expand Down
4 changes: 2 additions & 2 deletions frontend/webcoder_ui/src/components/layout/Navbar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { renderWithProviders, seedAuthUser, makeUser } from '../../test-utils';
import i18n from '../../i18n';

const mockNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
jest.mock('react-router', () => ({
...jest.requireActual('react-router'),
useNavigate: () => mockNavigate,
}));

Expand Down
2 changes: 1 addition & 1 deletion frontend/webcoder_ui/src/components/layout/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Link, NavLink, useNavigate } from 'react-router-dom'; // Import NavLink
import { Link, NavLink, useNavigate } from 'react-router'; // Import NavLink
import { useTranslation } from 'react-i18next';
import { useAuth } from '../../context/AuthContext';

Expand Down
2 changes: 1 addition & 1 deletion frontend/webcoder_ui/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import './i18n'; // Import the i18n configuration
import { BrowserRouter } from 'react-router-dom';
import { BrowserRouter } from 'react-router';
import { AuthProvider } from './context/AuthContext'; // Import AuthProvider

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
Expand Down
2 changes: 1 addition & 1 deletion frontend/webcoder_ui/src/pages/HomePage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Container, Typography, Button, Box } from '@mui/material';
import { Link as RouterLink } from 'react-router-dom';
import { Link as RouterLink } from 'react-router';
import { useAuth } from '../context/AuthContext';

const HomePage: React.FC = () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, useEffect, useCallback } from 'react';
import { Link } from 'react-router-dom';
import { Link } from 'react-router';
import { useTranslation } from 'react-i18next';
import { ProblemService } from '../../services/ApiService';
import { useAuth } from '../../context/AuthContext';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { renderWithProviders } from '../../test-utils';
import { AuthService } from '../../services/ApiService';

const mockNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
jest.mock('react-router', () => ({
...jest.requireActual('react-router'),
useNavigate: () => mockNavigate,
}));
jest.mock('../../services/ApiService', () => ({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, FormEvent, useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { useLocation, useNavigate } from 'react-router';
import { useTranslation } from 'react-i18next';
import { AuthService } from '../../services/ApiService';
import { useAuth } from '../../context/AuthContext';
Expand Down
4 changes: 2 additions & 2 deletions frontend/webcoder_ui/src/pages/auth/LoginPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { renderWithProviders } from '../../test-utils';
import { AuthService } from '../../services/ApiService';

const mockNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
jest.mock('react-router', () => ({
...jest.requireActual('react-router'),
useNavigate: () => mockNavigate,
}));
jest.mock('../../services/ApiService', () => ({
Expand Down
2 changes: 1 addition & 1 deletion frontend/webcoder_ui/src/pages/auth/LoginPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, FormEvent } from 'react';
import { useNavigate, Link as RouterLink } from 'react-router-dom';
import { useNavigate, Link as RouterLink } from 'react-router';
import { useTranslation } from 'react-i18next';
import { AuthService } from '../../services/ApiService';
import { useAuth } from '../../context/AuthContext';
Expand Down
4 changes: 2 additions & 2 deletions frontend/webcoder_ui/src/pages/auth/RegisterPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { renderWithProviders } from '../../test-utils';
import { AuthService } from '../../services/ApiService';

const mockNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
jest.mock('react-router', () => ({
...jest.requireActual('react-router'),
useNavigate: () => mockNavigate,
}));
jest.mock('../../services/ApiService', () => ({
Expand Down
2 changes: 1 addition & 1 deletion frontend/webcoder_ui/src/pages/auth/RegisterPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, FormEvent } from 'react';
import { useNavigate, Link as RouterLink } from 'react-router-dom';
import { useNavigate, Link as RouterLink } from 'react-router';
import { useTranslation } from 'react-i18next';
import { AuthService } from '../../services/ApiService';
import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { Link } from 'react-router';
import { useTranslation } from 'react-i18next';
import toast from 'react-hot-toast';
import { ProblemService } from '../../services/ApiService';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React from 'react';
import { screen, waitFor, fireEvent } from '@testing-library/react';
import { useParams } from 'react-router-dom';
import { useParams } from 'react-router';
import ProblemDetailPage from './ProblemDetailPage';
import { renderWithProviders, seedAuthUser, makeUser } from '../../test-utils';
import { ProblemService, SubmissionService } from '../../services/ApiService';

jest.mock('react-router-dom', () => {
const actual = jest.requireActual('react-router-dom');
jest.mock('react-router', () => {
const actual = jest.requireActual('react-router');
return { ...actual, useParams: jest.fn() };
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, FormEvent, useEffect } from 'react';
import { Link, useParams } from 'react-router-dom';
import { Link, useParams } from 'react-router';
import { useTranslation } from 'react-i18next';
import { ProblemService, SubmissionService } from '../../services/ApiService';
import { useAuth } from '../../context/AuthContext';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React from 'react';
import { screen, waitFor, fireEvent } from '@testing-library/react';
import { useParams, useNavigate } from 'react-router-dom';
import { useParams, useNavigate } from 'react-router';
import ProblemFormPage from './ProblemFormPage';
import { renderWithProviders, seedAuthUser, makeUser } from '../../test-utils';
import { ProblemService, TestCaseService } from '../../services/ApiService';
import * as authModule from '../../context/AuthContext';

jest.mock('react-router-dom', () => {
const actual = jest.requireActual('react-router-dom');
jest.mock('react-router', () => {
const actual = jest.requireActual('react-router');
return { ...actual, useParams: jest.fn(), useNavigate: jest.fn() };
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, FormEvent, useEffect } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router';
import { useTranslation } from 'react-i18next';
import { ProblemService, TestCaseService } from '../../services/ApiService';
import { useAuth } from '../../context/AuthContext';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import { Link } from 'react-router';
import { useTranslation } from 'react-i18next';
import { ProblemService } from '../../services/ApiService';
import { ProblemType } from '../../types';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, useEffect, useMemo } from 'react';
import { Link } from 'react-router-dom';
import { Link } from 'react-router';
import { useTranslation } from 'react-i18next';
import { ProblemService, SubmissionService } from '../../services/ApiService';
import { useAuth } from '../../context/AuthContext';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { renderWithProviders, seedAuthUser, makeUser } from '../../test-utils';
import { SubmissionService } from '../../services/ApiService';

let mockParams: { submissionId?: string } = { submissionId: '7' };
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
jest.mock('react-router', () => ({
...jest.requireActual('react-router'),
useParams: () => mockParams,
}));
jest.mock('../../services/ApiService', () => ({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { Link, useParams } from 'react-router-dom';
import { Link, useParams } from 'react-router';
import { useTranslation } from 'react-i18next';
import { SubmissionService } from '../../services/ApiService';
import { useAuth } from '../../context/AuthContext';
Expand Down
4 changes: 2 additions & 2 deletions frontend/webcoder_ui/src/pages/user/UserProfilePage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { renderWithProviders, seedAuthUser, makeUser } from '../../test-utils';
import { AuthService } from '../../services/ApiService';

let mockParams: { userId?: string } = {};
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
jest.mock('react-router', () => ({
...jest.requireActual('react-router'),
useParams: () => mockParams,
}));
jest.mock('../../services/ApiService', () => ({
Expand Down
2 changes: 1 addition & 1 deletion frontend/webcoder_ui/src/pages/user/UserProfilePage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, FormEvent, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { useParams } from 'react-router';
import { useTranslation } from 'react-i18next';
import { AuthService } from '../../services/ApiService';
import { useAuth } from '../../context/AuthContext';
Expand Down
13 changes: 13 additions & 0 deletions frontend/webcoder_ui/src/setupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,18 @@
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import { TextDecoder, TextEncoder } from 'util';

// react-router v7 constructs a `new TextEncoder()` at module scope (its bundled
// server-runtime crypto helper), but the jsdom environment shipped with
// react-scripts 5 / jest 27 does not expose TextEncoder or TextDecoder as
// globals, so importing react-router in a test throws
// "ReferenceError: TextEncoder is not defined". Assign them from Node's `util`
// before any test module is loaded.
//
// Deliberately unconditional: a `if (!global.TextEncoder)` guard would add an
// uncovered branch and this project enforces a 100% branch-coverage threshold.
Object.assign(globalThis, { TextEncoder, TextDecoder });

import '@testing-library/jest-dom';
import './i18n';
2 changes: 1 addition & 1 deletion frontend/webcoder_ui/src/test-utils.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { ReactElement, ReactNode } from 'react';
import { render, RenderOptions } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { MemoryRouter } from 'react-router';
import { AuthProvider } from './context/AuthContext';
import { User } from './types';

Expand Down
66 changes: 66 additions & 0 deletions osv-scanner.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@
# to its patched version (backend/requirements.txt pins + frontend npm
# overrides), taking the tree from 188 known vulns to a single genuinely
# unfixable transitive entry, recorded below.
#
# 2026-07-25: dependency modernization pass #2. Took the tree from 25 known
# vulns (1 Critical) to 0 actionable, by bumping Django 5.2.15 -> 5.2.16 and
# adding/raising bounded-floor npm overrides (websocket-driver, fast-xml-parser,
# body-parser, brace-expansion, fast-uri, find-my-way, sharp, shell-quote, svgo,
# js-yaml, postcss, webpack-dev-server) plus react-router-dom 6.30.4 -> 7.18.x.
# One residual react-router advisory is genuinely unfixable on React 18 and is
# recorded below with a reachability argument.

[[IgnoredVulns]]
id = "GHSA-848j-6mx2-7j84"
Expand All @@ -31,3 +39,61 @@ id = "GHSA-848j-6mx2-7j84"
# CRA webpack build; it is not used for any first-party signing/key-exchange in
# this product. Re-review when elliptic publishes a release > 6.6.1.
reason = "No fix available (6.6.1 is latest published); transitive via crypto-browserify polyfill, not first-party crypto. Reviewed 2026-06-20."

[[IgnoredVulns]]
id = "GHSA-qwww-vcr4-c8h2"
# react-router "RSC Mode CSRF Bypass Allows Action Execution Before 400 Response"
# (follow-up to CVE-2026-22030). Affected range is react-router >= 7.12.0 < 8.3.0.
#
# NOT REACHABLE IN THIS PRODUCT: the advisory text states verbatim "This only
# affects your application if you are using the unstable RSC APIs". webcoder_ui
# is a Create-React-App client-side SPA: it mounts <BrowserRouter> + <Routes> in
# src/index.tsx and uses only the declarative API (Link, NavLink, Navigate,
# useNavigate, useParams, useLocation). Verified 2026-07-25 that src/ contains no
# match for rsc / matchRSCServerRequest / createStaticHandler / StaticRouter /
# renderToString / renderToPipeableStream / unstable_ / createBrowserRouter /
# RouterProvider, and no route loader: or action: — so there is no RSC code path,
# no SSR, and no data-router server action to bypass CSRF on.
#
# NO FIX AVAILABLE ON REACT 18: the fix lands in react-router 8.3.0, whose
# peerDependencies require react >= 19.2.7 and react-dom >= 19.2.7 (verified
# 2026-07-25 via `npm view react-router@8.3.0 peerDependencies`); this app is on
# react/react-dom 18.3.1 under react-scripts 5.0.1. react-router-dom has no 8.x
# release at all (`npm view react-router-dom@8` -> E404). The union of the four
# open react-router advisories covers >= 6.0.0 < 8.3.0, so on React 18 there is
# no clean version: staying on 7.18.x is the minimum-vulnerability choice and it
# clears GHSA-337j-9hxr-rhxg, GHSA-wrjc-x8rr-h8h6 and GHSA-jjmj-jmhj-qwj2 (the
# last of which has no fix anywhere in the react-router-dom 6.x line).
#
# Re-review when this app migrates to React 19, at which point react-router
# should go to >= 8.3.0 and this entry must be deleted.
reason = "Unstable-RSC-only code path, not used by this CRA client-side SPA (no RSC/SSR/data-router in src/); fix requires react-router 8.3.0 which peer-requires React >= 19.2.7 while this app is on React 18.3.1. Reviewed 2026-07-25."

[[IgnoredVulns]]
id = "GHSA-mh99-v99m-4gvg"
# brace-expansion "DoS via unbounded expansion length causing an out-of-memory
# process crash". The advisory has a SINGLE affected range: introduced 0, fixed
# 5.0.8 (verified 2026-07-25 against api.osv.dev) -- i.e. there is NO patched
# release anywhere in the 1.x, 2.x, 3.x or 4.x lines. The tree carries 1.1.16
# (under minimatch 3.x) and 2.1.2 (under @wdio/config, filelist, sucrase); both
# are already the highest release in their line and both carry the fix for the
# other brace-expansion advisory, GHSA-3jxr-9vmj-r5cp.
#
# NO NON-BREAKING UPGRADE (measured, not assumed): brace-expansion 5.0.8
# restructured its package to an exports map with main "./dist/commonjs/index.js"
# and no longer provides a callable default export. Forcing the tree to
# ">=5.0.8 <6" via an override was attempted on 2026-07-25 and broke the
# production build outright -- `react-scripts build` failed with
# "[eslint] expand is not a function", because minimatch 3.x does
# `require("brace-expansion")` and calls the result. That is a hard build break,
# so per this file's policy there is no safe fix available.
#
# LIMITED REACHABILITY: brace-expansion is reached only through minimatch inside
# BUILD- and TEST-time tooling (eslint, jest, glob, filelist, sucrase, @wdio).
# The glob patterns it expands come from this repository's own config, not from
# user input, and it is not part of the shipped browser bundle. The impact is a
# crash of a developer/CI process on a hostile pattern nobody supplies.
#
# Re-review when a fix is backported to the 1.x/2.x lines, or when the toolchain
# moves off minimatch 3.x (at which point ">=5.0.8 <6" becomes viable).
reason = "No fix below 5.0.8 in any line (advisory range is introduced 0 -> fixed 5.0.8); forcing >=5.0.8 breaks the build (measured: [eslint] expand is not a function, minimatch 3.x requires a callable default). Build/test-time glob tooling only, repo-authored patterns, not in the shipped bundle. Reviewed 2026-07-25."
Loading