@oxy.so/contracts 4.8.0 → 4.9.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/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/accountGraph.js +13 -5
- package/dist/cjs/accountSubject.js +189 -0
- package/dist/cjs/agency.js +56 -4
- package/dist/cjs/agentKeys.js +67 -0
- package/dist/cjs/capabilityBindings.js +72 -0
- package/dist/cjs/index.js +60 -13
- package/dist/cjs/inference/economics.js +135 -0
- package/dist/cjs/products/access.js +60 -0
- package/dist/cjs/products/billing.js +32 -0
- package/dist/cjs/signIn.js +1 -1
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/accountGraph.js +13 -5
- package/dist/esm/accountSubject.js +182 -0
- package/dist/esm/agency.js +55 -3
- package/dist/esm/agentKeys.js +63 -0
- package/dist/esm/capabilityBindings.js +67 -0
- package/dist/esm/index.js +10 -1
- package/dist/esm/inference/economics.js +132 -0
- package/dist/esm/products/access.js +57 -0
- package/dist/esm/products/billing.js +29 -0
- package/dist/esm/signIn.js +1 -1
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/accountGraph.d.ts +23 -8
- package/dist/types/accountSubject.d.ts +210 -0
- package/dist/types/agency.d.ts +956 -190
- package/dist/types/agentKeys.d.ts +525 -0
- package/dist/types/capabilityBindings.d.ts +6 -0
- package/dist/types/deviceDirectory.d.ts +50 -50
- package/dist/types/deviceSession.d.ts +14 -14
- package/dist/types/externalIdentity.d.ts +4 -4
- package/dist/types/identity.d.ts +2 -2
- package/dist/types/index.d.ts +12 -2
- package/dist/types/inference/accountBilling.d.ts +30 -30
- package/dist/types/inference/aliaModelRelease.d.ts +83 -83
- package/dist/types/inference/catalogue.d.ts +180 -180
- package/dist/types/inference/economics.d.ts +376 -0
- package/dist/types/inference/entitlement.d.ts +47 -47
- package/dist/types/inference/inbox.d.ts +12 -12
- package/dist/types/inference/modelDocumentation.d.ts +231 -231
- package/dist/types/inference/priceVersion.d.ts +4 -4
- package/dist/types/inference/providerConnection.d.ts +38 -38
- package/dist/types/inference/realtime.d.ts +802 -802
- package/dist/types/inference/request.d.ts +844 -844
- package/dist/types/inference/routingPolicy.d.ts +4 -4
- package/dist/types/inference/scopedExecution.d.ts +38 -38
- package/dist/types/inference/streamEvents.d.ts +4 -4
- package/dist/types/inference/usage.d.ts +12 -12
- package/dist/types/keyRotation.d.ts +2 -2
- package/dist/types/notifications.d.ts +4 -4
- package/dist/types/oauth.d.ts +30 -30
- package/dist/types/products/access.d.ts +487 -0
- package/dist/types/products/billing.d.ts +563 -0
- package/dist/types/recommendations.d.ts +2 -2
- package/dist/types/sessionStatus.d.ts +10 -10
- package/dist/types/signIn.d.ts +6 -6
- package/dist/types/transparency.d.ts +2 -2
- package/package.json +1 -1
package/dist/cjs/accountGraph.js
CHANGED
|
@@ -67,6 +67,12 @@ exports.childAccountKindSchema = zod_1.z.enum(exports.CHILD_ACCOUNT_KINDS);
|
|
|
67
67
|
*
|
|
68
68
|
* Consumers must gate on this predicate rather than testing `kind === 'personal'`,
|
|
69
69
|
* which silently admits every kind added after it was written.
|
|
70
|
+
*
|
|
71
|
+
* Being act-as-eligible is NOT being without an identity of one's own. A bot is
|
|
72
|
+
* act-as-eligible AND its own actor (`accountKindActorNature` → `'agent'` in
|
|
73
|
+
* `accountSubject.ts`): an application acting as it on a person's authority
|
|
74
|
+
* records that person as the actor, and the bot acting with nobody operating it
|
|
75
|
+
* records the bot. Neither ever records the bot's owner in the bot's place.
|
|
70
76
|
*/
|
|
71
77
|
function isDelegatedActAsEligibleKind(kind) {
|
|
72
78
|
return kind === 'organization' || kind === 'project' || kind === 'bot';
|
|
@@ -80,11 +86,13 @@ function isDelegatedActAsEligibleKind(kind) {
|
|
|
80
86
|
* The two differ on exactly one kind, `bot`, and that difference is the whole
|
|
81
87
|
* reason both exist.
|
|
82
88
|
*
|
|
83
|
-
* **A bot is not something you become. It is
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* {@link isDelegatedActAsEligibleKind} admits it for.
|
|
89
|
+
* **A bot is not something you become. It is somebody of its own.** It is an
|
|
90
|
+
* agent's identity, with its own resources, roles, plan and balance, and it is
|
|
91
|
+
* the actor of what it does unoperated. A person may still act AS it on their
|
|
92
|
+
* own authority — that is delegation, recorded with the person as actor, and it
|
|
93
|
+
* is what {@link isDelegatedActAsEligibleKind} admits it for. What a person
|
|
94
|
+
* never does is occupy its seat. This is a refusal of a SEAT, not a capability
|
|
95
|
+
* restriction: nothing a bot may do depends on this predicate.
|
|
88
96
|
*
|
|
89
97
|
* Handing a person the bot's seat instead inverts that. It puts a human inside
|
|
90
98
|
* the identity that exists to act without one, and it does so on the human's own
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Account subject contract — what an account IS, kept apart from how it proves
|
|
4
|
+
* itself, who may become it, who may act as it, who acted, and whose money moves.
|
|
5
|
+
*
|
|
6
|
+
* `AccountKind` (`accountGraph.ts`) names the nature of an account. Five other
|
|
7
|
+
* questions are routinely asked of an account, and each has its own answer here
|
|
8
|
+
* or in `accountGraph.ts`. None of them may be answered by testing `kind`
|
|
9
|
+
* directly at a call site:
|
|
10
|
+
*
|
|
11
|
+
* | question | answered by |
|
|
12
|
+
* |-------------------------------------------|------------------------------------------|
|
|
13
|
+
* | may a PERSON switch into it? | `isOperatorSwitchTargetKind` |
|
|
14
|
+
* | may someone act AS it on their authority? | `isDelegatedActAsEligibleKind` |
|
|
15
|
+
* | who is the ACTOR when it acts unoperated? | {@link accountKindActorNature} |
|
|
16
|
+
* | who acted, and as whom, on this request? | {@link AccountActorChain} |
|
|
17
|
+
* | whose money / receipt is an effect? | {@link attributeFinancialEffect} |
|
|
18
|
+
* | roles, resources, plan, balance, payer | NOT kind — {@link KIND_INDEPENDENT_ACCOUNT_DIMENSIONS} |
|
|
19
|
+
*
|
|
20
|
+
* ## A bot is a complete account (issue #1520, I01)
|
|
21
|
+
*
|
|
22
|
+
* A `bot` is an AI agent's own identity. It owns resources, holds roles, has a
|
|
23
|
+
* plan, holds a balance, receives funds and pays for itself under exactly the
|
|
24
|
+
* rules a personal account does. Nothing commercial derives from it being a bot,
|
|
25
|
+
* and nothing about it requires its owner's approval merely because it is one.
|
|
26
|
+
*
|
|
27
|
+
* Two things DO differ, and both are about seats, not capability:
|
|
28
|
+
*
|
|
29
|
+
* - a person never switches INTO a bot (`isOperatorSwitchTargetKind`): a bot is
|
|
30
|
+
* somebody, not a seat a human occupies;
|
|
31
|
+
* - when a bot acts with nobody operating it, the actor recorded is the BOT
|
|
32
|
+
* ({@link accountKindActorNature} `'agent'`), never its owner.
|
|
33
|
+
*/
|
|
34
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
+
exports.financialEffectAttributionSchema = exports.FINANCIAL_EFFECT_DIRECTIONS = exports.accountActorChainSchema = exports.KIND_INDEPENDENT_ACCOUNT_DIMENSIONS = exports.accountActorNatureSchema = exports.ACCOUNT_ACTOR_NATURES = exports.ACCOUNT_SUBJECT_CONTRACT_VERSION = void 0;
|
|
36
|
+
exports.accountKindActorNature = accountKindActorNature;
|
|
37
|
+
exports.accountKindActsAsItself = accountKindActsAsItself;
|
|
38
|
+
exports.accountActorChainFromSession = accountActorChainFromSession;
|
|
39
|
+
exports.attributeFinancialEffect = attributeFinancialEffect;
|
|
40
|
+
const zod_1 = require("zod");
|
|
41
|
+
const identifiers_1 = require("./inference/identifiers");
|
|
42
|
+
/** Bumped when any shape in this module changes incompatibly. */
|
|
43
|
+
exports.ACCOUNT_SUBJECT_CONTRACT_VERSION = 1;
|
|
44
|
+
// ===========================================================================
|
|
45
|
+
// Actor nature
|
|
46
|
+
// ===========================================================================
|
|
47
|
+
/**
|
|
48
|
+
* Who is recorded as the ACTOR when an account of this kind acts and no other
|
|
49
|
+
* account is operating it.
|
|
50
|
+
*
|
|
51
|
+
* - `person` — a human; a personal account is its own actor.
|
|
52
|
+
* - `agent` — an AI agent; a bot is its own actor (ADR 0018 `ActorRef`
|
|
53
|
+
* `{type:'agent'}`), and audit records the bot, never the human who owns it.
|
|
54
|
+
* - `operated` — never its own actor. An organization, project or channel only
|
|
55
|
+
* acts through a member, and that member is the actor.
|
|
56
|
+
*/
|
|
57
|
+
exports.ACCOUNT_ACTOR_NATURES = ['person', 'agent', 'operated'];
|
|
58
|
+
exports.accountActorNatureSchema = zod_1.z.enum(exports.ACCOUNT_ACTOR_NATURES);
|
|
59
|
+
/**
|
|
60
|
+
* The actor nature of a kind. A `Record` over the full union, so a new kind does
|
|
61
|
+
* not compile until somebody decides this for it.
|
|
62
|
+
*/
|
|
63
|
+
const ACTOR_NATURE_BY_KIND = {
|
|
64
|
+
personal: 'person',
|
|
65
|
+
bot: 'agent',
|
|
66
|
+
organization: 'operated',
|
|
67
|
+
project: 'operated',
|
|
68
|
+
channel: 'operated',
|
|
69
|
+
};
|
|
70
|
+
/** `null` for a value that is not an account kind. Never a guess. */
|
|
71
|
+
function accountKindActorNature(kind) {
|
|
72
|
+
if (!kind || !Object.prototype.hasOwnProperty.call(ACTOR_NATURE_BY_KIND, kind)) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return ACTOR_NATURE_BY_KIND[kind];
|
|
76
|
+
}
|
|
77
|
+
/** Whether an account of this kind can be the actor of its own actions. */
|
|
78
|
+
function accountKindActsAsItself(kind) {
|
|
79
|
+
const nature = accountKindActorNature(kind);
|
|
80
|
+
return nature === 'person' || nature === 'agent';
|
|
81
|
+
}
|
|
82
|
+
// ===========================================================================
|
|
83
|
+
// Kind-independent dimensions
|
|
84
|
+
// ===========================================================================
|
|
85
|
+
/**
|
|
86
|
+
* What an account's KIND never decides.
|
|
87
|
+
*
|
|
88
|
+
* There is deliberately no predicate taking a kind for any of these. A member's
|
|
89
|
+
* role grants the same permissions whatever kind the member is; a plan, a
|
|
90
|
+
* balance, the payer and the beneficiary are resolved from billing state and
|
|
91
|
+
* membership, never from `kind`. A bot and a person with the same role and plan
|
|
92
|
+
* get the same action and the same commercial treatment.
|
|
93
|
+
*
|
|
94
|
+
* Listed so a consumer can cite the rule, and so the API's static guard
|
|
95
|
+
* (`commercialTreatmentIgnoresAccountKind.test.ts`) has a single source.
|
|
96
|
+
*/
|
|
97
|
+
exports.KIND_INDEPENDENT_ACCOUNT_DIMENSIONS = [
|
|
98
|
+
'roles',
|
|
99
|
+
'resources',
|
|
100
|
+
'plan',
|
|
101
|
+
'balance',
|
|
102
|
+
'payer',
|
|
103
|
+
'beneficiary',
|
|
104
|
+
];
|
|
105
|
+
// ===========================================================================
|
|
106
|
+
// Actor chain
|
|
107
|
+
// ===========================================================================
|
|
108
|
+
/**
|
|
109
|
+
* Who acted, and as whom, for one authenticated request.
|
|
110
|
+
*
|
|
111
|
+
* - `effectiveAccountId` — the account the request speaks AS (token `sub`).
|
|
112
|
+
* - `actorAccountId` — who actually acted (token `act.sub`): the human operating
|
|
113
|
+
* a managed account, or the account itself when nobody operates it.
|
|
114
|
+
* - `delegated` — exactly `actorAccountId !== effectiveAccountId`. Carried as
|
|
115
|
+
* its own field so a consumer reads a fact instead of re-deriving it, and
|
|
116
|
+
* refined so the two can never disagree.
|
|
117
|
+
*
|
|
118
|
+
* Produced ONLY by the session authority (Oxy's `/session/validate*`) from the
|
|
119
|
+
* session ROW. A header or an unverified token claim never produces one: that is
|
|
120
|
+
* what keeps a modified header from changing the actor.
|
|
121
|
+
*/
|
|
122
|
+
exports.accountActorChainSchema = zod_1.z
|
|
123
|
+
.object({
|
|
124
|
+
schemaVersion: zod_1.z.literal(exports.ACCOUNT_SUBJECT_CONTRACT_VERSION),
|
|
125
|
+
effectiveAccountId: identifiers_1.oxyAccountIdSchema,
|
|
126
|
+
actorAccountId: identifiers_1.oxyAccountIdSchema,
|
|
127
|
+
delegated: zod_1.z.boolean(),
|
|
128
|
+
})
|
|
129
|
+
.strict()
|
|
130
|
+
.refine((chain) => chain.delegated === (chain.actorAccountId !== chain.effectiveAccountId), {
|
|
131
|
+
message: 'delegated must be true exactly when the actor differs from the effective account',
|
|
132
|
+
path: ['delegated'],
|
|
133
|
+
});
|
|
134
|
+
/**
|
|
135
|
+
* Build the chain from a session's binding: its subject and the operator
|
|
136
|
+
* recorded on it (`sessions.operated_by_user_id`), if any.
|
|
137
|
+
*
|
|
138
|
+
* The one constructor, so producers cannot each invent a rule. An operator equal
|
|
139
|
+
* to the subject is not a delegation.
|
|
140
|
+
*/
|
|
141
|
+
function accountActorChainFromSession(binding) {
|
|
142
|
+
const actor = binding.operatedByAccountId || binding.subjectAccountId;
|
|
143
|
+
return exports.accountActorChainSchema.parse({
|
|
144
|
+
schemaVersion: exports.ACCOUNT_SUBJECT_CONTRACT_VERSION,
|
|
145
|
+
effectiveAccountId: binding.subjectAccountId,
|
|
146
|
+
actorAccountId: actor,
|
|
147
|
+
delegated: actor !== binding.subjectAccountId,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
// ===========================================================================
|
|
151
|
+
// Financial subject
|
|
152
|
+
// ===========================================================================
|
|
153
|
+
/** `debit` — the subject pays; `credit` — the subject receives. */
|
|
154
|
+
exports.FINANCIAL_EFFECT_DIRECTIONS = ['debit', 'credit'];
|
|
155
|
+
/**
|
|
156
|
+
* Whose money a financial effect is, and who caused it.
|
|
157
|
+
*
|
|
158
|
+
* `subjectAccountId` is the account the effect BELONGS to — the payer of a
|
|
159
|
+
* debit, the beneficiary of a credit — and it is always the EFFECTIVE account of
|
|
160
|
+
* the actor chain. Never the operator: a person paying from the bot they operate
|
|
161
|
+
* spends the bot's money, and the receipt names the bot as payer and the person
|
|
162
|
+
* as actor. Never the owner: a bot paying for itself is recorded as the bot.
|
|
163
|
+
*
|
|
164
|
+
* What this does NOT decide is which balance row FUNDS a debit. That is the
|
|
165
|
+
* billing walk's answer (ADR 0014: the account's own active profile, else its
|
|
166
|
+
* nearest ancestor's) and it is kind-independent; this contract only fixes the
|
|
167
|
+
* subject and the actor the receipt must carry. Moving money is not done here.
|
|
168
|
+
*/
|
|
169
|
+
exports.financialEffectAttributionSchema = zod_1.z
|
|
170
|
+
.object({
|
|
171
|
+
schemaVersion: zod_1.z.literal(exports.ACCOUNT_SUBJECT_CONTRACT_VERSION),
|
|
172
|
+
direction: zod_1.z.enum(exports.FINANCIAL_EFFECT_DIRECTIONS),
|
|
173
|
+
subjectAccountId: identifiers_1.oxyAccountIdSchema,
|
|
174
|
+
actor: exports.accountActorChainSchema,
|
|
175
|
+
})
|
|
176
|
+
.strict()
|
|
177
|
+
.refine((effect) => effect.subjectAccountId === effect.actor.effectiveAccountId, {
|
|
178
|
+
message: 'a financial effect belongs to the effective account, never the operator',
|
|
179
|
+
path: ['subjectAccountId'],
|
|
180
|
+
});
|
|
181
|
+
/** Attribute a payment or a receipt to the subject the actor chain speaks as. */
|
|
182
|
+
function attributeFinancialEffect(direction, actor) {
|
|
183
|
+
return exports.financialEffectAttributionSchema.parse({
|
|
184
|
+
schemaVersion: exports.ACCOUNT_SUBJECT_CONTRACT_VERSION,
|
|
185
|
+
direction,
|
|
186
|
+
subjectAccountId: actor.effectiveAccountId,
|
|
187
|
+
actor,
|
|
188
|
+
});
|
|
189
|
+
}
|
package/dist/cjs/agency.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.normalizedAppEventSchema = exports.catalogRegistrationSchema = exports.appCapabilityCatalogSchema = exports.catalogEventSchema = exports.catalogToolSchema = exports.auditEventSchema = exports.auditResultSchema = exports.policyDecisionSchema = exports.capabilityTicketClaimsSchema = exports.automationDefinitionSchema = exports.automationDataFlowSchema = exports.automationActorSelectionSchema = exports.automationTriggerSchema = exports.delegationGrantSchema = exports.capabilityCoordinatorSchema = exports.executionAuthorizationRefSchema = exports.capabilityCatalogBindingSchema = exports.grantLimitSchema = exports.toolGrantOverrideSchema = exports.resourceRefSchema = exports.actorRefSchema = exports.capabilityPackageSchema = exports.CAPABILITY_PACKAGES = exports.autonomyLevelSchema = exports.AUTONOMY_LEVELS = void 0;
|
|
3
|
+
exports.normalizedAppEventSchema = exports.catalogRegistrationSchema = exports.appCapabilityCatalogSchema = exports.catalogEventSchema = exports.catalogToolSchema = exports.auditEventSchema = exports.auditResultSchema = exports.policyDecisionSchema = exports.invocationPrincipalSchema = exports.capabilityTicketClaimsSchema = exports.automationDefinitionSchema = exports.automationDataFlowSchema = exports.automationActorSelectionSchema = exports.automationTriggerSchema = exports.delegationGrantSchema = exports.capabilityTicketRequestSchema = exports.capabilityCoordinatorSchema = exports.executionAuthorizationRefSchema = exports.capabilityCatalogBindingSchema = exports.grantLimitSchema = exports.toolGrantOverrideSchema = exports.resourceRefSchema = exports.foregroundExecutionAuthorizationInputSchema = exports.executionActorRefSchema = exports.actorRefSchema = exports.capabilityPackageSchema = exports.CAPABILITY_PACKAGES = exports.autonomyLevelSchema = exports.AUTONOMY_LEVELS = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const capabilityInvocation_1 = require("./capabilityInvocation");
|
|
6
6
|
const nonEmptyStringSchema = zod_1.z.string().trim().min(1);
|
|
@@ -38,6 +38,23 @@ exports.actorRefSchema = zod_1.z.discriminatedUnion('type', [
|
|
|
38
38
|
accountId: identifierSchema,
|
|
39
39
|
}).strict(),
|
|
40
40
|
]);
|
|
41
|
+
/** Present requester only; standing grants/automation retain actorRefSchema. */
|
|
42
|
+
exports.executionActorRefSchema = zod_1.z.discriminatedUnion('type', [
|
|
43
|
+
...exports.actorRefSchema.options,
|
|
44
|
+
zod_1.z.object({ type: zod_1.z.literal('requester'), accountId: identifierSchema }).strict(),
|
|
45
|
+
]);
|
|
46
|
+
/** Separate bearer lives only in the SDK option / authority request body. */
|
|
47
|
+
exports.foregroundExecutionAuthorizationInputSchema = zod_1.z.object({
|
|
48
|
+
tool: zod_1.z.enum(['recommendProfiles', 'readViewerGraph']),
|
|
49
|
+
expectedCatalog: zod_1.z.object({
|
|
50
|
+
registrationId: identifierSchema,
|
|
51
|
+
version: identifierSchema,
|
|
52
|
+
digest: sha256HexSchema,
|
|
53
|
+
}).strict(),
|
|
54
|
+
runId: identifierSchema,
|
|
55
|
+
stepId: identifierSchema.optional(),
|
|
56
|
+
expiresAt: zod_1.z.string().datetime(),
|
|
57
|
+
}).strict();
|
|
41
58
|
exports.resourceRefSchema = zod_1.z.object({
|
|
42
59
|
appId: identifierSchema,
|
|
43
60
|
effectiveAccountId: identifierSchema,
|
|
@@ -76,6 +93,13 @@ exports.capabilityCoordinatorSchema = zod_1.z.object({
|
|
|
76
93
|
applicationId: identifierSchema,
|
|
77
94
|
credentialId: identifierSchema,
|
|
78
95
|
}).strict();
|
|
96
|
+
/** Opt-in catalogue pin; legacy issuance omits expectedCatalog and its claim. */
|
|
97
|
+
exports.capabilityTicketRequestSchema = zod_1.z.object({
|
|
98
|
+
executionAuthorizationId: zod_1.z.string().min(1),
|
|
99
|
+
runId: zod_1.z.string().min(1).optional(),
|
|
100
|
+
stepId: zod_1.z.string().min(1).optional(),
|
|
101
|
+
expectedCatalog: exports.capabilityCatalogBindingSchema.optional(),
|
|
102
|
+
}).strict();
|
|
79
103
|
exports.delegationGrantSchema = zod_1.z.object({
|
|
80
104
|
id: identifierSchema,
|
|
81
105
|
ownerAccountId: identifierSchema,
|
|
@@ -142,17 +166,19 @@ exports.capabilityTicketClaimsSchema = zod_1.z.object({
|
|
|
142
166
|
automationId: identifierSchema.optional(),
|
|
143
167
|
executionAuthorization: exports.executionAuthorizationRefSchema,
|
|
144
168
|
coordinator: exports.capabilityCoordinatorSchema,
|
|
169
|
+
/** Signed only for callers that explicitly requested a pinned catalogue. */
|
|
170
|
+
catalog: exports.capabilityCatalogBindingSchema.optional(),
|
|
145
171
|
grantId: identifierSchema.optional(),
|
|
146
172
|
requesterAccountId: identifierSchema,
|
|
147
173
|
ownerAccountId: identifierSchema,
|
|
148
|
-
actor: exports.
|
|
174
|
+
actor: exports.executionActorRefSchema,
|
|
149
175
|
resource: exports.resourceRefSchema,
|
|
150
176
|
tool: identifierSchema,
|
|
151
177
|
capabilities: zod_1.z.array(identifierSchema).min(1),
|
|
152
178
|
limits: zod_1.z.array(exports.grantLimitSchema).default([]),
|
|
153
179
|
autonomy: exports.autonomyLevelSchema,
|
|
154
180
|
}).strict().superRefine((claims, context) => {
|
|
155
|
-
const expectedSubject = claims.actor.type
|
|
181
|
+
const expectedSubject = claims.actor.type !== 'alia'
|
|
156
182
|
? claims.actor.accountId
|
|
157
183
|
: `alia:${claims.actor.ownerAccountId}`;
|
|
158
184
|
if (claims.sub !== expectedSubject) {
|
|
@@ -169,6 +195,14 @@ exports.capabilityTicketClaimsSchema = zod_1.z.object({
|
|
|
169
195
|
path: ['actor', 'ownerAccountId'],
|
|
170
196
|
});
|
|
171
197
|
}
|
|
198
|
+
if (claims.actor.type === 'requester' && (claims.actor.accountId !== claims.requesterAccountId
|
|
199
|
+
|| claims.executionAuthorization.kind !== 'direct_request'
|
|
200
|
+
|| claims.autonomy !== 'read_only'
|
|
201
|
+
|| claims.grantId !== undefined
|
|
202
|
+
|| claims.automationId !== undefined)) {
|
|
203
|
+
context.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['actor'],
|
|
204
|
+
message: 'requester actors require their exact principal and direct read-only authority without standing grants' });
|
|
205
|
+
}
|
|
172
206
|
if (claims.exp <= claims.iat) {
|
|
173
207
|
context.addIssue({
|
|
174
208
|
code: zod_1.z.ZodIssueCode.custom,
|
|
@@ -202,6 +236,24 @@ exports.capabilityTicketClaimsSchema = zod_1.z.object({
|
|
|
202
236
|
}
|
|
203
237
|
}
|
|
204
238
|
});
|
|
239
|
+
/** Structural projections only: an authenticated transport must produce these. */
|
|
240
|
+
exports.invocationPrincipalSchema = zod_1.z.discriminatedUnion('kind', [
|
|
241
|
+
zod_1.z.object({
|
|
242
|
+
kind: zod_1.z.literal('oauth'),
|
|
243
|
+
subject: identifierSchema,
|
|
244
|
+
clientId: identifierSchema,
|
|
245
|
+
originAccountId: identifierSchema,
|
|
246
|
+
activeAccountId: identifierSchema,
|
|
247
|
+
scopes: zod_1.z.array(identifierSchema),
|
|
248
|
+
resource: zod_1.z.string().url(),
|
|
249
|
+
}).strict(),
|
|
250
|
+
zod_1.z.object({
|
|
251
|
+
kind: zod_1.z.literal('capability'),
|
|
252
|
+
claims: exports.capabilityTicketClaimsSchema.refine((claims) => claims.catalog !== undefined, {
|
|
253
|
+
message: 'internal MCP requires a signed catalogue binding',
|
|
254
|
+
}),
|
|
255
|
+
}).strict(),
|
|
256
|
+
]);
|
|
205
257
|
exports.policyDecisionSchema = zod_1.z.object({
|
|
206
258
|
allowed: zod_1.z.boolean(),
|
|
207
259
|
reason: identifierSchema,
|
|
@@ -217,7 +269,7 @@ exports.auditEventSchema = zod_1.z.object({
|
|
|
217
269
|
occurredAt: zod_1.z.string().datetime(),
|
|
218
270
|
requesterAccountId: identifierSchema,
|
|
219
271
|
coordinator: exports.capabilityCoordinatorSchema,
|
|
220
|
-
executor: exports.
|
|
272
|
+
executor: exports.executionActorRefSchema,
|
|
221
273
|
effectiveAccountId: identifierSchema,
|
|
222
274
|
resource: exports.resourceRefSchema,
|
|
223
275
|
appId: identifierSchema,
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.agentKeyListResponseSchema = exports.ACCOUNT_AUTH_METHODS = exports.agentKeyOperationResultSchema = exports.agentKeyOperationChallengeSchema = exports.executeAgentKeyOperationSchema = exports.agentKeyOperationProofSchema = exports.agentKeyOperationSchema = exports.agentVerifyRequestSchema = exports.agentChallengeRequestSchema = exports.agentSignatureSchema = exports.agentProofClaimsSchema = exports.AGENT_PROOF_ACTIONS = exports.AGENT_PROOF_TTL_MS = exports.AGENT_PROOF_AUDIENCE = void 0;
|
|
4
|
+
exports.buildAgentProofMessage = buildAgentProofMessage;
|
|
5
|
+
/** Autonomous runtime proof. No private key crosses this contract. */
|
|
6
|
+
const zod_1 = require("zod");
|
|
7
|
+
const signIn_1 = require("./signIn");
|
|
8
|
+
const identityProof_1 = require("./identityProof");
|
|
9
|
+
exports.AGENT_PROOF_AUDIENCE = 'oxy-api/agent';
|
|
10
|
+
exports.AGENT_PROOF_TTL_MS = 60000;
|
|
11
|
+
exports.AGENT_PROOF_ACTIONS = ['agent_signin', 'agent_enroll', 'agent_rotate', 'agent_recover', 'agent_governance'];
|
|
12
|
+
exports.agentProofClaimsSchema = zod_1.z.object({
|
|
13
|
+
version: zod_1.z.literal(1),
|
|
14
|
+
audience: zod_1.z.literal(exports.AGENT_PROOF_AUDIENCE),
|
|
15
|
+
action: zod_1.z.enum(exports.AGENT_PROOF_ACTIONS),
|
|
16
|
+
accountId: zod_1.z.string().min(1),
|
|
17
|
+
actorId: zod_1.z.string().min(1),
|
|
18
|
+
authMethodId: zod_1.z.string().nullable(),
|
|
19
|
+
publicKey: zod_1.z.string().min(1),
|
|
20
|
+
payloadDigest: zod_1.z.string().regex(/^[0-9a-f]{64}$/),
|
|
21
|
+
challenge: zod_1.z.string().regex(/^[0-9a-f]{64}$/),
|
|
22
|
+
expiresAt: zod_1.z.number().int().positive(),
|
|
23
|
+
}).strict();
|
|
24
|
+
/** Different proof roles cannot substitute for one another on the same operation. */
|
|
25
|
+
function buildAgentProofMessage(claims, timestamp, role = 'credential') {
|
|
26
|
+
return (0, identityProof_1.canonicalJson)({ domain: 'oxy-agent-proof', ...exports.agentProofClaimsSchema.parse(claims), timestamp, role });
|
|
27
|
+
}
|
|
28
|
+
exports.agentSignatureSchema = zod_1.z.object({
|
|
29
|
+
challenge: zod_1.z.string().regex(/^[0-9a-f]{64}$/),
|
|
30
|
+
signature: zod_1.z.string().regex(/^[0-9a-f]+$/i).max(160),
|
|
31
|
+
timestamp: zod_1.z.number().int().positive(),
|
|
32
|
+
}).strict();
|
|
33
|
+
exports.agentChallengeRequestSchema = zod_1.z.object({ publicKey: zod_1.z.string().trim().min(1).max(130) }).strict();
|
|
34
|
+
exports.agentVerifyRequestSchema = exports.agentSignatureSchema.extend({ publicKey: zod_1.z.string().trim().min(1).max(130) }).strict();
|
|
35
|
+
const newKey = { publicKey: zod_1.z.string().trim().min(1).max(130), label: zod_1.z.string().trim().min(1).max(120) };
|
|
36
|
+
exports.agentKeyOperationSchema = zod_1.z.discriminatedUnion('operation', [
|
|
37
|
+
zod_1.z.object({ operation: zod_1.z.literal('enroll'), ...newKey }).strict(),
|
|
38
|
+
zod_1.z.object({ operation: zod_1.z.literal('recover'), ...newKey }).strict(),
|
|
39
|
+
zod_1.z.object({ operation: zod_1.z.literal('rotate'), ...newKey, retireCurrent: zod_1.z.boolean().optional() }).strict(),
|
|
40
|
+
zod_1.z.object({ operation: zod_1.z.literal('revoke'), methodId: zod_1.z.string().min(1) }).strict(),
|
|
41
|
+
]);
|
|
42
|
+
exports.agentKeyOperationProofSchema = zod_1.z.object({
|
|
43
|
+
challenge: zod_1.z.string().regex(/^[0-9a-f]{64}$/),
|
|
44
|
+
timestamp: zod_1.z.number().int().positive(),
|
|
45
|
+
keySignature: zod_1.z.string().regex(/^[0-9a-f]+$/i).max(160).optional(),
|
|
46
|
+
governorSignature: zod_1.z.string().regex(/^[0-9a-f]+$/i).max(160).optional(),
|
|
47
|
+
reauth: signIn_1.reauthProofSchema.optional(),
|
|
48
|
+
}).strict();
|
|
49
|
+
exports.executeAgentKeyOperationSchema = zod_1.z.object({
|
|
50
|
+
operation: exports.agentKeyOperationSchema,
|
|
51
|
+
proof: exports.agentKeyOperationProofSchema,
|
|
52
|
+
}).strict();
|
|
53
|
+
exports.agentKeyOperationChallengeSchema = zod_1.z.object({
|
|
54
|
+
claims: exports.agentProofClaimsSchema,
|
|
55
|
+
governorPublicKey: zod_1.z.string().nullable(),
|
|
56
|
+
}).strict();
|
|
57
|
+
exports.agentKeyOperationResultSchema = zod_1.z.object({
|
|
58
|
+
methodId: zod_1.z.string().nullable(),
|
|
59
|
+
revokedMethodIds: zod_1.z.array(zod_1.z.string()),
|
|
60
|
+
}).strict();
|
|
61
|
+
exports.ACCOUNT_AUTH_METHODS = ['identity', 'agent_key'];
|
|
62
|
+
/** Public credential inventory. Never includes a proof, bearer or private key. */
|
|
63
|
+
exports.agentKeyListResponseSchema = zod_1.z.object({ keys: zod_1.z.array(zod_1.z.object({
|
|
64
|
+
id: zod_1.z.string(), publicKey: zod_1.z.string(), label: zod_1.z.string(),
|
|
65
|
+
enrolledByUserId: zod_1.z.string().nullable(), enrollmentMethod: zod_1.z.enum(['governor', 'rotation', 'recovery']),
|
|
66
|
+
linkedAt: zod_1.z.string().datetime(), lastUsedAt: zod_1.z.string().datetime().nullable(), revokedAt: zod_1.z.string().datetime().nullable(),
|
|
67
|
+
}).strict()) }).strict();
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.canonicalCapabilityJson = canonicalCapabilityJson;
|
|
4
|
+
exports.inputSatisfiesCapabilityLimits = inputSatisfiesCapabilityLimits;
|
|
5
|
+
exports.isLoopbackOrigin = isLoopbackOrigin;
|
|
6
|
+
function canonicalValue(value) {
|
|
7
|
+
if (Array.isArray(value))
|
|
8
|
+
return value.map(canonicalValue);
|
|
9
|
+
if (typeof value !== 'object' || value === null)
|
|
10
|
+
return value;
|
|
11
|
+
const record = value;
|
|
12
|
+
const sorted = Object.create(null);
|
|
13
|
+
for (const key of Object.keys(record).sort())
|
|
14
|
+
sorted[key] = canonicalValue(record[key]);
|
|
15
|
+
return sorted;
|
|
16
|
+
}
|
|
17
|
+
/** Registry-compatible JSON: sorted keys, omitted undefined object properties. */
|
|
18
|
+
function canonicalCapabilityJson(value) {
|
|
19
|
+
return JSON.stringify(canonicalValue(value));
|
|
20
|
+
}
|
|
21
|
+
function valuesAtPath(input, path) {
|
|
22
|
+
let current = [input];
|
|
23
|
+
for (const segment of path.split('.')) {
|
|
24
|
+
const next = [];
|
|
25
|
+
for (const value of current) {
|
|
26
|
+
const records = Array.isArray(value) ? value : [value];
|
|
27
|
+
for (const record of records) {
|
|
28
|
+
if (typeof record !== 'object' || record === null || Array.isArray(record))
|
|
29
|
+
continue;
|
|
30
|
+
if (Object.prototype.hasOwnProperty.call(record, segment)) {
|
|
31
|
+
next.push(record[segment]);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (next.length === 0)
|
|
36
|
+
return [];
|
|
37
|
+
current = next;
|
|
38
|
+
}
|
|
39
|
+
return current.flatMap((value) => Array.isArray(value) ? value : [value]);
|
|
40
|
+
}
|
|
41
|
+
/** Enforces the signed per-action bounds before a domain handler runs. */
|
|
42
|
+
function inputSatisfiesCapabilityLimits(tool, input, limits) {
|
|
43
|
+
for (const limit of limits) {
|
|
44
|
+
if (limit.tool !== tool)
|
|
45
|
+
return false;
|
|
46
|
+
const actualValues = valuesAtPath(input, limit.key);
|
|
47
|
+
if (actualValues.length === 0)
|
|
48
|
+
return false;
|
|
49
|
+
if (typeof limit.value === 'number') {
|
|
50
|
+
const maximum = limit.value;
|
|
51
|
+
if (!actualValues.every((actual) => (typeof actual === 'number' && Number.isFinite(actual) && actual <= maximum)))
|
|
52
|
+
return false;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (!actualValues.every((actual) => actual === limit.value))
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
function isLoopbackOrigin(origin) {
|
|
61
|
+
try {
|
|
62
|
+
const parsed = new URL(origin);
|
|
63
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
const host = parsed.hostname.toLowerCase();
|
|
67
|
+
return host === 'localhost' || host === '127.0.0.1' || host === '[::1]';
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|