예제 #1
0
 def test_python_lib(self):
     pylib = os.path.dirname(__file__) + "/test_files/pylib"
     g = {}
     safe_exec(
         "import constant; a = constant.THE_CONST",
         g, python_path=[pylib]
     )
예제 #2
0
 def test_python_lib(self):
     pylib = os.path.dirname(__file__) + "/test_files/pylib"
     g = {}
     safe_exec(
         "import constant; a = constant.THE_CONST",
         g, python_path=[pylib]
     )
예제 #3
0
 def test_unicode_submission(self):
     # Check that using non-ASCII unicode does not raise an encoding error.
     # Try several non-ASCII unicode characters
     for code in [129, 500, 2**8 - 1, 2**16 - 1]:
         code_with_unichr = unicode("# ") + unichr(code)
         try:
             safe_exec(code_with_unichr, {}, cache=DictCache({}))
         except UnicodeEncodeError:
             self.fail("Tried executing code with non-ASCII unicode: {0}".format(code))
예제 #4
0
 def test_unicode_submission(self):
     # Check that using non-ASCII unicode does not raise an encoding error.
     # Try several non-ASCII unicode characters.
     for code in [129, 500, 2 ** 8 - 1, 2 ** 16 - 1]:
         code_with_unichr = six.text_type("# ") + unichr(code)
         try:
             safe_exec(code_with_unichr, {}, cache=DictCache({}))
         except UnicodeEncodeError:
             self.fail("Tried executing code with non-ASCII unicode: {0}".format(code))
예제 #5
0
    def test_cache_large_code_chunk(self):
        # Caching used to die on memcache with more than 250 bytes of code.
        # Check that it doesn't any more.
        code = "a = 0\n" + ("a += 1\n" * 12345)

        g = {}
        cache = {}
        safe_exec(code, g, cache=DictCache(cache))
        self.assertEqual(g['a'], 12345)
예제 #6
0
 def test_can_do_something_forbidden_if_run_unsafely(self):
     '''
     Demonstrates that running unsafe code outside the code jail
     can cause issues directly in the calling process.
     '''
     g = {}
     with pytest.raises(SystemExit) as cm:
         safe_exec('import sys; sys.exit(1)', g, unsafely=True)
     assert "SystemExit" in text_type(cm)
예제 #7
0
    def test_cache_large_code_chunk(self):
        # Caching used to die on memcache with more than 250 bytes of code.
        # Check that it doesn't any more.
        code = "a = 0\n" + ("a += 1\n" * 12345)

        g = {}
        cache = {}
        safe_exec(code, g, cache=DictCache(cache))
        self.assertEqual(g['a'], 12345)
예제 #8
0
    def test_cant_do_something_forbidden(self):
        # Can't test for forbiddenness if CodeJail isn't configured for python.
        if not is_configured("python"):
            pytest.skip()

        g = {}
        with self.assertRaises(SafeExecException) as cm:
            safe_exec("import os; files = os.listdir('/')", g)
        assert "OSError" in text_type(cm.exception)
        assert "Permission denied" in text_type(cm.exception)
예제 #9
0
    def test_cant_do_something_forbidden(self):
        # Can't test for forbiddenness if CodeJail isn't configured for python.
        if not is_configured("python"):
            raise SkipTest

        g = {}
        with self.assertRaises(SafeExecException) as cm:
            safe_exec("import os; files = os.listdir('/')", g)
        self.assertIn("OSError", cm.exception.message)
        self.assertIn("Permission denied", cm.exception.message)
예제 #10
0
    def test_cant_do_something_forbidden(self):
        # Can't test for forbiddenness if CodeJail isn't configured for python.
        if not is_configured("python"):
            raise SkipTest

        g = {}
        with self.assertRaises(SafeExecException) as cm:
            safe_exec("import os; files = os.listdir('/')", g)
        self.assertIn("OSError", cm.exception.message)
        self.assertIn("Permission denied", cm.exception.message)
예제 #11
0
    def test_cant_do_something_forbidden(self):
        # Can't test for forbiddenness if CodeJail isn't configured for python.
        if not is_configured("python"):
            pytest.skip()

        g = {}
        with self.assertRaises(SafeExecException) as cm:
            safe_exec("import os; files = os.listdir('/')", g)
        assert "OSError" in text_type(cm.exception)
        assert "Permission denied" in text_type(cm.exception)
