Although I don’t know for sure, I suspect that administrators of computing infrastructure in educational establishments are wary of requests from academics for compute services that allow students to run arbitrary code.
One of the main reasons why an educator would want to support this is that becuase setting up an environment can be hard: if you want a student to focus on writing code that makes use of particular packages, you probably don’t want them engaging in arcane sys admin practices and spending all them time trying to install those packages in the first place.
For the IT department, the thought of running arbitrary code that could be produced either by novices or deliberately malicious users is likely to raise several well-founded concerns: how do we stop users using the code environment to attack the server or network the code is running on; how do we stop folk from running code on out servers that could be used to attack external sites; and how do we control the resource requirements (storage, compute, network) when mistakes happen and folk try to repeatedly download the internet to our server.
One way of making hosted compute available to students is to execute code within isolated sandboxed environments that you can park in a safe area of the network and monitor closely.
In our Moodle VLE, the Moodle CodeRunner environment is used to allow students to run small fragments of code within just such an environment when completing interactive quiz questions. (I provide a quick review of the Moodle CodeRunner plugin in post [A] Quick First Look At Moodle CodeRunner.)
Presumably, someone somewhere has done a security audit and decided that the sandboxed code execution environment is a safe one and signed off on its use.
Another approach, described in this fragment on Jupyter Notebooks and Moodle, the SageCell filter for Moodle, allows you to run code against an external (stateless) SageCell server:
<?php
/**
* SageCell filter for Moodle 3.4+
*
* This filter will replace any Sage code in [sage]...[/sage]
* with a Ajax code from http://sagecell.sagemath.org
*
* @package filter_sagecell
* @copyright 2015-2018 Eugene Modlo, Sergey Semerikov
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Automatic SageCell embedding filter class.
*
* @package filter_sagecell
* @copyright 2015-2016 Eugene Modlo, Sergey Semerikov
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class filter_sagecell extends moodle_text_filter {
/**
* Check text for Sage code in [sage]...[/sage].
*
* @param string $text
* @param array $options
* @return string
*/
public function filter($text, array $options = array()) {
if (!is_string($text) or empty($text)) {
// Non string data can not be filtered anyway.
return $text;
}
if (strpos($text, '[sage]') === false) {
// Performance shortcut - if there is no </a> tag, nothing can match.
return $text;
}
$newtext = $text; // Fullclone is slow and not needed here.
$search = '/\[sage](.+?)\[\/sage]/is';
$newtext = preg_replace_callback($search, 'filter_sagecell_callback', $newtext);
if (is_null($newtext) or $newtext === $text) {
// Error or not filtered.
return $text;
}
return $newtext;
}
}
/**
* Replace Sage code with embedded SageCell, if possible.
*
* @param array $sagecode
* @return string
*/
function filter_sagecell_callback($sagecode) {
// SageCell code from [sage]...[/sage].
$output = $sagecode[1];
$output = str_ireplace("", "\n", $output);
$output = str_ireplace("
", "\n", $output);
$output = str_ireplace("
", "\n", $output);
$output = str_ireplace("
", "\n", $output);
$output = str_ireplace("
", "\n", $output);
$output = str_ireplace(" ", "\x20", $output);
$output = str_ireplace("\xc2\xa0", "\x20", $output);
$output = clean_text($output);
$output = str_ireplace("<", "", $output);
$id = uniqid("");
$output = "" .
"" .
"sagecell.makeSagecell({inputLocation: \"#" . $id . "\"," .
"evalButtonText: \"Evaluate\"," .
"autoeval: true," .
"hide: [\"evalButton\", \"editor\", \"messages\", \"permalink\", \"language\"] }" .
");" .
"" .
"
<div id="">". $output. "</div>
";
return $output;
}
This looks to me like the SageCell Moodle filter essentially rewrites a [sage]...[/sage]
delimited code block within a Moodle environment as a Javascript backed SageCell form and then lets users run the code embedded in the form against the remote server. This sort of thing could presumably be used to support interactive, executable code activities within a Moodle hosted web page, for example.
As I remarked previously, it’s not hard to imagine doing something similar to provide a [mybinder repository="..."]...[/mybinder]
filter that could use a Javascript library such as ThebeLab or Juniper to provide a similar style of interaction backed by a MyBinder launched repository, though minor tweaks may be required around those packages to handle stateless rather than stateful transactions if repeated calls are made to the server.
Going back to the CodeRunner plugin (as described here):
[i]nternally CodeRunner is designed to support multiple sandboxes, implemented as subclasses of the abstract class qtype_coderunner_sandbox
– see sandbox.php. Sandboxes are essentially plugins to CodeRunner. Several different ones have been used over the years but the only current ones are the jobe sandbox (file jobesandbox.php) and the ideone sandbox. The latter interfaces to the Sphere On-line judge server but is now more-or-less defunct. Both of those sandboxes run as services. CodeRunner can support multiple sandboxes at the same time and questions can be configured to select a particular sandbox (if desired). By default the first available sandbox that supports the language required by the question is used.
So could we use a MyBinder launched Jupyter server to provide sandboxed code execution?
One advantage of this would be that we could define a Jupyter environment that students could use on their own machines, or that we could host via a hosted notebook server, and that same environment could be used for CodeRunner style assessment.
Another advantage would be that if we want to run student created arbitrary code for teaching activities as well as CodeRunner based assessment activities, we’d only need to sign off on one sandboxed code execution environment rather than several.
So what’s required?
It’s years since I had used PHP, but I thought I’d have a go at creating a simple Python client that would let me:
- start a MyBinder server against a specified Github repo;
- start a kernel;
- run a small code sample in the kernel and get a code execution response back.
Cribbing heavily from juniper.js and this rather handy sagecell-client.py, I came up with a hacky recipe that works a minimal proof of concept here: mybinder_py_client-ipynb.
I think this is stateful, in that we execute several code blocks one after the other and exploit state in previous calls to the same kernel. It would probably also make sense to have a call that forces a new kernel for each code execution call, as well as providing a recipe for killing a kernel.
The next step in trying to use this approach for CodeRunner sandbox would presumably be to try to create a simple PHP based MyBinder client; then the next step would be to use that in a CodeRunner sandbox subclass.
But that’s out of scope for me atm…
Please let me know in the comments if you have a go at this… or know of any other Moodle / Jupyter integrations…