The code validator (Documentation Index
Fetch the complete documentation index at: https://mintlify.com/elenacarino-max/Pildora4_ext_StarWars/llms.txt
Use this file to discover all available pages before exploring further.
core/code_validator.py) is the security core of MLflow Jedi. Rather than running anything a student types, it parses Python source text into an Abstract Syntax Tree using the built-in ast module and inspects only the tree’s structure. This means every submission — from a single mlflow.set_experiment call to a full mission script — is analysed purely as data. No import side-effects, no network calls, no filesystem writes can ever originate from student input.
Security model
Two guarantees underpin every submission check:- Student code is never executed.
_parse_safe()callsast.parse(code, mode="exec")and then walks the resulting tree. The code string never reacheseval(),exec(), orcompile(). - Only whitelisted MLflow calls are accepted. Any call whose dotted name is absent from
ALLOWED_CALLScauses immediate rejection with a descriptive Spanish-language error message.
ValidationResult
Every validator function returns a singleValidationResult dataclass:
| Field | Type | Description |
|---|---|---|
valid | bool | True if the submission satisfies all checks, False otherwise |
message | str | Human-readable feedback shown to the student (written in Spanish) |
calls | list[str] | Flat list of every dotted call name found during the AST walk |
calls field is populated even on failure so the UI can highlight which calls were detected.
Allowed calls
Only the following eight MLflow tracking calls are permitted anywhere in student-submitted code. Any other call — including helpers, builtins, or third-party functions — triggers an “not authorized in this terminal” error.Forbidden constructs
The_parse_safe() function rejects submissions before any per-challenge logic runs if any of the following are detected:
| Construct | AST node type | Reason |
|---|---|---|
import statement | ast.Import | Prevents arbitrary library loading |
from ... import | ast.ImportFrom | Same as above |
lambda expression | ast.Lambda | Prevents inline callable injection |
global statement | ast.Global | Prevents global scope manipulation |
nonlocal statement | ast.Nonlocal | Prevents closure scope manipulation |
Any call not in ALLOWED_CALLS | ast.Call | Enforces the MLflow-only whitelist |
| Code longer than 12,000 characters | — | Hard size cap applied before parsing |
validate_chamber(chamber_id, code) → ValidationResult
validate_chamber checks a single-concept snippet against the learning goal of one of the six Chambers. After _parse_safe() succeeds, it verifies that the specific required call is present and, for some chambers, applies additional structural constraints.
chamber_id | Required call | Extra constraint |
|---|---|---|
experiment | mlflow.set_experiment | First positional argument must be the string literal "Biblioteca_Jedi_Digits" |
run | mlflow.start_run | The call must appear inside an ast.With block |
parameters | mlflow.log_params | None beyond presence |
metrics | mlflow.log_metrics | None beyond presence |
artifacts | mlflow.log_artifact | None beyond presence |
model | mlflow.sklearn.log_model | Must supply keyword arguments sk_model and artifact_path |
experiment chamber).
validate_mission_submission(code, mission_id) → ValidationResult
validate_mission_submission enforces the full Código Jedi 5–4–2–1 pattern: five required MLflow calls, four registered metrics, two artifact files, and one logged model — all inside a named run.
All 5 required calls present
The submission must contain every call in
{mlflow.start_run, mlflow.log_params, mlflow.log_metrics, mlflow.log_artifact, mlflow.sklearn.log_model}. Missing calls are listed in the error message.Two artifact calls
mlflow.log_artifact must appear at least 2 times in the AST. A single call fails with “La misión necesita dos artefactos de evidencia.”log_params receives parametros
The first positional argument to
mlflow.log_params must be an ast.Name node with id == "parametros".log_metrics receives metricas
The first positional argument to
mlflow.log_metrics must be an ast.Name node with id == "metricas".Correct artifact filenames
The string literals passed to the two
mlflow.log_artifact calls must be exactly "matriz_confusion.png" and "classification_report.json".log_model keyword arguments
mlflow.sklearn.log_model must supply both sk_model and artifact_path as keyword arguments.validate_question_answer(question, answer) → ValidationResult
validate_question_answer handles the didactic questions embedded in the Chamber flow. Questions carry a kind field that selects the validation path.
_parse_safe() followed by checks driven by the question’s checks dict:
checks key | Behaviour |
|---|---|
expected_calls | Every listed call name must appear in the submission |
forbidden_calls | None of the listed call names may appear |
min_call_count | expected_calls[0] must appear at least this many times |
require_with | The AST must contain at least one ast.With node |
keyword / keywords | Each listed keyword argument name must appear somewhere in the call graph |
constant | A specific literal value must appear as an ast.Constant node |
Rejection flow example
The following snippet is syntactically valid Python but is always rejected because theimport statement is a forbidden construct:
After
validate_mission_submission returns valid=True, the app calls an internal execute_safe_mission() function that trains a scikit-learn RandomForestClassifier on the digits dataset using a fixed, controlled template (MISSION_TEMPLATE from missions.py). The student’s validated code is never evaluated as Python — it serves only as a structural proof that the student understands the 5–4–2–1 tracking pattern.