blob: e6e94936d2dbe1203a3e57b4a007992540b91504 [file] [log] [blame]
Srikrishna Iyerd8aca092022-02-02 11:17:44 -08001# 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
6import logging as log
7from pathlib import Path
8
9import hjson # type: ignore
10from mako import exceptions # type: ignore
11from mako.lookup import TemplateLookup # type: ignore
12from pkg_resources import resource_filename
13
Eunchan Kim2861a7c2022-07-29 11:52:36 -070014from reggen.ip_block import IpBlock
Srikrishna Iyerd8aca092022-02-02 11:17:44 -080015
16
17def 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