cortexm 0.3.0__py3-none-any.whl

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 (120) hide show
  1. context_m.py +17 -0
  2. cortexm/__init__.py +45 -0
  3. cortexm/accel.py +403 -0
  4. cortexm/api/__init__.py +0 -0
  5. cortexm/api/chaos.py +118 -0
  6. cortexm/api/memory.py +635 -0
  7. cortexm/bench/__init__.py +0 -0
  8. cortexm/bench/abilities.py +311 -0
  9. cortexm/bench/baselines.py +89 -0
  10. cortexm/bench/beam_loader.py +317 -0
  11. cortexm/bench/generator.py +376 -0
  12. cortexm/bench/harness.py +211 -0
  13. cortexm/bench/messy.py +218 -0
  14. cortexm/bench/micro.py +251 -0
  15. cortexm/bench/ood.py +443 -0
  16. cortexm/bench/run.py +137 -0
  17. cortexm/bridge/__init__.py +0 -0
  18. cortexm/bridge/dates.py +178 -0
  19. cortexm/bridge/decoders.py +204 -0
  20. cortexm/bridge/enrich.py +255 -0
  21. cortexm/bridge/extractor.py +316 -0
  22. cortexm/bridge/fallback.py +332 -0
  23. cortexm/bridge/onnx_runtime.py +158 -0
  24. cortexm/bridge/patterns.py +760 -0
  25. cortexm/bridge/ppr.py +104 -0
  26. cortexm/bridge/prefilter.py +188 -0
  27. cortexm/bridge/query_extract.py +420 -0
  28. cortexm/bridge/reader.py +1174 -0
  29. cortexm/bridge/rerank.py +204 -0
  30. cortexm/bridge/writer.py +492 -0
  31. cortexm/cli.py +295 -0
  32. cortexm/cognition/__init__.py +53 -0
  33. cortexm/cognition/abstraction.py +192 -0
  34. cortexm/cognition/analogy.py +159 -0
  35. cortexm/cognition/engine.py +204 -0
  36. cortexm/cognition/gaps.py +365 -0
  37. cortexm/cognition/scanner.py +204 -0
  38. cortexm/config.py +375 -0
  39. cortexm/cortexm.py +8 -0
  40. cortexm/enterprise/__init__.py +0 -0
  41. cortexm/enterprise/audit.py +178 -0
  42. cortexm/enterprise/governance.py +239 -0
  43. cortexm/errors.py +35 -0
  44. cortexm/features/__init__.py +0 -0
  45. cortexm/features/git.py +204 -0
  46. cortexm/features/prefetch.py +88 -0
  47. cortexm/features/zk.py +105 -0
  48. cortexm/federation/__init__.py +39 -0
  49. cortexm/federation/crdt.py +275 -0
  50. cortexm/federation/fabric.py +109 -0
  51. cortexm/federation/hlc.py +80 -0
  52. cortexm/federation/node.py +145 -0
  53. cortexm/federation/schema_report.py +73 -0
  54. cortexm/federation/transport.py +164 -0
  55. cortexm/index/__init__.py +19 -0
  56. cortexm/index/nsg.py +386 -0
  57. cortexm/mcp/__init__.py +0 -0
  58. cortexm/mcp/server.py +985 -0
  59. cortexm/metrics.py +62 -0
  60. cortexm/migrate/__init__.py +0 -0
  61. cortexm/migrate/importers.py +192 -0
  62. cortexm/provenance/__init__.py +78 -0
  63. cortexm/provenance/agent.py +214 -0
  64. cortexm/provenance/cose.py +201 -0
  65. cortexm/provenance/scitt.py +258 -0
  66. cortexm/provenance/vc.py +250 -0
  67. cortexm/security/__init__.py +0 -0
  68. cortexm/security/crypto.py +162 -0
  69. cortexm/security/hashes.py +140 -0
  70. cortexm/security/injection.py +149 -0
  71. cortexm/security/mind.py +154 -0
  72. cortexm/security/pii.py +265 -0
  73. cortexm/security/rbac.py +169 -0
  74. cortexm/security/sandbox.py +131 -0
  75. cortexm/security/zk_hamming.py +142 -0
  76. cortexm/security/zk_sql.py +485 -0
  77. cortexm/server/__init__.py +0 -0
  78. cortexm/server/metrics.py +88 -0
  79. cortexm/server/rest.py +936 -0
  80. cortexm/server/sparql.py +984 -0
  81. cortexm/text/__init__.py +0 -0
  82. cortexm/text/dissim.py +252 -0
  83. cortexm/text/embedder.py +155 -0
  84. cortexm/text/fuzzy.py +218 -0
  85. cortexm/text/idiolect.py +253 -0
  86. cortexm/text/labse.py +374 -0
  87. cortexm/text/tokenizer.py +79 -0
  88. cortexm/trace/__init__.py +0 -0
  89. cortexm/trace/blob_arena.py +277 -0
  90. cortexm/trace/consolidate.py +337 -0
  91. cortexm/trace/contradictions.py +69 -0
  92. cortexm/trace/dedup.py +114 -0
  93. cortexm/trace/edges.py +214 -0
  94. cortexm/trace/fact.py +121 -0
  95. cortexm/trace/fade.py +245 -0
  96. cortexm/trace/lifecycle.py +112 -0
  97. cortexm/trace/rebuild.py +173 -0
  98. cortexm/trace/rules.py +171 -0
  99. cortexm/trace/store.py +680 -0
  100. cortexm/trace/structural.py +183 -0
  101. cortexm/trace/tmt.py +335 -0
  102. cortexm/util.py +148 -0
  103. cortexm/vsa/__init__.py +0 -0
  104. cortexm/vsa/attribution.py +149 -0
  105. cortexm/vsa/cleanup.py +161 -0
  106. cortexm/vsa/codecs.py +397 -0
  107. cortexm/vsa/hologram_overlay.py +139 -0
  108. cortexm/vsa/index.py +163 -0
  109. cortexm/vsa/ops.py +149 -0
  110. cortexm/vsa/palace.py +446 -0
  111. cortexm/vsa/role_vectors.py +236 -0
  112. cortexm/vsa/slb.py +78 -0
  113. cortexm/vsa/tlsh_trie.py +137 -0
  114. cortexm/vsa/working_memory.py +249 -0
  115. cortexm-0.3.0.dist-info/METADATA +482 -0
  116. cortexm-0.3.0.dist-info/RECORD +120 -0
  117. cortexm-0.3.0.dist-info/WHEEL +5 -0
  118. cortexm-0.3.0.dist-info/entry_points.txt +2 -0
  119. cortexm-0.3.0.dist-info/licenses/LICENSE +190 -0
  120. cortexm-0.3.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,201 @@
