You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
|`s3_files.py`| Downloads `params["answer_files"]`/`params["response_files"]` objects into the per-request working directory |
15
14
|`dev.py`| CLI wrapper for local manual testing |
16
15
17
16
### Evaluation pipeline (`evaluation.py`)
18
17
19
18
1. Run AST security check on student code
20
-
2. Gather file specs from params via `_collect_file_specs`: `params["answer_files"]` (teacher, plus legacy `params["files"]`) and `params["response_files"]` (student); teacher files win on a name clash. The response and answer are plain code strings. If any files are listed, download the listed objects once into a per-request working directory (see `s3_files.py`), used as the subprocess `cwd` for every run in this request
21
-
3. Dispatch by `params["mode"]` (required):
19
+
2. Dispatch by `params["mode"]` (required):
22
20
-**`demo`**: execute code with no stdin; return stdout/plots as `output` feedback (no pass/fail)
23
21
-**`io_test`**: for each test in `params["tests"]`, execute with `test["input"]` as stdin and compare stdout against `test["expected_output"]`; upload matplotlib plots on pass or fail
4. Upload any captured matplotlib figures via `lf_toolkit``upload_image` (`_UPLOAD_FOLDER = "evaluatePython"`); backend is GCS or S3 per `IMAGE_UPLOAD_BACKEND`
26
-
5. Return a `Result` with feedback tags: `pass`, `fail`, `hidden_fail`, `error`, `output`, `summary`
23
+
3. Upload any captured matplotlib figures via `lf_toolkit``upload_image` (`_UPLOAD_FOLDER = "evaluatePython"`); backend is GCS or S3 per `IMAGE_UPLOAD_BACKEND`
24
+
4. Return a `Result` with feedback tags: `pass`, `fail`, `hidden_fail`, `error`, `output`, `summary`
27
25
28
26
### Request shape
29
27
@@ -92,41 +90,16 @@ All source lives in `evaluation_function/`:
92
90
"pep8_feedback": ["E225", "E231"], # custom rule list
93
91
"tests": [...]
94
92
}
95
-
96
-
# answer_files / response_files — optional, work with all modes
97
-
# answer_files: the teacher's files, saved in the response area's gradeParams.
98
-
# response_files: the student's uploads, sent with each check as additionalParams.
99
-
# params["files"] is still accepted as a legacy alias for answer_files.
100
-
# All listed files are downloaded into one per-request working directory
101
-
# (the subprocess's cwd) before student code runs, given a pre-signed or
102
-
# public HTTPS URL per file (fetched directly with a GET — no AWS
103
-
# credentials needed here). On a name clash the teacher's file wins. Entries
104
-
# may be dicts or JSON strings of dicts. Data files can be read with
105
-
# open()/pandas.read_csv()/etc.; .py files are importable since they're
106
-
# co-located with the generated script. The same files are also available
107
-
# to the answer code when use_answer_as_expected_output/use_answer_as_test_code is set.
-**Dunder attribute access**: any `__attr__` style attribute
127
102
128
-
`open`/`pathlib` are intentionally **not** blocked here — they're needed to read files loaded via `params["answer_files"]`/`params["response_files"]` (see above). **Important caveat**: `preview_function` (this check) and `evaluation_function` (actual grading) are registered as two independent RPC methods in `main.py`; `evaluation.py` never calls `preview.py`. This check only powers editor-time linting feedback — it does not gate what code can do at grading time. The real, load-bearing control for file access is a runtime-injected restricted `open`/`io.open` in `evaluation.py`'s subprocess preamble (`_safe_open`), which blocks *write* access to anything inside the per-run files directory. It is not a hard sandbox boundary — since `os`/`subprocess` remain fully importable and runnable at grading time regardless of this feature, a student can bypass file restrictions entirely via `os`. Treat this as scoping the intended file-access path, not as isolation.
129
-
130
103
## Key commands
131
104
132
105
```bash
@@ -180,7 +153,7 @@ CI runs on Python 3.12 and uploads JUnit XML results (`.github/workflows/test-li
180
153
|`LOG_LEVEL`|`debug`| Logging verbosity |
181
154
|`IMAGE_UPLOAD_BACKEND`|`gcs`| Plot upload backend in lf_toolkit (`gcs` set in Dockerfile; override to `s3` on the service to use AWS) |
182
155
|`GCS_BUCKET`| Runtime env | Target bucket for matplotlib plot uploads; set per-environment on the Cloud Run service. Auth is via the runtime service account (ADC) — no keys |
183
-
|`AWS_*` / `S3_BUCKET_URI`| Runtime env | Only for the legacy S3 plot-upload backend (`IMAGE_UPLOAD_BACKEND=s3`). Not needed for `answer_files` / `response_files` downloads — those are plain HTTPS GETs from a pre-signed/public URL|
156
+
|`AWS_*` / `S3_BUCKET_URI`| Runtime env | Only for the legacy S3 plot-upload backend (`IMAGE_UPLOAD_BACKEND=s3`) |
184
157
|`SANDBOX_ENABLED`|`true`| Wrap the worker in shimmy's nsjail sandbox (needs `--privileged` at run time) |
0 commit comments