예제 #12
0
    def _extract_context(self, tree):
        """
        Extract content of <script>...</script> from the problem.xml file, and exec it in the
        context of this problem.  Provides ability to randomize problems, and also set
        variables for problem answer checking.

        Problem XML goes to Python execution context. Runs everything in script tags.
        """
        context = {}
        context['seed'] = self.seed
        context['anonymous_student_id'] = self.capa_system.anonymous_student_id
        all_code = ''

        python_path = []

        for script in tree.findall('.//script'):

            stype = script.get('type')
            if stype:
                if 'javascript' in stype:
                    continue  # skip javascript
                if 'perl' in stype:
                    continue  # skip perl
            # TODO: evaluate only python

            for d in self._extract_system_path(script):
                if d not in python_path and os.path.exists(d):
                    python_path.append(d)

            XMLESC = {"&apos;": "'", "&quot;": '"'}
            code = unescape(script.text, XMLESC)
            all_code += code

        if all_code:
            try:
                safe_exec(
                    all_code,
                    context,
                    random_seed=self.seed,
                    python_path=python_path,
                    cache=self.capa_system.cache,
                    slug=self.problem_id,
                    unsafely=self.capa_system.can_execute_unsafe_code(),
                )
            except Exception as err:
                log.exception("Error while execing script code: " + all_code)
                msg = "Error while executing script code: %s" % str(
                    err).replace('<', '&lt;')
                raise responsetypes.LoncapaProblemError(msg)

        # Store code source in context, along with the Python path needed to run it correctly.
        context['script_code'] = all_code
        context['python_path'] = python_path
        return context
예제 #13
0
    def test_random_is_still_importable(self):
        g = {}
        r = random.Random(17)
        rnums = [r.randint(0, 999) for _ in xrange(100)]

        # With a seed, the results are predictable even from the random module
        safe_exec(
            "import random\n"
            "rnums = [random.randint(0, 999) for _ in xrange(100)]\n",
            g, random_seed=17)
        self.assertEqual(g['rnums'], rnums)
예제 #14
0
    def test_random_is_still_importable(self):
        g = {}
        r = random.Random(17)
        rnums = [r.randint(0, 999) for _ in range(100)]

        # With a seed, the results are predictable even from the random module
        safe_exec(
            "import random\n"
            "rnums = [random.randint(0, 999) for _ in xrange(100)]\n",
            g, random_seed=17)
        self.assertEqual(g['rnums'], rnums)
예제 #15
0
    def test_random_seeding(self):
        g = {}
        r = random.Random(17)
        rnums = [r.randint(0, 999) for _ in xrange(100)]

        # Without a seed, the results are unpredictable
        safe_exec("rnums = [random.randint(0, 999) for _ in xrange(100)]", g)
        self.assertNotEqual(g['rnums'], rnums)

        # With a seed, the results are predictable
        safe_exec("rnums = [random.randint(0, 999) for _ in xrange(100)]", g, random_seed=17)
        self.assertEqual(g['rnums'], rnums)
예제 #16
0
    def test_random_seeding(self):
        g = {}
        r = random.Random(17)
        rnums = [r.randint(0, 999) for _ in range(100)]

        # Without a seed, the results are unpredictable
        safe_exec("rnums = [random.randint(0, 999) for _ in xrange(100)]", g)
        self.assertNotEqual(g['rnums'], rnums)

        # With a seed, the results are predictable
        safe_exec("rnums = [random.randint(0, 999) for _ in xrange(100)]", g, random_seed=17)
        self.assertEqual(g['rnums'], rnums)
