test_sign.py
191 lines
| 6.7 KiB
| text/x-python
|
PythonLexer
MinRK
|
r14863 | """Test Notebook signing""" | ||
MinRK
|
r18579 | # Copyright (c) IPython Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||||
MinRK
|
r14863 | |||
Min RK
|
r19625 | import copy | ||
import time | ||||
MinRK
|
r14863 | from .base import TestsBase | ||
MinRK
|
r18603 | from IPython.nbformat import read, sign | ||
MinRK
|
r14863 | from IPython.core.getipython import get_ipython | ||
class TestNotary(TestsBase): | ||||
def setUp(self): | ||||
self.notary = sign.NotebookNotary( | ||||
Min RK
|
r19629 | db_file=':memory:', | ||
MinRK
|
r14863 | secret=b'secret', | ||
Min RK
|
r19625 | profile_dir=get_ipython().profile_dir, | ||
MinRK
|
r14863 | ) | ||
with self.fopen(u'test3.ipynb', u'r') as f: | ||||
MinRK
|
r18603 | self.nb = read(f, as_version=4) | ||
MinRK
|
r18612 | with self.fopen(u'test3.ipynb', u'r') as f: | ||
self.nb3 = read(f, as_version=3) | ||||
MinRK
|
r14863 | |||
def test_algorithms(self): | ||||
last_sig = '' | ||||
MinRK
|
r14908 | for algo in sign.algorithms: | ||
MinRK
|
r14863 | self.notary.algorithm = algo | ||
Min RK
|
r19625 | sig = self.notary.compute_signature(self.nb) | ||
MinRK
|
r14863 | self.assertNotEqual(last_sig, sig) | ||
last_sig = sig | ||||
def test_sign_same(self): | ||||
"""Multiple signatures of the same notebook are the same""" | ||||
sig1 = self.notary.compute_signature(self.nb) | ||||
sig2 = self.notary.compute_signature(self.nb) | ||||
self.assertEqual(sig1, sig2) | ||||
def test_change_secret(self): | ||||
"""Changing the secret changes the signature""" | ||||
sig1 = self.notary.compute_signature(self.nb) | ||||
self.notary.secret = b'different' | ||||
sig2 = self.notary.compute_signature(self.nb) | ||||
self.assertNotEqual(sig1, sig2) | ||||
def test_sign(self): | ||||
Min RK
|
r19625 | self.assertFalse(self.notary.check_signature(self.nb)) | ||
self.notary.sign(self.nb) | ||||
self.assertTrue(self.notary.check_signature(self.nb)) | ||||
def test_unsign(self): | ||||
MinRK
|
r14863 | self.notary.sign(self.nb) | ||
Min RK
|
r19625 | self.assertTrue(self.notary.check_signature(self.nb)) | ||
self.notary.unsign(self.nb) | ||||
self.assertFalse(self.notary.check_signature(self.nb)) | ||||
self.notary.unsign(self.nb) | ||||
self.assertFalse(self.notary.check_signature(self.nb)) | ||||
def test_cull_db(self): | ||||
# this test has various sleeps of 2ms | ||||
# to ensure low resolution timestamps compare as expected | ||||
dt = 2e-3 | ||||
nbs = [ | ||||
Min RK
|
r19626 | copy.deepcopy(self.nb) for i in range(10) | ||
Min RK
|
r19625 | ] | ||
Min RK
|
r19626 | for row in self.notary.db.execute("SELECT * FROM nbsignatures"): | ||
print(row) | ||||
self.notary.cache_size = 8 | ||||
for i, nb in enumerate(nbs[:8]): | ||||
Min RK
|
r19625 | nb.metadata.dirty = i | ||
self.notary.sign(nb) | ||||
Min RK
|
r19626 | for i, nb in enumerate(nbs[:8]): | ||
Min RK
|
r19625 | time.sleep(dt) | ||
self.assertTrue(self.notary.check_signature(nb), 'nb %i is trusted' % i) | ||||
Min RK
|
r19626 | # signing the 9th triggers culling of first 3 | ||
# (75% of 8 = 6, 9 - 6 = 3 culled) | ||||
self.notary.sign(nbs[8]) | ||||
self.assertFalse(self.notary.check_signature(nbs[0])) | ||||
self.assertFalse(self.notary.check_signature(nbs[1])) | ||||
self.assertFalse(self.notary.check_signature(nbs[2])) | ||||
self.assertTrue(self.notary.check_signature(nbs[3])) | ||||
# checking nb3 should keep it from being culled: | ||||
self.notary.sign(nbs[0]) | ||||
self.notary.sign(nbs[1]) | ||||
self.notary.sign(nbs[2]) | ||||
self.assertTrue(self.notary.check_signature(nbs[3])) | ||||
self.assertFalse(self.notary.check_signature(nbs[4])) | ||||
MinRK
|
r14863 | |||
def test_check_signature(self): | ||||
nb = self.nb | ||||
md = nb.metadata | ||||
notary = self.notary | ||||
check_signature = notary.check_signature | ||||
# no signature: | ||||
md.pop('signature', None) | ||||
self.assertFalse(check_signature(nb)) | ||||
# hash only, no algo | ||||
md.signature = notary.compute_signature(nb) | ||||
self.assertFalse(check_signature(nb)) | ||||
# proper signature, algo mismatch | ||||
notary.algorithm = 'sha224' | ||||
notary.sign(nb) | ||||
notary.algorithm = 'sha256' | ||||
self.assertFalse(check_signature(nb)) | ||||
# check correctly signed notebook | ||||
notary.sign(nb) | ||||
self.assertTrue(check_signature(nb)) | ||||
def test_mark_cells_untrusted(self): | ||||
MinRK
|
r18579 | cells = self.nb.cells | ||
MinRK
|
r14863 | self.notary.mark_cells(self.nb, False) | ||
for cell in cells: | ||||
MinRK
|
r18255 | self.assertNotIn('trusted', cell) | ||
MinRK
|
r14863 | if cell.cell_type == 'code': | ||
MinRK
|
r18255 | self.assertIn('trusted', cell.metadata) | ||
self.assertFalse(cell.metadata.trusted) | ||||
MinRK
|
r14863 | else: | ||
MinRK
|
r18255 | self.assertNotIn('trusted', cell.metadata) | ||
MinRK
|
r14863 | |||
def test_mark_cells_trusted(self): | ||||
MinRK
|
r18579 | cells = self.nb.cells | ||
MinRK
|
r14863 | self.notary.mark_cells(self.nb, True) | ||
for cell in cells: | ||||
MinRK
|
r18255 | self.assertNotIn('trusted', cell) | ||
MinRK
|
r14863 | if cell.cell_type == 'code': | ||
MinRK
|
r18255 | self.assertIn('trusted', cell.metadata) | ||
self.assertTrue(cell.metadata.trusted) | ||||
MinRK
|
r14863 | else: | ||
MinRK
|
r18255 | self.assertNotIn('trusted', cell.metadata) | ||
MinRK
|
r14863 | |||
def test_check_cells(self): | ||||
nb = self.nb | ||||
self.notary.mark_cells(nb, True) | ||||
self.assertTrue(self.notary.check_cells(nb)) | ||||
MinRK
|
r18579 | for cell in nb.cells: | ||
MinRK
|
r15023 | self.assertNotIn('trusted', cell) | ||
MinRK
|
r14863 | self.notary.mark_cells(nb, False) | ||
self.assertFalse(self.notary.check_cells(nb)) | ||||
MinRK
|
r18579 | for cell in nb.cells: | ||
MinRK
|
r15023 | self.assertNotIn('trusted', cell) | ||
MinRK
|
r15269 | |||
def test_trust_no_output(self): | ||||
nb = self.nb | ||||
self.notary.mark_cells(nb, False) | ||||
MinRK
|
r18579 | for cell in nb.cells: | ||
MinRK
|
r15269 | if cell.cell_type == 'code': | ||
cell.outputs = [] | ||||
self.assertTrue(self.notary.check_cells(nb)) | ||||
MinRK
|
r18612 | |||
def test_mark_cells_untrusted_v3(self): | ||||
nb = self.nb3 | ||||
cells = nb.worksheets[0].cells | ||||
self.notary.mark_cells(nb, False) | ||||
for cell in cells: | ||||
self.assertNotIn('trusted', cell) | ||||
if cell.cell_type == 'code': | ||||
self.assertIn('trusted', cell.metadata) | ||||
self.assertFalse(cell.metadata.trusted) | ||||
else: | ||||
self.assertNotIn('trusted', cell.metadata) | ||||
def test_mark_cells_trusted_v3(self): | ||||
nb = self.nb3 | ||||
cells = nb.worksheets[0].cells | ||||
self.notary.mark_cells(nb, True) | ||||
for cell in cells: | ||||
self.assertNotIn('trusted', cell) | ||||
if cell.cell_type == 'code': | ||||
self.assertIn('trusted', cell.metadata) | ||||
self.assertTrue(cell.metadata.trusted) | ||||
else: | ||||
self.assertNotIn('trusted', cell.metadata) | ||||
def test_check_cells_v3(self): | ||||
nb = self.nb3 | ||||
cells = nb.worksheets[0].cells | ||||
self.notary.mark_cells(nb, True) | ||||
self.assertTrue(self.notary.check_cells(nb)) | ||||
for cell in cells: | ||||
self.assertNotIn('trusted', cell) | ||||
self.notary.mark_cells(nb, False) | ||||
self.assertFalse(self.notary.check_cells(nb)) | ||||
for cell in cells: | ||||
self.assertNotIn('trusted', cell) | ||||
MinRK
|
r14863 | |||