From a92d242168e13ee62126d4bd80b5134424746756 Mon Sep 17 00:00:00 2001 From: wfptn Date: Fri, 4 Sep 2026 18:54:00 +0200 Subject: [PATCH 1/2] Update readme to match current architecture and roadmap Arrays problems now go through the generic Problem/ProblemDefinition architecture with server-side test-harness assembly; output-size and concurrency limits are implemented; CI/CD runs Checkstyle, tests, and a SonarQube Cloud quality gate with automatic Pi deployment on push to master. Collections/Algorithms problems are still on the old one-off page pattern, called out explicitly as the next migration step. --- readme.md | 86 +++++++++++++++++++++++++++---------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/readme.md b/readme.md index 3a1ea9f..a51a46e 100644 --- a/readme.md +++ b/readme.md @@ -3,7 +3,7 @@ > A browser-based Java playground and programming-practice platform built with Spring Boot, Docker, PostgreSQL, Thymeleaf, and GitHub OAuth. **Status:** Early development -**Last updated:** 7 August 2026 +**Last updated:** 4 September 2026 **Live demo:** https://java.ruslanlomaka.org ## What it does @@ -24,8 +24,10 @@ Current problem sections: Current problems: -- Bubble Sort -- Longest Substring Without Repeating Characters +- Bubble Sort (Arrays) +- Two Sum (Arrays) +- Binary Search (Arrays) +- Longest Substring Without Repeating Characters (Collections) ## Tech stack @@ -40,6 +42,8 @@ Current problems: - CodeMirror - Cloudflare Tunnel - Raspberry Pi +- Checkstyle (Google Java Style) +- SonarQube Cloud ## How execution works @@ -65,52 +69,45 @@ CPU restriction Process restriction Read-only filesystem Dropped Linux capabilities +File descriptor and file size ulimits Execution timeout -Automatic cleanup +Concurrency limit (bounded number of containers running at once) +Output size cap (containers are killed if output exceeds the limit) +Automatic cleanup, plus a scheduled reaper as a safety net for orphaned + containers/directories +Docker image pinned by digest, not by a mutable tag ``` +Memory limits (`--memory`) are set on the container but are not +currently enforced on the host, so this is not yet a real resource +guarantee — see [Current limitations](#current-limitations). + This is still an experimental project and not yet fully hardened for unrestricted public code execution. ## Current architecture -The project started as a fast prototype. - -Some problem pages currently contain too many responsibilities: - -- description; -- starter code; -- tests; -- Java source generation; -- console formatting; -- page-specific JavaScript. +The project started as a fast prototype, and one part of the planned refactor is done: Arrays problems now go through a generic, data-driven path instead of one hand-written page per problem. -The next major refactoring goal is to separate problem content from rendering and execution. +- Each Arrays problem is a small Java class (e.g. `BubbleSortProblem`) implementing `ProblemDefinition`, registered in `ProblemRegistry`. +- One controller route (`/problems/{category}/{slug}`) and one Thymeleaf template (`problem.html`) render every Arrays problem. +- One shared script (`problem.js`) drives the editor and submission flow for all of them. +- The full test harness (imports, student code, hidden tests) is assembled **server-side** (`ProblemDefinition.buildTestSource`) and only the student's method body is ever sent to the browser — hidden tests are no longer visible via view-source or the Network tab for these problems. -A future problem may look like: +This has **not** happened yet for the Collections/Algorithms categories: `Longest Substring Without Repeating Characters` is still its own hand-written page, CSS file, and JS file, and it still assembles the complete test source (including hidden tests) client-side and posts it to the generic `/sandbox/run` endpoint — so the original "hidden tests aren't actually hidden" problem still applies to that one problem specifically. -```text -problems/ -└── collections/ - └── longest-unique-substring/ - ├── problem.yaml - ├── statement.md - ├── starter.java - └── tests.java -``` - -Then one generic controller and one generic template can render all problems. +Migrating the remaining problems to the same pattern used for Arrays is the next concrete step, not a redesign — the generic controller, template, and script already exist and just need to be reused. ## Roadmap ### Near term -- [ ] refactor the problem system; -- [ ] create reusable problem definitions; -- [ ] separate hidden tests from HTML; -- [ ] create a generic problem page; +- [x] create reusable problem definitions; +- [x] separate hidden tests from HTML (done for Arrays problems); +- [x] create a generic problem page; +- [x] add output-size limits; +- [x] add execution queue (concurrency limit); +- [ ] migrate the Collections/Algorithms problems onto the generic problem page; - [ ] improve error handling; -- [ ] add output-size limits; -- [ ] add execution queue and rate limiting; - [ ] improve mobile layout; - [ ] add more Java problems. @@ -126,8 +123,8 @@ Then one generic controller and one generic template can render all problems. ### Security -- [ ] restore working memory limits; -- [ ] limit concurrent runner containers; +- [x] limit concurrent runner containers; +- [ ] restore working memory limits (the `--memory` flag is set, but not currently enforced on the host running the containers); - [ ] separate the runner from the web application; - [ ] reduce Docker socket exposure; - [ ] add abuse prevention; @@ -168,8 +165,8 @@ I am ready to explain: - how submitted Java code runs in Docker; - how the Raspberry Pi deployment works; - how PostgreSQL and Docker Compose are configured; -- how CI/CD should work; -- why the current architecture needs refactoring. +- how the CI/CD pipeline and quality gates work; +- why the remaining problem pages still need migrating to the generic architecture. What I need from contributors: @@ -303,8 +300,14 @@ docker compose logs -f postgres docker compose down ``` +## CI/CD + +Every pull request against `master` runs Checkstyle, the full test suite against a real PostgreSQL service container, and a SonarQube Cloud analysis with a quality gate that blocks merging on new bugs, vulnerabilities, or security hotspots. Pushes to `master` additionally deploy automatically: GitHub Actions connects to the Raspberry Pi over Tailscale, resets it to `origin/master`, and runs `docker compose up -d --build`. There is no staging environment — a merge to `master` goes straight to the live site. + ## Manual deployment +Only needed if the automatic deployment above isn't available: + ```bash cd ~/projects/OnlineJavaSandbox git pull @@ -317,12 +320,9 @@ docker compose up -d --build - no scores; - no comments; - no user profiles; -- no execution queue; -- no strict output limit; -- no working memory limit on the current host; -- problem logic is still mixed with HTML and JavaScript; -- deployment is manual; -- CI/CD is not yet reliable. +- no working memory limit on the current host (the container flag is set but not enforced there); +- problem logic is still mixed with HTML and JavaScript for the Collections/Algorithms problems (Arrays problems are already migrated to the generic architecture, see [Current architecture](#current-architecture)); +- no database or user entities yet (still file/code-defined problems, nothing persisted). ## Author From 7cb098c9f83b6da910bb372eda9fdcc6558f0797 Mon Sep 17 00:00:00 2001 From: wfptn Date: Fri, 4 Sep 2026 18:55:23 +0200 Subject: [PATCH 2/2] Fix misnamed package-info.java files Java only recognizes the exact filename package-info.java for package-level Javadoc. problem/ and problem/arrays/ had a PackageInfo.java (wrong case/name) instead, so they silently had no real package Javadoc; the root package had both a working package-info.java and a dead PackageInfo.java duplicate. Renamed the two real ones and deleted the duplicate. --- src/main/java/com/example/onlinejava/PackageInfo.java | 6 ------ .../problem/arrays/{PackageInfo.java => package-info.java} | 2 +- .../problem/{PackageInfo.java => package-info.java} | 0 3 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 src/main/java/com/example/onlinejava/PackageInfo.java rename src/main/java/com/example/onlinejava/problem/arrays/{PackageInfo.java => package-info.java} (51%) rename src/main/java/com/example/onlinejava/problem/{PackageInfo.java => package-info.java} (100%) diff --git a/src/main/java/com/example/onlinejava/PackageInfo.java b/src/main/java/com/example/onlinejava/PackageInfo.java deleted file mode 100644 index 8692639..0000000 --- a/src/main/java/com/example/onlinejava/PackageInfo.java +++ /dev/null @@ -1,6 +0,0 @@ - -/** - * Contains the main web application components. - */ -package com.example.onlinejava; - diff --git a/src/main/java/com/example/onlinejava/problem/arrays/PackageInfo.java b/src/main/java/com/example/onlinejava/problem/arrays/package-info.java similarity index 51% rename from src/main/java/com/example/onlinejava/problem/arrays/PackageInfo.java rename to src/main/java/com/example/onlinejava/problem/arrays/package-info.java index 530fc67..140385a 100644 --- a/src/main/java/com/example/onlinejava/problem/arrays/PackageInfo.java +++ b/src/main/java/com/example/onlinejava/problem/arrays/package-info.java @@ -2,4 +2,4 @@ /** * Contains array-based coding problems. */ -package com.example.onlinejava.problem.arrays; \ No newline at end of file +package com.example.onlinejava.problem.arrays; diff --git a/src/main/java/com/example/onlinejava/problem/PackageInfo.java b/src/main/java/com/example/onlinejava/problem/package-info.java similarity index 100% rename from src/main/java/com/example/onlinejava/problem/PackageInfo.java rename to src/main/java/com/example/onlinejava/problem/package-info.java