I found two trust levels sharing one environment
While learning an inherited autograding workflow, I noticed that submitted notebooks ran in the same environment as hidden tests and a token used to publish grades to Canvas.
That meant student-controlled code could reach files and credentials that only the trusted grader should have seen. I confirmed the boundary problem with a controlled test that exposed a harmless marker, then focused on changing the execution model rather than hiding individual files.
I separated evaluation from publication
I redesigned the grader around two Unix users and two Python processes. The trusted parent owned the tests, calculated the final score, and published it. A dedicated unprivileged worker ran each notebook cell and returned only its output through a small JSON protocol.
The worker received an allowlisted environment and access only to the files needed for the assignment. Credentials, hidden tests, trusted scripts, and the final result stayed owned by the parent. If submitted code crashed or timed out, the worker could be replaced without taking the grader down with it.
The secure path still had to grade correctly
Security was only half of the result. Existing notebooks still needed to receive the same scores, and the trusted process still needed to publish them successfully.
I tested both sides of that boundary: legitimate submissions behaved as before, while the student process could no longer read protected files, inherit deployment secrets, rewrite its inputs, or impersonate the control protocol.
The idea I carried forward was simple: when a system runs untrusted code and then performs a privileged action, those jobs should not happen inside the same process or identity. The evaluator can report what happened; the trusted side decides what that result is allowed to change.