예제 #17
0
    def _extract_context(self, tree):
        """
        Extract content of <script>...</script> from the problem.xml file, and exec it in the
        context of this problem.  Provides ability to randomize problems, and also set
        variables for problem answer checking.

        Problem XML goes to Python execution context. Runs everything in script tags.
        """
        context = {}
        context['seed'] = self.seed
        context['anonymous_student_id'] = self.capa_system.anonymous_student_id
        all_code = ''

        python_path = []

        for script in tree.findall('.//script'):

            stype = script.get('type')
            if stype:
                if 'javascript' in stype:
                    continue    # skip javascript
                if 'perl' in stype:
                    continue        # skip perl
            # TODO: evaluate only python

            for d in self._extract_system_path(script):
                if d not in python_path and os.path.exists(d):
                    python_path.append(d)

            XMLESC = {"&apos;": "'", "&quot;": '"'}
            code = unescape(script.text, XMLESC)
            all_code += code

        if all_code:
            try:
                safe_exec(
                    all_code,
                    context,
                    random_seed=self.seed,
                    python_path=python_path,
                    cache=self.capa_system.cache,
                    slug=self.problem_id,
                    unsafely=self.capa_system.can_execute_unsafe_code(),
                )
            except Exception as err:
                log.exception("Error while execing script code: " + all_code)
                msg = "Error while executing script code: %s" % str(err).replace('<', '&lt;')
                raise responsetypes.LoncapaProblemError(msg)

        # Store code source in context, along with the Python path needed to run it correctly.
        context['script_code'] = all_code
        context['python_path'] = python_path
        return context
예제 #18
0
    def test_cant_do_something_forbidden(self):
        '''
        Demonstrates that running unsafe code inside the code jail
        throws SafeExecException, protecting the calling process.
        '''
        # Can't test for forbiddenness if CodeJail isn't configured for python.
        if not jail_code.is_configured("python"):
            pytest.skip()

        g = {}
        with pytest.raises(SafeExecException) as cm:
            safe_exec('import sys; sys.exit(1)', g)
        assert "SystemExit" not in text_type(cm)
        assert "Couldn't execute jailed code" in text_type(cm)
예제 #19
0
    def test_cache_miss_then_hit(self):
        g = {}
        cache = {}

        # Cache miss
        safe_exec("a = int(math.pi)", g, cache=DictCache(cache))
        self.assertEqual(g['a'], 3)
        # A result has been cached
        self.assertEqual(cache.values()[0], (None, {'a': 3}))

        # Fiddle with the cache, then try it again.
        cache[cache.keys()[0]] = (None, {'a': 17})

        g = {}
        safe_exec("a = int(math.pi)", g, cache=DictCache(cache))
        self.assertEqual(g['a'], 17)
예제 #20
0
    def test_cache_miss_then_hit(self):
        g = {}
        cache = {}

        # Cache miss
        safe_exec("a = int(math.pi)", g, cache=DictCache(cache))
        self.assertEqual(g['a'], 3)
        # A result has been cached
        self.assertEqual(cache.values()[0], (None, {'a': 3}))

        # Fiddle with the cache, then try it again.
        cache[cache.keys()[0]] = (None, {'a': 17})

        g = {}
        safe_exec("a = int(math.pi)", g, cache=DictCache(cache))
        self.assertEqual(g['a'], 17)
예제 #21
0
    def test_cache_miss_then_hit(self):
        g = {}
        cache = {}

        # Cache miss
        safe_exec("a = int(math.pi)", g, cache=DictCache(cache))
        assert g['a'] == 3
        # A result has been cached
        assert list(cache.values())[0] == (None, {'a': 3})

        # Fiddle with the cache, then try it again.
        cache[list(cache.keys())[0]] = (None, {'a': 17})

        g = {}
        safe_exec("a = int(math.pi)", g, cache=DictCache(cache))
        assert g['a'] == 17
예제 #22
0
    def test_cache_exceptions(self):
        # Used to be that running code that raised an exception didn't cache
        # the result.  Check that now it does.
        code = "1/0"
        g = {}
        cache = {}
        with self.assertRaises(SafeExecException):
            safe_exec(code, g, cache=DictCache(cache))

        # The exception should be in the cache now.
        self.assertEqual(len(cache), 1)
        cache_exc_msg, cache_globals = cache.values()[0]
        self.assertIn("ZeroDivisionError", cache_exc_msg)

        # Change the value stored in the cache, the result should change.
        cache[cache.keys()[0]] = ("Hey there!", {})

        with self.assertRaises(SafeExecException):
            safe_exec(code, g, cache=DictCache(cache))

        self.assertEqual(len(cache), 1)
        cache_exc_msg, cache_globals = cache.values()[0]
        self.assertEqual("Hey there!", cache_exc_msg)

        # Change it again, now no exception!
        cache[cache.keys()[0]] = (None, {'a': 17})
        safe_exec(code, g, cache=DictCache(cache))
        self.assertEqual(g['a'], 17)
