warrant-graph 2.0.0a1__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.
- warrant_graph-2.0.0a1/LICENSE +21 -0
- warrant_graph-2.0.0a1/PKG-INFO +130 -0
- warrant_graph-2.0.0a1/README.md +112 -0
- warrant_graph-2.0.0a1/pyproject.toml +38 -0
- warrant_graph-2.0.0a1/setup.cfg +4 -0
- warrant_graph-2.0.0a1/warrant/__init__.py +11 -0
- warrant_graph-2.0.0a1/warrant/bindings.py +145 -0
- warrant_graph-2.0.0a1/warrant/cli.py +401 -0
- warrant_graph-2.0.0a1/warrant/compute.py +291 -0
- warrant_graph-2.0.0a1/warrant/engine.py +990 -0
- warrant_graph-2.0.0a1/warrant/jcs.py +140 -0
- warrant_graph-2.0.0a1/warrant/keys.py +80 -0
- warrant_graph-2.0.0a1/warrant/limits.py +39 -0
- warrant_graph-2.0.0a1/warrant/pilot.py +436 -0
- warrant_graph-2.0.0a1/warrant/records.py +318 -0
- warrant_graph-2.0.0a1/warrant/shapes.py +63 -0
- warrant_graph-2.0.0a1/warrant/store.py +469 -0
- warrant_graph-2.0.0a1/warrant/triggers.py +138 -0
- warrant_graph-2.0.0a1/warrant_agent/__init__.py +21 -0
- warrant_graph-2.0.0a1/warrant_agent/_assess_worker.py +60 -0
- warrant_graph-2.0.0a1/warrant_agent/api.py +486 -0
- warrant_graph-2.0.0a1/warrant_agent/cli.py +58 -0
- warrant_graph-2.0.0a1/warrant_agent/computeops.py +177 -0
- warrant_graph-2.0.0a1/warrant_agent/config.py +159 -0
- warrant_graph-2.0.0a1/warrant_agent/drafts.py +220 -0
- warrant_graph-2.0.0a1/warrant_agent/errors.py +24 -0
- warrant_graph-2.0.0a1/warrant_agent/glossary.py +102 -0
- warrant_graph-2.0.0a1/warrant_agent/handoff.py +283 -0
- warrant_graph-2.0.0a1/warrant_agent/init.py +312 -0
- warrant_graph-2.0.0a1/warrant_agent/mcp_server.py +238 -0
- warrant_graph-2.0.0a1/warrant_agent/objects.py +168 -0
- warrant_graph-2.0.0a1/warrant_agent/views.py +427 -0
- warrant_graph-2.0.0a1/warrant_graph.egg-info/PKG-INFO +130 -0
- warrant_graph-2.0.0a1/warrant_graph.egg-info/SOURCES.txt +36 -0
- warrant_graph-2.0.0a1/warrant_graph.egg-info/dependency_links.txt +1 -0
- warrant_graph-2.0.0a1/warrant_graph.egg-info/entry_points.txt +4 -0
- warrant_graph-2.0.0a1/warrant_graph.egg-info/requires.txt +7 -0
- warrant_graph-2.0.0a1/warrant_graph.egg-info/top_level.txt +2 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 s0fractal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: warrant-graph
|
|
3
|
+
Version: 2.0.0a1
|
|
4
|
+
Summary: Record transitions of work with their residual, close loops exactly, and hand the next agent a capsule instead of a transcript.
|
|
5
|
+
Author: s0fractal
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/s0fractal/warrant
|
|
8
|
+
Project-URL: Specification, https://github.com/s0fractal/warrant/blob/master/SPEC.md
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: cryptography>=41
|
|
13
|
+
Provides-Extra: compute
|
|
14
|
+
Requires-Dist: sigma-glyph==0.8.0; extra == "compute"
|
|
15
|
+
Provides-Extra: mcp
|
|
16
|
+
Requires-Dist: mcp==2.3.0; extra == "mcp"
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# Warrant
|
|
20
|
+
|
|
21
|
+
Warrant records transitions of work: what was done, on what basis, what it
|
|
22
|
+
established, which exact conditions it closed, which questions it opened, and
|
|
23
|
+
what it leaves unestablished. The next agent reads a short capsule instead of a
|
|
24
|
+
transcript, and cannot credit the work with more than its grounds support.
|
|
25
|
+
|
|
26
|
+
Review is one use. Ordinary decisions, running services, periodic obligations
|
|
27
|
+
and reproducible computations are others.
|
|
28
|
+
|
|
29
|
+
The core is small: six signed record types and one pure function, `assess`,
|
|
30
|
+
that reads one view of a store (its bytes, the reader's own trust file and
|
|
31
|
+
profile, a time) and answers what may be relied on now, what is still owed and
|
|
32
|
+
by whom. The package `warrant` holds the core and the `warrant` command, and
|
|
33
|
+
imports nothing but the Python standard library and `cryptography`;
|
|
34
|
+
`warrant_agent` is an interface for agents on top of it.
|
|
35
|
+
|
|
36
|
+
- **[Warrant in 15 minutes](https://github.com/s0fractal/warrant/blob/master/QUICKSTART.md)**:
|
|
37
|
+
one duty, its closure, an acceptance, a challenge; every command and output on
|
|
38
|
+
the page is run by CI.
|
|
39
|
+
- Contract: [SPEC.md](https://github.com/s0fractal/warrant/blob/master/SPEC.md)
|
|
40
|
+
- Handing work to another agent (Python API, CLI, stdio MCP): [AGENT.md](https://github.com/s0fractal/warrant/blob/master/AGENT.md)
|
|
41
|
+
- What the rebuild retired, and where the previous generation lives: [HISTORY.md](https://github.com/s0fractal/warrant/blob/master/HISTORY.md)
|
|
42
|
+
- The proof-space pilot (goal G9), its contract and resolution layer, outside SPEC.md: [PILOT.md](https://github.com/s0fractal/warrant/blob/master/PILOT.md)
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install --pre warrant-graph # Python ≥ 3.10; depends on `cryptography`
|
|
48
|
+
pip install --pre "warrant-graph[mcp]" # adds `warrant-agent-mcp` on the official MCP SDK
|
|
49
|
+
pip install --pre "warrant-graph[compute]" # adds the Sigma provider (sigma-glyph==0.8.0)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
This installs the commands `warrant` and `warrant-agent` and the packages
|
|
53
|
+
`warrant` and `warrant_agent`. The package published as `warrant-verify`
|
|
54
|
+
(≤ 0.12.0) is the retired 0.x generation.
|
|
55
|
+
|
|
56
|
+
Attest and observe need nothing else. `compute` conditions are replayed by the
|
|
57
|
+
Sigma provider, the `sigma_provider` module of the `sigma-glyph` distribution
|
|
58
|
+
(PyPI `0.8.0`, provider identity `0caff793…`; `warrant compute --store S
|
|
59
|
+
provider` prints it). A recipient accepts a provider by putting that identity
|
|
60
|
+
in its profile's `providers`; without an accepted, installed provider every
|
|
61
|
+
REPLAYED basis is UNVERIFIED.
|
|
62
|
+
|
|
63
|
+
## The model in one table
|
|
64
|
+
|
|
65
|
+
| Record | Says |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| `duty` | a condition someone owes someone: attest, observe, or compute; optionally scheduled |
|
|
68
|
+
| `transition` | work done: basis, evidence, established, residual, opened questions, exact closures |
|
|
69
|
+
| `accept` | acceptance of one exact closure item (or of a transition's results) |
|
|
70
|
+
| `observation` | what an observer saw, when, with which probe |
|
|
71
|
+
| `grant` | permission to release named duties, attenuable |
|
|
72
|
+
| `challenge` | a counterexample against a closure or a result |
|
|
73
|
+
|
|
74
|
+
Assessment is a pure function of one view: the store's bytes read once, the
|
|
75
|
+
recipient's trust file and profile, a time, and the current revision. It
|
|
76
|
+
answers `reliance` (ELIGIBLE, STALE, CHALLENGED, SUPERSEDED, UNASSESSED,
|
|
77
|
+
NOT_CLOSED, ...), `frontier`, `questions` and `capsule`. A key authenticates; it
|
|
78
|
+
does not authorize. A computation is credited only by the recipient's own replay.
|
|
79
|
+
|
|
80
|
+
## Status
|
|
81
|
+
|
|
82
|
+
**2.0.0a1 is an alpha**, the first publication of `warrant-graph`. A
|
|
83
|
+
pre-release may still change the record formats, the command line, the Python
|
|
84
|
+
API and the agent interface.
|
|
85
|
+
|
|
86
|
+
- **What is backed.** Every normative sentence of SPEC.md is a signed claim
|
|
87
|
+
record. Of 358 sentences, 281 are BACKED: each names the test cases that
|
|
88
|
+
witness it and the mutants those cases kill. 20 are UNBACKED, each with the
|
|
89
|
+
reason it is still open, and 57 are informative.
|
|
90
|
+
[SPEC-CLAIMS.md](https://github.com/s0fractal/warrant/blob/master/SPEC-CLAIMS.md)
|
|
91
|
+
lists every claim with its witnesses and mutants. A change to a rule is filed
|
|
92
|
+
as a new record that supersedes the old one and says why; the old one stays.
|
|
93
|
+
- **What is not.** Most of the code is exercised by tests but not tied to a
|
|
94
|
+
claim. At 7c6d80b, 304 of the 2317 statements of `warrant/` (13%), and 431 of
|
|
95
|
+
the 3980 statements of `warrant/` and `warrant_agent/` together (11%), are
|
|
96
|
+
changed by a mutant that a BACKED claim cites (`tools/claims.py why
|
|
97
|
+
--uncovered`). Raising that is the open goal G6. The other open goals,
|
|
98
|
+
among them an agent with no preparation using Warrant correctly (G2) and
|
|
99
|
+
admission of witnesses without an admin (G3), are in
|
|
100
|
+
[ROADMAP.md](https://github.com/s0fractal/warrant/blob/master/ROADMAP.md).
|
|
101
|
+
- **Review.** Pull requests are reviewed by a model reviewer through the
|
|
102
|
+
repository's review loop
|
|
103
|
+
([REVIEWS.md](https://github.com/s0fractal/warrant/blob/master/REVIEWS.md));
|
|
104
|
+
no external security audit is recorded. There is one implementation, this
|
|
105
|
+
Python one.
|
|
106
|
+
|
|
107
|
+
## Limits
|
|
108
|
+
|
|
109
|
+
Not in this version: threshold adoption, key rotation, P-256, policy
|
|
110
|
+
compilation, grants for acts other than release, goals as a distinct kind, and
|
|
111
|
+
any independent implementation besides this Python one. The process boundary
|
|
112
|
+
around the Sigma kernel isolates module names; it is not an OS sandbox. A view
|
|
113
|
+
cannot prove its own completeness, and every report says so. An assessment
|
|
114
|
+
has aggregate admission limits (records, bytes, `requires` edges, periods;
|
|
115
|
+
SPEC §9): beyond one it is refused, never answered in part.
|
|
116
|
+
|
|
117
|
+
## The repository
|
|
118
|
+
|
|
119
|
+
The repository also builds and checks Warrant with Warrant: SPEC.md is
|
|
120
|
+
generated from the claim records, the roadmap and the pull request reviews are
|
|
121
|
+
records in the same store, and a gate merges a pull request on a recorded
|
|
122
|
+
acceptance. That machinery (`tools/`, `.warrant/`, `.github/`) is evidence
|
|
123
|
+
behind the package, not part of it: `tests/boundary_test.py` refuses a core
|
|
124
|
+
module that imports it and a wheel or sdist that carries it.
|
|
125
|
+
[docs/REPOSITORY.md](https://github.com/s0fractal/warrant/blob/master/docs/REPOSITORY.md)
|
|
126
|
+
describes it, with the checks to run from a checkout;
|
|
127
|
+
[CHANGELOG.md](https://github.com/s0fractal/warrant/blob/master/CHANGELOG.md)
|
|
128
|
+
records what changed.
|
|
129
|
+
|
|
130
|
+
Licensed MIT. See [TRADEMARK.md](https://github.com/s0fractal/warrant/blob/master/TRADEMARK.md) for the name.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Warrant
|
|
2
|
+
|
|
3
|
+
Warrant records transitions of work: what was done, on what basis, what it
|
|
4
|
+
established, which exact conditions it closed, which questions it opened, and
|
|
5
|
+
what it leaves unestablished. The next agent reads a short capsule instead of a
|
|
6
|
+
transcript, and cannot credit the work with more than its grounds support.
|
|
7
|
+
|
|
8
|
+
Review is one use. Ordinary decisions, running services, periodic obligations
|
|
9
|
+
and reproducible computations are others.
|
|
10
|
+
|
|
11
|
+
The core is small: six signed record types and one pure function, `assess`,
|
|
12
|
+
that reads one view of a store (its bytes, the reader's own trust file and
|
|
13
|
+
profile, a time) and answers what may be relied on now, what is still owed and
|
|
14
|
+
by whom. The package `warrant` holds the core and the `warrant` command, and
|
|
15
|
+
imports nothing but the Python standard library and `cryptography`;
|
|
16
|
+
`warrant_agent` is an interface for agents on top of it.
|
|
17
|
+
|
|
18
|
+
- **[Warrant in 15 minutes](https://github.com/s0fractal/warrant/blob/master/QUICKSTART.md)**:
|
|
19
|
+
one duty, its closure, an acceptance, a challenge; every command and output on
|
|
20
|
+
the page is run by CI.
|
|
21
|
+
- Contract: [SPEC.md](https://github.com/s0fractal/warrant/blob/master/SPEC.md)
|
|
22
|
+
- Handing work to another agent (Python API, CLI, stdio MCP): [AGENT.md](https://github.com/s0fractal/warrant/blob/master/AGENT.md)
|
|
23
|
+
- What the rebuild retired, and where the previous generation lives: [HISTORY.md](https://github.com/s0fractal/warrant/blob/master/HISTORY.md)
|
|
24
|
+
- The proof-space pilot (goal G9), its contract and resolution layer, outside SPEC.md: [PILOT.md](https://github.com/s0fractal/warrant/blob/master/PILOT.md)
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install --pre warrant-graph # Python ≥ 3.10; depends on `cryptography`
|
|
30
|
+
pip install --pre "warrant-graph[mcp]" # adds `warrant-agent-mcp` on the official MCP SDK
|
|
31
|
+
pip install --pre "warrant-graph[compute]" # adds the Sigma provider (sigma-glyph==0.8.0)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This installs the commands `warrant` and `warrant-agent` and the packages
|
|
35
|
+
`warrant` and `warrant_agent`. The package published as `warrant-verify`
|
|
36
|
+
(≤ 0.12.0) is the retired 0.x generation.
|
|
37
|
+
|
|
38
|
+
Attest and observe need nothing else. `compute` conditions are replayed by the
|
|
39
|
+
Sigma provider, the `sigma_provider` module of the `sigma-glyph` distribution
|
|
40
|
+
(PyPI `0.8.0`, provider identity `0caff793…`; `warrant compute --store S
|
|
41
|
+
provider` prints it). A recipient accepts a provider by putting that identity
|
|
42
|
+
in its profile's `providers`; without an accepted, installed provider every
|
|
43
|
+
REPLAYED basis is UNVERIFIED.
|
|
44
|
+
|
|
45
|
+
## The model in one table
|
|
46
|
+
|
|
47
|
+
| Record | Says |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `duty` | a condition someone owes someone: attest, observe, or compute; optionally scheduled |
|
|
50
|
+
| `transition` | work done: basis, evidence, established, residual, opened questions, exact closures |
|
|
51
|
+
| `accept` | acceptance of one exact closure item (or of a transition's results) |
|
|
52
|
+
| `observation` | what an observer saw, when, with which probe |
|
|
53
|
+
| `grant` | permission to release named duties, attenuable |
|
|
54
|
+
| `challenge` | a counterexample against a closure or a result |
|
|
55
|
+
|
|
56
|
+
Assessment is a pure function of one view: the store's bytes read once, the
|
|
57
|
+
recipient's trust file and profile, a time, and the current revision. It
|
|
58
|
+
answers `reliance` (ELIGIBLE, STALE, CHALLENGED, SUPERSEDED, UNASSESSED,
|
|
59
|
+
NOT_CLOSED, ...), `frontier`, `questions` and `capsule`. A key authenticates; it
|
|
60
|
+
does not authorize. A computation is credited only by the recipient's own replay.
|
|
61
|
+
|
|
62
|
+
## Status
|
|
63
|
+
|
|
64
|
+
**2.0.0a1 is an alpha**, the first publication of `warrant-graph`. A
|
|
65
|
+
pre-release may still change the record formats, the command line, the Python
|
|
66
|
+
API and the agent interface.
|
|
67
|
+
|
|
68
|
+
- **What is backed.** Every normative sentence of SPEC.md is a signed claim
|
|
69
|
+
record. Of 358 sentences, 281 are BACKED: each names the test cases that
|
|
70
|
+
witness it and the mutants those cases kill. 20 are UNBACKED, each with the
|
|
71
|
+
reason it is still open, and 57 are informative.
|
|
72
|
+
[SPEC-CLAIMS.md](https://github.com/s0fractal/warrant/blob/master/SPEC-CLAIMS.md)
|
|
73
|
+
lists every claim with its witnesses and mutants. A change to a rule is filed
|
|
74
|
+
as a new record that supersedes the old one and says why; the old one stays.
|
|
75
|
+
- **What is not.** Most of the code is exercised by tests but not tied to a
|
|
76
|
+
claim. At 7c6d80b, 304 of the 2317 statements of `warrant/` (13%), and 431 of
|
|
77
|
+
the 3980 statements of `warrant/` and `warrant_agent/` together (11%), are
|
|
78
|
+
changed by a mutant that a BACKED claim cites (`tools/claims.py why
|
|
79
|
+
--uncovered`). Raising that is the open goal G6. The other open goals,
|
|
80
|
+
among them an agent with no preparation using Warrant correctly (G2) and
|
|
81
|
+
admission of witnesses without an admin (G3), are in
|
|
82
|
+
[ROADMAP.md](https://github.com/s0fractal/warrant/blob/master/ROADMAP.md).
|
|
83
|
+
- **Review.** Pull requests are reviewed by a model reviewer through the
|
|
84
|
+
repository's review loop
|
|
85
|
+
([REVIEWS.md](https://github.com/s0fractal/warrant/blob/master/REVIEWS.md));
|
|
86
|
+
no external security audit is recorded. There is one implementation, this
|
|
87
|
+
Python one.
|
|
88
|
+
|
|
89
|
+
## Limits
|
|
90
|
+
|
|
91
|
+
Not in this version: threshold adoption, key rotation, P-256, policy
|
|
92
|
+
compilation, grants for acts other than release, goals as a distinct kind, and
|
|
93
|
+
any independent implementation besides this Python one. The process boundary
|
|
94
|
+
around the Sigma kernel isolates module names; it is not an OS sandbox. A view
|
|
95
|
+
cannot prove its own completeness, and every report says so. An assessment
|
|
96
|
+
has aggregate admission limits (records, bytes, `requires` edges, periods;
|
|
97
|
+
SPEC §9): beyond one it is refused, never answered in part.
|
|
98
|
+
|
|
99
|
+
## The repository
|
|
100
|
+
|
|
101
|
+
The repository also builds and checks Warrant with Warrant: SPEC.md is
|
|
102
|
+
generated from the claim records, the roadmap and the pull request reviews are
|
|
103
|
+
records in the same store, and a gate merges a pull request on a recorded
|
|
104
|
+
acceptance. That machinery (`tools/`, `.warrant/`, `.github/`) is evidence
|
|
105
|
+
behind the package, not part of it: `tests/boundary_test.py` refuses a core
|
|
106
|
+
module that imports it and a wheel or sdist that carries it.
|
|
107
|
+
[docs/REPOSITORY.md](https://github.com/s0fractal/warrant/blob/master/docs/REPOSITORY.md)
|
|
108
|
+
describes it, with the checks to run from a checkout;
|
|
109
|
+
[CHANGELOG.md](https://github.com/s0fractal/warrant/blob/master/CHANGELOG.md)
|
|
110
|
+
records what changed.
|
|
111
|
+
|
|
112
|
+
Licensed MIT. See [TRADEMARK.md](https://github.com/s0fractal/warrant/blob/master/TRADEMARK.md) for the name.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
# Warrant 2 (SPEC.md). A new distribution name on purpose: `warrant-verify`
|
|
7
|
+
# (<= 0.12.0) is the retired 0.x generation and keeps its own meaning.
|
|
8
|
+
name = "warrant-graph"
|
|
9
|
+
version = "2.0.0a1"
|
|
10
|
+
description = "Record transitions of work with their residual, close loops exactly, and hand the next agent a capsule instead of a transcript."
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
license = { text = "MIT" }
|
|
14
|
+
authors = [{ name = "s0fractal" }]
|
|
15
|
+
dependencies = ["cryptography>=41"]
|
|
16
|
+
|
|
17
|
+
[project.optional-dependencies]
|
|
18
|
+
# `compute` conditions need the Sigma provider (sigma_provider in the sigma-glyph
|
|
19
|
+
# distribution, released on PyPI as 0.8.0). Its provider identity is
|
|
20
|
+
# 0caff793d00dd798fa0af89517674c2ca562e1d517e7c969cc40617778c776c5; CI checks the installed bytes against it, since a version
|
|
21
|
+
# pin alone does not name bytes. Without it, attest and observe work and every
|
|
22
|
+
# REPLAYED basis is UNVERIFIED.
|
|
23
|
+
compute = ["sigma-glyph==0.8.0"]
|
|
24
|
+
# The thin stdio MCP front end of warrant_agent (`warrant-agent-mcp`), on the
|
|
25
|
+
# official Python SDK at one exact version.
|
|
26
|
+
mcp = ["mcp==2.3.0"]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/s0fractal/warrant"
|
|
30
|
+
Specification = "https://github.com/s0fractal/warrant/blob/master/SPEC.md"
|
|
31
|
+
|
|
32
|
+
[project.scripts]
|
|
33
|
+
warrant = "warrant.cli:main"
|
|
34
|
+
warrant-agent = "warrant_agent.cli:main"
|
|
35
|
+
warrant-agent-mcp = "warrant_agent.mcp_server:main"
|
|
36
|
+
|
|
37
|
+
[tool.setuptools]
|
|
38
|
+
packages = ["warrant", "warrant_agent"]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""Warrant 2: transitions of work, exact closures and what remains open (SPEC.md)."""
|
|
2
|
+
from .jcs import canon, loads
|
|
3
|
+
from .engine import assess, capsule, frontier, profile, questions, reliance
|
|
4
|
+
from .keys import Key
|
|
5
|
+
from .records import accept, challenge, duty, grant, item, observation, record, transition
|
|
6
|
+
from .store import Snapshot, Store, Trust
|
|
7
|
+
|
|
8
|
+
__version__ = "2.0.0a1"
|
|
9
|
+
__all__ = ["Key", "Snapshot", "Store", "Trust", "accept", "assess", "canon", "capsule", "challenge", "duty",
|
|
10
|
+
"frontier", "grant", "item", "loads", "observation", "profile", "questions", "record", "reliance",
|
|
11
|
+
"transition"]
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""Bindings and roles of a repository's trust (the open circle of witnesses, part A, and
|
|
2
|
+
AMEND 1 of #170): the one rule tools/claims.py and a warrant-agent workspace admit keys by.
|
|
3
|
+
|
|
4
|
+
A binding certifies itself: its key signs canon({actor, public, purpose}). `admit_bindings`
|
|
5
|
+
admits one mechanically, in file order, under the roles .warrant/roles.json pins; nobody judges
|
|
6
|
+
who may join. A binding grants only "this key signs as this actor" (SPEC §6). This module reads
|
|
7
|
+
documents; it writes none and runs nothing (the claims tool writes them)."""
|
|
8
|
+
from . import jcs as C
|
|
9
|
+
from . import keys as K
|
|
10
|
+
from . import records as R
|
|
11
|
+
from . import shapes as S
|
|
12
|
+
from .store import Trust
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Open circle of witnesses: a binding certifies itself (its key signs it); nobody admits anyone.
|
|
16
|
+
BINDINGS = "warrant-claims/bindings@1" # .warrant/trust.json: {"bindings": BINDINGS, "keys": [...]}
|
|
17
|
+
BINDING = "warrant-claims/binding@1" # the purpose a proof signs: canon({actor, public, purpose})
|
|
18
|
+
BINDING_FIELDS = ("actor", "public", "proof")
|
|
19
|
+
ROLES = "warrant-claims/roles@1" # .warrant/roles.json: the actors the configuration gives a role
|
|
20
|
+
COLLECTIVE = "collective" # a role no key signs as (readers): never bindable
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def binding_message(actor, public):
|
|
24
|
+
"""The bytes a binding's proof signs: canon({actor, public, purpose}). It starts with `{`,
|
|
25
|
+
so it is never the message of a record signature ("warrant-sig-v1:" || id)."""
|
|
26
|
+
return C.canon({"actor": actor, "public": public, "purpose": BINDING})
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def binding_proof(key, actor):
|
|
30
|
+
return key.sign(binding_message(actor, key.public))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def read_roles(doc):
|
|
34
|
+
"""({actor: public hex | None | COLLECTIVE}, problems) of a roles document (.warrant/roles.json).
|
|
35
|
+
|
|
36
|
+
AMEND 1 of #170: a name the repository's own configuration gives a role (an acceptor, a
|
|
37
|
+
creditor, the claims' author) is not first-come. Its key is pinned here, as a receiver's
|
|
38
|
+
profile pins the keys it trusts: a hex64 public key (a binding of that actor is admitted
|
|
39
|
+
with exactly that key), null (reserved: not bindable until a pin names its key) or
|
|
40
|
+
"collective" (a role no key signs as, such as `readers`: never bindable). Every other
|
|
41
|
+
name stays first-come. Changing who a role is, is a diff of this reviewed file."""
|
|
42
|
+
if not (isinstance(doc, dict) and set(doc) == {"roles", "actors"} and doc["roles"] == ROLES
|
|
43
|
+
and isinstance(doc["actors"], dict)):
|
|
44
|
+
return {}, [("ROLES_SHAPE", f".warrant/roles.json is not {{\"roles\": {ROLES!r}, \"actors\": {{...}}}}")]
|
|
45
|
+
roles, problems = {}, []
|
|
46
|
+
for actor, v in doc["actors"].items():
|
|
47
|
+
try:
|
|
48
|
+
R.check_actor(actor)
|
|
49
|
+
except R.Invalid as e:
|
|
50
|
+
problems.append(("ROLES_SHAPE", f".warrant/roles.json: {actor[:60]!r} is not an actor id: {e}"))
|
|
51
|
+
continue
|
|
52
|
+
if not (v is None or v == COLLECTIVE or S.hex64(v)):
|
|
53
|
+
problems.append(("ROLES_SHAPE", f".warrant/roles.json: {actor}: a role is a hex64 public key, null or "
|
|
54
|
+
f"{COLLECTIVE!r}, not {str(v)[:70]!r}"))
|
|
55
|
+
continue
|
|
56
|
+
roles[actor] = v
|
|
57
|
+
return roles, problems
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _role_name(v):
|
|
61
|
+
"""A role value for a message: 'key <id>' for a key, else what it is (never raises)."""
|
|
62
|
+
if S.hex64(v):
|
|
63
|
+
return f"key {K.key_id(v)[:12]}"
|
|
64
|
+
if v == COLLECTIVE:
|
|
65
|
+
return "collective"
|
|
66
|
+
return "reserved" if v is None else repr(v)[:40]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def admit_bindings(doc, legacy=False, roles=None):
|
|
70
|
+
"""(admitted [(actor, public)], problems [(code, detail)]) of a bindings document.
|
|
71
|
+
|
|
72
|
+
A binding is admitted mechanically, in file order, iff its proof is the signature of its
|
|
73
|
+
own key over binding_message(actor, public), its actor id has SPEC-3-21's shape, its
|
|
74
|
+
actor's role (`roles`, read_roles) admits that key, its key is not bound already, and its
|
|
75
|
+
actor is not bound already to another key: the first binding of a name with no role
|
|
76
|
+
wins, and a second key for it would need a record signed by the first, which this tool
|
|
77
|
+
does not implement (rotation is out of scope), so it is refused. Nobody judges who may
|
|
78
|
+
join; what a binding grants is only "this key signs as this actor" (SPEC §6). `legacy`
|
|
79
|
+
reads a trust/2 document (actor, public, no proof) as admitted: only for a base revision
|
|
80
|
+
written before bindings carried proofs."""
|
|
81
|
+
if legacy and isinstance(doc, dict) and doc.get("warrant") == "trust/2":
|
|
82
|
+
try:
|
|
83
|
+
return [(a, p) for a, p in Trust(doc).keys.values()], []
|
|
84
|
+
except R.Invalid as e:
|
|
85
|
+
return [], [("BINDINGS_SHAPE", f".warrant/trust.json: {e}")]
|
|
86
|
+
if not (isinstance(doc, dict) and set(doc) == {"bindings", "keys"} and doc["bindings"] == BINDINGS
|
|
87
|
+
and isinstance(doc["keys"], list)):
|
|
88
|
+
return [], [("BINDINGS_SHAPE", f".warrant/trust.json is not {{\"bindings\": {BINDINGS!r}, \"keys\": [...]}} "
|
|
89
|
+
"(tools/claims.py bind writes it)")]
|
|
90
|
+
admitted, problems = [], []
|
|
91
|
+
publics = [k.get("public") for k in doc["keys"] if isinstance(k, dict)]
|
|
92
|
+
for i, k in enumerate(doc["keys"]):
|
|
93
|
+
code, why = _binding_problem(k, publics, admitted, roles or {})
|
|
94
|
+
if code:
|
|
95
|
+
problems.append((code, f".warrant/trust.json keys[{i}]: {why}"))
|
|
96
|
+
else:
|
|
97
|
+
admitted.append((k["actor"], k["public"]))
|
|
98
|
+
return admitted, problems
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _binding_problem(k, publics, admitted, roles):
|
|
102
|
+
"""(code, why) when entry `k` is not admitted after `admitted`, else (None, None)."""
|
|
103
|
+
if not (isinstance(k, dict) and set(k) <= set(BINDING_FIELDS) and {"actor", "public"} <= set(k)
|
|
104
|
+
and S.hex64(k["public"])):
|
|
105
|
+
return "BINDING_SHAPE", f"an entry is {{actor, public: hex64, proof: hex128}}, not {str(k)[:120]}"
|
|
106
|
+
try:
|
|
107
|
+
R.check_actor(k["actor"])
|
|
108
|
+
except R.Invalid as e:
|
|
109
|
+
return "BINDING_ACTOR_SHAPE", f"{str(k['actor'])[:60]!r} is not an actor id (SPEC-3-21): {e}"
|
|
110
|
+
if "proof" not in k:
|
|
111
|
+
return "BINDING_UNPROVEN", f"{k['actor']}: no proof; the key's own signature over the binding is needed"
|
|
112
|
+
msg = binding_message(k["actor"], k["public"])
|
|
113
|
+
if not K.verify(k["public"], k["proof"], msg):
|
|
114
|
+
other = [p for p in publics if p != k["public"] and isinstance(p, str) and K.verify(p, k["proof"], msg)]
|
|
115
|
+
if other:
|
|
116
|
+
return "BINDING_PROOF_OTHER_KEY", (f"{k['actor']}: the proof is signed by key {K.key_id(other[0])[:12]}, "
|
|
117
|
+
f"not by the key it binds ({K.key_id(k['public'])[:12]})")
|
|
118
|
+
return "BINDING_PROOF_FORGED", f"{k['actor']}: the proof is not the bound key's signature over this binding"
|
|
119
|
+
role = roles.get(k["actor"], k["public"])
|
|
120
|
+
if role != k["public"]: # one rule; the code only says which kind of role refused it
|
|
121
|
+
if role == COLLECTIVE:
|
|
122
|
+
return "BINDING_ROLE_COLLECTIVE", f"{k['actor']} is a collective role in .warrant/roles.json: no key signs as it"
|
|
123
|
+
if role is None:
|
|
124
|
+
return "BINDING_ROLE_RESERVED", (f"{k['actor']} is reserved in .warrant/roles.json: it is bindable once a "
|
|
125
|
+
"reviewed pin names its key")
|
|
126
|
+
return "BINDING_ROLE_KEY", (f"{k['actor']}: .warrant/roles.json pins {_role_name(role)}, this binding is of "
|
|
127
|
+
f"key {K.key_id(k['public'])[:12]}")
|
|
128
|
+
if any(p == k["public"] for _, p in admitted):
|
|
129
|
+
return "BINDING_KEY_TWICE", f"key {K.key_id(k['public'])[:12]} is bound already"
|
|
130
|
+
first = next((p for a, p in admitted if a == k["actor"]), None)
|
|
131
|
+
if first is not None:
|
|
132
|
+
return "BINDING_ACTOR_TAKEN", (f"{k['actor']} is bound already to key {K.key_id(first)[:12]}; the first "
|
|
133
|
+
"binding wins, and rotation (a record signed by the first key) is not "
|
|
134
|
+
"implemented, so a second key for an actor is refused")
|
|
135
|
+
return None, None
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def trust_of(bindings):
|
|
139
|
+
"""A Trust of (actor, public) pairs, the first binding of each key kept."""
|
|
140
|
+
seen, pairs = set(), []
|
|
141
|
+
for a, p in bindings:
|
|
142
|
+
if p not in seen:
|
|
143
|
+
seen.add(p)
|
|
144
|
+
pairs.append((a, p))
|
|
145
|
+
return Trust(Trust.document(pairs))
|