agentcert 0.2.7 → 0.4.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/README.md +37 -0
- package/dist/cli.js +8 -0
- package/dist/command-help.js +2 -0
- package/dist/index.js +1 -0
- package/dist/sandbox.js +323 -0
- package/dist/vendor/onegent-runtime/mock-procurement.d.ts +6 -0
- package/dist/vendor/onegent-runtime/mock-procurement.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/mock-procurement.js +33 -0
- package/dist/vendor/onegent-runtime/policies.d.ts +6 -0
- package/dist/vendor/onegent-runtime/policies.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/policies.js +109 -0
- package/dist/vendor/onegent-runtime/risk.d.ts +3 -0
- package/dist/vendor/onegent-runtime/risk.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/risk.js +54 -0
- package/dist/vendor/onegent-runtime/sandbox-adapter-kit.d.ts +45 -0
- package/dist/vendor/onegent-runtime/sandbox-adapter-kit.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/sandbox-adapter-kit.js +148 -0
- package/dist/vendor/onegent-runtime/sandbox-harness.d.ts +167 -0
- package/dist/vendor/onegent-runtime/sandbox-harness.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/sandbox-harness.js +729 -0
- package/dist/vendor/onegent-runtime/sandbox-hosted.d.ts +77 -0
- package/dist/vendor/onegent-runtime/sandbox-hosted.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/sandbox-hosted.js +133 -0
- package/dist/vendor/onegent-runtime/sdk.d.ts +29 -0
- package/dist/vendor/onegent-runtime/sdk.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/sdk.js +140 -0
- package/dist/vendor/onegent-runtime/service.d.ts +27 -0
- package/dist/vendor/onegent-runtime/service.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/service.js +421 -0
- package/dist/vendor/onegent-runtime/store.d.ts +16 -0
- package/dist/vendor/onegent-runtime/store.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/store.js +29 -0
- package/dist/vendor/onegent-runtime/stripe-test-readonly.d.ts +79 -0
- package/dist/vendor/onegent-runtime/stripe-test-readonly.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/stripe-test-readonly.js +163 -0
- package/dist/vendor/onegent-runtime/types.d.ts +284 -0
- package/dist/vendor/onegent-runtime/types.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/types.js +1 -0
- package/dist/vendor/onegent-runtime/vendor-sandbox-egress.d.ts +49 -0
- package/dist/vendor/onegent-runtime/vendor-sandbox-egress.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/vendor-sandbox-egress.js +152 -0
- package/package.json +2 -2
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { createBoundedVendorSandboxEgress, VendorSandboxEgressError, } from "./vendor-sandbox-egress.js";
|
|
2
|
+
export const STRIPE_TEST_API_ORIGIN = "https://api.stripe.com";
|
|
3
|
+
export const STRIPE_SANDBOX_TIMEOUT_MS = 5_000;
|
|
4
|
+
export const STRIPE_SANDBOX_MAX_REQUESTS_PER_MINUTE = 10;
|
|
5
|
+
export const STRIPE_PAYMENT_INTENT_RETRIEVE = "stripe.payment_intent.retrieve";
|
|
6
|
+
export const STRIPE_PAYMENT_INTENT_LIST = "stripe.payment_intent.list";
|
|
7
|
+
const STRIPE_RESOURCES = Object.freeze([
|
|
8
|
+
Object.freeze({
|
|
9
|
+
id: STRIPE_PAYMENT_INTENT_RETRIEVE,
|
|
10
|
+
method: "GET",
|
|
11
|
+
pathPattern: /^\/v1\/payment_intents\/pi_[A-Za-z0-9]{8,128}$/,
|
|
12
|
+
}),
|
|
13
|
+
Object.freeze({
|
|
14
|
+
id: STRIPE_PAYMENT_INTENT_LIST,
|
|
15
|
+
method: "GET",
|
|
16
|
+
pathPattern: /^\/v1\/payment_intents\?limit=(?:[1-9]|10)$/,
|
|
17
|
+
}),
|
|
18
|
+
]);
|
|
19
|
+
export function createStripeTestModeReadOnlyAdapter(options) {
|
|
20
|
+
const apiKey = options.restrictedApiKey.trim();
|
|
21
|
+
if (!/^rk_test_[A-Za-z0-9_]{8,}$/.test(apiKey)) {
|
|
22
|
+
throw new Error("Stripe read-only reference adapter requires an rk_test_ restricted test-mode key.");
|
|
23
|
+
}
|
|
24
|
+
const timeoutMs = options.timeoutMs ?? STRIPE_SANDBOX_TIMEOUT_MS;
|
|
25
|
+
const maxRequestsPerMinute = options.maxRequestsPerMinute ?? STRIPE_SANDBOX_MAX_REQUESTS_PER_MINUTE;
|
|
26
|
+
const egress = createBoundedVendorSandboxEgress({
|
|
27
|
+
policy: {
|
|
28
|
+
vendor: "stripe",
|
|
29
|
+
allowedOrigin: STRIPE_TEST_API_ORIGIN,
|
|
30
|
+
resources: STRIPE_RESOURCES,
|
|
31
|
+
timeoutMs,
|
|
32
|
+
maxRequestsPerMinute,
|
|
33
|
+
},
|
|
34
|
+
fetch: options.fetch,
|
|
35
|
+
now: options.now,
|
|
36
|
+
});
|
|
37
|
+
const get = (resource, path) => egress.requestJson({
|
|
38
|
+
resource,
|
|
39
|
+
method: "GET",
|
|
40
|
+
path,
|
|
41
|
+
headers: {
|
|
42
|
+
authorization: `Bearer ${apiKey}`,
|
|
43
|
+
accept: "application/json",
|
|
44
|
+
"user-agent": "agentcert-onegent-runtime/stripe-sandbox-readonly-v0.4",
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
return Object.freeze({
|
|
48
|
+
name: "stripe-test-mode-readonly",
|
|
49
|
+
safety: Object.freeze({
|
|
50
|
+
mode: "sandbox",
|
|
51
|
+
access: "read-only",
|
|
52
|
+
vendor: "stripe",
|
|
53
|
+
allowedOrigins: Object.freeze([STRIPE_TEST_API_ORIGIN]),
|
|
54
|
+
allowedMethods: Object.freeze(["GET"]),
|
|
55
|
+
allowedResources: Object.freeze([STRIPE_PAYMENT_INTENT_RETRIEVE, STRIPE_PAYMENT_INTENT_LIST]),
|
|
56
|
+
timeoutMs,
|
|
57
|
+
maxRequestsPerMinute,
|
|
58
|
+
}),
|
|
59
|
+
retrievePaymentIntent: async (id) => {
|
|
60
|
+
if (!/^pi_[A-Za-z0-9]{8,128}$/.test(id))
|
|
61
|
+
throw new Error("Stripe PaymentIntent ID is invalid.");
|
|
62
|
+
return paymentIntentSnapshot(await get(STRIPE_PAYMENT_INTENT_RETRIEVE, `/v1/payment_intents/${encodeURIComponent(id)}`));
|
|
63
|
+
},
|
|
64
|
+
listPaymentIntents: async (limit = 10) => {
|
|
65
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 10)
|
|
66
|
+
throw new Error("Stripe read-only list limit must be an integer from 1 to 10.");
|
|
67
|
+
const payload = await get(STRIPE_PAYMENT_INTENT_LIST, `/v1/payment_intents?limit=${limit}`);
|
|
68
|
+
if (!isRecord(payload) || payload.object !== "list" || !Array.isArray(payload.data)) {
|
|
69
|
+
throw new Error("Stripe returned an invalid PaymentIntent list response.");
|
|
70
|
+
}
|
|
71
|
+
return payload.data.map(paymentIntentSnapshot);
|
|
72
|
+
},
|
|
73
|
+
getRequestAudit: () => egress.getAuditLog(),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
export async function runStripeSandboxReadOnlyCertification(options) {
|
|
77
|
+
const generatedAt = new Date((options.now ?? Date.now)()).toISOString();
|
|
78
|
+
const timeoutMs = options.timeoutMs ?? STRIPE_SANDBOX_TIMEOUT_MS;
|
|
79
|
+
const maxRequestsPerMinute = options.maxRequestsPerMinute ?? STRIPE_SANDBOX_MAX_REQUESTS_PER_MINUTE;
|
|
80
|
+
const checks = [];
|
|
81
|
+
let adapter;
|
|
82
|
+
let observation;
|
|
83
|
+
try {
|
|
84
|
+
adapter = createStripeTestModeReadOnlyAdapter(options);
|
|
85
|
+
checks.push(passed("restricted-test-key", "Credential format is restricted to Stripe rk_test_ keys and is not retained."), passed("fixed-egress-policy", "Egress is fixed to Stripe HTTPS, GET, and allowlisted PaymentIntent resources."));
|
|
86
|
+
observation = await adapter.retrievePaymentIntent(options.paymentIntentId);
|
|
87
|
+
checks.push(passed("bounded-read", "The allowlisted PaymentIntent read completed within the configured bounds."), passed("test-mode-response", "Stripe explicitly returned livemode=false."), passed("evidence-redaction", "The evidence snapshot excludes credentials, client_secret, metadata, and raw response bytes."));
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (!adapter) {
|
|
91
|
+
checks.push(failed("restricted-test-key", "A valid Stripe rk_test_ restricted test-mode key was not available."), failed("fixed-egress-policy", "The request was not attempted because credential validation failed."));
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
checks.push(failed("bounded-read", safeStripeFailure(error)));
|
|
95
|
+
}
|
|
96
|
+
checks.push(failed("test-mode-response", "No validated Stripe test-mode observation was produced."), failed("evidence-redaction", "No successful redacted observation was produced."));
|
|
97
|
+
}
|
|
98
|
+
const passedCount = checks.filter((check) => check.status === "passed").length;
|
|
99
|
+
const report = {
|
|
100
|
+
schemaVersion: "agentcert.sandbox_vendor_egress.v0.4",
|
|
101
|
+
kind: "agentcert.sandbox_vendor_egress",
|
|
102
|
+
implementation: "stripe-payment-intent-readonly",
|
|
103
|
+
vendor: "stripe",
|
|
104
|
+
environment: "sandbox",
|
|
105
|
+
generatedAt,
|
|
106
|
+
verdict: { passed: passedCount === checks.length, score: Math.round((passedCount / checks.length) * 100) },
|
|
107
|
+
summary: { passed: passedCount, failed: checks.length - passedCount, total: checks.length },
|
|
108
|
+
checks,
|
|
109
|
+
policy: {
|
|
110
|
+
allowedOrigins: [STRIPE_TEST_API_ORIGIN],
|
|
111
|
+
allowedMethods: ["GET"],
|
|
112
|
+
allowedResources: [STRIPE_PAYMENT_INTENT_RETRIEVE, STRIPE_PAYMENT_INTENT_LIST],
|
|
113
|
+
timeoutMs,
|
|
114
|
+
maxRequestsPerMinute,
|
|
115
|
+
},
|
|
116
|
+
audit: adapter?.getRequestAudit() ?? [],
|
|
117
|
+
...(observation ? { observation } : {}),
|
|
118
|
+
disclaimer: "Stripe sandbox read-only evidence proves this bounded test-mode observation only. It does not authorize writes, attest Stripe controls, or certify production behavior.",
|
|
119
|
+
};
|
|
120
|
+
return structuredClone(report);
|
|
121
|
+
}
|
|
122
|
+
function paymentIntentSnapshot(value) {
|
|
123
|
+
if (!isRecord(value) || value.object !== "payment_intent" || typeof value.id !== "string") {
|
|
124
|
+
throw new Error("Stripe returned an invalid PaymentIntent response.");
|
|
125
|
+
}
|
|
126
|
+
if (value.livemode !== false)
|
|
127
|
+
throw new Error("Stripe read-only adapter refuses responses that are not explicitly test mode.");
|
|
128
|
+
return {
|
|
129
|
+
id: value.id,
|
|
130
|
+
object: "payment_intent",
|
|
131
|
+
livemode: false,
|
|
132
|
+
...numberField(value, "amount", "amount"),
|
|
133
|
+
...numberField(value, "amount_capturable", "amountCapturable"),
|
|
134
|
+
...numberField(value, "amount_received", "amountReceived"),
|
|
135
|
+
...stringField(value, "currency", "currency"),
|
|
136
|
+
...stringField(value, "status", "status"),
|
|
137
|
+
...numberField(value, "created", "created"),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function safeStripeFailure(error) {
|
|
141
|
+
if (error instanceof VendorSandboxEgressError)
|
|
142
|
+
return `Stripe sandbox read failed (${error.code}).`;
|
|
143
|
+
if (error instanceof Error && error.message.includes("not explicitly test mode"))
|
|
144
|
+
return "Stripe response was not explicitly test mode.";
|
|
145
|
+
if (error instanceof Error && error.message.includes("invalid PaymentIntent"))
|
|
146
|
+
return "Stripe returned an invalid PaymentIntent response.";
|
|
147
|
+
return "Stripe sandbox read failed before a validated observation was produced.";
|
|
148
|
+
}
|
|
149
|
+
function passed(id, message) {
|
|
150
|
+
return { id, status: "passed", message };
|
|
151
|
+
}
|
|
152
|
+
function failed(id, message) {
|
|
153
|
+
return { id, status: "failed", message };
|
|
154
|
+
}
|
|
155
|
+
function numberField(value, source, target) {
|
|
156
|
+
return typeof value[source] === "number" && Number.isFinite(value[source]) ? { [target]: value[source] } : {};
|
|
157
|
+
}
|
|
158
|
+
function stringField(value, source, target) {
|
|
159
|
+
return typeof value[source] === "string" ? { [target]: value[source] } : {};
|
|
160
|
+
}
|
|
161
|
+
function isRecord(value) {
|
|
162
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
163
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
export type ActionType = "SUBMIT" | "PAY" | "SEND" | "UPDATE";
|
|
2
|
+
export type ActionEnvironment = "demo" | "staging" | "production";
|
|
3
|
+
export type ActionIntentStatus = "CAPTURED" | "NEEDS_REVIEW" | "APPROVED" | "REJECTED" | "EXECUTED" | "VERIFIED" | "FAILED_VERIFICATION" | "ROLLED_BACK" | "ROLLBACK_FAILED" | "CANCELLED";
|
|
4
|
+
export type RiskLevel = "LOW" | "MEDIUM" | "HIGH" | "CRITICAL";
|
|
5
|
+
export type PolicyEffect = "ALLOW" | "REQUIRE_APPROVAL" | "BLOCK";
|
|
6
|
+
export type ApprovalStatus = "PENDING" | "APPROVED" | "REJECTED" | "EXPIRED";
|
|
7
|
+
export type VerificationMethod = "MOCK" | "LOCAL_MOCK_ERP" | "LOCAL_ADAPTER";
|
|
8
|
+
export interface ActionFieldChange {
|
|
9
|
+
field: string;
|
|
10
|
+
before?: unknown;
|
|
11
|
+
after?: unknown;
|
|
12
|
+
}
|
|
13
|
+
export interface AgentPrincipal {
|
|
14
|
+
id: string;
|
|
15
|
+
type: "agent" | "service";
|
|
16
|
+
version?: string;
|
|
17
|
+
owner?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ActionIntent {
|
|
20
|
+
id: string;
|
|
21
|
+
idempotencyKey: string;
|
|
22
|
+
workspaceId: string;
|
|
23
|
+
workflowId: string;
|
|
24
|
+
sourceAgentName: string;
|
|
25
|
+
sourceAgentRunId?: string;
|
|
26
|
+
principal: AgentPrincipal;
|
|
27
|
+
requestedPermissions: string[];
|
|
28
|
+
actionType: ActionType;
|
|
29
|
+
targetSystem: string;
|
|
30
|
+
targetUrl?: string;
|
|
31
|
+
environment: ActionEnvironment;
|
|
32
|
+
title: string;
|
|
33
|
+
description: string;
|
|
34
|
+
businessObjectType: string;
|
|
35
|
+
businessObjectId: string;
|
|
36
|
+
amount?: number;
|
|
37
|
+
currency?: string;
|
|
38
|
+
recipient?: string;
|
|
39
|
+
vendorName?: string;
|
|
40
|
+
beforeState: Record<string, unknown>;
|
|
41
|
+
proposedAfterState: Record<string, unknown>;
|
|
42
|
+
fieldsChanged: ActionFieldChange[];
|
|
43
|
+
rawAgentReasoningSummary?: string;
|
|
44
|
+
createdAt: string;
|
|
45
|
+
status: ActionIntentStatus;
|
|
46
|
+
}
|
|
47
|
+
export interface CreateActionIntentInput {
|
|
48
|
+
idempotencyKey?: string;
|
|
49
|
+
workspaceId?: string;
|
|
50
|
+
workflowId?: string;
|
|
51
|
+
sourceAgentName: string;
|
|
52
|
+
sourceAgentRunId?: string;
|
|
53
|
+
principal?: AgentPrincipal;
|
|
54
|
+
requestedPermissions?: string[];
|
|
55
|
+
actionType: ActionType;
|
|
56
|
+
targetSystem: string;
|
|
57
|
+
targetUrl?: string;
|
|
58
|
+
environment?: ActionEnvironment;
|
|
59
|
+
title: string;
|
|
60
|
+
description: string;
|
|
61
|
+
businessObjectType: string;
|
|
62
|
+
businessObjectId: string;
|
|
63
|
+
amount?: number;
|
|
64
|
+
currency?: string;
|
|
65
|
+
recipient?: string;
|
|
66
|
+
vendorName?: string;
|
|
67
|
+
beforeState?: Record<string, unknown>;
|
|
68
|
+
proposedAfterState?: Record<string, unknown>;
|
|
69
|
+
fieldsChanged?: ActionFieldChange[];
|
|
70
|
+
rawAgentReasoningSummary?: string;
|
|
71
|
+
}
|
|
72
|
+
export interface RiskAssessment {
|
|
73
|
+
id: string;
|
|
74
|
+
actionIntentId: string;
|
|
75
|
+
riskLevel: RiskLevel;
|
|
76
|
+
riskScore: number;
|
|
77
|
+
reasons: string[];
|
|
78
|
+
triggeredPolicies: string[];
|
|
79
|
+
requiresHumanApproval: boolean;
|
|
80
|
+
createdAt: string;
|
|
81
|
+
}
|
|
82
|
+
export interface PolicyRule {
|
|
83
|
+
id: string;
|
|
84
|
+
name: string;
|
|
85
|
+
description: string;
|
|
86
|
+
actionTypes: ActionType[];
|
|
87
|
+
effect: PolicyEffect;
|
|
88
|
+
enabled: boolean;
|
|
89
|
+
conditions?: PolicyCondition[];
|
|
90
|
+
}
|
|
91
|
+
export interface PolicyCondition {
|
|
92
|
+
field: string;
|
|
93
|
+
operator: "equals" | "notEquals" | "greaterThan" | "greaterThanOrEqual" | "lessThan" | "lessThanOrEqual" | "includes";
|
|
94
|
+
value: unknown;
|
|
95
|
+
}
|
|
96
|
+
export interface PolicyConfig {
|
|
97
|
+
schemaVersion: "1";
|
|
98
|
+
rules: PolicyRule[];
|
|
99
|
+
}
|
|
100
|
+
export interface PolicyEvaluation {
|
|
101
|
+
effect: PolicyEffect;
|
|
102
|
+
triggeredPolicies: string[];
|
|
103
|
+
reasons: string[];
|
|
104
|
+
requiresHumanApproval: boolean;
|
|
105
|
+
blocked: boolean;
|
|
106
|
+
}
|
|
107
|
+
export interface PolicyEngine {
|
|
108
|
+
evaluate(action: ActionIntent, risk: RiskAssessment, rules: PolicyRule[]): PolicyEvaluation;
|
|
109
|
+
}
|
|
110
|
+
export interface AuthorizationPolicyResult {
|
|
111
|
+
allowed: boolean;
|
|
112
|
+
grantedPermissions: string[];
|
|
113
|
+
policyVersion?: string;
|
|
114
|
+
reason: string;
|
|
115
|
+
}
|
|
116
|
+
export interface AuthorizationPolicy {
|
|
117
|
+
name: string;
|
|
118
|
+
authorize(action: ActionIntent): AuthorizationPolicyResult;
|
|
119
|
+
}
|
|
120
|
+
export interface AuthorizationDecision {
|
|
121
|
+
id: string;
|
|
122
|
+
actionIntentId: string;
|
|
123
|
+
principalId: string;
|
|
124
|
+
decision: "ALLOW" | "DENY";
|
|
125
|
+
requestedPermissions: string[];
|
|
126
|
+
grantedPermissions: string[];
|
|
127
|
+
policyName: string;
|
|
128
|
+
policyVersion?: string;
|
|
129
|
+
reason: string;
|
|
130
|
+
createdAt: string;
|
|
131
|
+
}
|
|
132
|
+
export interface ApprovalRequest {
|
|
133
|
+
id: string;
|
|
134
|
+
actionIntentId: string;
|
|
135
|
+
riskAssessmentId: string;
|
|
136
|
+
requestedBy: string;
|
|
137
|
+
assignedTo: string;
|
|
138
|
+
status: ApprovalStatus;
|
|
139
|
+
reviewerComment?: string;
|
|
140
|
+
createdAt: string;
|
|
141
|
+
reviewedAt?: string;
|
|
142
|
+
}
|
|
143
|
+
export interface ApprovalAdapterDecision {
|
|
144
|
+
approved?: boolean;
|
|
145
|
+
reviewerId?: string;
|
|
146
|
+
reviewerComment?: string;
|
|
147
|
+
decisionId?: string;
|
|
148
|
+
decidedAt?: string;
|
|
149
|
+
expiresAt?: string;
|
|
150
|
+
}
|
|
151
|
+
export interface ApprovalAdapterRequest {
|
|
152
|
+
action: ActionIntent;
|
|
153
|
+
risk: RiskAssessment;
|
|
154
|
+
policy: PolicyEvaluation;
|
|
155
|
+
approvalRequest: ApprovalRequest;
|
|
156
|
+
}
|
|
157
|
+
export interface ApprovalAdapter {
|
|
158
|
+
name: string;
|
|
159
|
+
requestApproval(input: ApprovalAdapterRequest): ApprovalAdapterDecision | void | Promise<ApprovalAdapterDecision | void>;
|
|
160
|
+
}
|
|
161
|
+
export interface VerificationResult {
|
|
162
|
+
id: string;
|
|
163
|
+
actionIntentId: string;
|
|
164
|
+
expectedState: Record<string, unknown>;
|
|
165
|
+
observedState: Record<string, unknown>;
|
|
166
|
+
success: boolean;
|
|
167
|
+
differences: string[];
|
|
168
|
+
verificationMethod: VerificationMethod;
|
|
169
|
+
createdAt: string;
|
|
170
|
+
}
|
|
171
|
+
export type AuditEventType = "ACTION_CAPTURED" | "AUTHORIZATION_CHECKED" | "RISK_ASSESSED" | "POLICY_EVALUATED" | "APPROVAL_REQUESTED" | "ACTION_APPROVED" | "ACTION_REJECTED" | "MOCK_EXECUTION_STARTED" | "MOCK_EXECUTION_COMPLETED" | "EXECUTION_REUSED" | "ROLLBACK_STARTED" | "ROLLBACK_COMPLETED" | "ROLLBACK_FAILED" | "VERIFICATION_PASSED" | "VERIFICATION_FAILED" | "AUDIT_PACKET_GENERATED";
|
|
172
|
+
export interface AuditEvent {
|
|
173
|
+
id: string;
|
|
174
|
+
actionIntentId: string;
|
|
175
|
+
eventType: AuditEventType;
|
|
176
|
+
actorType: "AGENT" | "HUMAN" | "SYSTEM";
|
|
177
|
+
actorId: string;
|
|
178
|
+
message: string;
|
|
179
|
+
metadata?: Record<string, unknown>;
|
|
180
|
+
createdAt: string;
|
|
181
|
+
}
|
|
182
|
+
export interface MockPurchaseOrder {
|
|
183
|
+
id: string;
|
|
184
|
+
vendor: string;
|
|
185
|
+
amount: number;
|
|
186
|
+
currency: string;
|
|
187
|
+
status: "DRAFT" | "SUBMITTED";
|
|
188
|
+
vendorApproved: boolean;
|
|
189
|
+
lineItem: string;
|
|
190
|
+
lastUpdatedAt: string;
|
|
191
|
+
actionIntentId?: string;
|
|
192
|
+
}
|
|
193
|
+
export interface ActionReview {
|
|
194
|
+
action: ActionIntent;
|
|
195
|
+
riskAssessment: RiskAssessment;
|
|
196
|
+
authorizationDecision?: AuthorizationDecision;
|
|
197
|
+
approvalRequest?: ApprovalRequest;
|
|
198
|
+
verificationResult?: VerificationResult;
|
|
199
|
+
auditEvents: AuditEvent[];
|
|
200
|
+
policyRules: PolicyRule[];
|
|
201
|
+
blocked: boolean;
|
|
202
|
+
}
|
|
203
|
+
export interface ActionExecutionSummary {
|
|
204
|
+
method: VerificationMethod;
|
|
205
|
+
status: "NOT_EXECUTED" | "COMPLETED";
|
|
206
|
+
targetSystem: string;
|
|
207
|
+
previousState?: Record<string, unknown>;
|
|
208
|
+
observedState?: Record<string, unknown>;
|
|
209
|
+
rollbackToken?: string;
|
|
210
|
+
}
|
|
211
|
+
export interface LocalActionAdapterResult {
|
|
212
|
+
method?: VerificationMethod;
|
|
213
|
+
targetSystem?: string;
|
|
214
|
+
previousState?: Record<string, unknown>;
|
|
215
|
+
observedState: Record<string, unknown>;
|
|
216
|
+
rollbackToken?: string;
|
|
217
|
+
}
|
|
218
|
+
export interface LocalActionAdapterSafety {
|
|
219
|
+
mode: "sandbox";
|
|
220
|
+
allowedTargetSystems: string[];
|
|
221
|
+
networkAccess: false;
|
|
222
|
+
}
|
|
223
|
+
export interface ActionExecutionContext {
|
|
224
|
+
idempotencyKey: string;
|
|
225
|
+
attempt: number;
|
|
226
|
+
}
|
|
227
|
+
export interface ActionRollbackContext {
|
|
228
|
+
idempotencyKey: string;
|
|
229
|
+
reason: string;
|
|
230
|
+
rollbackToken?: string;
|
|
231
|
+
}
|
|
232
|
+
export interface ActionRollbackResult {
|
|
233
|
+
success: boolean;
|
|
234
|
+
observedState: Record<string, unknown>;
|
|
235
|
+
message?: string;
|
|
236
|
+
}
|
|
237
|
+
export interface LocalActionAdapter {
|
|
238
|
+
name: string;
|
|
239
|
+
safety?: LocalActionAdapterSafety;
|
|
240
|
+
execute(action: ActionIntent, context?: ActionExecutionContext): LocalActionAdapterResult | Promise<LocalActionAdapterResult>;
|
|
241
|
+
rollback?(action: ActionIntent, execution: ActionExecutionSummary, context: ActionRollbackContext): ActionRollbackResult | Promise<ActionRollbackResult>;
|
|
242
|
+
}
|
|
243
|
+
export interface ActionExecutionReceipt {
|
|
244
|
+
idempotencyKey: string;
|
|
245
|
+
actionIntentId: string;
|
|
246
|
+
adapterName: string;
|
|
247
|
+
status: "COMPLETED" | "ROLLED_BACK" | "ROLLBACK_FAILED";
|
|
248
|
+
execution: ActionExecutionSummary;
|
|
249
|
+
rollbackToken?: string;
|
|
250
|
+
executedAt: string;
|
|
251
|
+
rollback?: ActionRollbackResult & {
|
|
252
|
+
attemptedAt: string;
|
|
253
|
+
reason: string;
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
export interface ExecutionStore {
|
|
257
|
+
name: string;
|
|
258
|
+
get(idempotencyKey: string): ActionExecutionReceipt | undefined | Promise<ActionExecutionReceipt | undefined>;
|
|
259
|
+
put(receipt: ActionExecutionReceipt): void | Promise<void>;
|
|
260
|
+
}
|
|
261
|
+
export interface ActionAuditPacket {
|
|
262
|
+
demo: true;
|
|
263
|
+
product: "AgentCert Onegent Runtime";
|
|
264
|
+
scenario: string;
|
|
265
|
+
actionIntent: ActionIntent;
|
|
266
|
+
riskAssessment: RiskAssessment;
|
|
267
|
+
authorizationDecision?: AuthorizationDecision;
|
|
268
|
+
triggeredPolicies: PolicyRule[];
|
|
269
|
+
approvalRequest?: ApprovalRequest;
|
|
270
|
+
execution: ActionExecutionSummary;
|
|
271
|
+
verificationResult?: VerificationResult;
|
|
272
|
+
auditEvents: AuditEvent[];
|
|
273
|
+
disclaimer: string;
|
|
274
|
+
}
|
|
275
|
+
export interface AuditStore {
|
|
276
|
+
name: string;
|
|
277
|
+
writeAuditPacket(packet: ActionAuditPacket): void | Promise<void>;
|
|
278
|
+
}
|
|
279
|
+
export interface ProcurementWalkthroughState {
|
|
280
|
+
purchaseOrder: MockPurchaseOrder;
|
|
281
|
+
review: ActionReview;
|
|
282
|
+
auditPacket?: ActionAuditPacket;
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../onegent-runtime/src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export type VendorSandboxHttpMethod = "GET";
|
|
2
|
+
export interface VendorSandboxResourceRule {
|
|
3
|
+
id: string;
|
|
4
|
+
method: VendorSandboxHttpMethod;
|
|
5
|
+
pathPattern: RegExp;
|
|
6
|
+
}
|
|
7
|
+
export interface VendorSandboxEgressPolicy {
|
|
8
|
+
vendor: string;
|
|
9
|
+
allowedOrigin: string;
|
|
10
|
+
resources: readonly VendorSandboxResourceRule[];
|
|
11
|
+
timeoutMs: number;
|
|
12
|
+
maxRequestsPerMinute: number;
|
|
13
|
+
}
|
|
14
|
+
export type VendorSandboxAuditOutcome = "allowed" | "denied" | "rate_limited" | "timeout" | "http_error" | "failed";
|
|
15
|
+
export interface VendorSandboxRequestAudit {
|
|
16
|
+
requestId: string;
|
|
17
|
+
timestamp: string;
|
|
18
|
+
vendor: string;
|
|
19
|
+
resource: string;
|
|
20
|
+
method: VendorSandboxHttpMethod;
|
|
21
|
+
origin: string;
|
|
22
|
+
outcome: VendorSandboxAuditOutcome;
|
|
23
|
+
durationMs: number;
|
|
24
|
+
status?: number;
|
|
25
|
+
errorCode?: VendorSandboxEgressErrorCode;
|
|
26
|
+
}
|
|
27
|
+
export type VendorSandboxEgressErrorCode = "ORIGIN_DENIED" | "METHOD_DENIED" | "RESOURCE_DENIED" | "RATE_LIMITED" | "TIMEOUT" | "HTTP_ERROR" | "REQUEST_FAILED";
|
|
28
|
+
export declare class VendorSandboxEgressError extends Error {
|
|
29
|
+
readonly code: VendorSandboxEgressErrorCode;
|
|
30
|
+
readonly status?: number | undefined;
|
|
31
|
+
constructor(code: VendorSandboxEgressErrorCode, message: string, status?: number | undefined);
|
|
32
|
+
}
|
|
33
|
+
export interface VendorSandboxEgressRequest {
|
|
34
|
+
resource: string;
|
|
35
|
+
method: VendorSandboxHttpMethod;
|
|
36
|
+
path: string;
|
|
37
|
+
headers?: HeadersInit;
|
|
38
|
+
}
|
|
39
|
+
export interface BoundedVendorSandboxEgress {
|
|
40
|
+
requestJson(request: VendorSandboxEgressRequest): Promise<unknown>;
|
|
41
|
+
getAuditLog(): VendorSandboxRequestAudit[];
|
|
42
|
+
}
|
|
43
|
+
export interface BoundedVendorSandboxEgressOptions {
|
|
44
|
+
policy: VendorSandboxEgressPolicy;
|
|
45
|
+
fetch?: typeof fetch;
|
|
46
|
+
now?: () => number;
|
|
47
|
+
}
|
|
48
|
+
export declare function createBoundedVendorSandboxEgress(options: BoundedVendorSandboxEgressOptions): BoundedVendorSandboxEgress;
|
|
49
|
+
//# sourceMappingURL=vendor-sandbox-egress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vendor-sandbox-egress.d.ts","sourceRoot":"","sources":["../../../../onegent-runtime/src/vendor-sandbox-egress.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,uBAAuB,GAAG,KAAK,CAAC;AAE5C,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,uBAAuB,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,MAAM,yBAAyB,GACjC,SAAS,GACT,QAAQ,GACR,cAAc,GACd,SAAS,GACT,YAAY,GACZ,QAAQ,CAAC;AAEb,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,uBAAuB,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,yBAAyB,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,4BAA4B,CAAC;CAC1C;AAED,MAAM,MAAM,4BAA4B,GACpC,eAAe,GACf,eAAe,GACf,iBAAiB,GACjB,cAAc,GACd,SAAS,GACT,YAAY,GACZ,gBAAgB,CAAC;AAErB,qBAAa,wBAAyB,SAAQ,KAAK;aAE/B,IAAI,EAAE,4BAA4B;aAElC,MAAM,CAAC,EAAE,MAAM;gBAFf,IAAI,EAAE,4BAA4B,EAClD,OAAO,EAAE,MAAM,EACC,MAAM,CAAC,EAAE,MAAM,YAAA;CAKlC;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,uBAAuB,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B;IACzC,WAAW,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnE,WAAW,IAAI,yBAAyB,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,iCAAiC;IAChD,MAAM,EAAE,yBAAyB,CAAC;IAClC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAID,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,iCAAiC,GACzC,0BAA0B,CA+G5B"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
export class VendorSandboxEgressError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
status;
|
|
4
|
+
constructor(code, message, status) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.name = "VendorSandboxEgressError";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const MAX_AUDIT_ENTRIES = 100;
|
|
12
|
+
export function createBoundedVendorSandboxEgress(options) {
|
|
13
|
+
const policy = validatePolicy(options.policy);
|
|
14
|
+
const requestFetch = options.fetch ?? fetch;
|
|
15
|
+
const now = options.now ?? Date.now;
|
|
16
|
+
const audit = [];
|
|
17
|
+
let requestSequence = 0;
|
|
18
|
+
let windowStartedAt = now();
|
|
19
|
+
let requestsInWindow = 0;
|
|
20
|
+
const record = (entry) => {
|
|
21
|
+
audit.push(Object.freeze({ ...entry }));
|
|
22
|
+
if (audit.length > MAX_AUDIT_ENTRIES)
|
|
23
|
+
audit.splice(0, audit.length - MAX_AUDIT_ENTRIES);
|
|
24
|
+
};
|
|
25
|
+
return Object.freeze({
|
|
26
|
+
requestJson: async (request) => {
|
|
27
|
+
const startedAt = now();
|
|
28
|
+
const requestId = `${policy.vendor}-${++requestSequence}`;
|
|
29
|
+
const method = request.method;
|
|
30
|
+
const url = safeUrl(request.path, policy.allowedOrigin);
|
|
31
|
+
const baseAudit = {
|
|
32
|
+
requestId,
|
|
33
|
+
timestamp: new Date(startedAt).toISOString(),
|
|
34
|
+
vendor: policy.vendor,
|
|
35
|
+
resource: request.resource,
|
|
36
|
+
method,
|
|
37
|
+
origin: url?.origin ?? policy.allowedOrigin,
|
|
38
|
+
};
|
|
39
|
+
const deny = (error) => {
|
|
40
|
+
record({ ...baseAudit, outcome: "denied", durationMs: elapsed(now, startedAt), errorCode: error.code });
|
|
41
|
+
throw error;
|
|
42
|
+
};
|
|
43
|
+
if (!url || url.origin !== policy.allowedOrigin || url.protocol !== "https:" || url.username || url.password || url.hash) {
|
|
44
|
+
return deny(new VendorSandboxEgressError("ORIGIN_DENIED", "Vendor sandbox request origin is not allowlisted."));
|
|
45
|
+
}
|
|
46
|
+
const resource = policy.resources.find((entry) => entry.id === request.resource);
|
|
47
|
+
if (!resource) {
|
|
48
|
+
return deny(new VendorSandboxEgressError("RESOURCE_DENIED", "Vendor sandbox resource is not allowlisted."));
|
|
49
|
+
}
|
|
50
|
+
if (method !== resource.method) {
|
|
51
|
+
return deny(new VendorSandboxEgressError("METHOD_DENIED", "Vendor sandbox HTTP method is not allowlisted for this resource."));
|
|
52
|
+
}
|
|
53
|
+
resource.pathPattern.lastIndex = 0;
|
|
54
|
+
if (!resource.pathPattern.test(`${url.pathname}${url.search}`)) {
|
|
55
|
+
return deny(new VendorSandboxEgressError("RESOURCE_DENIED", "Vendor sandbox path is not allowlisted for this resource."));
|
|
56
|
+
}
|
|
57
|
+
const current = now();
|
|
58
|
+
if (current - windowStartedAt >= 60_000) {
|
|
59
|
+
windowStartedAt = current;
|
|
60
|
+
requestsInWindow = 0;
|
|
61
|
+
}
|
|
62
|
+
if (requestsInWindow >= policy.maxRequestsPerMinute) {
|
|
63
|
+
const error = new VendorSandboxEgressError("RATE_LIMITED", "Vendor sandbox request limit exceeded. Retry after the current one-minute window.");
|
|
64
|
+
record({ ...baseAudit, outcome: "rate_limited", durationMs: elapsed(now, startedAt), errorCode: error.code });
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
requestsInWindow += 1;
|
|
68
|
+
const controller = new AbortController();
|
|
69
|
+
let timedOut = false;
|
|
70
|
+
let timeout;
|
|
71
|
+
const operation = (async () => {
|
|
72
|
+
const response = await requestFetch(url, {
|
|
73
|
+
method,
|
|
74
|
+
headers: request.headers,
|
|
75
|
+
redirect: "error",
|
|
76
|
+
signal: controller.signal,
|
|
77
|
+
});
|
|
78
|
+
if (!response.ok) {
|
|
79
|
+
throw new VendorSandboxEgressError("HTTP_ERROR", `Vendor sandbox returned HTTP ${response.status}.`, response.status);
|
|
80
|
+
}
|
|
81
|
+
return { payload: await response.json(), status: response.status };
|
|
82
|
+
})();
|
|
83
|
+
const timeoutOperation = new Promise((_, reject) => {
|
|
84
|
+
timeout = setTimeout(() => {
|
|
85
|
+
timedOut = true;
|
|
86
|
+
controller.abort();
|
|
87
|
+
reject(new VendorSandboxEgressError("TIMEOUT", `Vendor sandbox request exceeded ${policy.timeoutMs} ms.`));
|
|
88
|
+
}, policy.timeoutMs);
|
|
89
|
+
});
|
|
90
|
+
try {
|
|
91
|
+
const result = await Promise.race([operation, timeoutOperation]);
|
|
92
|
+
record({ ...baseAudit, outcome: "allowed", durationMs: elapsed(now, startedAt), status: result.status });
|
|
93
|
+
return result.payload;
|
|
94
|
+
}
|
|
95
|
+
catch (cause) {
|
|
96
|
+
const error = cause instanceof VendorSandboxEgressError
|
|
97
|
+
? cause
|
|
98
|
+
: timedOut
|
|
99
|
+
? new VendorSandboxEgressError("TIMEOUT", `Vendor sandbox request exceeded ${policy.timeoutMs} ms.`)
|
|
100
|
+
: new VendorSandboxEgressError("REQUEST_FAILED", "Vendor sandbox request failed.");
|
|
101
|
+
record({
|
|
102
|
+
...baseAudit,
|
|
103
|
+
outcome: error.code === "TIMEOUT" ? "timeout" : error.code === "HTTP_ERROR" ? "http_error" : "failed",
|
|
104
|
+
durationMs: elapsed(now, startedAt),
|
|
105
|
+
status: error.status,
|
|
106
|
+
errorCode: error.code,
|
|
107
|
+
});
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
if (timeout)
|
|
112
|
+
clearTimeout(timeout);
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
getAuditLog: () => audit.map((entry) => ({ ...entry })),
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function validatePolicy(policy) {
|
|
119
|
+
const origin = new URL(policy.allowedOrigin);
|
|
120
|
+
if (origin.protocol !== "https:" || origin.origin !== policy.allowedOrigin || origin.pathname !== "/" || origin.search || origin.hash) {
|
|
121
|
+
throw new Error("Vendor sandbox allowedOrigin must be an exact HTTPS origin without a path.");
|
|
122
|
+
}
|
|
123
|
+
if (!policy.vendor.trim())
|
|
124
|
+
throw new Error("Vendor sandbox policy vendor is required.");
|
|
125
|
+
if (!Number.isSafeInteger(policy.timeoutMs) || policy.timeoutMs < 100 || policy.timeoutMs > 30_000) {
|
|
126
|
+
throw new Error("Vendor sandbox timeoutMs must be an integer from 100 to 30000.");
|
|
127
|
+
}
|
|
128
|
+
if (!Number.isSafeInteger(policy.maxRequestsPerMinute) || policy.maxRequestsPerMinute < 1 || policy.maxRequestsPerMinute > 60) {
|
|
129
|
+
throw new Error("Vendor sandbox maxRequestsPerMinute must be an integer from 1 to 60.");
|
|
130
|
+
}
|
|
131
|
+
if (policy.resources.length === 0 || new Set(policy.resources.map((entry) => entry.id)).size !== policy.resources.length) {
|
|
132
|
+
throw new Error("Vendor sandbox policy requires unique resource rules.");
|
|
133
|
+
}
|
|
134
|
+
return Object.freeze({
|
|
135
|
+
...policy,
|
|
136
|
+
resources: Object.freeze(policy.resources.map((entry) => Object.freeze({
|
|
137
|
+
...entry,
|
|
138
|
+
pathPattern: new RegExp(entry.pathPattern.source, entry.pathPattern.flags),
|
|
139
|
+
}))),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function safeUrl(path, origin) {
|
|
143
|
+
try {
|
|
144
|
+
return new URL(path, `${origin}/`);
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function elapsed(now, startedAt) {
|
|
151
|
+
return Math.max(0, Math.round(now() - startedAt));
|
|
152
|
+
}
|