certgraph 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. {certgraph-0.2.0 → certgraph-0.3.0}/PKG-INFO +1 -1
  2. {certgraph-0.2.0 → certgraph-0.3.0}/pyproject.toml +1 -1
  3. {certgraph-0.2.0 → certgraph-0.3.0}/src/certgraph/certgraph.py +16 -14
  4. {certgraph-0.2.0 → certgraph-0.3.0}/src/certgraph.egg-info/PKG-INFO +1 -1
  5. certgraph-0.3.0/tests/test_export_dot.py +54 -0
  6. certgraph-0.2.0/tests/test_export_dot.py +0 -9
  7. {certgraph-0.2.0 → certgraph-0.3.0}/LICENSE +0 -0
  8. {certgraph-0.2.0 → certgraph-0.3.0}/README.md +0 -0
  9. {certgraph-0.2.0 → certgraph-0.3.0}/setup.cfg +0 -0
  10. {certgraph-0.2.0 → certgraph-0.3.0}/src/certgraph/__init__.py +0 -0
  11. {certgraph-0.2.0 → certgraph-0.3.0}/src/certgraph.egg-info/SOURCES.txt +0 -0
  12. {certgraph-0.2.0 → certgraph-0.3.0}/src/certgraph.egg-info/dependency_links.txt +0 -0
  13. {certgraph-0.2.0 → certgraph-0.3.0}/src/certgraph.egg-info/requires.txt +0 -0
  14. {certgraph-0.2.0 → certgraph-0.3.0}/src/certgraph.egg-info/top_level.txt +0 -0
  15. {certgraph-0.2.0 → certgraph-0.3.0}/tests/test_clear.py +0 -0
  16. {certgraph-0.2.0 → certgraph-0.3.0}/tests/test_fingerprint_search.py +0 -0
  17. {certgraph-0.2.0 → certgraph-0.3.0}/tests/test_get_certificate.py +0 -0
  18. {certgraph-0.2.0 → certgraph-0.3.0}/tests/test_get_child_fingerprints.py +0 -0
  19. {certgraph-0.2.0 → certgraph-0.3.0}/tests/test_get_issuer_fingerprint.py +0 -0
  20. {certgraph-0.2.0 → certgraph-0.3.0}/tests/test_graph.py +0 -0
  21. {certgraph-0.2.0 → certgraph-0.3.0}/tests/test_import_certificates.py +0 -0
  22. {certgraph-0.2.0 → certgraph-0.3.0}/tests/test_remove_certificate.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: certgraph
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Utility for exploring and mapping X509 certificate chains.
5
5
  Author: Chris Adshead
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "certgraph"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Utility for exploring and mapping X509 certificate chains."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -5,7 +5,7 @@ from rapidfuzz import fuzz
5
5
 
6
6
 
7
7
  class certgraph:
8
- """Class for creating and exploring directed graphs of X509 certificates."""
8
+ """Class for creating and exploring directed graphs of X.509 certificates."""
9
9
 
10
10
  def __init__(self) -> None:
11
11
  """Initialise an empty certgraph object."""
@@ -88,25 +88,27 @@ class certgraph:
88
88
  """
89
89
  return [f"{edge[0][:8]} -> {edge[1][:8]}" for edge in self._graph.edges()]
90
90
 
91
- def export_dot(self, format: str = "svg") -> str:
92
- """Function to export the current certificate digraph in the dot language. NOTE: Still in progress."""
93
- allowed_types = ["svg", "png"]
94
-
95
- if format not in allowed_types:
96
- raise ValueError(
97
- f"Cannot export dot graph of type {format} - must be one of {allowed_types}"
98
- )
91
+ def export_dot(self) -> str:
92
+ """
93
+ Export the current certificate digraph in the dot language.
99
94
 
