sello 0.1.0
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.
- package/LICENSE +200 -0
- package/README.md +195 -0
- package/SPEC.md +738 -0
- package/docs/assets/sello-banner.png +0 -0
- package/docs/assets/sello-social-preview.png +0 -0
- package/docs/decisions.md +79 -0
- package/docs/paper/notarized-agents.md +523 -0
- package/docs/paper/notarized-agents.pdf +0 -0
- package/docs/paper/notarized-agents.tex +1387 -0
- package/docs/paper/refs.bib +245 -0
- package/docs/performance.md +24 -0
- package/docs/release-checklist.md +56 -0
- package/docs/sdk-build-plan.md +214 -0
- package/docs/sdk-quickstart.md +115 -0
- package/docs/sdk-security-audit.md +53 -0
- package/docs/security-review.md +54 -0
- package/examples/mcp-tool-server.ts +250 -0
- package/examples/quickstart-tool.ts +178 -0
- package/fixtures/vectors/.gitkeep +1 -0
- package/fixtures/vectors/sello-v0.1.json +101 -0
- package/package.json +52 -0
- package/src/cbor.ts +337 -0
- package/src/cli/bench.ts +390 -0
- package/src/cli/demo.ts +114 -0
- package/src/cli/sello.ts +514 -0
- package/src/cose/protected-header.ts +210 -0
- package/src/cose/sign1.ts +124 -0
- package/src/crypto/ed25519.ts +117 -0
- package/src/crypto/identifiers.ts +64 -0
- package/src/hpke/base.ts +349 -0
- package/src/hpke/receipt.ts +79 -0
- package/src/index.ts +15 -0
- package/src/log/canonical-url.ts +168 -0
- package/src/log/mock-log.ts +170 -0
- package/src/log/rekor.ts +147 -0
- package/src/log/types.ts +27 -0
- package/src/mcp/middleware.ts +198 -0
- package/src/owner/verify.ts +276 -0
- package/src/receipt/body.ts +210 -0
- package/src/registry/json-registry.ts +233 -0
- package/src/sdk/index.ts +22 -0
- package/src/sdk/keys.ts +191 -0
- package/src/sdk/logs.ts +200 -0
- package/src/sdk/publisher.ts +145 -0
- package/src/sdk/service.ts +562 -0
- package/src/service/create-receipt.ts +178 -0
- package/src/token/jws-profile.ts +174 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
@techreport{RFC6962,
|
|
2
|
+
author = {Laurie, B. and Langley, A. and Kasper, E.},
|
|
3
|
+
title = {Certificate Transparency},
|
|
4
|
+
institution = {IETF},
|
|
5
|
+
type = {RFC},
|
|
6
|
+
number = {6962},
|
|
7
|
+
year = {2013},
|
|
8
|
+
month = jun
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@techreport{RFC9162,
|
|
12
|
+
author = {Laurie, B. and Messeri, E. and Stradling, R.},
|
|
13
|
+
title = {Certificate Transparency Version 2.0},
|
|
14
|
+
institution = {IETF},
|
|
15
|
+
type = {RFC},
|
|
16
|
+
number = {9162},
|
|
17
|
+
year = {2021},
|
|
18
|
+
month = dec
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@techreport{RFC7515,
|
|
22
|
+
author = {Jones, M. and Bradley, J. and Sakimura, N.},
|
|
23
|
+
title = {JSON Web Signature (JWS)},
|
|
24
|
+
institution = {IETF},
|
|
25
|
+
type = {RFC},
|
|
26
|
+
number = {7515},
|
|
27
|
+
year = {2015},
|
|
28
|
+
month = may
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@techreport{RFC8610,
|
|
32
|
+
author = {Birkholz, H. and Vigano, C. and Bormann, C.},
|
|
33
|
+
title = {Concise {Data} {Definition} {Language} ({CDDL}): {A} {Notational} {Convention} to {Express} {Concise} {Binary} {Object} {Representation} ({CBOR}) and {JSON} {Data} {Structures}},
|
|
34
|
+
institution = {IETF},
|
|
35
|
+
type = {RFC},
|
|
36
|
+
number = {8610},
|
|
37
|
+
year = {2019},
|
|
38
|
+
month = jun
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@techreport{RFC9052,
|
|
42
|
+
author = {Schaad, J.},
|
|
43
|
+
title = {{CBOR} {Object} {Signing} and {Encryption} ({COSE}): {Structures} and {Process}},
|
|
44
|
+
institution = {IETF},
|
|
45
|
+
type = {RFC},
|
|
46
|
+
number = {9052},
|
|
47
|
+
year = {2022},
|
|
48
|
+
month = aug
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@techreport{RFC9180,
|
|
52
|
+
author = {Barnes, R. and Bhargavan, K. and Lipp, B. and Wood, C.},
|
|
53
|
+
title = {Hybrid {Public} {Key} {Encryption}},
|
|
54
|
+
institution = {IETF},
|
|
55
|
+
type = {RFC},
|
|
56
|
+
number = {9180},
|
|
57
|
+
year = {2022},
|
|
58
|
+
month = feb
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@techreport{RFC9449,
|
|
62
|
+
author = {Fett, D. and Campbell, B. and Bradley, J. and Lodderstedt, T. and Jones, M. and Waite, D.},
|
|
63
|
+
title = {{OAuth} 2.0 {Demonstrating} {Proof} of {Possession} ({DPoP})},
|
|
64
|
+
institution = {IETF},
|
|
65
|
+
type = {RFC},
|
|
66
|
+
number = {9449},
|
|
67
|
+
year = {2023},
|
|
68
|
+
month = sep
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@article{Heinrich2021,
|
|
72
|
+
author = {Heinrich, A. and Stute, M. and Kornhuber, T. and Hollick, M.},
|
|
73
|
+
title = {Who {Can} {Find} {My} {Devices}? {Security} and {Privacy} of {Apple}'s {Crowd}-{Sourced} {Bluetooth} {Location} {Tracking} {System}},
|
|
74
|
+
journal = {Proceedings on Privacy Enhancing Technologies},
|
|
75
|
+
volume = {2021},
|
|
76
|
+
number = {3},
|
|
77
|
+
pages = {227--245},
|
|
78
|
+
year = {2021}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@inproceedings{Syta2016,
|
|
82
|
+
author = {Syta, E. and Tamas, I. and Visher, D. and Wolinsky, D. I. and Jovanovic, P. and Gasser, L. and Gailly, N. and Khoffi, I. and Ford, B.},
|
|
83
|
+
title = {Keeping {Authorities} `{Honest} or {Bust}' with {Decentralized} {Witness} {Cosigning}},
|
|
84
|
+
booktitle = {IEEE Symposium on Security and Privacy},
|
|
85
|
+
pages = {526--545},
|
|
86
|
+
year = {2016}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@article{bernstein2012ed25519,
|
|
90
|
+
author = {Bernstein, D. J. and Duif, N. and Lange, T. and Schwabe, P. and Yang, B.},
|
|
91
|
+
title = {High-speed high-security signatures},
|
|
92
|
+
journal = {Journal of Cryptographic Engineering},
|
|
93
|
+
volume = {2},
|
|
94
|
+
number = {2},
|
|
95
|
+
year = {2012}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@misc{sigstore-rekor,
|
|
99
|
+
author = {{The Sigstore Authors}},
|
|
100
|
+
title = {Rekor: {Software} {Supply} {Chain} {Transparency} {Log}},
|
|
101
|
+
howpublished = {\url{https://github.com/sigstore/rekor}},
|
|
102
|
+
year = {2024}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@misc{sello-repo,
|
|
106
|
+
author = {Figuera, J.},
|
|
107
|
+
title = {Sello: {A} protocol for receiver-attested confidential receipts for {AI} agent actions},
|
|
108
|
+
howpublished = {Reference implementation, \url{https://github.com/juanfiguera/sello}},
|
|
109
|
+
year = {2026}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@techreport{scitt-architecture,
|
|
113
|
+
author = {Birkholz, H. and Delignat-Lavaud, A. and Fournet, C. and Deshpande, Y. and Lasker, S.},
|
|
114
|
+
title = {An {Architecture} for {Trustworthy} and {Transparent} {Digital} {Supply} {Chains}},
|
|
115
|
+
institution = {IETF},
|
|
116
|
+
type = {Internet-Draft},
|
|
117
|
+
number = {draft-ietf-scitt-architecture},
|
|
118
|
+
year = {2026}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@techreport{scitt-scrapi,
|
|
122
|
+
author = {Steele, O. and Birkholz, H.},
|
|
123
|
+
title = {{SCITT} {Reference} {APIs}},
|
|
124
|
+
institution = {IETF},
|
|
125
|
+
type = {Internet-Draft},
|
|
126
|
+
number = {draft-ietf-scitt-scrapi},
|
|
127
|
+
year = {2026}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@techreport{scitt-ccf,
|
|
131
|
+
author = {Delignat-Lavaud, A. and others},
|
|
132
|
+
title = {{SCITT} {Receipts}: {CCF} {Profile}},
|
|
133
|
+
institution = {IETF},
|
|
134
|
+
type = {Internet-Draft},
|
|
135
|
+
number = {draft-ietf-scitt-receipts-ccf-profile},
|
|
136
|
+
year = {2026}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@misc{agentreceipts,
|
|
140
|
+
author = {Jongerius, O.},
|
|
141
|
+
title = {Agent {Receipts}},
|
|
142
|
+
howpublished = {\url{https://agentreceipts.ai}},
|
|
143
|
+
year = {2025--2026}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@misc{signet,
|
|
147
|
+
author = {Hou, W.},
|
|
148
|
+
title = {Signet: {Cryptographic} {Action} {Receipts} for {AI} {Agents}},
|
|
149
|
+
howpublished = {\url{https://github.com/Prismer-AI/signet}},
|
|
150
|
+
year = {2025--2026}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@misc{pipelock,
|
|
154
|
+
author = {{PipeLab}},
|
|
155
|
+
title = {Pipelock: {AI} {Agent} {Security} {Gateway}},
|
|
156
|
+
howpublished = {\url{https://pipelab.org}},
|
|
157
|
+
year = {2026}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@misc{aps,
|
|
161
|
+
author = {Pidlisnyi, T.},
|
|
162
|
+
title = {Agent {Passport} {System}},
|
|
163
|
+
howpublished = {\url{https://github.com/aeoess/agent-passport-system}},
|
|
164
|
+
year = {2025--2026}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
@techreport{farley-acta,
|
|
168
|
+
author = {Farley, T.},
|
|
169
|
+
title = {Signed {Decision} {Receipts} for {Machine}-to-{Machine} {Access} {Control}},
|
|
170
|
+
institution = {IETF},
|
|
171
|
+
type = {Internet-Draft},
|
|
172
|
+
number = {draft-farley-acta-signed-receipts},
|
|
173
|
+
year = {2026}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
@techreport{nivalto-agentroa,
|
|
177
|
+
author = {Michalak, J.},
|
|
178
|
+
title = {Agent {Route} {Origin} {Authorization} ({AgentROA}): {A} {Cryptographic} {Policy} {Enforcement} {Framework} for {AI} {Agent} {Actions}},
|
|
179
|
+
institution = {IETF},
|
|
180
|
+
type = {Internet-Draft},
|
|
181
|
+
number = {draft-nivalto-agentroa-route-authorization},
|
|
182
|
+
year = {2026}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@misc{attestedintelligence,
|
|
186
|
+
author = {{Attested Intelligence Holdings LLC}},
|
|
187
|
+
title = {Attested {Governance} {Artifacts}: {Public} {Comment} on {Docket} {NIST}-2025-0035},
|
|
188
|
+
year = {2026},
|
|
189
|
+
month = mar
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
@techreport{kamimura-scitt,
|
|
193
|
+
author = {Kamimura, S.},
|
|
194
|
+
title = {{SCITT} {Profile} for {Financial} {Trading} {Audit} {Trails}},
|
|
195
|
+
institution = {IETF},
|
|
196
|
+
type = {Internet-Draft},
|
|
197
|
+
number = {draft-kamimura-scitt-vcp},
|
|
198
|
+
year = {2026}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
@article{zhang-righttohistory,
|
|
202
|
+
author = {Zhang, J.},
|
|
203
|
+
title = {Right to {History}: {A} {Sovereignty} {Kernel} for {Verifiable} {AI} {Agent} {Execution}},
|
|
204
|
+
journal = {arXiv preprint arXiv:2602.20214},
|
|
205
|
+
year = {2026},
|
|
206
|
+
month = feb
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
@article{gupta-verifiabilityfirst,
|
|
210
|
+
author = {Gupta, A.},
|
|
211
|
+
title = {Verifiability-{First} {Agents}: {Provable} {Observability} and {Lightweight} {Audit} {Agents} for {Controlling} {Autonomous} {LLM} {Systems}},
|
|
212
|
+
journal = {arXiv preprint arXiv:2512.17259},
|
|
213
|
+
year = {2025},
|
|
214
|
+
month = dec
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
@article{basu-toolreceipts,
|
|
218
|
+
author = {Basu, A.},
|
|
219
|
+
title = {Tool {Receipts}, {Not} {Zero}-{Knowledge} {Proofs}: {Practical} {Hallucination} {Detection} for {AI} {Agents}},
|
|
220
|
+
journal = {arXiv preprint arXiv:2603.10060},
|
|
221
|
+
year = {2026},
|
|
222
|
+
month = mar
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
@inproceedings{casper-blackbox,
|
|
226
|
+
author = {Casper, Stephen and Ezell, Carson and Siegmann, Charlotte and Kolt, Noam and Curtis, Taylor Lynn and Bucknall, Benjamin and Haupt, Andreas and Wei, Kevin and Scheurer, J{\'e}r{\'e}my and Hobbhahn, Marius and Sharkey, Lee and Krishna, Satyapriya and Von Hagen, Marvin and Alberti, Silas and Chan, Alan and Sun, Qinyi and Gerovitch, Michael and Bau, David and Tegmark, Max and Krueger, David and Hadfield-Menell, Dylan},
|
|
227
|
+
title = {Black-Box {Access} is {Insufficient} for {Rigorous} {AI} {Audits}},
|
|
228
|
+
booktitle = {Proceedings of the 2024 ACM Conference on Fairness, Accountability, and Transparency (FAccT)},
|
|
229
|
+
pages = {2254--2272},
|
|
230
|
+
year = {2024}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
@inproceedings{kales-pir-ct,
|
|
234
|
+
author = {Kales, D. and Omolola, O. and Ramacher, S.},
|
|
235
|
+
title = {Revisiting {User} {Privacy} for {Certificate} {Transparency}},
|
|
236
|
+
booktitle = {IEEE European Symposium on Security and Privacy},
|
|
237
|
+
year = {2019}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@misc{euaiact,
|
|
241
|
+
key = {EU AI Act},
|
|
242
|
+
title = {Regulation ({EU}) 2024/1689 of the {European} {Parliament} and of the {Council} laying down harmonised rules on artificial intelligence ({Artificial} {Intelligence} {Act})},
|
|
243
|
+
year = {2024},
|
|
244
|
+
month = jul
|
|
245
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Performance And Receipt Size
|
|
2
|
+
|
|
3
|
+
Sello includes a small local benchmark for tracking rough receipt size and implementation performance:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
node --run bench
|
|
7
|
+
node --run bench -- --iterations 500 --warmup 500 --json
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
The benchmark uses the reference implementation with fixed local keys and the mock transparency log. By default it runs 500 warmup iterations before measuring. It reports:
|
|
11
|
+
|
|
12
|
+
- CBOR receipt body size.
|
|
13
|
+
- COSE protected-header size.
|
|
14
|
+
- HPKE payload size.
|
|
15
|
+
- Full COSE_Sign1 envelope size.
|
|
16
|
+
- Mock proof JSON size.
|
|
17
|
+
- Average receipt creation time.
|
|
18
|
+
- Average one-receipt verification time.
|
|
19
|
+
- Batch verification time and per-receipt average.
|
|
20
|
+
- Mean, median, p95, p99, and standard deviation for per-receipt creation and one-receipt verification samples.
|
|
21
|
+
|
|
22
|
+
These numbers are useful for local regression tracking and integration planning. They are not formal cryptographic benchmarks: results vary by CPU, Node version, OS, and thermal state, and the mock log is not a live Rekor deployment.
|
|
23
|
+
|
|
24
|
+
For production capacity planning, measure against the real service middleware, real action payload canonicalization, the chosen log adapter, and the deployment's key storage path.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Release Checklist
|
|
2
|
+
|
|
3
|
+
Use this checklist before publishing a Sello npm release.
|
|
4
|
+
|
|
5
|
+
## Preflight
|
|
6
|
+
|
|
7
|
+
- Confirm `git status --short` is clean.
|
|
8
|
+
- Confirm `node -v` is `v24.0.0` or newer.
|
|
9
|
+
- If multiple Node versions are installed, confirm `PATH` resolves `node` to Node 24 before running package scripts.
|
|
10
|
+
- Confirm `package.json` has the intended version.
|
|
11
|
+
- Confirm `README.md` and `docs/sdk-quickstart.md` match the current CLI and examples.
|
|
12
|
+
- Confirm the paper link and local PDF are current, if the paper changed.
|
|
13
|
+
|
|
14
|
+
## Local Verification
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
node --run test
|
|
18
|
+
npm pack --dry-run
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Fresh clone smoke test:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
tmpdir=$(mktemp -d)
|
|
25
|
+
git clone https://github.com/juanfiguera/sello.git "$tmpdir/sello"
|
|
26
|
+
cd "$tmpdir/sello"
|
|
27
|
+
node -v # must be v24.0.0 or newer
|
|
28
|
+
node --run test
|
|
29
|
+
npm pack --dry-run
|
|
30
|
+
node --experimental-strip-types src/cli/sello.ts --help
|
|
31
|
+
node --experimental-strip-types src/cli/sello.ts dev --dry-run
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## npm Verification
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm whoami
|
|
38
|
+
npm view sello version
|
|
39
|
+
npm publish --dry-run
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
If the package name is already published, confirm the local version is greater than the registry version before publishing.
|
|
43
|
+
|
|
44
|
+
## Publish
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm publish
|
|
48
|
+
git tag v$(node -p "require('./package.json').version")
|
|
49
|
+
git push origin main --tags
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
After publishing:
|
|
53
|
+
|
|
54
|
+
- Confirm `npm view sello version` shows the new version.
|
|
55
|
+
- Confirm `npx sello --help` works from a clean temp directory.
|
|
56
|
+
- Confirm GitHub Actions passes on `main`.
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Stripe-Style Sello SDK Integration Plan
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
Build the first Sello SDK around a complete, Stripe-like loop:
|
|
6
|
+
|
|
7
|
+
1. Add one import.
|
|
8
|
+
2. Call `sello.service()`.
|
|
9
|
+
3. Wrap an existing tool handler.
|
|
10
|
+
4. Run the tool.
|
|
11
|
+
5. See verified logged actions.
|
|
12
|
+
|
|
13
|
+
Quickstart service code:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { sello } from "sello";
|
|
17
|
+
|
|
18
|
+
const receipts = sello.service();
|
|
19
|
+
|
|
20
|
+
export const createEvent = receipts.tool("calendar.create_event", async (request) => {
|
|
21
|
+
return calendar.events.create(request);
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Quickstart viewing:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx sello actions --token <agent-token>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Local dev can also show:
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
http://localhost:8787/actions
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Sello must work without `sello.build`. Self-hosting is first-class. Hosted `sello.build` is optional convenience.
|
|
38
|
+
|
|
39
|
+
## Configuration Model
|
|
40
|
+
|
|
41
|
+
Keep service emission and owner viewing separate.
|
|
42
|
+
|
|
43
|
+
### Service Runtime Env
|
|
44
|
+
|
|
45
|
+
Used by the app/tool server that emits receipts.
|
|
46
|
+
|
|
47
|
+
Self-hosted development:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
SELLO_SERVICE_ID=calendar.example.com/mcp/v1
|
|
51
|
+
SELLO_SERVICE_KEY=sello_dev_...
|
|
52
|
+
SELLO_TOKEN_ISSUER_PUBLIC_KEY=...
|
|
53
|
+
SELLO_LOG_URL=https://localhost:8787/api
|
|
54
|
+
SELLO_LOG_ENDPOINT=http://localhost:8787/api
|
|
55
|
+
SELLO_SUBMIT_MODE=background
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Self-hosted production:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
SELLO_SERVICE_ID=calendar.example.com/mcp/v1
|
|
62
|
+
SELLO_SERVICE_KEY=sello_live_local_...
|
|
63
|
+
SELLO_TOKEN_ISSUER_JWKS=https://auth.example.com/.well-known/jwks.json
|
|
64
|
+
SELLO_LOG_URL=https://logs.example.com/api
|
|
65
|
+
SELLO_SUBMIT_MODE=background
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Hosted `sello.build`:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
SELLO_SECRET_KEY=sello_test_...
|
|
72
|
+
SELLO_SECRET_KEY=sello_live_...
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Hosted mode uses one server-side secret to fetch service config and enable local receipt signing by default. Managed remote signing must be a later explicit opt-in because it changes the trust model.
|
|
76
|
+
|
|
77
|
+
### Viewer Runtime Env
|
|
78
|
+
|
|
79
|
+
Used by the owner CLI, local UI, or hosted dashboard to verify/decrypt actions.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
SELLO_OWNER_KEY=sello_owner_...
|
|
83
|
+
SELLO_REGISTRY_URL=https://registry.example.com/sello.json
|
|
84
|
+
SELLO_REGISTRY_SIGNATURE=...
|
|
85
|
+
SELLO_REGISTRY_TRUST_ROOT_PUBLIC_KEY=...
|
|
86
|
+
SELLO_LOG_URL=https://logs.example.com/api
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The owner key must not be required in the service process.
|
|
90
|
+
|
|
91
|
+
## Public API
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const receipts = sello.service();
|
|
95
|
+
const receipts = sello.service("calendar.example.com/mcp/v1");
|
|
96
|
+
const receipts = sello.service({ service, serviceKey, tokenIssuer, log, submit });
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
const wrapped = receipts.tool(actionType, handler, options);
|
|
101
|
+
await receipts.flush();
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Tool behavior:
|
|
105
|
+
|
|
106
|
+
- Verify token before handler execution.
|
|
107
|
+
- Emit `success`, `error`, or `denied` receipts.
|
|
108
|
+
- Return handler response unchanged.
|
|
109
|
+
- Rethrow handler errors.
|
|
110
|
+
- Use canonical JSON hashing by default.
|
|
111
|
+
- Submit in background by default.
|
|
112
|
+
- Support `submit.mode: "await"` for strict durability.
|
|
113
|
+
- Support explicit custom log adapters for self-hosting.
|
|
114
|
+
|
|
115
|
+
## Logged Actions UX
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npx sello actions --token <agent-token>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Behavior:
|
|
122
|
+
|
|
123
|
+
- Loads viewer config, not service config.
|
|
124
|
+
- Computes `sello_token_ref`.
|
|
125
|
+
- Queries trusted logs.
|
|
126
|
+
- Verifies inclusion, service signature, revocation, HPKE decryption, and receipt body shape.
|
|
127
|
+
- Prints verified actions and rejected receipts.
|
|
128
|
+
|
|
129
|
+
Local dev:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
npx sello dev
|
|
133
|
+
npx sello actions
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
In dev mode, `sello dev` remembers the latest dev token and owner key in ignored local state so `npx sello actions` works without extra flags.
|
|
137
|
+
|
|
138
|
+
Privacy rule:
|
|
139
|
+
|
|
140
|
+
- Public logs store encrypted receipts.
|
|
141
|
+
- Viewing action details requires the owner private key or delegated viewer key.
|
|
142
|
+
- Self-hosted CLI decrypts locally.
|
|
143
|
+
- Hosted dashboard must use client-side decryption or explicit delegated viewer keys.
|
|
144
|
+
|
|
145
|
+
## Phase Plan
|
|
146
|
+
|
|
147
|
+
### Phase 0: Baseline And SDK Contract
|
|
148
|
+
|
|
149
|
+
- Write SDK examples into docs first.
|
|
150
|
+
- Define env names, config precedence, and friendly errors.
|
|
151
|
+
- Document service env versus viewer env.
|
|
152
|
+
- Record deferred items: production Rekor proof verification, hosted dashboard, managed signing, durable queue.
|
|
153
|
+
- Run `node --run test` and `node --run pack:check`.
|
|
154
|
+
- Security audit: check the SDK contract does not weaken receiver-side signing or owner-side decryption.
|
|
155
|
+
|
|
156
|
+
### Phase 1: Env-First SDK Facade
|
|
157
|
+
|
|
158
|
+
- Add `sello.service()`.
|
|
159
|
+
- Add env config loader.
|
|
160
|
+
- Add key normalization for `Uint8Array` and encoded string inputs.
|
|
161
|
+
- Add explicit config override path.
|
|
162
|
+
- Add friendly missing-config errors.
|
|
163
|
+
- Tests: env loading, service id override, explicit config override, hosted config selection, no owner key required for service emission.
|
|
164
|
+
- Security audit: check secret handling, env precedence, errors, logging, and hosted/self-hosted boundaries.
|
|
165
|
+
|
|
166
|
+
### Phase 2: Receipt Build/Submit Split And Background Publisher
|
|
167
|
+
|
|
168
|
+
- Refactor receipt creation into build/encrypt/sign first, append second.
|
|
169
|
+
- Keep existing `createReceipt()` behavior by composing build + append.
|
|
170
|
+
- Add bounded background publisher with concurrency, `flush()`, `onSubmitError`, and `onDrop`.
|
|
171
|
+
- Default to background submission.
|
|
172
|
+
- Support `submit.mode: "await"`.
|
|
173
|
+
- Tests: existing receipt tests, built envelope verification, background latency, `flush()`, overflow, failures, await mode, concurrency.
|
|
174
|
+
- Security audit: check durability wording, queue bounds, memory pressure, failure handling, and unchanged cryptography.
|
|
175
|
+
|
|
176
|
+
### Phase 3: Tool Wrapper MVP
|
|
177
|
+
|
|
178
|
+
- Implement `receipts.tool(actionType, handler, options)`.
|
|
179
|
+
- Default token extraction, input hashing, output hashing, and error hashing.
|
|
180
|
+
- Support custom token extraction and canonicalizers.
|
|
181
|
+
- Preserve handler semantics exactly.
|
|
182
|
+
- Tests: success, error, denied, invalid token, custom extraction, custom canonicalizers, unchanged response, MCP compatibility.
|
|
183
|
+
- Security audit: check token verification ordering, plaintext leakage, and service identity binding.
|
|
184
|
+
|
|
185
|
+
### Phase 4: Logs And Action Viewing
|
|
186
|
+
|
|
187
|
+
- Add `sello.logs.memory(url)` for local tests/dev.
|
|
188
|
+
- Add `sello.logs.http(url, options?)` for self-hosted Sello-compatible log servers.
|
|
189
|
+
- Add `npx sello actions --token <token>`.
|
|
190
|
+
- Add local dev `/actions` page.
|
|
191
|
+
- Action viewing uses owner-side verification and decryption.
|
|
192
|
+
- Tests: memory log, HTTP append/query, CLI output, dev-mode token fallback, rejected reason codes, `/actions` states, no action details without owner/delegated key.
|
|
193
|
+
- Security audit: check owner-side decryption, no plaintext in public logs, and safe rejected-receipt display.
|
|
194
|
+
|
|
195
|
+
### Phase 5: Docs Polish And First-Run Flow
|
|
196
|
+
|
|
197
|
+
- Add README section: **Add Sello in a Few Lines**.
|
|
198
|
+
- Add `docs/sdk-quickstart.md`.
|
|
199
|
+
- Document self-hosted development, self-hosted production, `sello.build` development, and `sello.build` production.
|
|
200
|
+
- Document action viewing, token requirement, and privacy model.
|
|
201
|
+
- Keep advanced explicit config separate from quickstart.
|
|
202
|
+
- Tests: `node --run test`, `node --run pack:check`, manual quickstart run, docs do not require `sello.build`.
|
|
203
|
+
- Security audit: review README, quickstart, CLI help, and examples with the full plan in hand.
|
|
204
|
+
|
|
205
|
+
## Assumptions
|
|
206
|
+
|
|
207
|
+
- MVP ships inside the current `sello` package.
|
|
208
|
+
- One excellent generic tool wrapper beats many shallow adapters.
|
|
209
|
+
- Testing is required for every phase before the next phase starts.
|
|
210
|
+
- A security audit is required after every phase before the next phase starts.
|
|
211
|
+
- Each auditor receives the full plan, current phase scope, deferred-item list, and threat model.
|
|
212
|
+
- The service process emits receipts but does not need the owner private key.
|
|
213
|
+
- Local/self-hosted usage is first-class.
|
|
214
|
+
- `sello.build` is optional convenience, not a protocol requirement.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Sello SDK Quickstart
|
|
2
|
+
|
|
3
|
+
Sello's SDK is designed to make the first receipt easy: wrap a tool handler, run it, and inspect verified actions.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { sello } from "sello";
|
|
7
|
+
|
|
8
|
+
const receipts = sello.service();
|
|
9
|
+
|
|
10
|
+
export const createEvent = receipts.tool("calendar.create_event", async (request) => {
|
|
11
|
+
return calendar.events.create(request);
|
|
12
|
+
});
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The service process emits receipts. It does not need the owner private key.
|
|
16
|
+
|
|
17
|
+
## Local Development
|
|
18
|
+
|
|
19
|
+
Inside this repo, start the local log and action viewer:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
node --run dev
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
In another terminal, run the repo's wrapped tool example:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
node --run example:tool
|
|
29
|
+
node --run actions
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
For an MCP-shaped `tools/call` boundary, run:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
node --run example:mcp
|
|
36
|
+
node --run actions
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
or open:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
http://localhost:8787/actions
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Both examples read `.sello/dev.json`, wrap a fake calendar handler, submit one encrypted receipt, and let the owner verify it locally.
|
|
46
|
+
|
|
47
|
+
For your own tool server, copy the printed service env:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
SELLO_SERVICE_ID=calendar.example.com/mcp/v1
|
|
51
|
+
SELLO_SERVICE_KEY=sello_dev_...
|
|
52
|
+
SELLO_TOKEN_ISSUER_PUBLIC_KEY=...
|
|
53
|
+
SELLO_LOG_URL=https://localhost:8787/api
|
|
54
|
+
SELLO_LOG_ENDPOINT=http://localhost:8787/api
|
|
55
|
+
SELLO_SUBMIT_MODE=background
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Call your wrapped tool with the printed dev token. Then view actions:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npx sello actions
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Self-Hosted Production
|
|
65
|
+
|
|
66
|
+
Use your own Sello-compatible log server:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
SELLO_SERVICE_ID=calendar.example.com/mcp/v1
|
|
70
|
+
SELLO_SERVICE_KEY=sello_live_local_...
|
|
71
|
+
SELLO_TOKEN_ISSUER_JWKS=https://auth.example.com/.well-known/jwks.json
|
|
72
|
+
SELLO_LOG_URL=https://logs.example.com/api
|
|
73
|
+
SELLO_SUBMIT_MODE=background
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
View actions from an owner-controlled environment:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
SELLO_OWNER_KEY=sello_owner_live_...
|
|
80
|
+
SELLO_REGISTRY_URL=https://registry.example.com/sello.json
|
|
81
|
+
SELLO_REGISTRY_SIGNATURE=...
|
|
82
|
+
SELLO_REGISTRY_TRUST_ROOT_PUBLIC_KEY=...
|
|
83
|
+
SELLO_LOG_URL=https://logs.example.com/api
|
|
84
|
+
npx sello actions --token <agent-token>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Hosted Sello
|
|
88
|
+
|
|
89
|
+
Hosted mode keeps the application code the same:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
SELLO_SECRET_KEY=sello_test_...
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The secret is server-side only. Hosted mode is optional; Sello does not require `sello.build`.
|
|
96
|
+
|
|
97
|
+
## Advanced Explicit Config
|
|
98
|
+
|
|
99
|
+
You can bypass env config entirely:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
const receipts = sello.service({
|
|
103
|
+
service: "calendar.example.com/mcp/v1",
|
|
104
|
+
serviceKey: { kid, privateKey },
|
|
105
|
+
tokenIssuer: tokenIssuerPublicKey,
|
|
106
|
+
log: sello.logs.memory("https://localhost:8787/api"),
|
|
107
|
+
submit: { mode: "await" },
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Use explicit config for tests, embedded runtimes, or custom self-hosted deployments.
|
|
112
|
+
|
|
113
|
+
## Privacy
|
|
114
|
+
|
|
115
|
+
Public logs store encrypted receipts. Viewing action details requires the owner private key or an explicitly delegated viewer key. The CLI decrypts locally; hosted dashboards must use client-side decryption or delegated viewer keys.
|