예제 #23
0
    def test_cache_exceptions(self):
        # Used to be that running code that raised an exception didn't cache
        # the result.  Check that now it does.
        code = "1/0"
        g = {}
        cache = {}
        with self.assertRaises(SafeExecException):
            safe_exec(code, g, cache=DictCache(cache))

        # The exception should be in the cache now.
        self.assertEqual(len(cache), 1)
        cache_exc_msg, cache_globals = cache.values()[0]
        self.assertIn("ZeroDivisionError", cache_exc_msg)

        # Change the value stored in the cache, the result should change.
        cache[cache.keys()[0]] = ("Hey there!", {})

        with self.assertRaises(SafeExecException):
            safe_exec(code, g, cache=DictCache(cache))

        self.assertEqual(len(cache), 1)
        cache_exc_msg, cache_globals = cache.values()[0]
        self.assertEqual("Hey there!", cache_exc_msg)

        # Change it again, now no exception!
        cache[cache.keys()[0]] = (None, {'a': 17})
        safe_exec(code, g, cache=DictCache(cache))
        self.assertEqual(g['a'], 17)
예제 #24
0
    def test_cache_exceptions(self):
        # Used to be that running code that raised an exception didn't cache
        # the result.  Check that now it does.
        code = "1/0"
        g = {}
        cache = {}
        with pytest.raises(SafeExecException):
            safe_exec(code, g, cache=DictCache(cache))

        # The exception should be in the cache now.
        assert len(cache) == 1
        cache_exc_msg, cache_globals = list(cache.values())[0]  # lint-amnesty, pylint: disable=unused-variable
        assert 'ZeroDivisionError' in cache_exc_msg

        # Change the value stored in the cache, the result should change.
        cache[list(cache.keys())[0]] = ("Hey there!", {})

        with pytest.raises(SafeExecException):
            safe_exec(code, g, cache=DictCache(cache))

        assert len(cache) == 1
        cache_exc_msg, cache_globals = list(cache.values())[0]
        assert 'Hey there!' == cache_exc_msg

        # Change it again, now no exception!
        cache[list(cache.keys())[0]] = (None, {'a': 17})
        safe_exec(code, g, cache=DictCache(cache))
        assert g['a'] == 17
예제 #25
0
 def test_raising_exceptions(self):
     g = {}
     with self.assertRaises(SafeExecException) as cm:
         safe_exec("1/0", g)
     self.assertIn("ZeroDivisionError", cm.exception.message)
예제 #26
0
 def test_can_do_something_forbidden_if_run_unsafely(self):
     g = {}
     safe_exec("import os; files = os.listdir('/')", g, unsafely=True)
     self.assertEqual(g['files'], os.listdir('/'))
예제 #27
0
 def test_raising_exceptions(self):
     g = {}
     with self.assertRaises(SafeExecException) as cm:
         safe_exec("1/0", g)
     self.assertIn("ZeroDivisionError", text_type(cm.exception))
