@nullsquare/agent-authority 0.4.1 → 0.4.3
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/README.md +37 -12
- package/ROADMAP.md +15 -9
- package/docs/authority-extractor-conformance.md +95 -0
- package/docs/evidence.md +134 -32
- package/docs/npm-release.md +4 -2
- package/docs/task-leases.md +95 -28
- package/examples/live-github-derived-mutation.js +82 -65
- package/examples/live-google-cross-provider.js +13 -8
- package/package.json +3 -2
- package/src/authority-evidence.js +146 -0
- package/src/guard.js +8 -1
- package/src/providers/github.js +148 -18
- package/src/providers/google.js +37 -0
- package/src/task-lease.js +77 -0
package/README.md
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
|
|
9
9
|
**Agent Authority turns a human-approved task into temporary execution authority, then keeps that authority bounded as the agent discovers resources, crosses tools, and performs side effects.**
|
|
10
10
|
|
|
11
|
-
[Task Leases](docs/task-leases.md) · [Validate](docs/validation.md) · [Integration contract](docs/integration-contract.md) · [CLI](docs/cli.md) · [Architecture](docs/architecture.md) · [Roadmap](ROADMAP.md) · [Contributing](CONTRIBUTING.md)
|
|
11
|
+
[Task Leases](docs/task-leases.md) · [Validate](docs/validation.md) · [Google proof](docs/live-google-validation.md) · [Integration contract](docs/integration-contract.md) · [CLI](docs/cli.md) · [Architecture](docs/architecture.md) · [Roadmap](ROADMAP.md) · [Contributing](CONTRIBUTING.md)
|
|
12
12
|
|
|
13
|
-
> **Status: public pre-alpha / v0.4.
|
|
13
|
+
> **Status: public pre-alpha / v0.4.2 Developer Preview.** Published on npm as `@nullsquare/agent-authority`. The repository has a working policy runtime, protocol-neutral guard, Task Lease prototype, execution-bound derived facts, approvals, revocation, idempotency, credential isolation, MCP v2 gateway, GitHub and Google provider integrations, CI and CodeQL. It is not production-ready yet.
|
|
14
14
|
|
|
15
15
|
</div>
|
|
16
16
|
|
|
@@ -97,6 +97,12 @@ Human-approved task
|
|
|
97
97
|
Gmail thread #91
|
|
98
98
|
|
|
|
99
99
|
authorized read
|
|
100
|
+
|
|
|
101
|
+
+--> ALLOW receipt
|
|
102
|
+
+--> exact output hash evidence
|
|
103
|
+
|
|
|
104
|
+
v
|
|
105
|
+
reviewed adapter extractor
|
|
100
106
|
|
|
|
101
107
|
v
|
|
102
108
|
derived fact
|
|
@@ -152,12 +158,15 @@ The demo performs this flow without provider credentials:
|
|
|
152
158
|
|
|
153
159
|
The side-effect callbacks for blocked actions never run.
|
|
154
160
|
|
|
161
|
+
The repository also includes a real Gmail → Calendar validation path and a reusable Google provider adapter. The stricter v0.4.2 path binds the derived sender to the exact guarded output before it becomes authority. See [Live Gmail → Calendar validation](docs/live-google-validation.md) and [Executable Evidence](docs/evidence.md).
|
|
162
|
+
|
|
155
163
|
## Minimal developer API
|
|
156
164
|
|
|
157
165
|
```js
|
|
158
166
|
import { AuthorityRuntime } from '@nullsquare/agent-authority';
|
|
159
167
|
import { createTaskLease } from '@nullsquare/agent-authority/task-lease';
|
|
160
168
|
import { createTaskLeaseGuard } from '@nullsquare/agent-authority/guard';
|
|
169
|
+
import { gmailThreadSenderAuthorityExtractor } from '@nullsquare/agent-authority/providers/google';
|
|
161
170
|
|
|
162
171
|
const lease = createTaskLease({
|
|
163
172
|
mission,
|
|
@@ -169,7 +178,7 @@ const lease = createTaskLease({
|
|
|
169
178
|
{
|
|
170
179
|
service: 'calendar',
|
|
171
180
|
action: 'event.create',
|
|
172
|
-
context_field: '
|
|
181
|
+
context_field: 'attendee_email',
|
|
173
182
|
fact_id: 'fact:sender-email'
|
|
174
183
|
}
|
|
175
184
|
]
|
|
@@ -183,25 +192,30 @@ const guard = createTaskLeaseGuard({
|
|
|
183
192
|
const read = await guard.run({
|
|
184
193
|
service: 'gmail',
|
|
185
194
|
action: 'thread.read',
|
|
186
|
-
context: {
|
|
195
|
+
context: { thread_id: 'thread:demo-91' }
|
|
187
196
|
}, () => gmail.readThread('thread:demo-91'));
|
|
188
197
|
|
|
189
|
-
lease.
|
|
198
|
+
const senderFact = lease.deriveFromEvidence({
|
|
190
199
|
fact_id: 'fact:sender-email',
|
|
191
200
|
kind: 'email.address',
|
|
192
|
-
value: read.output.sender,
|
|
193
201
|
from: ['fact:thread'],
|
|
194
202
|
receipt: read.receipt,
|
|
195
|
-
|
|
203
|
+
evidence: read.evidence,
|
|
204
|
+
output: read.output,
|
|
205
|
+
extractor: gmailThreadSenderAuthorityExtractor
|
|
196
206
|
});
|
|
197
207
|
|
|
198
208
|
await guard.run({
|
|
199
209
|
service: 'calendar',
|
|
200
210
|
action: 'event.create',
|
|
201
|
-
context: {
|
|
202
|
-
}, () => calendar.createEvent({ attendee:
|
|
211
|
+
context: { attendee_email: senderFact.value }
|
|
212
|
+
}, () => calendar.createEvent({ attendee: senderFact.value }));
|
|
203
213
|
```
|
|
204
214
|
|
|
215
|
+
`deriveFromEvidence()` does not accept the authority value. The reviewed extractor selects a normalized output field, and Task Lease resolves that value only after verifying that the output still matches the exact allowed execution evidence.
|
|
216
|
+
|
|
217
|
+
The older `derive()` API remains available as the explicitly **host-trusted compatibility path**.
|
|
218
|
+
|
|
205
219
|
The host keeps its existing SDK, connector and authentication. Agent Authority controls whether the effect may happen.
|
|
206
220
|
|
|
207
221
|
## Three integration modes, one authority model
|
|
@@ -247,7 +261,11 @@ The long-term validation target is the **same Task Lease and authority lineage a
|
|
|
247
261
|
- Task Lease prototype
|
|
248
262
|
- explicit authority roots
|
|
249
263
|
- same-lease provenance-bound derived facts
|
|
250
|
-
-
|
|
264
|
+
- execution evidence binding an allowed receipt, request and exact output hash
|
|
265
|
+
- strict `deriveFromEvidence()` path where the caller cannot provide the authority value
|
|
266
|
+
- reviewed Gmail sender authority extractor bound to `gmail:thread.read`
|
|
267
|
+
- legacy host-trusted `derive()` compatibility path
|
|
268
|
+
- required parent lineage and extraction selector
|
|
251
269
|
- exact context-field bindings
|
|
252
270
|
- authority-delta step-up signal
|
|
253
271
|
- immediate task completion/expiry enforcement
|
|
@@ -257,6 +275,7 @@ The long-term validation target is the **same Task Lease and authority lineage a
|
|
|
257
275
|
|
|
258
276
|
- protocol-neutral `guard.run()` wrapper
|
|
259
277
|
- blocked side effects never invoke their callback
|
|
278
|
+
- successful guarded effects return separate execution evidence
|
|
260
279
|
- one-time human approvals bound to exact request
|
|
261
280
|
- mutation idempotency
|
|
262
281
|
- conservative uncertain-state handling
|
|
@@ -269,15 +288,19 @@ The long-term validation target is the **same Task Lease and authority lineage a
|
|
|
269
288
|
- AES-256-GCM local encrypted secret store
|
|
270
289
|
- safe reconnect cleanup
|
|
271
290
|
- GitHub brokered execution without returning the token to the agent
|
|
291
|
+
- Google REST provider mappings for Gmail thread reads and Calendar event mutations
|
|
272
292
|
- short-lived signed local agent-instance tokens
|
|
273
293
|
- local CLI/daemon
|
|
274
294
|
|
|
275
295
|
### Engineering quality
|
|
276
296
|
|
|
277
297
|
- adversarial authorization tests
|
|
298
|
+
- execution-evidence substitution, tampering, replay, cross-lease and selector tests
|
|
278
299
|
- Node 20 and Node 22 CI
|
|
279
300
|
- coverage run
|
|
280
301
|
- package checks
|
|
302
|
+
- clean-consumer npm registry verification
|
|
303
|
+
- live GitHub read and mutation proofs
|
|
281
304
|
- CodeQL
|
|
282
305
|
|
|
283
306
|
## What is different from OAuth, IAM and MCP authorization?
|
|
@@ -333,7 +356,7 @@ Allow a natural workflow across mail, calendar, CRM and internal systems without
|
|
|
333
356
|
1. **Task before credential.** A provider token is not task authority.
|
|
334
357
|
2. **Mission is the ceiling.** Task Leases cannot override explicit denies.
|
|
335
358
|
3. **No side effect before authorization.** Denied and step-up actions never execute.
|
|
336
|
-
4. **Authority lineage matters.**
|
|
359
|
+
4. **Authority lineage matters.** Provider-derived authority should bind the exact allowed receipt and guarded output to a reviewed extractor; legacy host-trusted derivation remains identifiable in provenance.
|
|
337
360
|
5. **No silent resource expansion.** A different concrete resource becomes an authority delta.
|
|
338
361
|
6. **Task authority ends with the task.** Completion and expiry are independent from provider credential lifetime.
|
|
339
362
|
7. **Authority may shrink, never silently grow.** Delegation and transport changes must preserve non-amplification.
|
|
@@ -348,7 +371,9 @@ See [SECURITY.md](SECURITY.md).
|
|
|
348
371
|
This is still a validation implementation.
|
|
349
372
|
|
|
350
373
|
- Task Lease state is currently process-local.
|
|
351
|
-
-
|
|
374
|
+
- `deriveFromEvidence()` proves consistency with the exact output returned through the trusted Agent Authority guard, but the output is not cryptographically attested by Gmail, GitHub, or another remote provider.
|
|
375
|
+
- The legacy `derive()` API remains host-trusted for compatibility; audit provenance distinguishes it from `execution-evidence-v1` derivation.
|
|
376
|
+
- Source-data changes do not yet automatically invalidate already-derived authority facts.
|
|
352
377
|
- Bindings currently target top-level request context fields.
|
|
353
378
|
- Approved authority deltas are surfaced but not automatically applied back into a live lease.
|
|
354
379
|
- GitHub token-stdin is a developer bridge, not final browser OAuth onboarding.
|
package/ROADMAP.md
CHANGED
|
@@ -77,19 +77,25 @@ Build only what the real M1 workflow proves necessary.
|
|
|
77
77
|
|
|
78
78
|
**Success criterion:** a Task Lease survives daemon/process restarts without gaining authority or losing its provenance lineage.
|
|
79
79
|
|
|
80
|
-
## M3 — Trustworthy derived facts
|
|
80
|
+
## M3 — Trustworthy derived facts — two-provider proof established
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
The first real Gmail -> Calendar integration showed that recording a host-supplied value plus selector was too weak for the strongest derived-authority claim. The compatibility `derive()` path remains host-trusted; new provider work should prefer execution-bound evidence and reviewed adapter extractors.
|
|
83
83
|
|
|
84
|
-
- [
|
|
85
|
-
- [
|
|
86
|
-
- [
|
|
87
|
-
- [
|
|
88
|
-
- [
|
|
84
|
+
- [x] define a small trusted-adapter extractor contract for authority-relevant normalized provider fields
|
|
85
|
+
- [x] bind successful guarded outputs to the exact ALLOW receipt, request and output hash
|
|
86
|
+
- [x] add `TaskLease.deriveFromEvidence()` so the caller cannot provide the authority value
|
|
87
|
+
- [x] migrate Gmail sender -> Calendar attendee derivation to the evidence-verified path
|
|
88
|
+
- [x] migrate the real GitHub issue discovery -> comment mutation proof to the same evidence-verified path
|
|
89
|
+
- [x] adversarial tests for value substitution, output/evidence tampering, receipt replay, cross-lease reuse, wrong-operation extraction and dangerous selectors
|
|
90
|
+
- [x] shared conformance fixtures for reviewed operation -> authority-field mappings across Google and GitHub
|
|
91
|
+
- [ ] define provider/result attestation stronger than a trusted host output hash where practical
|
|
92
|
+
- [ ] define freshness/invalidation rules when a source resource changes
|
|
93
|
+
|
|
94
|
+
The shared contract is documented in `docs/authority-extractor-conformance.md`. Google and GitHub now use the same `guard.run()` -> execution evidence -> reviewed extractor -> `deriveFromEvidence()` primitive, and the same conformance suite attacks both mappings.
|
|
89
95
|
|
|
90
96
|
Do **not** build a general semantic policy language unless real integrations require it.
|
|
91
97
|
|
|
92
|
-
**Success criterion:**
|
|
98
|
+
**Success criterion:** provider-derived authority cannot be established through the strict path unless the exact guarded output, ALLOW receipt and reviewed extractor contract agree on the selected value. This behavior is now exercised across two provider mappings. Stronger provider attestation and source invalidation remain separate follow-on problems.
|
|
93
99
|
|
|
94
100
|
## M4 — Same task, multiple transports
|
|
95
101
|
|
|
@@ -147,7 +153,7 @@ Only after operational evidence.
|
|
|
147
153
|
|
|
148
154
|
## Research questions
|
|
149
155
|
|
|
150
|
-
1. What
|
|
156
|
+
1. What provider-side or transport-side evidence can strengthen output integrity without turning Agent Authority into an attestation protocol?
|
|
151
157
|
2. How should an approved authority delta update a running task without opening a broader wildcard permission?
|
|
152
158
|
3. How should source-data changes invalidate downstream derived authority?
|
|
153
159
|
4. What provider/tool metadata is required to map operations to resource context reliably?
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Authority extractor conformance
|
|
2
|
+
|
|
3
|
+
Agent Authority treats provider-derived authority as a small adapter contract, not a general semantic policy language.
|
|
4
|
+
|
|
5
|
+
The strict path is:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
authorized request
|
|
9
|
+
|
|
|
10
|
+
v
|
|
11
|
+
reviewed provider adapter
|
|
12
|
+
|
|
|
13
|
+
v
|
|
14
|
+
normalized provider output
|
|
15
|
+
|
|
|
16
|
+
+--> ALLOW receipt
|
|
17
|
+
+--> execution output hash
|
|
18
|
+
|
|
|
19
|
+
v
|
|
20
|
+
adapter.authorityExtractor(request, factKind)
|
|
21
|
+
|
|
|
22
|
+
v
|
|
23
|
+
{ extractor_id, selector }
|
|
24
|
+
|
|
|
25
|
+
v
|
|
26
|
+
TaskLease.deriveFromEvidence()
|
|
27
|
+
|
|
|
28
|
+
v
|
|
29
|
+
derived authority fact
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Adapter requirements
|
|
33
|
+
|
|
34
|
+
A provider mapping intended to establish downstream authority SHOULD satisfy all of these:
|
|
35
|
+
|
|
36
|
+
1. **Reviewed operation mapping.** The adapter owns the mapping from Agent Authority `service` + `action` to the external provider operation.
|
|
37
|
+
2. **Normalized authority field.** Provider data is normalized into a small output shape before authority extraction. Credentials and unrelated raw payloads should not be copied into the authority result.
|
|
38
|
+
3. **Fail-closed extractor advertisement.** `adapter.authorityExtractor(request, factKind)` returns an extractor only for an explicitly supported operation/fact-kind pair. Unsupported mappings return `null`.
|
|
39
|
+
4. **Selector, never value.** The extractor returns `{ extractor_id, selector }`. It must not return the derived authority value itself.
|
|
40
|
+
5. **Operation binding.** The extractor rejects receipts from another provider action.
|
|
41
|
+
6. **Canonical output.** The extractor rejects malformed, ambiguous, or non-canonical normalized output.
|
|
42
|
+
7. **Task lineage.** `TaskLease.deriveFromEvidence()` requires an ALLOW receipt from the same mission and Task Lease plus at least one existing parent fact.
|
|
43
|
+
8. **Exact-output integrity.** The output passed to derivation must still hash to the output bound into the execution evidence.
|
|
44
|
+
|
|
45
|
+
This is an integrity contract inside the trusted Agent Authority host/adapter boundary. It is not provider-signed remote attestation.
|
|
46
|
+
|
|
47
|
+
## Current fixtures
|
|
48
|
+
|
|
49
|
+
### Google Gmail sender
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
gmail:thread.read
|
|
53
|
+
-> normalized sender_email
|
|
54
|
+
-> google.gmail.thread.sender-email.v1
|
|
55
|
+
-> email.address
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The Gmail extractor accepts only canonical normalized `sender_email` output and selects `output.sender_email`.
|
|
59
|
+
|
|
60
|
+
### GitHub selected issue
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
github:issue.list
|
|
64
|
+
+ root-bound repository
|
|
65
|
+
+ root-bound fixture_marker
|
|
66
|
+
-> exactly one normalized marker match
|
|
67
|
+
-> github.issue.list.selected-number.v1
|
|
68
|
+
-> github.issue.number
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The GitHub adapter performs marker matching against the provider response, does not expose issue bodies in the normalized output, and the extractor selects only `output.selected_issue_number` when exactly one non-pull-request issue matched.
|
|
72
|
+
|
|
73
|
+
## Shared adversarial conformance suite
|
|
74
|
+
|
|
75
|
+
`test/provider-authority-conformance.test.js` applies the same strict-path checks to both provider fixtures:
|
|
76
|
+
|
|
77
|
+
- positive derivation obtains the value from the evidence-bound output rather than caller input;
|
|
78
|
+
- modified output under unchanged evidence is rejected;
|
|
79
|
+
- execution evidence cannot be replayed under a second ALLOW receipt;
|
|
80
|
+
- receipt/evidence from one Task Lease cannot establish authority in another lease;
|
|
81
|
+
- an extractor cannot be reused with evidence from another provider operation.
|
|
82
|
+
|
|
83
|
+
Provider-specific tests additionally verify canonical normalization, exact REST mappings, extractor advertisement, and ambiguity failure.
|
|
84
|
+
|
|
85
|
+
## What conformance does not prove
|
|
86
|
+
|
|
87
|
+
Passing this contract does not prove that:
|
|
88
|
+
|
|
89
|
+
- a provider cryptographically signed the normalized result;
|
|
90
|
+
- the trusted host itself is non-malicious;
|
|
91
|
+
- a source resource has not changed since the read;
|
|
92
|
+
- a derived fact is automatically invalidated when provider data changes;
|
|
93
|
+
- an agent cannot bypass Agent Authority through a separate credential or unguarded provider path.
|
|
94
|
+
|
|
95
|
+
Those are separate trust, freshness, and deployment-boundary problems and should not be hidden inside the extractor API.
|
package/docs/evidence.md
CHANGED
|
@@ -10,9 +10,85 @@ This page records the strongest properties the repository currently demonstrates
|
|
|
10
10
|
|
|
11
11
|
The guarantee applies to effects that actually pass through the Agent Authority enforcement boundary. A separate unguarded provider path is outside this guarantee.
|
|
12
12
|
|
|
13
|
+
## Execution-bound derived authority
|
|
14
|
+
|
|
15
|
+
The strict derived-authority path binds provider-derived authority to the exact output returned by an authorized `guard.run()` effect.
|
|
16
|
+
|
|
17
|
+
A successful guarded effect returns three relevant records:
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
ALLOW receipt
|
|
21
|
+
+
|
|
22
|
+
exact effect output
|
|
23
|
+
|
|
|
24
|
+
v
|
|
25
|
+
execution evidence
|
|
26
|
+
(receipt + request + output hash)
|
|
27
|
+
|
|
|
28
|
+
v
|
|
29
|
+
reviewed adapter extractor
|
|
30
|
+
(selector only, no value)
|
|
31
|
+
|
|
|
32
|
+
v
|
|
33
|
+
TaskLease.deriveFromEvidence()
|
|
34
|
+
|
|
|
35
|
+
v
|
|
36
|
+
derived authority fact
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`deriveFromEvidence()` does not accept the derived authority value. The trusted adapter extractor chooses a reviewed selector, and Task Lease resolves that selector itself only after verifying the execution evidence.
|
|
40
|
+
|
|
41
|
+
`test/authority-evidence.test.js` attacks this boundary directly and proves that:
|
|
42
|
+
|
|
43
|
+
- caller-supplied value substitution does not control the resulting fact;
|
|
44
|
+
- modified provider output is rejected with `evidence_output_mismatch`;
|
|
45
|
+
- modified execution-evidence contents are rejected;
|
|
46
|
+
- evidence cannot be replayed under a second ALLOW receipt;
|
|
47
|
+
- a receipt/evidence chain from another Task Lease is rejected;
|
|
48
|
+
- the Gmail sender extractor rejects the wrong provider operation;
|
|
49
|
+
- dangerous selector paths such as `__proto__` fail closed.
|
|
50
|
+
|
|
51
|
+
The legacy `TaskLease.derive()` API remains for compatibility and records `derivation_mode: host-trusted`. New provider-derived authority should prefer `deriveFromEvidence()`, which records `derivation_mode: execution-evidence-v1`, extractor ID, source output hash, and execution-evidence hash.
|
|
52
|
+
|
|
53
|
+
### Boundary of this claim
|
|
54
|
+
|
|
55
|
+
Execution evidence is an integrity mechanism inside the trusted host/runtime boundary. It proves that the value selected for strict derivation came from the exact output object bound to that Agent Authority receipt.
|
|
56
|
+
|
|
57
|
+
It does **not** prove that Gmail, GitHub, or another provider cryptographically signed that output, and it does not protect a malicious host that bypasses or replaces the Agent Authority enforcement path. Stronger provider/transport attestation remains open M3 work.
|
|
58
|
+
|
|
59
|
+
## Two-provider authority-extractor conformance
|
|
60
|
+
|
|
61
|
+
The same strict primitive is now exercised by two independent provider mappings:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
Google Gmail
|
|
65
|
+
thread.read
|
|
66
|
+
-> sender_email
|
|
67
|
+
-> reviewed extractor
|
|
68
|
+
-> email.address authority
|
|
69
|
+
|
|
70
|
+
GitHub
|
|
71
|
+
issue.list
|
|
72
|
+
-> selected_issue_number
|
|
73
|
+
-> reviewed extractor
|
|
74
|
+
-> github.issue.number authority
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`test/provider-authority-conformance.test.js` applies the same contract to both mappings:
|
|
78
|
+
|
|
79
|
+
- positive derivation gets its value from the evidence-bound output rather than caller input;
|
|
80
|
+
- modifying the selected output under unchanged evidence is rejected;
|
|
81
|
+
- evidence replay under another ALLOW receipt is rejected;
|
|
82
|
+
- cross-Task-Lease receipt/evidence reuse is rejected;
|
|
83
|
+
- an extractor rejects evidence from another operation.
|
|
84
|
+
|
|
85
|
+
Provider-specific tests additionally verify canonical normalization and fail-closed extractor advertisement. The contract is documented in [Authority extractor conformance](authority-extractor-conformance.md).
|
|
86
|
+
|
|
87
|
+
This is the current evidence that execution-bound derived authority is a reusable provider primitive rather than a Gmail-only special case.
|
|
88
|
+
|
|
13
89
|
## Cross-provider derived authority — Gmail → Calendar
|
|
14
90
|
|
|
15
|
-
Agent Authority
|
|
91
|
+
Agent Authority includes a real Google provider mapping, an adversarial cross-provider test, a live validation script, and an opt-in GitHub Actions workflow.
|
|
16
92
|
|
|
17
93
|
The task shape is:
|
|
18
94
|
|
|
@@ -22,9 +98,11 @@ one Gmail thread
|
|
|
22
98
|
|
|
|
23
99
|
v
|
|
24
100
|
ALLOW Gmail thread.read
|
|
101
|
+
|
|
|
102
|
+
+--> output-bound execution evidence
|
|
25
103
|
|
|
|
26
104
|
v
|
|
27
|
-
|
|
105
|
+
trusted Gmail sender extractor
|
|
28
106
|
|
|
|
29
107
|
v
|
|
30
108
|
derive fact: sender_email
|
|
@@ -57,19 +135,21 @@ A controlled self-test was exercised against the connected NullSquare Gmail and
|
|
|
57
135
|
|
|
58
136
|
No unrelated external person was invited. The smoke test establishes that the concrete Gmail and Calendar operations used by the validation are available and compatible with the intended data shape.
|
|
59
137
|
|
|
60
|
-
The live connected-account smoke is not presented as a public CI proof of the repository script. The Task Lease zero-call assertions are separately executable in `test/google-cross-provider.test.js`, and `.github/workflows/live-google-validation.yml` is provided for a rerunnable provider-backed proof once repository Google OAuth secrets are configured.
|
|
138
|
+
The live connected-account smoke is not presented as a public CI proof of the repository script. The Task Lease zero-call and execution-evidence assertions are separately executable in `test/google-cross-provider.test.js` and `test/authority-evidence.test.js`, and `.github/workflows/live-google-validation.yml` is provided for a rerunnable provider-backed proof once repository Google OAuth secrets are configured.
|
|
61
139
|
|
|
62
140
|
### Executable local/CI assertions
|
|
63
141
|
|
|
64
142
|
`test/google-cross-provider.test.js` proves deterministically that:
|
|
65
143
|
|
|
66
144
|
- the approved Gmail thread callback runs exactly once;
|
|
67
|
-
- its sender becomes a same-lease
|
|
145
|
+
- its sender becomes a same-lease `execution-evidence-v1` authority fact;
|
|
68
146
|
- one Calendar mutation for that sender runs exactly once;
|
|
69
147
|
- a different attendee produces `authority_delta_required` and the Calendar callback is not invoked;
|
|
70
148
|
- after lease completion, the previously valid attendee produces `task_lease_completed` and the Calendar callback is not invoked again.
|
|
71
149
|
|
|
72
|
-
`test/google-provider.test.js`
|
|
150
|
+
`test/google-provider.test.js` validates the Google REST mappings, metadata-only Gmail sender extraction, Calendar attendee body, default `sendUpdates=none`, credential redaction, unsupported-action failure, and mutation classification.
|
|
151
|
+
|
|
152
|
+
`test/google-authority-extractor.test.js` separately verifies that the reviewed Gmail extractor only accepts canonical `gmail:thread.read` sender output and that the Google adapter advertises it only for the supported authority mapping.
|
|
73
153
|
|
|
74
154
|
### Public workflow
|
|
75
155
|
|
|
@@ -89,9 +169,10 @@ The connected GitHub tool does not expose repository Actions-secret management,
|
|
|
89
169
|
|
|
90
170
|
### What this proves
|
|
91
171
|
|
|
92
|
-
Taken together, the deterministic Task Lease
|
|
172
|
+
Taken together, the deterministic Task Lease tests plus the controlled provider smoke show that:
|
|
93
173
|
|
|
94
174
|
- the Gmail → Calendar derived-authority shape is implemented, not just diagrammed;
|
|
175
|
+
- strict derivation binds the sender to the exact guarded Gmail output before it becomes authority;
|
|
95
176
|
- the exact attendee binding is enforced before the Calendar mutation callback;
|
|
96
177
|
- provider operations exist and work against real Gmail and Calendar accounts;
|
|
97
178
|
- cleanup can keep the live proof reversible and self-contained.
|
|
@@ -99,20 +180,21 @@ Taken together, the deterministic Task Lease test plus the controlled provider s
|
|
|
99
180
|
### What this does not prove yet
|
|
100
181
|
|
|
101
182
|
- a public GitHub Actions run has executed the full repository live script;
|
|
102
|
-
-
|
|
183
|
+
- `sender_email` is cryptographically attested by Gmail rather than integrity-bound to the trusted host's guarded output;
|
|
103
184
|
- the agent cannot bypass Agent Authority if it independently holds a Google credential;
|
|
104
185
|
- Task Lease state is durable across process failure;
|
|
186
|
+
- source-data changes automatically invalidate downstream facts;
|
|
105
187
|
- the refresh-token setup is production credential onboarding.
|
|
106
188
|
|
|
107
189
|
See [Live Gmail → Calendar validation](live-google-validation.md).
|
|
108
190
|
|
|
109
|
-
## Live derived
|
|
191
|
+
## Live evidence-derived mutation — GitHub
|
|
110
192
|
|
|
111
193
|
Public fixture: [issue #9](https://github.com/Null-Square/agent-authority/issues/9)
|
|
112
194
|
|
|
113
195
|
Validation workflow: CI job `live-derived-github-mutation`
|
|
114
196
|
|
|
115
|
-
Passing run: [CI run
|
|
197
|
+
Passing evidence-derived run: [CI run 262](https://github.com/Null-Square/agent-authority/actions/runs/32600963479)
|
|
116
198
|
|
|
117
199
|
The job uses a GitHub Actions token with:
|
|
118
200
|
|
|
@@ -121,25 +203,40 @@ contents: read
|
|
|
121
203
|
issues: write
|
|
122
204
|
```
|
|
123
205
|
|
|
124
|
-
The Task Lease
|
|
206
|
+
The Task Lease begins with two explicit authority roots:
|
|
207
|
+
|
|
208
|
+
```text
|
|
209
|
+
repository = Null-Square/agent-authority
|
|
210
|
+
fixture_marker = agent-authority-live-fixture-v1
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Both values are bound to the `issue.list` request. The brokered GitHub provider adapter owns the external issue-list operation and normalizes the provider response. Issue bodies are used internally for marker matching but are not copied into the normalized authority output.
|
|
125
214
|
|
|
126
215
|
### Executed path
|
|
127
216
|
|
|
128
217
|
```text
|
|
129
|
-
Task
|
|
130
|
-
|
|
218
|
+
Task roots
|
|
219
|
+
repository + fixture marker
|
|
220
|
+
|
|
|
221
|
+
v
|
|
222
|
+
ALLOW github:issue.list
|
|
223
|
+
through reviewed provider adapter
|
|
224
|
+
|
|
|
225
|
+
+--> exact output-bound execution evidence
|
|
131
226
|
|
|
|
132
227
|
v
|
|
133
|
-
|
|
228
|
+
adapter selects exactly one marker match
|
|
229
|
+
selected_issue_number = 9
|
|
134
230
|
|
|
|
135
231
|
v
|
|
136
|
-
|
|
232
|
+
reviewed GitHub issue-number extractor
|
|
137
233
|
|
|
|
138
234
|
v
|
|
139
|
-
|
|
235
|
+
TaskLease.deriveFromEvidence()
|
|
236
|
+
issue_number = 9
|
|
140
237
|
|
|
|
141
238
|
v
|
|
142
|
-
ALLOW one real comment
|
|
239
|
+
ALLOW one real github:issue.comment on #9
|
|
143
240
|
|
|
|
144
241
|
+--> attempt comment on #1
|
|
145
242
|
| -> authority_delta_required
|
|
@@ -156,38 +253,41 @@ complete Task Lease
|
|
|
156
253
|
The passing job recorded:
|
|
157
254
|
|
|
158
255
|
```text
|
|
159
|
-
ALLOW ->
|
|
160
|
-
|
|
256
|
+
ALLOW -> selected issue #9: Agent Authority live validation fixture — do not close
|
|
257
|
+
Evidence-verified authority -> issue #9
|
|
161
258
|
ALLOW -> real GitHub comment mutation executed
|
|
162
259
|
STEP-UP -> unrelated issue #1 blocked before provider mutation
|
|
163
260
|
DENY -> post-completion mutation blocked for issue #9
|
|
261
|
+
PASS -> GitHub provider output became downstream authority only through execution evidence and a reviewed extractor
|
|
164
262
|
Provider calls observed before cleanup: reads=1, task_mutations=1
|
|
165
263
|
```
|
|
166
264
|
|
|
167
|
-
The temporary validation comment
|
|
265
|
+
The temporary validation comment was deleted by harness cleanup after the proof. Cleanup remains intentionally outside the Task Lease authority path and is counted separately.
|
|
168
266
|
|
|
169
267
|
### What this proves
|
|
170
268
|
|
|
171
|
-
-
|
|
172
|
-
-
|
|
173
|
-
-
|
|
174
|
-
-
|
|
175
|
-
- a
|
|
176
|
-
-
|
|
177
|
-
- the
|
|
269
|
+
- the same execution-evidence + reviewed-extractor primitive used for Gmail works against a second real provider;
|
|
270
|
+
- the brokered GitHub adapter, rather than arbitrary host extraction code, owns provider response normalization;
|
|
271
|
+
- the caller does not provide the issue number to `deriveFromEvidence()`;
|
|
272
|
+
- repository and discovery marker are explicit Task Lease roots;
|
|
273
|
+
- a real provider mutation is limited to the issue selected from the authorized provider result;
|
|
274
|
+
- another issue causes zero additional task-side provider mutation calls;
|
|
275
|
+
- completing the Task Lease prevents reuse of the previously authorized issue;
|
|
276
|
+
- the provider credential can remain valid after task authority disappears.
|
|
178
277
|
|
|
179
278
|
### What this does not prove
|
|
180
279
|
|
|
181
|
-
-
|
|
280
|
+
- GitHub cryptographically attests the normalized Agent Authority output;
|
|
281
|
+
- source issue changes automatically invalidate a derived fact;
|
|
182
282
|
- an agent cannot bypass Agent Authority if it independently possesses the provider credential or another unguarded provider path;
|
|
183
283
|
- Task Lease state is durable across process failure;
|
|
184
284
|
- the current prototype is ready for adversarial production use.
|
|
185
285
|
|
|
186
286
|
## Live provider read boundary — GitHub
|
|
187
287
|
|
|
188
|
-
CI also runs `demo:live-github` against the
|
|
288
|
+
CI also runs `demo:live-github` against the GitHub API.
|
|
189
289
|
|
|
190
|
-
It proves that one repository permitted by the Task Lease causes one live
|
|
290
|
+
It proves that one repository permitted by the Task Lease causes one live provider read while another repository produces `authority_delta_required` before a second provider request occurs.
|
|
191
291
|
|
|
192
292
|
## Network-boundary integration test
|
|
193
293
|
|
|
@@ -209,7 +309,9 @@ The test suite also covers:
|
|
|
209
309
|
- receipts from another mission are rejected;
|
|
210
310
|
- receipts from another Task Lease are rejected;
|
|
211
311
|
- parent lineage is required;
|
|
212
|
-
-
|
|
312
|
+
- legacy host-trusted derivation records its extraction selector;
|
|
313
|
+
- strict execution-evidence derivation rejects substitution/replay/tampering cases;
|
|
314
|
+
- the shared provider conformance suite applies the same attacks to Google and GitHub mappings;
|
|
213
315
|
- explicit mission deny rules remain the ceiling;
|
|
214
316
|
- lease expiry and mission expiry are enforced against a consistent evaluation clock.
|
|
215
317
|
|
|
@@ -224,8 +326,8 @@ Current pull requests run:
|
|
|
224
326
|
- package checks;
|
|
225
327
|
- coverage;
|
|
226
328
|
- live GitHub read validation;
|
|
227
|
-
- live derived GitHub mutation validation for trusted in-repository branches;
|
|
228
|
-
- Google provider and
|
|
329
|
+
- live evidence-derived GitHub mutation validation for trusted in-repository branches;
|
|
330
|
+
- Google and GitHub provider/extractor conformance and execution-evidence adversarial tests;
|
|
229
331
|
- CodeQL.
|
|
230
332
|
|
|
231
333
|
The live Google provider mutation workflow is manual because it requires repository-owned Google OAuth secrets. It should be added to the public evidence list after its first successful run.
|
package/docs/npm-release.md
CHANGED
|
@@ -13,17 +13,19 @@ Before any publication:
|
|
|
13
13
|
After publication, verify from a fresh project with:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npm install @nullsquare/agent-authority@0.4.
|
|
16
|
+
npm install @nullsquare/agent-authority@0.4.2
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
Then run the same consumer smoke flow through the registry-installed package. Registry verification is part of the release gate; a successful `npm publish` command alone is not sufficient.
|
|
20
20
|
|
|
21
|
+
The repository also includes `.github/workflows/verify-npm-registry.yml`, which verifies registry visibility and a clean consumer install. For v0.4.2 it additionally verifies the public `@nullsquare/agent-authority/authority-evidence` export plus the Google provider and Gmail authority-extractor exports.
|
|
22
|
+
|
|
21
23
|
## npm vs GitHub release surfaces
|
|
22
24
|
|
|
23
25
|
Publishing to the public npm registry does not automatically create either a GitHub Release or a GitHub Packages entry.
|
|
24
26
|
|
|
25
27
|
- **npm registry** — `npm publish --access public` publishes `@nullsquare/agent-authority` to `registry.npmjs.org` / npmjs.com. This is the package users install with `npm install`.
|
|
26
|
-
- **GitHub Releases** — a separate GitHub object, normally backed by a Git tag such as `v0.4.
|
|
28
|
+
- **GitHub Releases** — a separate GitHub object, normally backed by a Git tag such as `v0.4.2`. A release must be created explicitly or by release automation.
|
|
27
29
|
- **GitHub Packages** — a separate package registry. It only appears when the package is published to GitHub's npm registry (`npm.pkg.github.com`); publishing to npmjs.com does not populate it.
|
|
28
30
|
|
|
29
31
|
Agent Authority currently uses npmjs.com as its public package registry. Therefore an empty GitHub **Packages** section is expected unless the project intentionally adopts dual publication. A GitHub **Release** is still useful for source-release discoverability and should track published versions, but it is independent from npm publication.
|