Project_Demo / SECURITY.md
steveyehtw's picture
Restore HF demo execution with explicit resource-limited process mode
4415019
|
Raw History Blame Contribute Delete
3.56 kB

Security and deployment notes

Student Python execution

  • Docker installs Bubblewrap and prlimit; the app runs as the unprivileged telearn account.
  • Each public Python run gets a copied, size-limited project workspace and CPU/address-space/file/process limits. Child environments use an allowlist and do not inherit application tokens or admin credentials.
  • RUNNER_ISOLATION_MODE=sandbox (the source default) additionally requires Linux user/PID/network namespaces and read-only system mounts, and fails closed if the host blocks namespace creation.
  • At the owner's request, the Docker image explicitly sets RUNNER_ISOLATION_MODE=process to restore Python demos on Hugging Face, whose current host rejects unprivileged namespace creation. This mode runs a separate, resource-limited process as telearn, but provides no filesystem, network, or same-user process isolation. Environment filtering and temporary project copies are not a security sandbox. Set the mode back to sandbox on a compatible execution host.
  • Uvicorn caps WebSocket frames at 1 MiB. Classroom sockets also have per-IP handshake and per-student message budgets; saved checkpoints/submissions have per-hour limits, cooldowns, a per-course quota, and a rolling retention cap.

Classroom storage

Defaults are configured in Dockerfile and may be changed with CLASSROOM_* environment variables. The database retains up to 100 checkpoints and 100 submissions per student per Lesson, with a 1 GiB active-data quota per course. Older versions are removed from the active SQLite history and Hugging Face repository tree.

Deleting a file from a Hugging Face repository's current tree does not rewrite earlier Git commits. Therefore these limits bound the active version set and current tree, but cannot strictly cap the repository's historical Git object storage. A hard lifetime storage cap requires moving classroom versions to bounded object storage or periodically archiving/recreating the repository; neither is performed automatically.

Browser security

The app sends CSP, COOP/COEP, X-Content-Type-Options, Referrer Policy, Permissions Policy, and HSTS (enabled in the Docker image). CodeMirror, JSZip, and Pyodide are served same-origin from exact package versions included during image build. The pinned pygame-ce wheel and its lockfile dependency closure are also vendored same-origin, with each wheel SHA-256 checked against Pyodide's lockfile during the image build. Google Fonts, the QR service, Appetize, and MakeCode remain explicit external sources. Student HTML remains inside an opaque-origin sandbox iframe.

After deployment, inspect the final public HTTPS response headers: Hugging Face's edge proxy must preserve or add HSTS and must not replace the application CSP with a weaker policy. Local source changes cannot prove what the edge returns.

Dependency scanning and lock files

Every Docker build resolves requirements.txt in a Python 3.11 build stage, generates a complete transitive lock with hashes, audits that resolved lock using pip-audit, then installs the runtime dependencies with --require-hashes. The generated lock is included in the image as /app/requirements.lock; it is build-specific rather than checked into source, so rebuilding later may select newer versions allowed by requirements.txt. GitHub Actions also runs pip-audit on pull requests and weekly when this repo is mirrored to GitHub; the canonical remote for this project is Hugging Face, which does not execute that GitHub workflow by itself.