예제 #28
0
    def test_802x(self):
        code = textwrap.dedent("""\
            import math
            import random
            import numpy
            e=1.602e-19 #C
            me=9.1e-31  #kg
            mp=1.672e-27 #kg
            eps0=8.854e-12 #SI units
            mu0=4e-7*math.pi #SI units

            Rd1=random.randrange(1,30,1)
            Rd2=random.randrange(30,50,1)
            Rd3=random.randrange(50,70,1)
            Rd4=random.randrange(70,100,1)
            Rd5=random.randrange(100,120,1)

            Vd1=random.randrange(1,20,1)
            Vd2=random.randrange(20,40,1)
            Vd3=random.randrange(40,60,1)

            #R=[0,10,30,50,70,100] #Ohm
            #V=[0,12,24,36] # Volt

            R=[0,Rd1,Rd2,Rd3,Rd4,Rd5] #Ohms
            V=[0,Vd1,Vd2,Vd3] #Volts
            #here the currents IL and IR are defined as in figure ps3_p3_fig2
            a=numpy.array([  [  R[1]+R[4]+R[5],R[4] ],[R[4], R[2]+R[3]+R[4] ] ])
            b=numpy.array([V[1]-V[2],-V[3]-V[2]])
            x=numpy.linalg.solve(a,b)
            IL='%.2e' % x[0]
            IR='%.2e' % x[1]
            ILR='%.2e' % (x[0]+x[1])
            def sign(x):
                return abs(x)/x

            RW="Rightwards"
            LW="Leftwards"
            UW="Upwards"
            DW="Downwards"
            I1='%.2e' % abs(x[0])
            I1d=LW if sign(x[0])==1 else RW
            I1not=LW if I1d==RW else RW
            I2='%.2e' % abs(x[1])
            I2d=RW if sign(x[1])==1 else LW
            I2not=LW if I2d==RW else RW
            I3='%.2e' % abs(x[1])
            I3d=DW if sign(x[1])==1 else UW
            I3not=DW if I3d==UW else UW
            I4='%.2e' % abs(x[0]+x[1])
            I4d=UW if sign(x[1]+x[0])==1 else DW
            I4not=DW if I4d==UW else UW
            I5='%.2e' % abs(x[0])
            I5d=RW if sign(x[0])==1 else LW
            I5not=LW if I5d==RW else RW
            VAP=-x[0]*R[1]-(x[0]+x[1])*R[4]
            VPN=-V[2]
            VGD=+V[1]-x[0]*R[1]+V[3]+x[1]*R[2]
            aVAP='%.2e' % VAP
            aVPN='%.2e' % VPN
            aVGD='%.2e' % VGD
            """)
        g = {}
        safe_exec(code, g)
        self.assertIn("aVAP", g)
예제 #29
0
 def test_set_values(self):
     g = {}
     safe_exec("a = 17", g)
     self.assertEqual(g['a'], 17)
예제 #30
0
 def test_division(self):
     g = {}
     # Future division: 1/2 is 0.5.
     safe_exec("a = 1/2", g)
     self.assertEqual(g['a'], 0.5)
예제 #31
0
    def test_802x(self):
        code = textwrap.dedent("""\
            import math
            import random
            import numpy
            e=1.602e-19 #C
            me=9.1e-31  #kg
            mp=1.672e-27 #kg
            eps0=8.854e-12 #SI units
            mu0=4e-7*math.pi #SI units

            Rd1=random.randrange(1,30,1)
            Rd2=random.randrange(30,50,1)
            Rd3=random.randrange(50,70,1)
            Rd4=random.randrange(70,100,1)
            Rd5=random.randrange(100,120,1)

            Vd1=random.randrange(1,20,1)
            Vd2=random.randrange(20,40,1)
            Vd3=random.randrange(40,60,1)

            #R=[0,10,30,50,70,100] #Ohm
            #V=[0,12,24,36] # Volt

            R=[0,Rd1,Rd2,Rd3,Rd4,Rd5] #Ohms
            V=[0,Vd1,Vd2,Vd3] #Volts
            #here the currents IL and IR are defined as in figure ps3_p3_fig2
            a=numpy.array([  [  R[1]+R[4]+R[5],R[4] ],[R[4], R[2]+R[3]+R[4] ] ])
            b=numpy.array([V[1]-V[2],-V[3]-V[2]])
            x=numpy.linalg.solve(a,b)
            IL='%.2e' % x[0]
            IR='%.2e' % x[1]
            ILR='%.2e' % (x[0]+x[1])
            def sign(x):
                return abs(x)/x

            RW="Rightwards"
            LW="Leftwards"
            UW="Upwards"
            DW="Downwards"
            I1='%.2e' % abs(x[0])
            I1d=LW if sign(x[0])==1 else RW
            I1not=LW if I1d==RW else RW
            I2='%.2e' % abs(x[1])
            I2d=RW if sign(x[1])==1 else LW
            I2not=LW if I2d==RW else RW
            I3='%.2e' % abs(x[1])
            I3d=DW if sign(x[1])==1 else UW
            I3not=DW if I3d==UW else UW
            I4='%.2e' % abs(x[0]+x[1])
            I4d=UW if sign(x[1]+x[0])==1 else DW
            I4not=DW if I4d==UW else UW
            I5='%.2e' % abs(x[0])
            I5d=RW if sign(x[0])==1 else LW
            I5not=LW if I5d==RW else RW
            VAP=-x[0]*R[1]-(x[0]+x[1])*R[4]
            VPN=-V[2]
            VGD=+V[1]-x[0]*R[1]+V[3]+x[1]*R[2]
            aVAP='%.2e' % VAP
            aVPN='%.2e' % VPN
            aVGD='%.2e' % VGD
            """)
        g = {}
        safe_exec(code, g)
        self.assertIn("aVAP", g)