95
+ Returns:
96
+ The certificate digraph rendered as a dot language string.
97
+ """
100
98
  dot_graph = nx.DiGraph()
101
99
 
102
100
  for fingerprint, data in self._graph.nodes(data=True):
103
- label = data["certificate"].subject.rfc4514_string()
104
- dot_graph.add_node(fingerprint, label=label)
105
- dot_graph.add_edges_from(self._graph.edges())
101
+ cert: x509.Certificate = data["certificate"]
102
+ validity_time_str = f"{cert.not_valid_before_utc.isoformat()} → {cert.not_valid_after_utc.isoformat()}"
103
+
104
+ label = f"DN: {cert.subject.rfc4514_string()}"
105
+ label += f"\nValid: {validity_time_str}"
106
106
 
107
- nx.drawing.nx_pydot.write_dot(dot_graph, "./test_out.dot")
107
+ dot_graph.add_node(fingerprint, label=label, shape="box")
108
+
109
+ dot_graph.add_edges_from(self._graph.edges())
108
110
 
109
- return "dot"
111
+ return nx.drawing.nx_pydot.to_pydot(dot_graph).to_string()
110
112
 
111
113
  def clear(self) -> certgraph:
112
114
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: certgraph
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Utility for exploring and mapping X509 certificate chains.
5
5
  Author: Chris Adshead
6
6
  License: MIT License
@@ -0,0 +1,54 @@
1
+ def test_export_dot_returns_string(graph):
2
+ assert isinstance(graph.export_dot(), str)
3
+
4
+
5
+ def test_export_dot_empty_graph_has_no_edges(graph):
6
+ dot = graph.export_dot()
7
+ assert "digraph" in dot
8
+ assert "->" not in dot
9
+
10
+
11
+ def test_export_dot_includes_node_labels(graph, self_signed_cert):
12
+ graph.import_certificates(self_signed_cert)
13
+ dn = self_signed_cert.subject.rfc4514_string()
14
+
15
+ dot = graph.export_dot()
16
+
17
+ assert f"DN: {dn}" in dot
18
+
19
+
20
+ def test_export_dot_includes_validity_period(graph, self_signed_cert):
21
+ graph.import_certificates(self_signed_cert)
22
+ not_before = self_signed_cert.not_valid_before_utc.isoformat()
23
+ not_after = self_signed_cert.not_valid_after_utc.isoformat()
24
+
25
+ dot = graph.export_dot()
26
+
27
+ # joined with an arrow character rather than '->', to avoid being confused with edge syntax
28
+ assert f"Valid: {not_before} → {not_after}" in dot
29
+
30
+
31
+ def test_export_dot_node_shape_is_box(graph, self_signed_cert):
32
+ graph.import_certificates(self_signed_cert)
33
+
34
+ dot = graph.export_dot()
35
+
36
+ assert "shape=box" in dot
37
+
38
+
39
+ def test_export_dot_includes_edges(graph, chain_certs):
40
+ graph.import_certificates(chain_certs)
41
+
42
+ dot = graph.export_dot()
43
+
44
+ # one self-loop for the root, plus one edge per subsequent certificate
45
+ assert dot.count("->") == len(chain_certs)
46
+
47
+
48
+ def test_export_dot_does_not_write_file(graph, self_signed_cert, tmp_path, monkeypatch):
49
+ monkeypatch.chdir(tmp_path)
50
+ graph.import_certificates(self_signed_cert)
51
+
52
+ graph.export_dot()
53
+
54
+ assert not (tmp_path / "test_out.dot").exists()
@@ -1,9 +0,0 @@
1
- import pytest
2
-
3
- # export_dot()'s actual output generation is still rough and not covered here.
4
- # Only the argument validation, which happens before anything is written, is tested.
5
-
6
-
7
- def test_export_dot_rejects_invalid_format(graph):
8
- with pytest.raises(ValueError):
9
- graph.export_dot(format="jpeg")
File without changes
File without changes
File without changes
File without changes
File without changes