From 5e6b83d17629fb8e8ae81638b2056a37364ec703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20D=C3=A9trez?= Date: Tue, 28 Jun 2022 16:46:42 +0200 Subject: Allow --sigkey-file to be a symlink Also adds the first tests (using pytest) & a short paragraph to the README on how to run them. --- README.md | 10 ++++++++ sigsum-witness.py | 27 +++++++++++++++------ sigsum-witness_test.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 sigsum-witness_test.py diff --git a/README.md b/README.md index ed9a389..65a8b37 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,13 @@ The full license text can be found in the file LICENSE. This license is also known as the BSD-2-Clause and the Simplified BSD License. + +## Hacking + +### Running tests + +Use [`pytest`](https://docs.pytest.org/) to run the automated tests: + +``` +$ pytest . +``` diff --git a/sigsum-witness.py b/sigsum-witness.py index 15bfb07..ef63c4c 100755 --- a/sigsum-witness.py +++ b/sigsum-witness.py @@ -386,14 +386,10 @@ def generate_and_store_sigkey(fn): f.write(signing_key.encode(encoder=nacl.encoding.HexEncoder).decode('ascii')) def read_sigkeyfile(fn): - s = os.stat(fn, follow_symlinks=False) - if not S_ISREG(s.st_mode): - return None, (ERR_SIGKEYFILE, - "ERROR: Signing key file {} must be a regular file".format(fn)) - if S_IMODE(s.st_mode) & 0o077 != 0: - return None, (ERR_SIGKEYFILE, - "ERROR: Signing key file {} permissions too lax: {:04o}".format(fn, S_IMODE(s.st_mode))) - + try: + check_sigkeyfile(fn) + except SigKeyFileError as err: + return None, (ERR_SIGKEYFILE, str(err)) with open(fn, 'r') as f: try: signing_key = nacl.signing.SigningKey(f.readline().strip(), nacl.encoding.HexEncoder) @@ -405,6 +401,21 @@ def read_sigkeyfile(fn): return signing_key, None +def check_sigkeyfile(fn): + try: + s = os.stat(fn, follow_symlinks=True) + except FileNotFoundError: + raise SigKeyFileError(f"ERROR: File not found: {fn}") + if not S_ISREG(s.st_mode): + raise SigKeyFileError(f"ERROR: Signing key file {fn} must be a regular file") + if S_IMODE(s.st_mode) & 0o077 != 0: + raise SigKeyFileError(f"ERROR: Signing key file {fn} permissions too lax: {S_IMODE(s.st_mode):04o}") + + +class SigKeyFileError(Exception): + pass + + # Read signature key from file, or generate one and write it to file. def ensure_sigkey(fn): try: diff --git a/sigsum-witness_test.py b/sigsum-witness_test.py new file mode 100644 index 0000000..3c0241b --- /dev/null +++ b/sigsum-witness_test.py @@ -0,0 +1,66 @@ +import importlib + +import pytest + +witness = importlib.import_module("sigsum-witness") # To import a module with a '-' + + +class Test_check_sigkeyfile: + def test_file_ok(self, tmp_path): + path = tmp_path / "key" + path.touch(mode=0o700) + witness.check_sigkeyfile(path) + + def test_file_notfound(self, tmp_path): + path = tmp_path / "key" + with pytest.raises( + witness.SigKeyFileError, + match=f"ERROR: File not found: {path}", + ): + witness.check_sigkeyfile(path) + + def test_notafile(self, tmp_path): + path = tmp_path / "key" + path.mkdir() + with pytest.raises( + witness.SigKeyFileError, + match=f"ERROR: Signing key file {path} must be a regular file", + ): + witness.check_sigkeyfile(path) + + def test_file_badmode(self, tmp_path): + path = tmp_path / "key" + path.touch(mode=0o755) + with pytest.raises( + witness.SigKeyFileError, + match=f"ERROR: Signing key file {path} permissions too lax: 0755", + ): + witness.check_sigkeyfile(path) + + def test_symlink_ok(self, tmp_path): + filepath = tmp_path / "thekey" + filepath.touch(mode=0o700) + linkpath = tmp_path / "key" + linkpath.symlink_to(filepath) + assert witness.check_sigkeyfile(linkpath) is None + + def test_symlink_badmode(self, tmp_path): + filepath = tmp_path / "thekey" + filepath.touch(mode=0o755) + linkpath = tmp_path / "key" + linkpath.symlink_to(filepath) + with pytest.raises( + witness.SigKeyFileError, + match=f"ERROR: Signing key file {linkpath} permissions too lax: 0755", + ): + witness.check_sigkeyfile(linkpath) + + def test_symlink_dangling(self, tmp_path): + filepath = tmp_path / "thekey" + linkpath = tmp_path / "key" + linkpath.symlink_to(filepath) + with pytest.raises( + witness.SigKeyFileError, + match=f"ERROR: File not found: {linkpath}", + ): + witness.check_sigkeyfile(linkpath) -- cgit v1.2.3