tibet-cbom 0.1.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.
@@ -0,0 +1 @@
1
+ MIT License — Copyright (c) 2026 Humotica, Jasper van de Meent, Root AI, Codex
@@ -0,0 +1,214 @@
1
+ Metadata-Version: 2.4
2
+ Name: tibet-cbom
3
+ Version: 0.1.0
4
+ Summary: Continuity bill of materials and State of Manifest inspector for sealed TIBET envelopes.
5
+ Author-email: Jasper van de Meent <info@humotica.com>, Codex <codex@humotica.nl>
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Keywords: audit,cbom,continuity,icc,manifest,provenance,som,tbz,tibet,timeline
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Intended Audience :: System Administrators
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Security
18
+ Classifier: Topic :: System :: Logging
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+
22
+ # tibet-cbom
23
+
24
+ **Continuity Bill of Materials and State of Manifest inspector for sealed TIBET envelopes.**
25
+
26
+ This sandbox package sketches a tool family around two closely related
27
+ ideas:
28
+
29
+ - `CBOM`
30
+ - continuity-aware bill of materials
31
+ - what is in the object, plus how that object sits in a continuity
32
+ chain
33
+ - `SoM`
34
+ - State of Manifest
35
+ - who asserted what, when, and how the manifest/surface relationship
36
+ evolved over time
37
+
38
+ The first operator surface is intentionally simple:
39
+
40
+ ```bash
41
+ tibet-cbom inspect file.tza
42
+ tibet-cbom inspect file.tza --json
43
+ ```
44
+
45
+ And the more human/forensic framing remains available through the alias:
46
+
47
+ ```bash
48
+ tibet-som inspect file.tza
49
+ ```
50
+
51
+ ## Why this exists
52
+
53
+ Normal file inspection answers:
54
+
55
+ - what is this file called
56
+ - how large is it
57
+ - what extension does it have
58
+
59
+ CBOM / SoM should answer richer questions:
60
+
61
+ - what class of sealed object is this
62
+ - what does its canonical surface appear to be
63
+ - what continuity identifiers are attached
64
+ - what events happened to it over time
65
+ - when was it renamed
66
+ - when was it verified
67
+ - when was a surface mismatch marked as partial or suspicious
68
+
69
+ That makes `tibet-cbom` feel less like `file(1)` and more like:
70
+
71
+ - `git log`
72
+ - for continuity-bearing envelopes
73
+
74
+ ## Current sandbox scope
75
+
76
+ This skeleton does **not** claim full TBZ parsing yet.
77
+
78
+ It provides:
79
+
80
+ - package layout
81
+ - datamodel sketch
82
+ - CLI shape
83
+ - human and JSON rendering
84
+ - a first local file inspector that can grow into real manifest/event
85
+ extraction later
86
+ - optional continuityd audit JSONL merge for early SoM timelines
87
+
88
+ ## Commands
89
+
90
+ ### `inspect`
91
+
92
+ Compact human summary or JSON object.
93
+
94
+ ```bash
95
+ tibet-cbom inspect 2026-05-12.peer-eval.claude.urgent.tza
96
+ tibet-cbom inspect vergadering-dinsdag.pdf
97
+ tibet-cbom inspect file.tza --json
98
+ tibet-cbom inspect file.tza --audit-file expected-audit-example.jsonl
99
+ ```
100
+
101
+ ### `timeline`
102
+
103
+ Reserved for a later event-only view.
104
+
105
+ ```bash
106
+ tibet-cbom timeline file.tza
107
+ tibet-cbom timeline file.tza --audit-file expected-audit-example.jsonl --json
108
+ ```
109
+
110
+ ### `authority`
111
+
112
+ Compact current authority state.
113
+
114
+ ```bash
115
+ tibet-cbom authority file.tza
116
+ tibet-cbom authority file.tza --json
117
+ ```
118
+
119
+ ### `verify`
120
+
121
+ Explicit manifest and authority-step consistency check.
122
+
123
+ ```bash
124
+ tibet-cbom verify file.tza
125
+ tibet-cbom verify file.tza --json
126
+ tibet-cbom verify file.tza --audit-file expected-audit-example.jsonl
127
+ ```
128
+
129
+ ### `rewrap`
130
+
131
+ Sandbox ownership-transition event sketch.
132
+
133
+ ```bash
134
+ tibet-cbom rewrap task.tza \
135
+ --audit-file audit.jsonl \
136
+ --actor jis:humotica:jasper.admin \
137
+ --authority-mode admin \
138
+ --transition-type freeze \
139
+ --status frozen \
140
+ --effective-assignee jis:humotica:agent.ai \
141
+ --reason "manual triage hold" \
142
+ --freeze-reason-code human-review
143
+ ```
144
+
145
+ If you also want a sandbox sealed bundle:
146
+
147
+ ```bash
148
+ tibet-cbom rewrap task.tza \
149
+ --audit-file audit.jsonl \
150
+ --actor jis:humotica:jasper.admin \
151
+ --authority-mode admin \
152
+ --transition-type freeze \
153
+ --status frozen \
154
+ --effective-assignee jis:humotica:agent.ai \
155
+ --reason "manual triage hold" \
156
+ --freeze-reason-code human-review \
157
+ --identity-dir ./admin-identity \
158
+ --emit-bundle /tmp/admin-freeze.tza
159
+ ```
160
+
161
+ Basic policy guards now apply:
162
+
163
+ - `handoff` requires `--handoff-target`
164
+ - `freeze` requires `--freeze-reason-code`
165
+ - `authority-mode=admin` expects an admin actor id
166
+ - emitted bundle signing identity must match transition actor
167
+
168
+ ## Data model direction
169
+
170
+ The package uses two main record types:
171
+
172
+ - `CBOMDocument`
173
+ - file path
174
+ - human name
175
+ - canonical name hint
176
+ - continuity identifiers
177
+ - surface status
178
+ - material facts
179
+ - event timeline
180
+ - `SoMEvent`
181
+ - timestamp
182
+ - action
183
+ - actor
184
+ - action id
185
+ - notes / fields
186
+
187
+ This keeps the distinction clear:
188
+
189
+ - CBOM is the object summary
190
+ - SoM is the walkable event chain inside or around that object
191
+
192
+ ## Likely next steps
193
+
194
+ - extract canonical surface from real manifests
195
+ - map continuity IDs from real payloads/manifests
196
+ - render surface status transitions:
197
+ - `MATCH`
198
+ - `PARTIAL`
199
+ - `DISGUISED`
200
+ - `RENAMED`
201
+ - deepen `verify` into fuller chain integrity / succession validation
202
+
203
+ ## Short framing
204
+
205
+ VCs answer:
206
+
207
+ - who are you
208
+
209
+ SoM answers:
210
+
211
+ - what did you manifest and when
212
+
213
+ CBOM then becomes the readable continuity-aware object view that ties
214
+ those together.
@@ -0,0 +1,193 @@
1
+ # tibet-cbom
2
+
3
+ **Continuity Bill of Materials and State of Manifest inspector for sealed TIBET envelopes.**
4
+
5
+ This sandbox package sketches a tool family around two closely related
6
+ ideas:
7
+
8
+ - `CBOM`
9
+ - continuity-aware bill of materials
10
+ - what is in the object, plus how that object sits in a continuity
11
+ chain
12
+ - `SoM`
13
+ - State of Manifest
14
+ - who asserted what, when, and how the manifest/surface relationship
15
+ evolved over time
16
+
17
+ The first operator surface is intentionally simple:
18
+
19
+ ```bash
20
+ tibet-cbom inspect file.tza
21
+ tibet-cbom inspect file.tza --json
22
+ ```
23
+
24
+ And the more human/forensic framing remains available through the alias:
25
+
26
+ ```bash
27
+ tibet-som inspect file.tza
28
+ ```
29
+
30
+ ## Why this exists
31
+
32
+ Normal file inspection answers:
33
+
34
+ - what is this file called
35
+ - how large is it
36
+ - what extension does it have
37
+
38
+ CBOM / SoM should answer richer questions:
39
+
40
+ - what class of sealed object is this
41
+ - what does its canonical surface appear to be
42
+ - what continuity identifiers are attached
43
+ - what events happened to it over time
44
+ - when was it renamed
45
+ - when was it verified
46
+ - when was a surface mismatch marked as partial or suspicious
47
+
48
+ That makes `tibet-cbom` feel less like `file(1)` and more like:
49
+
50
+ - `git log`
51
+ - for continuity-bearing envelopes
52
+
53
+ ## Current sandbox scope
54
+
55
+ This skeleton does **not** claim full TBZ parsing yet.
56
+
57
+ It provides:
58
+
59
+ - package layout
60
+ - datamodel sketch
61
+ - CLI shape
62
+ - human and JSON rendering
63
+ - a first local file inspector that can grow into real manifest/event
64
+ extraction later
65
+ - optional continuityd audit JSONL merge for early SoM timelines
66
+
67
+ ## Commands
68
+
69
+ ### `inspect`
70
+
71
+ Compact human summary or JSON object.
72
+
73
+ ```bash
74
+ tibet-cbom inspect 2026-05-12.peer-eval.claude.urgent.tza
75
+ tibet-cbom inspect vergadering-dinsdag.pdf
76
+ tibet-cbom inspect file.tza --json
77
+ tibet-cbom inspect file.tza --audit-file expected-audit-example.jsonl
78
+ ```
79
+
80
+ ### `timeline`
81
+
82
+ Reserved for a later event-only view.
83
+
84
+ ```bash
85
+ tibet-cbom timeline file.tza
86
+ tibet-cbom timeline file.tza --audit-file expected-audit-example.jsonl --json
87
+ ```
88
+
89
+ ### `authority`
90
+
91
+ Compact current authority state.
92
+
93
+ ```bash
94
+ tibet-cbom authority file.tza
95
+ tibet-cbom authority file.tza --json
96
+ ```
97
+
98
+ ### `verify`
99
+
100
+ Explicit manifest and authority-step consistency check.
101
+
102
+ ```bash
103
+ tibet-cbom verify file.tza
104
+ tibet-cbom verify file.tza --json
105
+ tibet-cbom verify file.tza --audit-file expected-audit-example.jsonl
106
+ ```
107
+
108
+ ### `rewrap`
109
+
110
+ Sandbox ownership-transition event sketch.
111
+
112
+ ```bash
113
+ tibet-cbom rewrap task.tza \
114
+ --audit-file audit.jsonl \
115
+ --actor jis:humotica:jasper.admin \
116
+ --authority-mode admin \
117
+ --transition-type freeze \
118
+ --status frozen \
119
+ --effective-assignee jis:humotica:agent.ai \
120
+ --reason "manual triage hold" \
121
+ --freeze-reason-code human-review
122
+ ```
123
+
124
+ If you also want a sandbox sealed bundle:
125
+
126
+ ```bash
127
+ tibet-cbom rewrap task.tza \
128
+ --audit-file audit.jsonl \
129
+ --actor jis:humotica:jasper.admin \
130
+ --authority-mode admin \
131
+ --transition-type freeze \
132
+ --status frozen \
133
+ --effective-assignee jis:humotica:agent.ai \
134
+ --reason "manual triage hold" \
135
+ --freeze-reason-code human-review \
136
+ --identity-dir ./admin-identity \
137
+ --emit-bundle /tmp/admin-freeze.tza
138
+ ```
139
+
140
+ Basic policy guards now apply:
141
+
142
+ - `handoff` requires `--handoff-target`
143
+ - `freeze` requires `--freeze-reason-code`
144
+ - `authority-mode=admin` expects an admin actor id
145
+ - emitted bundle signing identity must match transition actor
146
+
147
+ ## Data model direction
148
+
149
+ The package uses two main record types:
150
+
151
+ - `CBOMDocument`
152
+ - file path
153
+ - human name
154
+ - canonical name hint
155
+ - continuity identifiers
156
+ - surface status
157
+ - material facts
158
+ - event timeline
159
+ - `SoMEvent`
160
+ - timestamp
161
+ - action
162
+ - actor
163
+ - action id
164
+ - notes / fields
165
+
166
+ This keeps the distinction clear:
167
+
168
+ - CBOM is the object summary
169
+ - SoM is the walkable event chain inside or around that object
170
+
171
+ ## Likely next steps
172
+
173
+ - extract canonical surface from real manifests
174
+ - map continuity IDs from real payloads/manifests
175
+ - render surface status transitions:
176
+ - `MATCH`
177
+ - `PARTIAL`
178
+ - `DISGUISED`
179
+ - `RENAMED`
180
+ - deepen `verify` into fuller chain integrity / succession validation
181
+
182
+ ## Short framing
183
+
184
+ VCs answer:
185
+
186
+ - who are you
187
+
188
+ SoM answers:
189
+
190
+ - what did you manifest and when
191
+
192
+ CBOM then becomes the readable continuity-aware object view that ties
193
+ those together.
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "tibet-cbom"
7
+ version = "0.1.0"
8
+ description = "Continuity bill of materials and State of Manifest inspector for sealed TIBET envelopes."
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ {name = "Jasper van de Meent", email = "info@humotica.com"},
14
+ {name = "Codex", email = "codex@humotica.nl"},
15
+ ]
16
+ keywords = [
17
+ "tibet", "cbom", "som", "manifest", "continuity", "tbz",
18
+ "icc", "timeline", "audit", "provenance",
19
+ ]
20
+ classifiers = [
21
+ "Development Status :: 3 - Alpha",
22
+ "Intended Audience :: Developers",
23
+ "Intended Audience :: System Administrators",
24
+ "License :: OSI Approved :: MIT License",
25
+ "Programming Language :: Python :: 3",
26
+ "Programming Language :: Python :: 3.10",
27
+ "Programming Language :: Python :: 3.11",
28
+ "Programming Language :: Python :: 3.12",
29
+ "Topic :: Security",
30
+ "Topic :: System :: Logging",
31
+ ]
32
+ dependencies = []
33
+
34
+ [project.scripts]
35
+ tibet-cbom = "tibet_cbom.cli:main"
36
+ tcbom = "tibet_cbom.cli:main"
37
+ tibet-som = "tibet_cbom.cli:main"
38
+
39
+ [tool.hatch.build.targets.sdist]
40
+ include = ["/src"]
41
+
42
+ [tool.hatch.build.targets.wheel]
43
+ packages = ["src/tibet_cbom"]
@@ -0,0 +1,3 @@
1
+ """tibet-cbom — continuity bill of materials / State of Manifest sketch."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,115 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from datetime import datetime, timezone
5
+ from pathlib import Path
6
+
7
+ from .models import CBOMDocument, SoMEvent
8
+
9
+
10
+ def _ts_to_iso(value) -> str:
11
+ if isinstance(value, (int, float)):
12
+ return datetime.fromtimestamp(value, tz=timezone.utc).strftime(
13
+ "%Y-%m-%dT%H:%M:%SZ"
14
+ )
15
+ if isinstance(value, str) and value:
16
+ return value
17
+ return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
18
+
19
+
20
+ def _event_notes(record: dict) -> list[str]:
21
+ notes: list[str] = []
22
+ for key in (
23
+ "intake_class",
24
+ "disposition_hint",
25
+ "surface_status",
26
+ "disposition",
27
+ "canonical_name",
28
+ ):
29
+ value = record.get(key)
30
+ if value not in (None, "", [], {}):
31
+ notes.append(f"{key}={value}")
32
+ if record.get("renamed_by_operator"):
33
+ notes.append("renamed_by_operator=true")
34
+ return notes
35
+
36
+
37
+ def merge_audit_file(doc: CBOMDocument, audit_path: str) -> CBOMDocument:
38
+ path = Path(audit_path)
39
+ if not path.exists():
40
+ raise FileNotFoundError(f"no such audit file: {path}")
41
+
42
+ matched: list[dict] = []
43
+ with open(path, "r", encoding="utf-8", errors="replace") as f:
44
+ for line in f:
45
+ line = line.strip()
46
+ if not line:
47
+ continue
48
+ try:
49
+ record = json.loads(line)
50
+ except json.JSONDecodeError:
51
+ continue
52
+ if record.get("name") == doc.file_name:
53
+ matched.append(record)
54
+
55
+ if not matched:
56
+ doc.events.append(
57
+ SoMEvent(
58
+ timestamp=datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
59
+ action="audit-unmatched",
60
+ actor="tibet-cbom",
61
+ action_id="act_audit_unmatched",
62
+ notes=[f"audit_file={path.name}", "no records matched file name"],
63
+ )
64
+ )
65
+ return doc
66
+
67
+ if len(matched) > 1:
68
+ doc.events.append(
69
+ SoMEvent(
70
+ timestamp=datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
71
+ action="audit-name-collision",
72
+ actor="tibet-cbom",
73
+ action_id="act_audit_collision",
74
+ notes=[
75
+ f"audit_file={path.name}",
76
+ f"matched_records={len(matched)}",
77
+ "top-level fields not overwritten because name-only match is ambiguous",
78
+ ],
79
+ )
80
+ )
81
+
82
+ for idx, record in enumerate(matched, start=1):
83
+ stage = record.get("stage", "audit")
84
+ actor = record.get("actor_id") or record.get("actor") or "continuityd"
85
+ action_id = record.get("action_id") or f"act_audit_{idx}"
86
+ doc.events.append(
87
+ SoMEvent(
88
+ timestamp=_ts_to_iso(record.get("ts")),
89
+ action=stage,
90
+ actor=actor,
91
+ action_id=action_id,
92
+ notes=_event_notes(record),
93
+ )
94
+ )
95
+
96
+ if len(matched) > 1:
97
+ return doc
98
+
99
+ latest = matched[-1]
100
+ if latest.get("canonical_name"):
101
+ doc.canonical_name = latest["canonical_name"]
102
+ if latest.get("continuity_id"):
103
+ doc.continuity_id = latest["continuity_id"]
104
+ if latest.get("object_id"):
105
+ doc.object_id = latest["object_id"]
106
+ if latest.get("surface_status"):
107
+ doc.surface_status = latest["surface_status"]
108
+ if latest.get("disposition"):
109
+ doc.disposition_hint = latest["disposition"]
110
+ elif latest.get("disposition_hint"):
111
+ doc.disposition_hint = latest["disposition_hint"]
112
+ if latest.get("intake_class"):
113
+ doc.intake_class = latest["intake_class"]
114
+
115
+ return doc