예제 #32
0
 def test_assumed_imports(self):
     g = {}
     # Math is always available.
     safe_exec("a = int(math.pi)", g)
     self.assertEqual(g['a'], 3)
예제 #33
0
 def test_set_values(self):
     g = {}
     safe_exec("a = 17", g)
     self.assertEqual(g['a'], 17)
예제 #34
0
 def test_division(self):
     g = {}
     # Future division: 1/2 is 0.5.
     safe_exec("a = 1/2", g)
     self.assertEqual(g['a'], 0.5)
예제 #35
0
 def test_set_values(self):
     g = {}
     safe_exec("a = 17", g)
     assert g['a'] == 17
예제 #36
0
 def test_assumed_imports(self):
     g = {}
     # Math is always available.
     safe_exec("a = int(math.pi)", g)
     self.assertEqual(g['a'], 3)
예제 #37
0
 def test_division(self):
     g = {}
     # Future division: 1/2 is 0.5.
     safe_exec("a = 1/2", g)
     assert g['a'] == 0.5
예제 #38
0
 def test_assumed_imports(self):
     g = {}
     # Math is always available.
     safe_exec("a = int(math.pi)", g)
     assert g['a'] == 3
예제 #39
0
 def test_raising_exceptions(self):
     g = {}
     with pytest.raises(SafeExecException) as cm:
         safe_exec("1/0", g)
     assert 'ZeroDivisionError' in text_type(cm.value)
예제 #40
0
    def _extract_context(self, tree):
        """
        Extract content of <script>...</script> from the problem.xml file, and exec it in the
        context of this problem.  Provides ability to randomize problems, and also set
        variables for problem answer checking.

        Problem XML goes to Python execution context. Runs everything in script tags.
        """
        context = {}
        context["seed"] = self.seed
        context["anonymous_student_id"] = self.capa_system.anonymous_student_id
        all_code = ""

        python_path = []

        for script in tree.findall(".//script"):

            stype = script.get("type")
            if stype:
                if "javascript" in stype:
                    continue  # skip javascript
                if "perl" in stype:
                    continue  # skip perl
            # TODO: evaluate only python

            for d in self._extract_system_path(script):
                if d not in python_path and os.path.exists(d):
                    python_path.append(d)

            XMLESC = {"&apos;": "'", "&quot;": '"'}
            code = unescape(script.text, XMLESC)
            all_code += code

        extra_files = []
        if all_code:
            # An asset named python_lib.zip can be imported by Python code.
            zip_lib = self.capa_system.get_python_lib_zip()
            if zip_lib is not None:
                extra_files.append(("python_lib.zip", zip_lib))
                python_path.append("python_lib.zip")

            try:
                safe_exec(
                    all_code,
                    context,
                    random_seed=self.seed,
                    python_path=python_path,
                    extra_files=extra_files,
                    cache=self.capa_system.cache,
                    slug=self.problem_id,
                    unsafely=self.capa_system.can_execute_unsafe_code(),
                )
            except Exception as err:
                log.exception("Error while execing script code: " + all_code)
                msg = "Error while executing script code: %s" % str(err).replace("<", "&lt;")
                raise responsetypes.LoncapaProblemError(msg)

        # Store code source in context, along with the Python path needed to run it correctly.
        context["script_code"] = all_code
        context["python_path"] = python_path
        context["extra_files"] = extra_files or None
        return context
예제 #41
0
 def test_can_do_something_forbidden_if_run_unsafely(self):
     g = {}
     safe_exec("import os; files = os.listdir('/')", g, unsafely=True)
     self.assertEqual(g['files'], os.listdir('/'))