Skip to content

Commit

Permalink
lobster-report allow optional up-linking in tracing policies
Browse files Browse the repository at this point in the history
  • Loading branch information
TannazVhdBMWExt committed Sep 27, 2024
1 parent 77e74a1 commit 7a0d454
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 69 deletions.
96 changes: 43 additions & 53 deletions lobster/config/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,11 @@ def parse_level_declaration(self):
"duplicate declaration")

item = {
"name" : level_name,
"kind" : level_kind,
"traces" : [],
"source" : [],
"needs_tracing_up" : False,
"needs_tracing_down" : False,
"raw_trace_requirements" : []
"name" : level_name,
"kind" : level_kind,
"source" : [],
"trace_to" : [],
"trace_from" : []
}
self.levels[level_name] = item

Expand Down Expand Up @@ -175,39 +173,40 @@ def parse_level_declaration(self):

elif self.peek("KEYWORD", "trace"):
self.match("KEYWORD", "trace")
self.match("KEYWORD", "to")
self.match("COLON")
self.match("STRING")
if self.ct.value() == level_name:
self.error(self.ct.loc,
"cannot trace to yourself")
elif self.ct.value() not in self.levels:
self.error(self.ct.loc,
"unknown item %s" % self.ct.value())
else:
self.levels[self.ct.value()]["needs_tracing_down"] = True
item["traces"].append(self.ct.value())
item["needs_tracing_up"] = True

self.match("SEMI")
if self.peek("KEYWORD", "to"):
self.match("KEYWORD", "to")
self.match("COLON")

elif self.peek("KEYWORD", "requires"):
self.match("KEYWORD", "requires")
self.match("COLON")
req_list = []
self.match("STRING")
req_list.append(self.ct.value())

req_list = []
while self.peek("KEYWORD", "or"):
self.match("KEYWORD", "or")
self.match("STRING")
req_list.append(self.ct.value())

self.match("STRING")
req_list.append(self.ct)
self.match("SEMI")

item["trace_to"].append(req_list)

while self.peek("KEYWORD", "or"):
self.match("KEYWORD", "or")
elif self.peek("KEYWORD", "from"):
self.match("KEYWORD", "from")
self.match("COLON")

req_list = []
self.match("STRING")
req_list.append(self.ct)
req_list.append(self.ct.value())

self.match("SEMI")
while self.peek("KEYWORD", "or"):
self.match("KEYWORD", "or")
self.match("STRING")
req_list.append(self.ct.value())

item["raw_trace_requirements"].append(req_list)
self.match("SEMI")

item["trace_from"].append(req_list)

else:
self.error(self.nt.loc,
Expand All @@ -219,28 +218,19 @@ def parse_level_declaration(self):
def load(mh, file_name):
parser = Parser(mh, file_name)
ast = parser.parse()

# Resolve requires links now
item_names = list(ast.keys())
for item in ast.values():
item["breakdown_requirements"] = []
if len(item["raw_trace_requirements"]) > 0:
for chain in item["raw_trace_requirements"]:
new_chain = []
for tok in chain:
if tok.value() not in ast:
mh.error(tok.loc, "unknown level %s" % tok.value())
if item["name"] not in ast[tok.value()]["traces"]:
mh.error(tok.loc,
"%s cannot trace to %s items" %
(tok.value(),
item["name"]))
new_chain.append(tok.value())
item["breakdown_requirements"].append(new_chain)
else:
for src in ast.values():
if item["name"] in src["traces"]:
item["breakdown_requirements"].append([src["name"]])
del item["raw_trace_requirements"]
if len(item["trace_to"]) > 0:
for trace_to in item["trace_to"]:
if not set(trace_to).issubset(item_names):
mh.error(set(trace_to).issubset(item_names),
"cannot trace to %s items" % ",".join(trace_to))

if len(item["trace_from"]) > 0:
for trace_from in item["trace_from"]:
if not set(trace_from).issubset(item_names):
mh.error(set(trace_to).issubset(item_names),
"cannot trace from %s items" % ",".join(trace_from))

return ast

Expand Down
40 changes: 24 additions & 16 deletions lobster/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,31 +134,41 @@ def determine_status(self, config, stab):
level = config[self.level]

has_up_ref = len(self.ref_up) > 0
has_down_ref = len(self.ref_down) > 0
has_just_up = len(self.just_up) > 0 or len(self.just_global) > 0
has_just_down = len(self.just_down) > 0 or len(self.just_global) > 0
has_init_errors = len(self.messages) > 0

# Check up references
ok_up = True
if level["needs_tracing_up"]:
if level["trace_to"]:
if not has_up_ref and not has_just_up:
ok_up = False
self.messages.append("missing up reference")

for trace_to in level["trace_to"]:
# and
if not ok_up:
break

# or
refs_levels = [stab[ref.key()].level for ref in self.ref_up]
ok_up = len(set(refs_levels).intersection(set(trace_to))) > 0

# Check set of down references
ok_down = True
if level["needs_tracing_down"]:
has_trace = {name : False
for name in config
if self.level in config[name]["traces"]}
for ref in self.ref_down:
has_trace[stab[ref.key()].level] = True
for chain in level["breakdown_requirements"]:
if not any(has_trace[src] for src in chain) and \
not has_just_down:
ok_down = False
self.messages.append("missing reference to %s" %
" or ".join(sorted(chain)))
if level["trace_from"]:
if not has_down_ref and not has_just_down:
ok_down = False
self.messages.append("missing down reference")

for trace_from in level["trace_from"]:
# and
if not ok_down:
break
# or
refs_levels = [stab[ref.key()].level for ref in self.ref_down]
ok_down = len(set(refs_levels).intersection(set(trace_from))) > 0

# Set status
if self.has_error:
Expand All @@ -168,9 +178,7 @@ def determine_status(self, config, stab):
self.tracing_status = Tracing_Status.JUSTIFIED
else:
self.tracing_status = Tracing_Status.OK
elif (ok_up or ok_down) and \
level["needs_tracing_up"] and \
level["needs_tracing_down"]:
elif ok_up or ok_down:
self.tracing_status = Tracing_Status.PARTIAL
else:
self.tracing_status = Tracing_Status.MISSING
Expand Down

0 comments on commit 7a0d454

Please sign in to comment.