From ff0a1231d06648efc96b358ef16ccdd9aaa5d1b2 Mon Sep 17 00:00:00 2001 From: actyp Date: Wed, 25 Mar 2026 23:59:01 -0400 Subject: [PATCH 1/5] Update beautify_model scripts --- scripts/beautify_model.py | 410 ++++++++++++++++++++++++-------------- scripts/beautify_model.sh | 9 +- 2 files changed, 265 insertions(+), 154 deletions(-) diff --git a/scripts/beautify_model.py b/scripts/beautify_model.py index aacae342..b8078c67 100644 --- a/scripts/beautify_model.py +++ b/scripts/beautify_model.py @@ -3,22 +3,18 @@ def create_pattern_dct(pattern_string): - pattern_dct = { - 'i': set(), - 'o': set(), - 'l': set() - } + pattern_dct = {"i": set(), "o": set(), "l": set()} if pattern_string is None or pattern_string == "": return pattern_dct - for patt in pattern_string.strip('\' "').split(','): + for patt in pattern_string.strip("' \"").split(","): p = patt.strip() - if p[0] not in ['i', 'o', 'l'] or p[1] != '_': + if p[0] not in ["i", "o", "l"] or p[1] != "_": raise Exception("Invalid pattern provided: " + p) - if p[0] == 'l': - i, o = map(lambda s: s.strip(), p[2:].split('/')) + if p[0] == "l": + i, o = map(lambda s: s.strip(), p[2:].split("/")) pattern_dct[p[0]].add(f"{i} / {o}") else: pattern_dct[p[0]].add(p[2:]) @@ -27,23 +23,18 @@ def create_pattern_dct(pattern_string): def create_pattern_dct_with_label_symbol(label_symbol_pattern_string_list): - label_pattern_dct = { - 'label_symbol': '/', - 'i': set(), - 'o': set(), - 'l': set() - } + label_pattern_dct = {"label_symbol": "/", "i": set(), "o": set(), "l": set()} - if label_symbol_pattern_string_list is None or len(label_symbol_pattern_string_list) != 2: + if ( + label_symbol_pattern_string_list is None + or len(label_symbol_pattern_string_list) != 2 + ): return label_pattern_dct label_symbol, pattern_string = label_symbol_pattern_string_list pattern_dct = create_pattern_dct(pattern_string) - return { - 'label_symbol': label_symbol, - **pattern_dct - } + return {"label_symbol": label_symbol, **pattern_dct} def read_replacement_file(filename, sep): @@ -70,56 +61,72 @@ def read_replacement_file(filename, sep): # in case of old name is already seen, inform and overwrite new name if old in replacement_dct: - print(f"Overwriting replacement: [{old} -> {new}] will overwrite [{old} -> {replacement_dct[old]}]") + print( + f"Overwriting replacement: [{old} -> {new}] will overwrite [{old} -> {replacement_dct[old]}]" + ) replacement_dct[old] = new return replacement_dct -def get_info_from_graph(graph_name, shorten_node_names, remove_dct, label_symbol_dct, replacement_dct, - initial_hidden_node_name, initial_edge_label): +def get_info_from_graph( + graph_name, + shorten_node_names, + remove_dct, + label_symbol_dct, + replacement_dct, + initial_hidden_node_name, + initial_edge_label, +): """ - remove_dct = { - 'i': {i1, i2, ...}, - 'o': {o1, o2, ...}, - 'l': {i1 / o1, i2 / o2, ...} - } - - label_symbol_dct = { - 'i': {i1, i2, ...}, - 'o': {o1, o2, ...}, - 'l': {i1 / o1, i2 / o2, ...} - } - - replacement_dct = { - old_name: new_name, - ... - } + remove_dct = { + 'i': {i1, i2, ...}, + 'o': {o1, o2, ...}, + 'l': {i1 / o1, i2 / o2, ...} + } - prefix 'r' means new replaced symbol name + label_symbol_dct = { + 'i': {i1, i2, ...}, + 'o': {o1, o2, ...}, + 'l': {i1 / o1, i2 / o2, ...} + } - (returned) new_edge_info_dct = { - (source, dest): { - r_o1: [r_i1, r_i2, ...], - r_o2: [r_i1, r_i2, ...], - ... - }, + replacement_dct = { + old_name: new_name, + ... + } + + prefix 'r' means new replaced symbol name + + (returned) new_edge_info_dct = { + (source, dest): { + r_o1: [r_i1, r_i2, ...], + r_o2: [r_i1, r_i2, ...], ... - } + }, + ... + } - (returned) new_label_symbol_dct = { - 'i': {r_i1, r_i2, ...}, - 'o': {r_o1, r_o2, ...}, - 'l': {r_i1 / r_o1, r_i2 / r_o2, ...} - } + (returned) new_label_symbol_dct = { + 'i': {r_i1, r_i2, ...}, + 'o': {r_o1, r_o2, ...}, + 'l': {r_i1 / r_o1, r_i2 / r_o2, ...} + } """ + def should_remove_label(label): - i, o = label.strip('\' "').split(' / ') - return (i in remove_dct['i']) or (o in remove_dct['o']) or (label in remove_dct['l']) + i, o = label.strip("' \"").split(" / ") + return ( + (i in remove_dct["i"]) + or (o in remove_dct["o"]) + or (label in remove_dct["l"]) + ) def find_index_of_same_edges(edge): - for idx, e in enumerate(graph.get_edge(edge.get_source(), edge.get_destination())): + for idx, e in enumerate( + graph.get_edge(edge.get_source(), edge.get_destination()) + ): if edge.get_label() == e.get_label(): return idx return -1 @@ -128,10 +135,10 @@ def replace_symbol(s): return replacement_dct[s] if s in replacement_dct else s def replace_label(label): - if label == "" or ' / ' not in label: + if label == "" or " / " not in label: return label - i, o = label.strip('\' "').split(' / ') + i, o = label.strip("' \"").split(" / ") ri = replace_symbol(i) ro = replace_symbol(o) return f"{ri} / {ro}" @@ -139,14 +146,19 @@ def replace_label(label): initial_edge = None # read graph, implies that graph is connected and there is a single graph - graph = pydot.graph_from_dot_file(graph_name)[0] + graphs = pydot.graph_from_dot_file(graph_name) + if graphs is None: + print(f"Invalid parsing of dot file: {graph_name}") + return + + graph = graphs[0] # shorten node names, if applicable and remove any falsely read nodes, most common '\\n\\n' for node in graph.get_nodes(): name = node.get_name() - if name.startswith('s'): + if name.startswith("s"): if shorten_node_names: - node.set_label('"' + node.get_label().strip('\' "').lstrip('s') + '"') + node.set_label('"' + node.get_label().strip("' \"").lstrip("s") + '"') elif name != initial_hidden_node_name: if graph.del_node(node): @@ -160,7 +172,7 @@ def replace_label(label): # initial edge is stored separately from info dict if source_dest_pair[0] == initial_hidden_node_name: initial_edge = e - if initial_edge_label is not None and initial_edge_label != '': + if initial_edge_label is not None and initial_edge_label != "": initial_edge.set_label(replace_label(initial_edge_label)) continue @@ -177,7 +189,7 @@ def replace_label(label): new_edge_info_dct[source_dest_pair] = {} # replace the old label - in_label, out_label = replace_label(e.get_label()).split(' / ') + in_label, out_label = replace_label(e.get_label()).split(" / ") # append the input to the inputs list of the output key in source_dest sub-dict if out_label not in new_edge_info_dct[source_dest_pair]: @@ -187,16 +199,18 @@ def replace_label(label): # create new label_symbol_dct with replaced symbols new_label_symbol_dct = { - 'label_symbol': label_symbol_dct['label_symbol'], - 'i': set(map(replace_symbol, label_symbol_dct['i'])), - 'o': set(map(replace_symbol, label_symbol_dct['o'])), - 'l': set(map(replace_symbol, label_symbol_dct['l'])), + "label_symbol": label_symbol_dct["label_symbol"], + "i": set(map(replace_symbol, label_symbol_dct["i"])), + "o": set(map(replace_symbol, label_symbol_dct["o"])), + "l": set(map(replace_symbol, label_symbol_dct["l"])), } return graph.get_nodes(), new_edge_info_dct, initial_edge, new_label_symbol_dct -def create_new_graph(nodes, edge_info_dct, initial_edge, label_info_dct, label_symbol_dct): +def create_new_graph( + nodes, edge_info_dct, initial_edge, label_info_dct, label_symbol_dct +): """ nodes: node object list that should contain the initial_hidden_node @@ -228,16 +242,21 @@ def create_new_graph(nodes, edge_info_dct, initial_edge, label_info_dct, label_s 'l': {r_i1 / r_o1, r_i2 / r_o2, ...} } """ + def sort_key_of_label(label): # ascending sort based on the label's input # first by length and then alphabetically - input = label.split(' / ')[0] + input = label.split(" / ")[0] return (len(input), input) def create_label(i, o): label = f"{i} / {o}" - if (i in label_symbol_dct['i']) or (o in label_symbol_dct['o']) or (label in label_symbol_dct['l']): - label_symbol = label_symbol_dct['label_symbol'] + if ( + (i in label_symbol_dct["i"]) + or (o in label_symbol_dct["o"]) + or (label in label_symbol_dct["l"]) + ): + label_symbol = label_symbol_dct["label_symbol"] label = f"{i} {label_symbol} {o}" return label @@ -249,29 +268,29 @@ def stack_op(source_dest_pair): # sort and then join labels labels = sorted(labels, key=sort_key_of_label) - return label_info_dct['stack_sep'].join(labels) + return label_info_dct["stack_sep"].join(labels) def merge_op(source_dest_pair): labels = [] # gather all labels to be stacked for output, inputs in edge_info_dct[source_dest_pair].items(): - merged_inputs = label_info_dct['merge_input_sep'].join(inputs) + merged_inputs = label_info_dct["merge_input_sep"].join(inputs) labels.append(create_label(merged_inputs, output)) # sort and then join labels labels = sorted(labels, key=sort_key_of_label) - return label_info_dct['merge_label_sep'].join(labels) + return label_info_dct["merge_label_sep"].join(labels) def pad_label(label): - return label_info_dct['start_padding'] + label + label_info_dct['end_padding'] + return label_info_dct["start_padding"] + label + label_info_dct["end_padding"] def html_like_wrap_label(label): - return f"<{label}>" if label_info_dct['html_like_labels'] else label + return f"<{label}>" if label_info_dct["html_like_labels"] else label def finalize_label(label): return html_like_wrap_label(pad_label(label)) - graph = pydot.Dot(graph_name='g', graph_type='digraph') + graph = pydot.Dot(graph_name="g", graph_type="digraph") # add nodes (first hidden node should be included) for node in nodes: @@ -286,124 +305,211 @@ def finalize_label(label): # add other edges after stacking or merging the labels of similar ones for source_dest_pair in edge_info_dct: - if label_info_dct['same_edges_op'] == 'stack': + if label_info_dct["same_edges_op"] == "stack": new_label = stack_op(source_dest_pair) - elif label_info_dct['same_edges_op'] == 'merge': + elif label_info_dct["same_edges_op"] == "merge": new_label = merge_op(source_dest_pair) else: - raise Exception("Unsupported same_edges_op in label_info_dct: " + label_info_dct['same_edges_op']) + raise Exception( + "Unsupported same_edges_op in label_info_dct: " + + label_info_dct["same_edges_op"] + ) # finalize label and create and add the new edge new_label = finalize_label(new_label) - graph.add_edge(pydot.Edge(source_dest_pair[0], source_dest_pair[1], label=new_label)) + graph.add_edge( + pydot.Edge(source_dest_pair[0], source_dest_pair[1], label=new_label) + ) return graph def format_and_write_dot_string(graph_raw_string, initial_hidden_node_name, filename): - prefix = '\t' + prefix = "\t" initial_hidden_node_lines = "" - with open(filename, 'w') as f: + with open(filename, "w") as f: for line in graph_raw_string.strip().splitlines(): line = line.strip() - if line == 'digraph g {': + if line == "digraph g {": # start of graph - f.write(line + '\n\n') + f.write(line + "\n\n") elif line.startswith(initial_hidden_node_name): # store them to move them to the bottom - initial_hidden_node_lines += (line + '\n') - elif line == '}': + initial_hidden_node_lines += line + "\n" + elif line == "}": # end of graph - f.write('\n' + initial_hidden_node_lines + '\n' + '}' + '\n') - elif line != '': + f.write("\n" + initial_hidden_node_lines + "\n" + "}" + "\n") + elif line != "": # other non-empty line - f.write(prefix + line + '\n') + f.write(prefix + line + "\n") -if __name__ == '__main__': +if __name__ == "__main__": parser = argparse.ArgumentParser( - description='Beautify a .dot file by merging similar edges and replacing labels', - formatter_class=argparse.ArgumentDefaultsHelpFormatter) - - parser.add_argument('i', metavar='Input', help='Input .dot file') - parser.add_argument('-r', help='Replacements file with non-empty lines of the default format: old -> new') - parser.add_argument('-o', help='Output .dot file') - - parser.add_argument('--disable-shorten-nodes', default=False, action='store_true', help='Disable node name conversion: "sN" -> "N"') - parser.add_argument('--start-node-name', default='__start0', help='Name of the hidden starting node') - parser.add_argument('--start-edge-label', default='', help='Label of the starting visible edge') - parser.add_argument('--replacement-sep', default=' -> ', help='Separator of names in replacements file') - - parser.add_argument('--same-edges-op', default='stack', help='Operation to be performed on same edges, available: stack, merge') - parser.add_argument('--stack-sep', default='\l ', help='Separator of stacked input/output pairs of same edges') - parser.add_argument('--merge-input-sep', default=' | ', help='Separator of merged inputs with common output') - parser.add_argument('--merge-label-sep', default='\l ', help='Separator of merged labels of same edges') - - parser.add_argument('--start-padding', type=int, default=1, help='Left padding of labels (in spaces)') - parser.add_argument('--end-padding', type=int, default=5, help='Right padding of labels (in spaces)') - - parser.add_argument('--remove-edge-pattern', help="Remove the edges that have labels of the provided pattern. " - "Format: i_ (match input), o_ (match output), l_ (match label). " - "So the general format is: (i|o|l)_[,(i|o|l)_]*") - - parser.add_argument('--set-label-symbol-pattern', nargs=2, metavar=('NEW_LABEL_SYMBOL', 'PATTERN'), - help="Change the label symbol (which is '/' by default) of the edges that have labels of the provided pattern. " - "Pattern Format: i_ (match input), o_ (match output), l_ (match label). " - "So the general format is: (i|o|l)_[,(i|o|l)_]*") - - parser.add_argument('--html-like-labels', default=False, action='store_true', help="Enable html-like syntax in label names. " - "It defaults --stack-sep and --merge-label-sep to '
'. " - "It defaults --end-padding to 1.") - - parser.add_argument('--overwrite-dot-input', default=False, action='store_true', help="Overwrite input dot file " - "with the output dot file in case they have the same name") - parser.add_argument('--no-dot-output', default=False, action='store_true', help='Do not output the resulting .dot file') - parser.add_argument('--other-formats', nargs='*', default=['pdf'], help='Additional output formats other than .dot') + description="Beautify a .dot file by merging similar edges and replacing labels", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + + parser.add_argument("i", metavar="Input", help="Input .dot file") + parser.add_argument( + "-r", + help="Replacements file with non-empty lines of the default format: old -> new", + ) + parser.add_argument("-o", help="Output .dot file") + + parser.add_argument( + "--disable-shorten-nodes", + default=False, + action="store_true", + help='Disable node name conversion: "sN" -> "N"', + ) + parser.add_argument( + "--start-node-name", default="__start0", help="Name of the hidden starting node" + ) + parser.add_argument( + "--start-edge-label", default="", help="Label of the starting visible edge" + ) + parser.add_argument( + "--replacement-sep", + default=" -> ", + help="Separator of names in replacements file", + ) + + parser.add_argument( + "--same-edges-op", + default="stack", + help="Operation to be performed on same edges, available: stack, merge", + ) + parser.add_argument( + "--stack-sep", + default=r"\l ", + help="Separator of stacked input/output pairs of same edges", + ) + parser.add_argument( + "--merge-input-sep", + default=" | ", + help="Separator of merged inputs with common output", + ) + parser.add_argument( + "--merge-label-sep", + default=r"\l ", + help="Separator of merged labels of same edges", + ) + + parser.add_argument( + "--start-padding", + type=int, + default=1, + help="Left padding of labels (in spaces)", + ) + parser.add_argument( + "--end-padding", type=int, default=5, help="Right padding of labels (in spaces)" + ) + + parser.add_argument( + "--remove-edge-pattern", + help="Remove the edges that have labels of the provided pattern. " + "Format: i_ (match input), o_ (match output), l_ (match label). " + "So the general format is: (i|o|l)_[,(i|o|l)_]*", + ) + + parser.add_argument( + "--set-label-symbol-pattern", + nargs=2, + metavar=("NEW_LABEL_SYMBOL", "PATTERN"), + help="Change the label symbol (which is '/' by default) of the edges that have labels of the provided pattern. " + "Pattern Format: i_ (match input), o_ (match output), l_ (match label). " + "So the general format is: (i|o|l)_[,(i|o|l)_]*", + ) + + parser.add_argument( + "--html-like-labels", + default=False, + action="store_true", + help="Enable html-like syntax in label names. " + "It defaults --stack-sep and --merge-label-sep to '
'. " + "It defaults --end-padding to 1.", + ) + + parser.add_argument( + "--overwrite-dot-input", + default=False, + action="store_true", + help="Overwrite input dot file " + "with the output dot file in case they have the same name", + ) + parser.add_argument( + "--no-dot-output", + default=False, + action="store_true", + help="Do not output the resulting .dot file", + ) + parser.add_argument( + "--other-formats", + nargs="*", + default=["pdf"], + help="Additional output formats other than .dot", + ) args = parser.parse_args() - def set_if_default(var, new, default): return new if var == default else var # check same edges op - if args.same_edges_op not in ['stack', 'merge']: - print(f"Invalid --same-edge-op value '{args.same_edges_op}'. Available: stack, merge.") + if args.same_edges_op not in ["stack", "merge"]: + print( + f"Invalid --same-edge-op value '{args.same_edges_op}'. Available: stack, merge." + ) exit(1) if args.html_like_labels: - args.stack_sep = set_if_default(args.stack_sep, '
', '\l ') - args.merge_label_sep = set_if_default(args.merge_label_sep, '
', '\l ') + args.stack_sep = set_if_default(args.stack_sep, '
', r"\l ") + args.merge_label_sep = set_if_default( + args.merge_label_sep, '
', r"\l " + ) args.end_padding = set_if_default(args.end_padding, 1, 5) # print some visual separators in command line - cmd_line_sep = 100 * '=' + cmd_line_sep = 100 * "=" print(cmd_line_sep) remove_dct = create_pattern_dct(args.remove_edge_pattern) - original_label_symbol_dct = create_pattern_dct_with_label_symbol(args.set_label_symbol_pattern) + original_label_symbol_dct = create_pattern_dct_with_label_symbol( + args.set_label_symbol_pattern + ) replacement_dct = read_replacement_file(args.r, args.replacement_sep) nodes, edge_info_dct, initial_edge, label_symbol_dct = get_info_from_graph( - args.i, not args.disable_shorten_nodes, remove_dct, original_label_symbol_dct, - replacement_dct, args.start_node_name, args.start_edge_label) + args.i, + not args.disable_shorten_nodes, + remove_dct, + original_label_symbol_dct, + replacement_dct, + args.start_node_name, + args.start_edge_label, + ) label_info_dct = { - 'same_edges_op': args.same_edges_op, - 'stack_sep': args.stack_sep, - 'merge_input_sep': args.merge_input_sep, - 'merge_label_sep': args.merge_label_sep, - 'start_padding': args.start_padding * " ", - 'end_padding': args.end_padding * " ", - 'html_like_labels': args.html_like_labels + "same_edges_op": args.same_edges_op, + "stack_sep": args.stack_sep, + "merge_input_sep": args.merge_input_sep, + "merge_label_sep": args.merge_label_sep, + "start_padding": args.start_padding * " ", + "end_padding": args.end_padding * " ", + "html_like_labels": args.html_like_labels, } - new_graph = create_new_graph(nodes, edge_info_dct, initial_edge, label_info_dct, label_symbol_dct) + new_graph = create_new_graph( + nodes, edge_info_dct, initial_edge, label_info_dct, label_symbol_dct + ) - prefix = args.o.replace('.dot', '') if args.o else (args.i.replace('.dot', '') + 'btf') - new_graph_dot_name = prefix + '.dot' - other_format_pairs = [ (prefix + '.' + fmt, fmt) for fmt in args.other_formats ] + prefix = ( + args.o.replace(".dot", "") if args.o else (args.i.replace(".dot", "") + "btf") + ) + new_graph_dot_name = prefix + ".dot" + other_format_pairs = [(prefix + "." + fmt, fmt) for fmt in args.other_formats] print(cmd_line_sep) @@ -412,9 +518,11 @@ def set_if_default(var, new, default): print("Output dot file name coincides with the input dot file name") if not args.overwrite_dot_input: - new_graph_dot_name = new_graph_dot_name.replace('.dot', '') + 'btf.dot' + new_graph_dot_name = new_graph_dot_name.replace(".dot", "") + "btf.dot" print(f"The new output dot file name will be {new_graph_dot_name}") - print("Add --overwrite-dot-input option to overwrite the input dot file") + print( + "Add --overwrite-dot-input option to overwrite the input dot file" + ) else: print("Option --overwrite-dot-input is applicable") print("Input dot file will be overwritten by output dot file") @@ -422,7 +530,9 @@ def set_if_default(var, new, default): print(cmd_line_sep) # alternative without formatting: new_graph.write(new_graph_dot_name, format='raw') - format_and_write_dot_string(new_graph.to_string(), args.start_node_name, new_graph_dot_name) + format_and_write_dot_string( + new_graph.to_string(), args.start_node_name, new_graph_dot_name + ) print(f"Written {new_graph_dot_name}") for graph_name, fmt in other_format_pairs: diff --git a/scripts/beautify_model.sh b/scripts/beautify_model.sh index 1341180e..978931fd 100755 --- a/scripts/beautify_model.sh +++ b/scripts/beautify_model.sh @@ -12,14 +12,15 @@ start_edge_label="" if [[ ${#} = 0 ]]; then echo "Usage: ${0##*/} [-cI|--clientInitiator] [-cR|--clientResponder] dot_model" else - while [[ "${1}" =~ ^- ]]; do case ${1} in - -cI | --clientInitiator ) + while [[ "${1}" =~ ^- ]]; do + case ${1} in + -cI | --clientInitiator) start_edge_label='"TIMEOUT / EDHOC_MESSAGE_1"' ;; - -cR | --clientResponder ) + -cR | --clientResponder) start_edge_label='"TIMEOUT / COAP_EMPTY_MESSAGE"' ;; - * ) + *) echo "Unsupported option ${1}" ;; esac From a605e7ea0acbfb0ddf5b77b9a230ea5e72e2bd61 Mon Sep 17 00:00:00 2001 From: actyp Date: Tue, 2 Jun 2026 21:01:14 -0400 Subject: [PATCH 2/5] Add uv related files --- .python-version | 1 + pyproject.toml | 9 +++++++++ uv.lock | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 .python-version create mode 100644 pyproject.toml create mode 100644 uv.lock diff --git a/.python-version b/.python-version new file mode 100644 index 00000000..24ee5b1b --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.13 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..28946a18 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,9 @@ +[project] +name = "edhoc-fuzzer" +version = "0.0.0" +description = "A protocol state fuzzer of EDHOC clients and servers." +readme = "README.md" +requires-python = ">=3.13" +dependencies = [ + "pydot>=4.0.1", +] diff --git a/uv.lock b/uv.lock new file mode 100644 index 00000000..48235847 --- /dev/null +++ b/uv.lock @@ -0,0 +1,35 @@ +version = 1 +revision = 3 +requires-python = ">=3.13" + +[[package]] +name = "edhoc-fuzzer" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "pydot" }, +] + +[package.metadata] +requires-dist = [{ name = "pydot", specifier = ">=4.0.1" }] + +[[package]] +name = "pydot" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyparsing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/35/b17cb89ff865484c6a20ef46bf9d95a5f07328292578de0b295f4a6beec2/pydot-4.0.1.tar.gz", hash = "sha256:c2148f681c4a33e08bf0e26a9e5f8e4099a82e0e2a068098f32ce86577364ad5", size = 162594, upload-time = "2025-06-17T20:09:56.454Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/32/a7125fb28c4261a627f999d5fb4afff25b523800faed2c30979949d6facd/pydot-4.0.1-py3-none-any.whl", hash = "sha256:869c0efadd2708c0be1f916eb669f3d664ca684bc57ffb7ecc08e70d5e93fee6", size = 37087, upload-time = "2025-06-17T20:09:55.25Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, +] From 5303c1df25f4c122215d21e31f91de3725dc7a34 Mon Sep 17 00:00:00 2001 From: actyp Date: Tue, 2 Jun 2026 21:39:56 -0400 Subject: [PATCH 3/5] Ignore virtual environment --- .gitignore | 1 + pom.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 490cb658..d5fd497c 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ hs_err_pid* # project structure files .idea/ +.venv/ target/ diff --git a/pom.xml b/pom.xml index e6da3753..cbb61bca 100644 --- a/pom.xml +++ b/pom.xml @@ -203,6 +203,7 @@ experiments/models/sources/** target/** + .venv/** From a5c706560957a82ec5a2d02764d482f07be2546b Mon Sep 17 00:00:00 2001 From: actyp Date: Tue, 2 Jun 2026 21:01:39 -0400 Subject: [PATCH 4/5] Update README and beautify_model.sh based on uv --- README.md | 24 +++++++++++++++--------- scripts/beautify_model.sh | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 23f47651..838f1526 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ published in the proceedings of ISSTA 2023. * Java 21 JDK. * maven correctly setup to point to Java 21 JDK. * graphviz library, containing the dot utility, which should be located in the system's PATH. -* python >=3.6 and pydot interface >=1.4.2, in order to use the [beautify_model.sh](scripts/beautify_model.sh) script. +* [uv](https://docs.astral.sh/uv/) to use the [beautify_model.sh](scripts/beautify_model.sh), [beautify_model.py](scripts/beautify_model.py) scripts. * (suggested) make utility, rust and cargo required by the setup of some SULs. * (optional) openssl utility, required by the [gen_auth_hierarchy.sh](scripts/gen_auth_hierarchy.sh) script. @@ -45,14 +45,20 @@ Assuming the commands are executed from the root directory: 1. To check the prerequisites use: ```bash -java -version -mvn -version -dot -V -python3 --version -pip3 show pydot +java --version +mvn --version +dot --version +uv --version ``` -2. To set up EDHOC-Fuzzer use: +2. Setup python virtual environment +```bash +uv sync +``` + +The virtual environment `.venv` should have been created. + +3. To set up EDHOC-Fuzzer use: ```bash ./scripts/setup_fuzzer.sh -l ``` @@ -61,7 +67,7 @@ The fetched source files are deleted after the installation. After the first ins be used without the `-l` flag, in order to rebuild the project. After a successful build, the soft link `edhoc-fuzzer.jar` is created in the root directory. -3. To set up a System Under Learning (SUL) use: +4. To set up a System Under Learning (SUL) use: ```bash ./scripts/setup_sul.sh ``` @@ -172,7 +178,7 @@ the client implementation sends to start the EDHOC protocol. The above script is just a convenient wrapper of the following more customizable script: ```bash -python3 ./scripts/beautify_model.py -h +uv run ./scripts/beautify_model.py -h ``` diff --git a/scripts/beautify_model.sh b/scripts/beautify_model.sh index 978931fd..fbd9339f 100755 --- a/scripts/beautify_model.sh +++ b/scripts/beautify_model.sh @@ -37,5 +37,5 @@ else exit 1 fi - python3 "${PY_SCRIPT}" "${1}" -r "${REPL_FILE}" --start-edge-label "${start_edge_label}" #--remove-edge-pattern "${remove_edge_pattern}" + uv run "${PY_SCRIPT}" "${1}" -r "${REPL_FILE}" --start-edge-label "${start_edge_label}" #--remove-edge-pattern "${remove_edge_pattern}" fi From aa34004cd19971f8ef0ebb0b44f3a5f4855b3923 Mon Sep 17 00:00:00 2001 From: actyp Date: Tue, 2 Jun 2026 21:45:31 -0400 Subject: [PATCH 5/5] Refine and update workflows to setup the virtual environment --- .github/workflows/ci.yml | 166 +++++++++++++++------------ .github/workflows/codespell.yml | 2 +- .github/workflows/concretization.yml | 20 ++-- .github/workflows/shellcheck.yml | 2 +- .github/workflows/spotless.yml | 4 +- 5 files changed, 107 insertions(+), 87 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81443aaf..541206d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,11 +11,13 @@ jobs: - uses: actions/checkout@v6 - uses: actions/setup-java@v5 with: - java-version: '21' - distribution: 'temurin' + java-version: "21" + distribution: "temurin" - uses: ts-graphviz/setup-graphviz@v2 - - name: Install pydot - run: pip3 install pydot + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + + - name: Setup venv + run: uv sync - name: Setup EDHOC-Fuzzer run: ./scripts/setup_fuzzer.sh -l @@ -41,11 +43,13 @@ jobs: - uses: actions/checkout@v6 - uses: actions/setup-java@v5 with: - java-version: '21' - distribution: 'temurin' + java-version: "21" + distribution: "temurin" - uses: ts-graphviz/setup-graphviz@v2 - - name: Install pydot - run: pip3 install pydot + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + + - name: Setup venv + run: uv sync - name: Setup EDHOC-Fuzzer run: ./scripts/setup_fuzzer.sh -l @@ -71,11 +75,13 @@ jobs: - uses: actions/checkout@v6 - uses: actions/setup-java@v5 with: - java-version: '21' - distribution: 'temurin' + java-version: "21" + distribution: "temurin" - uses: ts-graphviz/setup-graphviz@v2 - - name: Install pydot - run: pip3 install pydot + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + + - name: Setup venv + run: uv sync - name: Setup EDHOC-Fuzzer run: ./scripts/setup_fuzzer.sh -l @@ -97,11 +103,13 @@ jobs: - uses: actions/checkout@v6 - uses: actions/setup-java@v5 with: - java-version: '21' - distribution: 'temurin' + java-version: "21" + distribution: "temurin" - uses: ts-graphviz/setup-graphviz@v2 - - name: Install pydot - run: pip3 install pydot + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + + - name: Setup venv + run: uv sync - name: Setup EDHOC-Fuzzer run: ./scripts/setup_fuzzer.sh -l @@ -114,57 +122,61 @@ jobs: java -jar edhoc-fuzzer.jar @experiments/args/rise/server_m4_app -roundLimit 5 ./scripts/diff_hyps.sh experiments/saved_results/servers/rise_m4_app experiments/results/servers/rise_m4_app 5 -# SIFIS-HOME-Client: -# if: ${{ !contains(github.event.head_commit.message, 'ci skip') }} -# runs-on: ubuntu-latest -# strategy: -# fail-fast: true -# steps: -# - uses: actions/checkout@v6 -# - uses: actions/setup-java@v5 -# with: -# java-version: '21' -# distribution: 'temurin' -# - uses: ts-graphviz/setup-graphviz@v2 -# - name: Install pydot -# run: pip3 install pydot -# -# - name: Setup EDHOC-Fuzzer -# run: ./scripts/setup_fuzzer.sh -l -# -# - name: Setup SIFIS-HOME -# run: ./scripts/setup_sul.sh sifis-home -# -# - name: Test SIFIS-HOME Client (phase_1) -# run: | -# java -jar edhoc-fuzzer.jar @experiments/args/sifis-home/client_phase_1 -roundLimit 4 -# ./scripts/diff_hyps.sh experiments/saved_results/clients/sifis-home_phase_1 experiments/results/clients/sifis-home_phase_1 4 -# -# SIFIS-HOME-Server: -# if: ${{ !contains(github.event.head_commit.message, 'ci skip') }} -# runs-on: ubuntu-latest -# strategy: -# fail-fast: true -# steps: -# - uses: actions/checkout@v6 -# - uses: actions/setup-java@v5 -# with: -# java-version: '21' -# distribution: 'temurin' -# - uses: ts-graphviz/setup-graphviz@v2 -# - name: Install pydot -# run: pip3 install pydot -# -# - name: Setup EDHOC-Fuzzer -# run: ./scripts/setup_fuzzer.sh -l -# -# - name: Setup SIFIS-HOME -# run: ./scripts/setup_sul.sh sifis-home -# -# - name: Test SIFIS-HOME Server (phase_1) -# run: | -# java -jar edhoc-fuzzer.jar @experiments/args/sifis-home/server_phase_1 -roundLimit 5 -# ./scripts/diff_hyps.sh experiments/saved_results/servers/sifis-home_phase_1 experiments/results/servers/sifis-home_phase_1 5 + # SIFIS-HOME-Client: + # if: ${{ !contains(github.event.head_commit.message, 'ci skip') }} + # runs-on: ubuntu-latest + # strategy: + # fail-fast: true + # steps: + # - uses: actions/checkout@v6 + # - uses: actions/setup-java@v5 + # with: + # java-version: '21' + # distribution: 'temurin' + # - uses: ts-graphviz/setup-graphviz@v2 + # - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + # + # - name: Setup venv + # run: uv sync + # + # - name: Setup EDHOC-Fuzzer + # run: ./scripts/setup_fuzzer.sh -l + # + # - name: Setup SIFIS-HOME + # run: ./scripts/setup_sul.sh sifis-home + # + # - name: Test SIFIS-HOME Client (phase_1) + # run: | + # java -jar edhoc-fuzzer.jar @experiments/args/sifis-home/client_phase_1 -roundLimit 4 + # ./scripts/diff_hyps.sh experiments/saved_results/clients/sifis-home_phase_1 experiments/results/clients/sifis-home_phase_1 4 + # + # SIFIS-HOME-Server: + # if: ${{ !contains(github.event.head_commit.message, 'ci skip') }} + # runs-on: ubuntu-latest + # strategy: + # fail-fast: true + # steps: + # - uses: actions/checkout@v6 + # - uses: actions/setup-java@v5 + # with: + # java-version: '21' + # distribution: 'temurin' + # - uses: ts-graphviz/setup-graphviz@v2 + # - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + # + # - name: Setup venv + # run: uv sync + # + # - name: Setup EDHOC-Fuzzer + # run: ./scripts/setup_fuzzer.sh -l + # + # - name: Setup SIFIS-HOME + # run: ./scripts/setup_sul.sh sifis-home + # + # - name: Test SIFIS-HOME Server (phase_1) + # run: | + # java -jar edhoc-fuzzer.jar @experiments/args/sifis-home/server_phase_1 -roundLimit 5 + # ./scripts/diff_hyps.sh experiments/saved_results/servers/sifis-home_phase_1 experiments/results/servers/sifis-home_phase_1 5 uOSCORE-uEDHOC-Client: if: ${{ !contains(github.event.head_commit.message, 'ci skip') }} @@ -175,11 +187,13 @@ jobs: - uses: actions/checkout@v6 - uses: actions/setup-java@v5 with: - java-version: '21' - distribution: 'temurin' + java-version: "21" + distribution: "temurin" - uses: ts-graphviz/setup-graphviz@v2 - - name: Install pydot - run: pip3 install pydot + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + + - name: Setup venv + run: uv sync - name: Setup EDHOC-Fuzzer run: ./scripts/setup_fuzzer.sh -l @@ -201,11 +215,13 @@ jobs: - uses: actions/checkout@v6 - uses: actions/setup-java@v5 with: - java-version: '21' - distribution: 'temurin' + java-version: "21" + distribution: "temurin" - uses: ts-graphviz/setup-graphviz@v2 - - name: Install pydot - run: pip3 install pydot + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + + - name: Setup venv + run: uv sync - name: Setup EDHOC-Fuzzer run: ./scripts/setup_fuzzer.sh -l diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index bdcbbfc6..373d5517 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -8,4 +8,4 @@ jobs: - uses: codespell-project/actions-codespell@master with: ignore_words_list: errorprone,keypair,keypairs - skip: '*.patch,*.pdf' + skip: "*.patch,*.pdf" diff --git a/.github/workflows/concretization.yml b/.github/workflows/concretization.yml index c475dfc3..a44af087 100644 --- a/.github/workflows/concretization.yml +++ b/.github/workflows/concretization.yml @@ -11,11 +11,13 @@ jobs: - uses: actions/checkout@v6 - uses: actions/setup-java@v5 with: - java-version: '21' - distribution: 'temurin' + java-version: "21" + distribution: "temurin" - uses: ts-graphviz/setup-graphviz@v2 - - name: Install pydot - run: pip3 install pydot + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + + - name: Setup venv + run: uv sync - name: Setup EDHOC-Fuzzer run: ./scripts/setup_fuzzer.sh -l @@ -42,11 +44,13 @@ jobs: - uses: actions/checkout@v6 - uses: actions/setup-java@v5 with: - java-version: '21' - distribution: 'temurin' + java-version: "21" + distribution: "temurin" - uses: ts-graphviz/setup-graphviz@v2 - - name: Install pydot - run: pip3 install pydot + - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 + + - name: Setup venv + run: uv sync - name: Setup EDHOC-Fuzzer run: ./scripts/setup_fuzzer.sh -l diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index a26e70ae..eee2ac50 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -7,4 +7,4 @@ jobs: - uses: actions/checkout@v6 - uses: ludeeus/action-shellcheck@master with: - scandir: './scripts' + scandir: "./scripts" diff --git a/.github/workflows/spotless.yml b/.github/workflows/spotless.yml index a55c5d7a..9e3e3781 100644 --- a/.github/workflows/spotless.yml +++ b/.github/workflows/spotless.yml @@ -9,7 +9,7 @@ jobs: - name: Set up JDK 21 uses: actions/setup-java@v5 with: - java-version: '21' - distribution: 'temurin' + java-version: "21" + distribution: "temurin" - name: spotlessCheck run: mvn spotless:check