Srikrishna Iyer | d8aca09 | 2022-02-02 11:17:44 -0800 | [diff] [blame] | 1 | # Copyright lowRISC contributors. |
| 2 | # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | # SPDX-License-Identifier: Apache-2.0 |
| 4 | """Generate the initial testplan for the listed countermeasures.""" |
| 5 | |
| 6 | import logging as log |
| 7 | from pathlib import Path |
| 8 | |
| 9 | import hjson # type: ignore |
| 10 | from mako import exceptions # type: ignore |
| 11 | from mako.lookup import TemplateLookup # type: ignore |
| 12 | from pkg_resources import resource_filename |
| 13 | |
Eunchan Kim | 2861a7c | 2022-07-29 11:52:36 -0700 | [diff] [blame] | 14 | from reggen.ip_block import IpBlock |
Srikrishna Iyer | d8aca09 | 2022-02-02 11:17:44 -0800 | [diff] [blame] | 15 | |
| 16 | |
| 17 | def gen_sec_cm_testplan(block: IpBlock, outdir: str) -> int: |
| 18 | """Generate the security countermeasures testplan. |
| 19 | |
| 20 | A new testplan is created only if it does not exist yet. If it already |
| 21 | exists, then it checks if the list of countermeasures match the list |
| 22 | of countermeasures in the design specification Hjson. If not, it throws |
| 23 | an error to prompt the user to keep the testplan up-to-date manually. |
| 24 | """ |
| 25 | if not block.countermeasures: |
| 26 | return 0 |
| 27 | |
| 28 | outfile = Path(outdir) / f"{block.name.lower()}_sec_cm_testplan.hjson" |
| 29 | if outfile.exists(): |
| 30 | names_from_testplan = [] |
| 31 | with open(outfile, "r", encoding='UTF-8') as f: |
| 32 | data = hjson.load(f) |
| 33 | try: |
| 34 | names_from_testplan = [tp["name"] for tp in data["testpoints"]] |
| 35 | except KeyError as e: |
| 36 | raise KeyError(f"Malformed testplan {outfile}:\n{e}") |
| 37 | |
| 38 | # Check if the testpoint names match the list in the design spec. |
| 39 | names_from_spec = [ |
| 40 | "sec_cm_{}".format(str(cm).lower().replace(".", "_")) |
| 41 | for cm in block.countermeasures |
| 42 | ] |
| 43 | |
| 44 | if sorted(names_from_spec) != sorted(names_from_testplan): |
| 45 | log.error("The generated security countermeasures testplan " |
| 46 | f"{outfile} is stale. Please manually update it " |
| 47 | "with the newly added (or removed) countermeasures.\n" |
| 48 | f"Deltas:\nSpec: {names_from_spec}\n" |
| 49 | f"Testplan: {names_from_testplan}.") |
| 50 | return 1 |
| 51 | |
| 52 | return 0 |
| 53 | |
| 54 | lookup = TemplateLookup(directories=[resource_filename('reggen', '.')]) |
| 55 | sec_cm_testplan_tpl = lookup.get_template('sec_cm_testplan.hjson.tpl') |
| 56 | with open(outfile, 'w', encoding='UTF-8') as f: |
| 57 | try: |
| 58 | f.write( |
| 59 | sec_cm_testplan_tpl.render(block=block, |
| 60 | block_name=block.name.lower())) |
| 61 | except: # noqa F722 for template Exception handling |
| 62 | log.error(exceptions.text_error_template().render()) |
| 63 | return 1 |
| 64 | |
| 65 | return 0 |