heptagon7 1.0.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 (33) hide show
  1. heptagon7-1.0.0/LICENSE +23 -0
  2. heptagon7-1.0.0/PKG-INFO +124 -0
  3. heptagon7-1.0.0/README.md +104 -0
  4. heptagon7-1.0.0/heptagon/__init__.py +44 -0
  5. heptagon7-1.0.0/heptagon/__main__.py +7 -0
  6. heptagon7-1.0.0/heptagon/audit/__init__.py +0 -0
  7. heptagon7-1.0.0/heptagon/audit/log.py +78 -0
  8. heptagon7-1.0.0/heptagon/audit/signing.py +127 -0
  9. heptagon7-1.0.0/heptagon/cirp/__init__.py +0 -0
  10. heptagon7-1.0.0/heptagon/cirp/model.py +974 -0
  11. heptagon7-1.0.0/heptagon/cirp/yaml_loader.py +148 -0
  12. heptagon7-1.0.0/heptagon/cli/__init__.py +0 -0
  13. heptagon7-1.0.0/heptagon/cli/main.py +395 -0
  14. heptagon7-1.0.0/heptagon/core/__init__.py +0 -0
  15. heptagon7-1.0.0/heptagon/core/symbolic.py +659 -0
  16. heptagon7-1.0.0/heptagon/simulation/__init__.py +1 -0
  17. heptagon7-1.0.0/heptagon/simulation/internal_simulator.py +134 -0
  18. heptagon7-1.0.0/heptagon/simulation/stuxnet_test.py +117 -0
  19. heptagon7-1.0.0/heptagon7.egg-info/PKG-INFO +124 -0
  20. heptagon7-1.0.0/heptagon7.egg-info/SOURCES.txt +31 -0
  21. heptagon7-1.0.0/heptagon7.egg-info/dependency_links.txt +1 -0
  22. heptagon7-1.0.0/heptagon7.egg-info/entry_points.txt +2 -0
  23. heptagon7-1.0.0/heptagon7.egg-info/requires.txt +8 -0
  24. heptagon7-1.0.0/heptagon7.egg-info/top_level.txt +1 -0
  25. heptagon7-1.0.0/pyproject.toml +39 -0
  26. heptagon7-1.0.0/setup.cfg +4 -0
  27. heptagon7-1.0.0/tests/test_cirp_checks.py +384 -0
  28. heptagon7-1.0.0/tests/test_cli.py +107 -0
  29. heptagon7-1.0.0/tests/test_log_and_audit.py +176 -0
  30. heptagon7-1.0.0/tests/test_signing.py +170 -0
  31. heptagon7-1.0.0/tests/test_simulation.py +76 -0
  32. heptagon7-1.0.0/tests/test_symbolic.py +311 -0
  33. heptagon7-1.0.0/tests/test_yaml_loader.py +109 -0
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Muhammad Ali
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: heptagon7
3
+ Version: 1.0.0
4
+ Summary: Seven coordinates. Every incident. Verified.
5
+ Author: Muhammad Ali
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/claythe3ed/heptagon
8
+ Project-URL: Repository, https://github.com/claythe3ed/heptagon
9
+ Requires-Python: >=3.11
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: numpy>=2.0
13
+ Requires-Dist: PyYAML>=6.0
14
+ Requires-Dist: jsonschema>=4.0
15
+ Requires-Dist: PyNaCl>=1.5
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest>=8.0; extra == "dev"
18
+ Requires-Dist: pytest-cov>=6.0; extra == "dev"
19
+ Dynamic: license-file
20
+
21
+ # Heptagon
22
+
23
+ **Seven coordinates. Every incident. Verified.**
24
+
25
+ A symbolic, formal, and executable framework for cybersecurity
26
+ incident response planning and management.
27
+
28
+ ## What it does
29
+
30
+ Heptagon treats every incident record as a seven-coordinate object.
31
+ An incident without a timestamp, rationale, effect, or lineage is
32
+ not a complete record — and an incomplete record cannot be certified
33
+ as truthful.
34
+
35
+ The framework:
36
+
37
+ 1. **Declares** a Cyber Incident Response Plan in code
38
+ 2. **Verifies** plan completeness against six compliance gates
39
+ 3. **Simulates** scenario escalations through the reporting DAG
40
+ 4. **Logs** incidents with tamper-evident evidence and decisions
41
+ 5. **Audits** every record for 7D coordinate coverage
42
+ 6. **Rejects** incomplete records with specific, actionable reasons
43
+
44
+ ## The seven coordinates
45
+
46
+ | Coordinate | Name | Meaning |
47
+ |---|---|---|
48
+ | **B** | Spacetime | Timestamp + origin |
49
+ | **F5** | Intention | Why the actor acted |
50
+ | **F6** | Effect | What changed downstream |
51
+ | **F7** | Lineage | Position in the reporting chain |
52
+
53
+ A complete record populates all seven. The `check_7d_completeness()`
54
+ gate enforces this on every logged evidence and decision.
55
+
56
+ ## Install
57
+
58
+ pip install heptagon7
59
+
60
+ The PyPI project is named **heptagon7** — the name `heptagon` was
61
+ already taken on PyPI. After installing, the Python import and the
62
+ CLI command are both `heptagon`:
63
+
64
+ import heptagon # library
65
+ heptagon --help # CLI
66
+
67
+ For local development:
68
+
69
+ python3 -m venv .venv
70
+ source .venv/bin/activate
71
+ pip install -e .
72
+
73
+ ## Quick start
74
+
75
+ python -m heptagon.cirp.model # reference CIRP demo
76
+ python -m heptagon.core.symbolic # symbolic layer demo
77
+ python -m heptagon.simulation.stuxnet_test # historical validation
78
+ python -m pytest tests/ -v # full test suite
79
+
80
+ ## The six compliance gates
81
+
82
+ `CIRPModel.verify_all()` runs:
83
+
84
+ 1. `check_teams_complete` — all 5 R-C-C-P-T roles present and complete
85
+ 2. `check_reporting_chain` — every reporter can reach an executive
86
+ 3. `check_evidence_completeness`— unique hashes, no dangling refs, chronology valid
87
+ 4. `check_no_hidden_thing` — every source's slice reconciles with the global log
88
+ 5. `check_break_glass_logged` — every emergency override is marked AND evidenced
89
+ 6. `check_7d_completeness` — every record populates all seven coordinates
90
+
91
+ ## Architecture
92
+
93
+ heptagon/
94
+ core/ Symbolic layer (bundle, sheaf, lineage, operators)
95
+ cirp/ CIRP primitives + compliance checks + tabletop
96
+ simulation/ Deterministic agent-based simulator
97
+ audit/ (future) signature verification, reporting
98
+
99
+ ## Honest limits
100
+
101
+ - **Assumes honest actors.** This tool catches accidental omission,
102
+ not adversarial falsification. Signatures are content hashes, not
103
+ PKI signatures. A v1 threat model will address the malicious case.
104
+ - **Does not replace human judgment.** It verifies that decisions are
105
+ logged, not that they are wise.
106
+ - **Does not certify compliance.** It reports whether a plan is
107
+ internally consistent, not whether it meets any specific regulation.
108
+ - **Not production-ready before v1.0.** The API may change.
109
+
110
+ ## History
111
+
112
+ The framework's design traces to a symbolic model of comprehensive
113
+ presentation (al-'ard fi fada' al-shumul). The mathematics is a
114
+ language for meaning, not a claim about physics. See `docs/PHILOSOPHY.md`
115
+ (future) for the full derivation.
116
+
117
+ ## License
118
+
119
+ MIT. See `LICENSE`.
120
+
121
+ ## Status
122
+
123
+ **v0.1.0** — Audit-closed. All twelve originally identified issues
124
+ resolved or retracted. 58 tests passing.
@@ -0,0 +1,104 @@
1
+ # Heptagon
2
+
3
+ **Seven coordinates. Every incident. Verified.**
4
+
5
+ A symbolic, formal, and executable framework for cybersecurity
6
+ incident response planning and management.
7
+
8
+ ## What it does
9
+
10
+ Heptagon treats every incident record as a seven-coordinate object.
11
+ An incident without a timestamp, rationale, effect, or lineage is
12
+ not a complete record — and an incomplete record cannot be certified
13
+ as truthful.
14
+
15
+ The framework:
16
+
17
+ 1. **Declares** a Cyber Incident Response Plan in code
18
+ 2. **Verifies** plan completeness against six compliance gates
19
+ 3. **Simulates** scenario escalations through the reporting DAG
20
+ 4. **Logs** incidents with tamper-evident evidence and decisions
21
+ 5. **Audits** every record for 7D coordinate coverage
22
+ 6. **Rejects** incomplete records with specific, actionable reasons
23
+
24
+ ## The seven coordinates
25
+
26
+ | Coordinate | Name | Meaning |
27
+ |---|---|---|
28
+ | **B** | Spacetime | Timestamp + origin |
29
+ | **F5** | Intention | Why the actor acted |
30
+ | **F6** | Effect | What changed downstream |
31
+ | **F7** | Lineage | Position in the reporting chain |
32
+
33
+ A complete record populates all seven. The `check_7d_completeness()`
34
+ gate enforces this on every logged evidence and decision.
35
+
36
+ ## Install
37
+
38
+ pip install heptagon7
39
+
40
+ The PyPI project is named **heptagon7** — the name `heptagon` was
41
+ already taken on PyPI. After installing, the Python import and the
42
+ CLI command are both `heptagon`:
43
+
44
+ import heptagon # library
45
+ heptagon --help # CLI
46
+
47
+ For local development:
48
+
49
+ python3 -m venv .venv
50
+ source .venv/bin/activate
51
+ pip install -e .
52
+
53
+ ## Quick start
54
+
55
+ python -m heptagon.cirp.model # reference CIRP demo
56
+ python -m heptagon.core.symbolic # symbolic layer demo
57
+ python -m heptagon.simulation.stuxnet_test # historical validation
58
+ python -m pytest tests/ -v # full test suite
59
+
60
+ ## The six compliance gates
61
+
62
+ `CIRPModel.verify_all()` runs:
63
+
64
+ 1. `check_teams_complete` — all 5 R-C-C-P-T roles present and complete
65
+ 2. `check_reporting_chain` — every reporter can reach an executive
66
+ 3. `check_evidence_completeness`— unique hashes, no dangling refs, chronology valid
67
+ 4. `check_no_hidden_thing` — every source's slice reconciles with the global log
68
+ 5. `check_break_glass_logged` — every emergency override is marked AND evidenced
69
+ 6. `check_7d_completeness` — every record populates all seven coordinates
70
+
71
+ ## Architecture
72
+
73
+ heptagon/
74
+ core/ Symbolic layer (bundle, sheaf, lineage, operators)
75
+ cirp/ CIRP primitives + compliance checks + tabletop
76
+ simulation/ Deterministic agent-based simulator
77
+ audit/ (future) signature verification, reporting
78
+
79
+ ## Honest limits
80
+
81
+ - **Assumes honest actors.** This tool catches accidental omission,
82
+ not adversarial falsification. Signatures are content hashes, not
83
+ PKI signatures. A v1 threat model will address the malicious case.
84
+ - **Does not replace human judgment.** It verifies that decisions are
85
+ logged, not that they are wise.
86
+ - **Does not certify compliance.** It reports whether a plan is
87
+ internally consistent, not whether it meets any specific regulation.
88
+ - **Not production-ready before v1.0.** The API may change.
89
+
90
+ ## History
91
+
92
+ The framework's design traces to a symbolic model of comprehensive
93
+ presentation (al-'ard fi fada' al-shumul). The mathematics is a
94
+ language for meaning, not a claim about physics. See `docs/PHILOSOPHY.md`
95
+ (future) for the full derivation.
96
+
97
+ ## License
98
+
99
+ MIT. See `LICENSE`.
100
+
101
+ ## Status
102
+
103
+ **v0.1.0** — Audit-closed. All twelve originally identified issues
104
+ resolved or retracted. 58 tests passing.
@@ -0,0 +1,44 @@
1
+ """
2
+ Heptagon — Seven coordinates. Every incident. Verified.
3
+
4
+ A symbolic, formal, and executable framework for cybersecurity
5
+ incident response planning and management.
6
+ """
7
+ __version__ = "1.0.0"
8
+
9
+ from heptagon.core.symbolic import (
10
+ FiberBundle7D,
11
+ MoralSheaf,
12
+ Lineage,
13
+ PresentationOperator,
14
+ TestimonyOperator,
15
+ MoralJacobians,
16
+ UnifiedEvaluation,
17
+ IncidentResponsePipeline,
18
+ )
19
+
20
+ from heptagon.cirp.model import (
21
+ CIRPModel,
22
+ Team,
23
+ Stakeholder,
24
+ Scenario,
25
+ Evidence,
26
+ Decision,
27
+ )
28
+
29
+ __all__ = [
30
+ "FiberBundle7D",
31
+ "MoralSheaf",
32
+ "Lineage",
33
+ "PresentationOperator",
34
+ "TestimonyOperator",
35
+ "MoralJacobians",
36
+ "UnifiedEvaluation",
37
+ "IncidentResponsePipeline",
38
+ "CIRPModel",
39
+ "Team",
40
+ "Stakeholder",
41
+ "Scenario",
42
+ "Evidence",
43
+ "Decision",
44
+ ]
@@ -0,0 +1,7 @@
1
+ """Entry point for ``python -m heptagon``."""
2
+ import sys
3
+
4
+ from heptagon.cli.main import main
5
+
6
+ if __name__ == "__main__":
7
+ sys.exit(main())
File without changes
@@ -0,0 +1,78 @@
1
+ """
2
+ log.py
3
+ ======
4
+
5
+ Read and write incident logs.
6
+
7
+ An incident log is a JSONL file. Each line is one JSON object of
8
+ the form::
9
+
10
+ {"type": "evidence", "data": { ... Evidence fields ... }}
11
+ {"type": "decision", "data": { ... Decision fields ... }}
12
+
13
+ Records are stored in insertion order. Append-only semantics are
14
+ recommended: never rewrite a log once written, only append to it.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import json
20
+ from dataclasses import dataclass, field
21
+ from pathlib import Path
22
+ from typing import List, Union
23
+
24
+ from heptagon.cirp.model import Decision, Evidence
25
+
26
+
27
+ @dataclass
28
+ class IncidentLog:
29
+ """An ordered collection of evidence and decisions."""
30
+ evidence: List[Evidence] = field(default_factory=list)
31
+ decisions: List[Decision] = field(default_factory=list)
32
+
33
+ def append_evidence(self, ev: Evidence) -> None:
34
+ self.evidence.append(ev)
35
+
36
+ def append_decision(self, d: Decision) -> None:
37
+ self.decisions.append(d)
38
+
39
+ def to_jsonl(self) -> str:
40
+ lines: List[str] = []
41
+ for ev in self.evidence:
42
+ lines.append(json.dumps({"type": "evidence", "data": ev.to_dict()}))
43
+ for d in self.decisions:
44
+ lines.append(json.dumps({"type": "decision", "data": d.to_dict()}))
45
+ return "\n".join(lines) + "\n"
46
+
47
+ @classmethod
48
+ def from_jsonl(cls, text: str) -> "IncidentLog":
49
+ log = cls()
50
+ for lineno, raw in enumerate(text.splitlines(), start=1):
51
+ stripped = raw.strip()
52
+ if not stripped:
53
+ continue
54
+ try:
55
+ record = json.loads(stripped)
56
+ except json.JSONDecodeError as e:
57
+ raise ValueError(f"line {lineno}: invalid JSON: {e}") from e
58
+ rtype = record.get("type")
59
+ data = record.get("data", {})
60
+ if rtype == "evidence":
61
+ log.evidence.append(Evidence.from_dict(data))
62
+ elif rtype == "decision":
63
+ log.decisions.append(Decision.from_dict(data))
64
+ else:
65
+ raise ValueError(
66
+ f"line {lineno}: unknown record type {rtype!r}"
67
+ )
68
+ return log
69
+
70
+
71
+ def save_log(log: IncidentLog, path: Union[str, Path]) -> None:
72
+ """Write an IncidentLog to a JSONL file."""
73
+ Path(path).write_text(log.to_jsonl(), encoding="utf-8")
74
+
75
+
76
+ def load_log(path: Union[str, Path]) -> IncidentLog:
77
+ """Read an IncidentLog from a JSONL file."""
78
+ return IncidentLog.from_jsonl(Path(path).read_text(encoding="utf-8"))
@@ -0,0 +1,127 @@
1
+ """
2
+ signing.py
3
+ ==========
4
+
5
+ Ed25519 signing for incident-response records.
6
+
7
+ Provides a ``Signer`` class that wraps a private/public keypair and
8
+ signs canonical byte representations of Decision records.
9
+
10
+ Key storage format
11
+ ------------------
12
+ A signer is serialized as JSON:
13
+
14
+ {
15
+ "algorithm": "ed25519",
16
+ "private_key_hex": "...",
17
+ "public_key_hex": "...",
18
+ "created_utc": "2026-10-10T20:35:00+00:00"
19
+ }
20
+
21
+ The private key should be stored with strict filesystem permissions
22
+ (0600). The public key can be shared freely — it is the identifier
23
+ used to verify signed records.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import json
29
+ import os
30
+ from dataclasses import dataclass
31
+ from datetime import datetime, timezone
32
+ from pathlib import Path
33
+ from typing import Optional, Union
34
+
35
+ from nacl import signing as ed25519
36
+ from nacl.exceptions import BadSignatureError
37
+
38
+
39
+ ALGORITHM_NAME = "ed25519"
40
+
41
+
42
+ @dataclass
43
+ class Signer:
44
+ """An Ed25519 keypair capable of signing and verifying records."""
45
+ private_key_bytes: bytes
46
+ public_key_bytes: bytes
47
+ created_utc: str = ""
48
+
49
+ # ------------------------------------------------------------------
50
+ # Construction
51
+ # ------------------------------------------------------------------
52
+
53
+ @classmethod
54
+ def generate(cls) -> "Signer":
55
+ """Generate a fresh random keypair."""
56
+ vk = ed25519.SigningKey.generate()
57
+ sk_bytes = bytes(vk)
58
+ pk_bytes = bytes(vk.verify_key)
59
+ return cls(
60
+ private_key_bytes=sk_bytes,
61
+ public_key_bytes=pk_bytes,
62
+ created_utc=datetime.now(timezone.utc).isoformat(),
63
+ )
64
+
65
+ # ------------------------------------------------------------------
66
+ # Persistence
67
+ # ------------------------------------------------------------------
68
+
69
+ def save(self, path: Union[str, Path]) -> None:
70
+ """Write the keypair to a JSON file with 0600 permissions."""
71
+ p = Path(path)
72
+ payload = {
73
+ "algorithm": ALGORITHM_NAME,
74
+ "private_key_hex": self.private_key_bytes.hex(),
75
+ "public_key_hex": self.public_key_bytes.hex(),
76
+ "created_utc": self.created_utc,
77
+ }
78
+ p.write_text(json.dumps(payload, indent=2), encoding="utf-8")
79
+ # Lock permissions down
80
+ try:
81
+ os.chmod(p, 0o600)
82
+ except OSError:
83
+ pass
84
+
85
+ @classmethod
86
+ def load(cls, path: Union[str, Path]) -> "Signer":
87
+ """Load a keypair from a JSON file."""
88
+ p = Path(path)
89
+ data = json.loads(p.read_text(encoding="utf-8"))
90
+ if data.get("algorithm") != ALGORITHM_NAME:
91
+ raise ValueError(
92
+ f"unsupported algorithm: {data.get('algorithm')}"
93
+ )
94
+ return cls(
95
+ private_key_bytes=bytes.fromhex(data["private_key_hex"]),
96
+ public_key_bytes=bytes.fromhex(data["public_key_hex"]),
97
+ created_utc=data.get("created_utc", ""),
98
+ )
99
+
100
+ # ------------------------------------------------------------------
101
+ # Sign / verify
102
+ # ------------------------------------------------------------------
103
+
104
+ @property
105
+ def public_key_hex(self) -> str:
106
+ return self.public_key_bytes.hex()
107
+
108
+ def sign(self, payload: bytes) -> bytes:
109
+ """Sign raw bytes. Returns the 64-byte signature."""
110
+ vk = ed25519.SigningKey(self.private_key_bytes)
111
+ # PyNaCl's SigningKey.sign() returns a SignedMessage container
112
+ # (signature + original message). Extract only the signature.
113
+ return vk.sign(payload).signature
114
+
115
+ @staticmethod
116
+ def verify(
117
+ public_key_bytes: bytes,
118
+ payload: bytes,
119
+ signature_bytes: bytes,
120
+ ) -> bool:
121
+ """Verify a signature against a payload and public key."""
122
+ try:
123
+ vk = ed25519.VerifyKey(public_key_bytes)
124
+ vk.verify(payload, signature_bytes)
125
+ return True
126
+ except (BadSignatureError, Exception):
127
+ return False
File without changes