Skip to content

Instructor Role & Workflow ​

Purpose ​

Instructors are faculty who supervise lab sessions. The implemented instructor features are monitoring and grading: they watch live labs, follow each student's progress and SIEM alerts, examine the evidence behind a report, and approve, reject or return reviews. They do not operate infrastructure or manage accounts.

ExplainerThe instructor1:00

Pages and navigation ​

Sidebar: Dashboard, Live labs, Students, Reviews (instructorNavItems in cyberrange/portal/src/lib/navigation.ts). All /instructor/* pages require the instructor or admin role, and an instructor who opens /dashboard or /admin is sent to /instructor (redirectPathForRole() in cyberrange/portal/src/lib/routeRoles.ts).

On first sign-in an instructor sees a one-time instructor orientation at /orientation (Watch live labs, Check student progress, Decide reviews, Export results) before reaching the requested page; Continue to the instructor dashboard records it with POST /users/me/orientation (cyberrange/portal/src/app/orientation/page.tsx, pull request 188).

PageWhat it showsBackend calls
/instructor DashboardReview queue preview, live labs, students and reviews summary, Knowledge-gain export (format and scenario; always anonymized for instructors, and the page reports how many test or staff accounts were left out)GET /instructor/reviews, GET /instructor/students, GET /instructor/export/knowledge-gain
/instructor/pods Live labsEvery live lab (student, scenario, status, time left), with Refresh. Container names, connection IDs and Wazuh agent IDs are removed from this view.GET /instructor/pods
/instructor/students StudentsRoster of every student who has any lab, score or review on record: progress by scenario chips (tasks passed / total and points per scenario), total points, active pod, pending reviews and last activity. Each row expands to a per-scenario task table (status, points, detection) with a link to the full detail (pull request 220)GET /instructor/students
/instructor/students/[id] Student detailDownload of the student's milestones, reviews and live alerts as one CSV; active lab; SIEM alerts panel (live alerts for the active lab, plus Past labs with archived alerts per ended lab and a triaged view), with a milestone score strip and filters by search text, rule, agent and severity (pull request 214); check-failure reasons per scenario, milestone and lab; milestone attempt history with Source and SIEM detection columns; review historyGET /instructor/students/{id}, GET /instructor/students/{id}/diagnostics, GET /instructor/pods/{id}/alerts, GET /instructor/students/{id}/labs, GET /instructor/students/{id}/labs/{pod}/alerts
/instructor/reviews Review queueReview cases filtered by status (PENDING, APPROVED, REJECTED, RETRY, ALL)GET /instructor/reviews?status_filter=
/instructor/reviews/[id] Review detailMilestone attempt, submitted report text, reported conflict reason, student screenshots, automated verifier evidence, alerts captured with this report, previous resolution, and the Instructor Evaluation form (score 0 to 100, feedback, and ✓ Approve Submission, ✕ Reject Submission, ↺ Request Student Retry)GET /instructor/reviews/{id}, GET /reviews/{id}/images, GET /instructor/reviews/{id}/alert-snapshot, POST /instructor/reviews/{id}/resolve

Where the student list comes from

The student list is built from the platform's own records (anyone with a lab, milestone result or review in SQLite), not from Keycloak. A newly created student who has never started a lab does not appear yet (instructor_list_students in cyberrange/src/provisioning/pods_router.py).

Instructor workflow ​

Main features and actions ​

Monitoring live labs and students ​

  • Live labs: all labs that are not destroyed, for every student (GET /instructor/pods).
  • Student progress: every milestone attempt with its status, catalog points, detection score and time, so an instructor can see not only the result but how many tries it took (GET /instructor/students/{id}).
  • Where an attempt came from: since schema v15 each attempt records a source: auto (background poller), manual (Manual Check), browser (Scenario 2 DVWA), flag or review (instructor approval). Older rows show "—". Background auto results that are not a PASS are hidden by default behind Show background checks (N), because the poller writes one every few seconds (pull request 268, lib/instructorStudentProgress.ts).
  • SIEM detection label: the detection score is shown separately from points as Detected, Not detected, Not configured (no Wazuh rule is configured for that milestone, currently Scenarios 1, 2 and 4 and Scenario 3 after Task 1) or Unknown (pull request 209, cyberrange/portal/src/lib/siemDetection.ts).
  • Check-failure reasons: for scenarios switched on in SCORING_DIAGNOSTICS_SCENARIOS, the student page lists why the latest check of an unpassed milestone failed, as allowlisted reason codes with plain-language text (for example a missing artifact or a rule that does not match). Students only ever see a generic result. Rows are replaced by a PASS and purged after SCORING_DIAGNOSTICS_RETENTION_DAYS (default 14) (GET /instructor/students/{id}/diagnostics, cyberrange/src/provisioning/scoring_diagnostics.py, components/instructor/ScoringDiagnostics.tsx).
  • SIEM visibility: the same six safe alert fields students see, for any live lab, for ended labs (read from the Wazuh manager's daily archives using the recorded lab time window), and frozen with each report at submission time. A triaged view groups alerts by rule and separates alerts expected for the scenario, likely student activity, and background noise (cyberrange/src/provisioning/alerts_endpoint.py, lab_history.py, cyberrange/portal/src/lib/siemTriage.ts).

Grading reviews ​

  • Resolve a case as APPROVED, REJECTED or RETRY, with a score from 0 to 100 and feedback. The grader's username is stored in graded_by. A version check (expected_status) stops two instructors from overwriting each other's decision.
  • Approving credits the student. Approving any case tied to a milestone (a scoring conflict, a written report or a manual review, including the ones created when a student's one Manual Check fails) inserts a milestone PASS, marked instructor_approved_conflict or instructor_approved_review, and never twice for the same milestone. This PASS row is what the student's score reads. Before pull request 141 only conflict approvals did this, so approved reports never reached the student's score.
  • Changing your mind: moving an approved case to REJECTED or RETRY deletes the instructor-granted PASS again; auto-detected and flag PASS rows are never touched.
  • Scoring conflicts: when the hybrid scoring path escalates a case (flag and lab state disagree), it appears as a SCORING_CONFLICT case visible only to staff. RETRY is not allowed for this case type.
  • Lab lists show each lab's own time limit (ttl_minutes).
  • Every resolution writes a REVIEW_CASE_RESOLVED audit event.

Exporting research data ​

GET /instructor/export/knowledge-gain returns completion rates, time from lab start to first PASS, detection indicators and rubric scores as JSON or CSV. Student IDs are anonymized with a salted HMAC (TELEMETRY_ANONYMIZATION_SALT). Since pull request 272, anonymize=false (cleartext IDs) is admin only: an instructor gets 403 and the attempt is audited. Every export writes a KNOWLEDGE_GAIN_EXPORTED audit event without student IDs. CSV output is protected against spreadsheet formula injection (cyberrange/src/provisioning/knowledge_gain.py, pods_router.py).

  • Who is counted: accounts an admin marked as test accounts, and every account holding the instructor or admin role in Keycloak, are left out. The summary (and, for CSV, the X-Excluded-Accounts and X-Staff-Exclusion headers) says how many were left out and whether staff could be resolved (applied) or Keycloak was unreachable (unavailable, staff may be included). Only an admin can pass include_excluded=true (pull requests 273 and 301).
  • Time to milestone: the start of the lab is read from lab_sessions, so it stays correct after the lab slot is reused; PASS rows created by an instructor approval carry no time-to-milestone, because the approval time is the instructor's (pull request 270).
  • Each record also has a scenario_number (1 to 4, the paper's numbering) next to the internal scenario_id.

Using the student workspace ​

The lab pages (/scenarios, /scenario/[id]) are open to every application role, so an instructor can start their own lab to try a scenario; only the student /dashboard redirects them to /instructor. It is limited exactly like a student's: one lab, their own data.

Allowed and restricted routes ​

AllowedRestricted
/instructor/* pages; /scenarios and /scenario/[id] for their own lab/admin/* pages and /dashboard (redirect to /instructor)
All instructor API routes (instructor or admin)All admin API routes, and the identified or include_excluded knowledge-gain export: 403
All self-scoped routes for their own labs and reviewsAnother user's lab actions (status, terminal, destroy, lab URLs): 404
Reading any review and its screenshotsUploading or deleting screenshots on another user's review: 404

Backend permissions ​

EndpointPurpose
GET /instructor/podsAll live labs, internals stripped
GET /instructor/students, GET /instructor/students/{id}Student list and detail (detail includes each attempt's source)
GET /instructor/students/{id}/diagnosticsCheck-failure reason codes, optionally for one lab (pod_id, pod_created_at)
GET /instructor/pods/{id}/alertsLive SIEM alerts for any lab
GET /instructor/students/{id}/labs, GET /instructor/students/{id}/labs/{pod}/alerts?started_at=Lab history and archived alerts
GET /instructor/reviews/{id}/alert-snapshotAlerts frozen with a report
GET /instructor/reviews, GET /instructor/reviews/{id}, POST /instructor/reviews/{id}/resolveReview queue and decisions
GET /instructor/export/knowledge-gainResearch export (anonymized; identified and include_excluded are admin only)
GET /reviews/{id}, GET /reviews/{id}/images, GET /reviews/{id}/images/{image}Read any review and its screenshots (owner or staff)

All are guarded by require_role(["instructor", "admin"]) or the owner-or-staff check, behind the router-level require_app_role (cyberrange/src/provisioning/pods_router.py, alerts_endpoint.py).

Data an instructor can view or modify ​

DataViewModify
All live labs (without container names or agent IDs)YesNo (cannot destroy)
Every student's milestone history and detection evidenceYesOnly indirectly, by approving (or un-approving) a milestone-scoped review
All review cases, including staff-only scoring conflictsYesResolve (status, score, feedback)
Evidence screenshotsYesNo
SIEM alerts (allow-listed fields)YesNo
Check-failure reasons (allowlisted codes)YesNo
Knowledge-gain exportAnonymized onlyNo
Accounts, roles, research exclusions, system health, audit logNoNo

What instructors cannot do ​

These are not role restrictions that were forgotten; the code has no path for them:

  • Destroy or force-destroy another user's lab (owner-only destroy; force-destroy is admin-only).
  • Open a terminal into a student's lab (the bridge's ownership check refuses non-owners who are not admins).
  • Create, edit or reorder scenarios, milestones or points (Not implemented; the catalog is static).
  • Message students directly (feedback is only written on a review).
  • Manage users or roles.

Sources

cyberrange/portal/src/app/instructor/**, cyberrange/portal/src/app/orientation/page.tsx, cyberrange/portal/src/components/instructor/*, cyberrange/portal/src/lib/navigation.ts, lib/instructorStudentProgress.ts, lib/siemDetection.ts, lib/studentProgressCsv.ts, cyberrange/src/provisioning/pods_router.py (instructor and review routes), alerts_endpoint.py, lab_history.py, knowledge_gain.py, scoring_diagnostics.py, research_exclusions.py, test_sec01_rbac_matrix.py.

Cyber Range capstone documentation (Capstone 2 · Group 2 · A4102). Documents main at commit 6971373.