1
+ """COSE Sign1 envelopes (RFC 9052) for memory commits.
2
+
3
+ Every memory commit gets wrapped in a COSE Sign1 envelope signed with
4
+ the agent's Ed25519 key. External verifiers can confirm the commit came
5
+ from a known agent without trusting the host's audit log.
6
+
7
+ The COSE Sign1 structure (per RFC 9052 §4.1):
8
+
9
+ [
10
+ protected: bstr .cbor {1: -8, "alg": "EdDSA"}, // header
11
+ unprotected: {}, // empty
12
+ payload: bstr, // commit hash + metadata
13
+ signature: bstr // Ed25519 sig
14
+ ]
15
+
16
+ We serialize as JSON (CBOR is the spec-preferred format, but JSON works
17
+ for the prototype and is easier to inspect).
18
+
19
+ Payload format (JSON object, base64url-encoded as a bstr):
20
+ {
21
+ "commit_id": "...", // Trace commit ID
22
+ "chain_hash": "...", // BLAKE3 chain hash from the commit
23
+ "n_facts": int, // number of facts in the commit
24
+ "ts": "...", // ISO timestamp
25
+ "agent_did": "did:key:..." // agent identifier
26
+ }
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import base64
32
+ import hashlib
33
+ import json
34
+ from dataclasses import dataclass, field
35
+ from datetime import datetime, timezone
36
+ from typing import Any
37
+
38
+ from cortexm.provenance.agent import Ed25519AgentKey, get_default_agent
39
+
40
+
41
+ def _b64url(b: bytes) -> str:
42
+ return base64.urlsafe_b64encode(b).decode("ascii").rstrip("=")
43
+
44
+
45
+ def _b64url_decode(s: str) -> bytes:
46
+ pad = "=" * (-len(s) % 4)
47
+ return base64.urlsafe_b64decode(s + pad)
48
+
49
+
50
+ @dataclass
51
+ class CoseSign1Envelope:
52
+ """A COSE Sign1 envelope (RFC 9052) wrapping a memory commit."""
53
+ protected: dict # protected header (e.g. {"alg": "EdDSA"})
54
+ payload: dict # decoded payload (commit metadata)
55
+ signature: str = "" # base64url-encoded signature
56
+ agent_did: str = "" # did:key of the signing agent
57
+ ts: str = "" # ISO timestamp when signed
58
+ raw_b64: str = "" # the full envelope, base64url-encoded
59
+
60
+ def to_dict(self) -> dict:
61
+ return {
62
+ "protected": self.protected,
63
+ "payload": self.payload,
64
+ "signature": self.signature,
65
+ "agent_did": self.agent_did,
66
+ "ts": self.ts,
67
+ }
68
+
69
+ def to_json(self) -> str:
70
+ """JSON serialization of the envelope."""
71
+ return json.dumps(self.to_dict(), sort_keys=True, indent=2)
72
+
73
+
74
+ def sign_commit(commit_id: str, chain_hash: str, n_facts: int,
75
+ agent: Ed25519AgentKey | None = None,
76
+ extra_payload: dict | None = None) -> CoseSign1Envelope:
77
+ """Sign a memory commit with an Ed25519 agent key.
78
+
79
+ Args:
80
+ commit_id: Trace commit ID (hex string)
81
+ chain_hash: BLAKE3 chain hash from the commit
82
+ n_facts: number of facts in the commit
83
+ agent: agent key to sign with. If None, uses the default agent
84
+ (auto-generated on first call; persisted if Config.
85
+ provenance_agent_key_path is set).
86
+ extra_payload: additional fields to include in the payload
87
+ (e.g. user_id, branch, message).
88
+
89
+ Returns:
90
+ CoseSign1Envelope with the signature + payload + protected header.
91
+ """
92
+ if agent is None:
93
+ agent = get_default_agent()
94
+
95
+ ts = datetime.now(timezone.utc).isoformat()
96
+
97
+ payload = {
98
+ "commit_id": commit_id,
99
+ "chain_hash": chain_hash,
100
+ "n_facts": n_facts,
101
+ "ts": ts,
102
+ "agent_did": agent.did,
103
+ "agent_label": agent.label,
104
+ }
105
+ if extra_payload:
106
+ payload.update(extra_payload)
107
+
108
+ protected = {
109
+ "alg": "EdDSA",
110
+ "kid": agent.did,
111
+ "typ": "cortexm-commit",
112
+ "alg_id": -8, # COSE alg ID for EdDSA
113
+ }
114
+
115
+ payload_bytes = json.dumps(payload, sort_keys=True).encode("utf-8")
116
+ protected_bytes = json.dumps(protected, sort_keys=True).encode("utf-8")
117
+
118
+ # COSE Sig_structure (RFC 9052 §4.4):
119
+ # ["Signature1", protected, external_aad (empty), payload]
120
+ sig_structure = json.dumps(
121
+ ["Signature1",
122
+ _b64url(protected_bytes),
123
+ "", # external_aad (empty)
124
+ _b64url(payload_bytes)],
125
+ sort_keys=True).encode("utf-8")
126
+
127
+ signature = agent.sign(sig_structure)
128
+
129
+ envelope = CoseSign1Envelope(
130
+ protected=protected,
131
+ payload=payload,
132
+ signature=_b64url(signature),
133
+ agent_did=agent.did,
134
+ ts=ts,
135
+ )
136
+ # full envelope serialization for storage
137
+ envelope.raw_b64 = _b64url(
138
+ json.dumps(envelope.to_dict(), sort_keys=True).encode("utf-8"))
139
+ return envelope
140
+
141
+
142
+ def verify_commit(envelope: CoseSign1Envelope,
143
+ agent: Ed25519AgentKey | None = None,
144
+ expected_commit_id: str | None = None,
145
+ expected_chain_hash: str | None = None) -> bool:
146
+ """Verify a COSE Sign1 envelope.
147
+
148
+ Args:
149
+ envelope: the envelope to verify
150
+ agent: agent key to verify with. If None, a key with the
151
+ envelope's agent_did must be registered (via
152
+ set_default_agent or a future DID resolver).
153
+ expected_commit_id: if set, the payload's commit_id must match
154
+ expected_chain_hash: if set, the payload's chain_hash must match
155
+
156
+ Returns:
157
+ True if the signature is valid AND (if set) the expected
158
+ commit_id and chain_hash match.
159
+ """
160
+ if agent is None:
161
+ agent = get_default_agent()
162
+ if agent.did != envelope.agent_did:
163
+ # in production: resolve the key from did:key
164
+ # for now: only verify if the registered agent matches
165
+ return False
166
+
167
+ payload = envelope.payload
168
+ if expected_commit_id and payload.get("commit_id") != expected_commit_id:
169
+ return False
170
+ if expected_chain_hash and payload.get("chain_hash") != expected_chain_hash:
171
+ return False
172
+
173
+ protected_bytes = json.dumps(envelope.protected, sort_keys=True).encode("utf-8")
174
+ payload_bytes = json.dumps(payload, sort_keys=True).encode("utf-8")
175
+ sig_structure = json.dumps(
176
+ ["Signature1",
177
+ _b64url(protected_bytes),
178
+ "",
179
+ _b64url(payload_bytes)],
180
+ sort_keys=True).encode("utf-8")
181
+
182
+ signature = _b64url_decode(envelope.signature)
183
+ return agent.verify(sig_structure, signature)
184
+
185
+
186
+ def envelope_from_dict(d: dict) -> CoseSign1Envelope:
187
+ """Reconstruct an envelope from a dict (e.g. loaded from JSON)."""
188
+ return CoseSign1Envelope(
189
+ protected=d.get("protected", {}),
190
+ payload=d.get("payload", {}),
191
+ signature=d.get("signature", ""),
192
+ agent_did=d.get("agent_did", ""),
193
+ ts=d.get("ts", ""),
194
+ )
195
+
196
+
197
+ __all__ = [
198
+ "CoseSign1Envelope",
199
+ "sign_commit", "verify_commit",
200
+ "envelope_from_dict",
201
+ ]
@@ -0,0 +1,258 @@
1
+ """SCITT (Secure Coding Infrastructure Transparency) signed statements.
2
+
3
+ Forwards a COSE Sign1 envelope to a SCITT transparency log, returns a
4
+ receipt that can be verified by a third party.
5
+
6
+ In a production deployment, SCITT runs as an external service (e.g. an
7
+ Azure SCITT instance, or a notary.localhost fake service for dev). For
8
+ the prototype, we implement an in-process mock SCITT that:
9
+ - accepts a COSE Sign1 envelope
10
+ - appends it to an append-only log (hash-chained)
11
+ - returns a receipt with the leaf hash + the chain head at the time
12
+ of submission + the inclusion path (sibling hashes + direction)
13
+ - signs the receipt with the SCITT service's key
14
+
15
+ This is NOT a real transparency log (it doesn't gossip, doesn't publish
16
+ to a public append-only store) but it implements the API surface that
17
+ a real SCITT integration would expose. The signature is verifiable
18
+ by any third party that trusts the SCITT service's public key.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import base64
24
+ import hashlib
25
+ import json
26
+ import threading
27
+ from dataclasses import dataclass, field
28
+ from datetime import datetime, timezone
29
+
30
+ from cortexm.provenance.agent import Ed25519AgentKey
31
+ from cortexm.provenance.cose import CoseSign1Envelope
32
+
33
+
34
+ @dataclass
35
+ class ScittReceipt:
36
+ """A SCITT transparency log receipt."""
37
+ leaf_hash: str # hash of this statement in the log
38
+ tree_size: int # log size at time of submission
39
+ chain_head: str # root hash of the log at time of submission
40
+ # inclusion path: list of (sibling_hash, direction) where direction
41
+ # is 'L' (sibling is to the left of the current node) or 'R' (right)
42
+ inclusion_path: list[tuple[str, str]] = field(default_factory=list)
43
+ service_did: str = ""
44
+ service_signature: str = "" # base64url Ed25519 sig from SCITT service
45
+ ts: str = ""
46
+
47
+
48
+ @dataclass
49
+ class ScittStatement:
50
+ """A SCITT-signed statement (a COSE Sign1 + a SCITT receipt)."""
51
+ envelope: CoseSign1Envelope
52
+ receipt: ScittReceipt
53
+ service_did: str = ""
54
+
55
+
56
+ def _h(data: bytes) -> str:
57
+ """BLAKE3 or BLAKE2b fallback."""
58
+ try:
59
+ import blake3
60
+ return blake3.blake3(data).hexdigest()
61
+ except ImportError:
62
+ return hashlib.blake2b(data, digest_size=32).hexdigest()
63
+
64
+
65
+ def _merkle_level(leaves: list[str]) -> list[str]:
66
+ """Compute the next level up in the Merkle tree."""
67
+ if len(leaves) == 1:
68
+ return leaves
69
+ if len(leaves) % 2 == 1:
70
+ leaves = leaves + [leaves[-1]] # pad
71
+ out = []
72
+ for i in range(0, len(leaves), 2):
73
+ out.append(_h((leaves[i] + leaves[i + 1]).encode("utf-8")))
74
+ return out
75
+
76
+
77
+ def _merkle_root(leaves: list[str]) -> str:
78
+ """Compute the Merkle root over a list of leaf hashes."""
79
+ if not leaves:
80
+ return ""
81
+ level = list(leaves)
82
+ while len(level) > 1:
83
+ level = _merkle_level(level)
84
+ return level[0]
85
+
86
+
87
+ def _inclusion_path(leaves: list[str], idx: int) -> list[tuple[str, str]]:
88
+ """Build the Merkle inclusion proof path for leaf at idx.
89
+
90
+ Returns a list of (sibling_hash, direction) where direction is
91
+ 'L' (sibling is to the left of the current node) or 'R' (right).
92
+ The verifier walks the path from the leaf up to the root.
93
+ """
94
+ if idx < 0 or idx >= len(leaves):
95
+ return []
96
+ path: list[tuple[str, str]] = []
97
+ level = list(leaves)
98
+ cur_idx = idx
99
+ while len(level) > 1:
100
+ if len(level) % 2 == 1:
101
+ level = level + [level[-1]] # pad
102
+ if cur_idx % 2 == 0:
103
+ # current is the left child — sibling is to the right
104
+ sib_idx = cur_idx + 1
105
+ direction = "R"
106
+ else:
107
+ sib_idx = cur_idx - 1
108
+ direction = "L"
109
+ path.append((level[sib_idx], direction))
110
+ level = _merkle_level(level)
111
+ cur_idx //= 2
112
+ return path
113
+
114
+
115
+ def _verify_inclusion(leaf: str,
116
+ path: list[tuple[str, str]]) -> str:
117
+ """Walk an inclusion path from a leaf, return the recomputed root."""
118
+ cur = leaf
119
+ for sib, direction in path:
120
+ if direction == "R":
121
+ cur = _h((cur + sib).encode("utf-8"))
122
+ else:
123
+ cur = _h((sib + cur).encode("utf-8"))
124
+ return cur
125
+
126
+
127
+ class _ScittLog:
128
+ """In-process mock SCITT transparency log.
129
+
130
+ A production SCITT service persists the log to disk + gossips.
131
+ This mock keeps an in-process append-only list. For tests/dev
132
+ only — restart the process and the log is empty (verifications of
133
+ prior receipts will fail since the service key has changed).
134
+ """
135
+
136
+ def __init__(self) -> None:
137
+ self._entries: list[str] = []
138
+ self._service_key: Ed25519AgentKey = Ed25519AgentKey.generate(
139
+ label="scitt-mock-service")
140
+ self._service_did = self._service_key.did
141
+ self._lock = threading.Lock()
142
+
143
+ @property
144
+ def service_did(self) -> str:
145
+ return self._service_did
146
+
147
+ def submit(self, envelope: CoseSign1Envelope) -> ScittReceipt:
148
+ """Submit a COSE Sign1 envelope to the log."""
149
+ with self._lock:
150
+ envelope_b64 = envelope.signature.encode("utf-8")
151
+ leaf = _h(envelope_b64)
152
+ self._entries.append(leaf)
153
+ tree_size = len(self._entries)
154
+ chain_head = _merkle_root(self._entries)
155
+ ts = datetime.now(timezone.utc).isoformat()
156
+ inclusion = _inclusion_path(self._entries, tree_size - 1)
157
+
158
+ receipt_data = json.dumps({
159
+ "leaf_hash": leaf,
160
+ "tree_size": tree_size,
161
+ "chain_head": chain_head,
162
+ "ts": ts,
163
+ "service_did": self._service_did,
164
+ }, sort_keys=True).encode("utf-8")
165
+ service_sig = self._service_key.sign(receipt_data)
166
+
167
+ return ScittReceipt(
168
+ leaf_hash=leaf,
169
+ tree_size=tree_size,
170
+ chain_head=chain_head,
171
+ inclusion_path=inclusion,
172
+ service_did=self._service_did,
173
+ service_signature=base64.urlsafe_b64encode(
174
+ service_sig).decode().rstrip("="),
175
+ ts=ts,
176
+ )
177
+
178
+ def verify_receipt(self, receipt: ScittReceipt) -> bool:
179
+ """Verify a SCITT receipt against this log's service key."""
180
+ if not receipt.leaf_hash or not receipt.chain_head:
181
+ return False
182
+
183
+ sig_b64 = receipt.service_signature
184
+ if not sig_b64:
185
+ return False
186
+ try:
187
+ sig = base64.urlsafe_b64decode(
188
+ sig_b64 + "=" * (-len(sig_b64) % 4))
189
+ except Exception:
190
+ return False
191
+
192
+ receipt_data = json.dumps({
193
+ "leaf_hash": receipt.leaf_hash,
194
+ "tree_size": receipt.tree_size,
195
+ "chain_head": receipt.chain_head,
196
+ "ts": receipt.ts,
197
+ "service_did": receipt.service_did,
198
+ }, sort_keys=True).encode("utf-8")
199
+
200
+ # verify the service's signature on the receipt metadata
201
+ if receipt.service_did == self._service_did:
202
+ if not self._service_key.verify(receipt_data, sig):
203
+ return False
204
+ else:
205
+ # production: resolve did:key from a registry
206
+ # prototype: reject unknown service DIDs
207
+ return False
208
+
209
+ # recompute the Merkle root from the leaf + inclusion path
210
+ recomputed = _verify_inclusion(receipt.leaf_hash,
211
+ receipt.inclusion_path)
212
+ return recomputed == receipt.chain_head
213
+
214
+
215
+ # Process-global mock log
216
+ _mock_log = _ScittLog()
217
+
218
+
219
+ def submit_to_scitt(envelope: CoseSign1Envelope) -> ScittStatement:
220
+ """Submit a COSE Sign1 envelope to the SCITT transparency log."""
221
+ receipt = _mock_log.submit(envelope)
222
+ return ScittStatement(
223
+ envelope=envelope,
224
+ receipt=receipt,
225
+ service_did=receipt.service_did,
226
+ )
227
+
228
+
229
+ def verify_receipt(statement: ScittStatement) -> bool:
230
+ """Verify a SCITT statement's receipt.
231
+
232
+ Verifies:
233
+ 1. The service's Ed25519 signature on the receipt metadata
234
+ 2. The Merkle inclusion proof (leaf + path = chain_head)
235
+
236
+ Returns True only if both checks pass. Production deployments
237
+ would resolve the service key from a did:key registry rather than
238
+ trusting the in-process mock log.
239
+ """
240
+ return _mock_log.verify_receipt(statement.receipt)
241
+
242
+
243
+ def reset_scitt_log() -> None:
244
+ """Reset the in-process SCITT log (test-only)."""
245
+ global _mock_log
246
+ _mock_log = _ScittLog()
247
+
248
+
249
+ def get_scitt_service_did() -> str:
250
+ """Return the SCITT service's DID (for external verification setup)."""
251
+ return _mock_log.service_did
252
+
253
+
254
+ __all__ = [
255
+ "ScittStatement", "ScittReceipt",
256
+ "submit_to_scitt", "verify_receipt",
257
+ "reset_scitt_log", "get_scitt_service_did",
258
+ ]