@svsprotocol/solana 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +158 -0
- package/README.md +365 -0
- package/dist/action-production-proof-evidence.js +553 -0
- package/dist/adapter-catalog.d.ts +29 -0
- package/dist/adapter-catalog.js +146 -0
- package/dist/adapter-core.d.ts +48 -0
- package/dist/adapter-core.js +249 -0
- package/dist/approval-signature.js +197 -0
- package/dist/base58.js +69 -0
- package/dist/bot-auth.js +50 -0
- package/dist/bot-certification-evidence.js +342 -0
- package/dist/bot-first-action-runbook.js +299 -0
- package/dist/bot-integration-contract.js +41 -0
- package/dist/certified-submit-status.js +176 -0
- package/dist/common.d.ts +1135 -0
- package/dist/elizaos.d.ts +43 -0
- package/dist/elizaos.js +227 -0
- package/dist/goat.d.ts +47 -0
- package/dist/goat.js +261 -0
- package/dist/index.d.ts +330 -0
- package/dist/index.js +128 -0
- package/dist/protocol.d.ts +205 -0
- package/dist/protocol.js +900 -0
- package/dist/receipt.js +51 -0
- package/dist/signed-proof-read-protection.js +495 -0
- package/dist/solana-agent-kit.d.ts +35 -0
- package/dist/solana-agent-kit.js +151 -0
- package/dist/svs-client.js +1232 -0
- package/dist/vercel-ai.d.ts +47 -0
- package/dist/vercel-ai.js +266 -0
- package/dist/verified-agent-adoption-kit.js +471 -0
- package/dist/verified-agent-profile.js +329 -0
- package/dist/verified-agent-registry-consumer.js +421 -0
- package/dist/verified-agent-registry.d.ts +36 -0
- package/dist/verified-agent-registry.js +826 -0
- package/dist/verified-agent-trust-score.js +335 -0
- package/dist/webhooks.js +834 -0
- package/package.json +72 -0
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { hashObject } from "./receipt.js";
|
|
4
|
+
import {
|
|
5
|
+
verifyBotCertificationEvidence
|
|
6
|
+
} from "./bot-certification-evidence.js";
|
|
7
|
+
|
|
8
|
+
export const VERIFIED_AGENT_PROFILE_VERSION = "svs.verified-agent-profile.v1";
|
|
9
|
+
export const VERIFIED_AGENT_PROFILE_VERIFICATION_VERSION = "svs.verified-agent-profile-verification.v1";
|
|
10
|
+
export const VERIFIED_AGENT_BADGE_VERSION = "svs.verified-agent-badge.v1";
|
|
11
|
+
export const DEFAULT_VERIFIED_AGENT_PROFILE_PATH = "./data/security/verified-agent-profile.json";
|
|
12
|
+
export const DEFAULT_VERIFIED_AGENT_BADGE_PATH = "./data/security/verified-agent-badge.svg";
|
|
13
|
+
|
|
14
|
+
export function createVerifiedAgentProfile({
|
|
15
|
+
certificationEvidence,
|
|
16
|
+
agentName = null,
|
|
17
|
+
agentUrl = null,
|
|
18
|
+
profileUrl = null,
|
|
19
|
+
badgeUrl = null,
|
|
20
|
+
generatedAt = new Date(),
|
|
21
|
+
staleAfterMs = null,
|
|
22
|
+
now = generatedAt
|
|
23
|
+
} = {}) {
|
|
24
|
+
if (!certificationEvidence || typeof certificationEvidence !== "object") {
|
|
25
|
+
throw new Error("certificationEvidence is required.");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const verification = verifyBotCertificationEvidence(certificationEvidence, {
|
|
29
|
+
requireOk: true,
|
|
30
|
+
staleAfterMs,
|
|
31
|
+
now
|
|
32
|
+
});
|
|
33
|
+
const status = verification.ok ? "verified" : verification.stale ? "stale" : "not_verified";
|
|
34
|
+
const botId = verification.botId ??
|
|
35
|
+
certificationEvidence.certificationCheck?.botId ??
|
|
36
|
+
certificationEvidence.certification?.botId ??
|
|
37
|
+
null;
|
|
38
|
+
const unsigned = {
|
|
39
|
+
version: VERIFIED_AGENT_PROFILE_VERSION,
|
|
40
|
+
generatedAt: generatedAt instanceof Date ? generatedAt.toISOString() : new Date(generatedAt).toISOString(),
|
|
41
|
+
agent: {
|
|
42
|
+
botId,
|
|
43
|
+
name: agentName ?? botId,
|
|
44
|
+
url: agentUrl,
|
|
45
|
+
profileUrl,
|
|
46
|
+
badgeUrl
|
|
47
|
+
},
|
|
48
|
+
status: {
|
|
49
|
+
ok: verification.ok === true,
|
|
50
|
+
value: status,
|
|
51
|
+
label: verification.ok ? "SVS Verified" : verification.stale ? "SVS Stale" : "SVS Not Verified",
|
|
52
|
+
nextAction: verification.ok
|
|
53
|
+
? {
|
|
54
|
+
code: "none",
|
|
55
|
+
message: "Agent has current SVS production certification."
|
|
56
|
+
}
|
|
57
|
+
: certificationEvidence.nextAction ?? certificationEvidence.certificationCheck?.nextAction ?? null
|
|
58
|
+
},
|
|
59
|
+
certification: {
|
|
60
|
+
evidenceHash: verification.evidenceHash,
|
|
61
|
+
computedEvidenceHash: verification.computedEvidenceHash,
|
|
62
|
+
certificationHash: verification.certificationHash,
|
|
63
|
+
recordId: verification.recordId,
|
|
64
|
+
generatedAt: verification.generatedAt,
|
|
65
|
+
stale: verification.stale,
|
|
66
|
+
ageMs: verification.ageMs,
|
|
67
|
+
staleAfterMs: verification.staleAfterMs
|
|
68
|
+
},
|
|
69
|
+
qualityTarget: verification.qualityTarget
|
|
70
|
+
? {
|
|
71
|
+
ready: verification.qualityTarget.ready === true,
|
|
72
|
+
score: Number.isInteger(verification.qualityTarget.score) ? verification.qualityTarget.score : null,
|
|
73
|
+
targetScore: Number.isInteger(verification.qualityTarget.targetScore) ? verification.qualityTarget.targetScore : null,
|
|
74
|
+
status: verification.qualityTarget.status ?? null
|
|
75
|
+
}
|
|
76
|
+
: null,
|
|
77
|
+
proofs: {
|
|
78
|
+
actionRecordVerificationOk: certificationEvidence.proofs?.actionRecordVerificationOk === true,
|
|
79
|
+
receiptRegistrySubmissionVerificationOk: certificationEvidence.proofs?.receiptRegistrySubmissionVerificationOk === true,
|
|
80
|
+
portableSetVerified: certificationEvidence.proofs?.portableSetVerified === true,
|
|
81
|
+
integrationContractCurrent: certificationEvidence.proofs?.integrationContractCurrent === true,
|
|
82
|
+
verificationSetHash: certificationEvidence.proofs?.verificationSetHash ?? null,
|
|
83
|
+
botIntegrationReportHash: certificationEvidence.proofs?.botIntegrationReportHash ?? null,
|
|
84
|
+
integrationContractHash: certificationEvidence.proofs?.integrationContractHash ?? null,
|
|
85
|
+
currentIntegrationContractHash: certificationEvidence.proofs?.currentIntegrationContractHash ?? null
|
|
86
|
+
},
|
|
87
|
+
display: {
|
|
88
|
+
badgeText: verification.ok ? "SVS Verified" : verification.stale ? "SVS Stale" : "SVS Not Verified",
|
|
89
|
+
badgeColor: verification.ok ? "#14f195" : verification.stale ? "#f59e0b" : "#ef4444",
|
|
90
|
+
badgeTextColor: "#08111f"
|
|
91
|
+
},
|
|
92
|
+
reportSafety: {
|
|
93
|
+
secretsIncluded: false,
|
|
94
|
+
sourceEvidenceSecretsIncluded: certificationEvidence.reportSafety?.secretsIncluded === true ||
|
|
95
|
+
certificationEvidence.proofs?.secretsIncluded === true,
|
|
96
|
+
redactedFields: [
|
|
97
|
+
"SVS_BOT_API_KEY",
|
|
98
|
+
"SVS_BOT_REQUEST_SIGNING_SECRET",
|
|
99
|
+
"SVS_BOT_PENDING_REQUEST_SIGNING_SECRET",
|
|
100
|
+
"apiKey",
|
|
101
|
+
"requestSigningSecret",
|
|
102
|
+
"pendingRequestSigningSecret",
|
|
103
|
+
"webhookSecret",
|
|
104
|
+
"svs-request-signature"
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
...unsigned,
|
|
111
|
+
profileHash: hashVerifiedAgentProfile(unsigned)
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export async function persistVerifiedAgentProfile({
|
|
116
|
+
certificationEvidence,
|
|
117
|
+
outputPath = DEFAULT_VERIFIED_AGENT_PROFILE_PATH,
|
|
118
|
+
badgeOutputPath = null,
|
|
119
|
+
...options
|
|
120
|
+
} = {}) {
|
|
121
|
+
const profile = createVerifiedAgentProfile({
|
|
122
|
+
certificationEvidence,
|
|
123
|
+
...options
|
|
124
|
+
});
|
|
125
|
+
const text = `${JSON.stringify(profile, null, 2)}\n`;
|
|
126
|
+
|
|
127
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
128
|
+
await writeFile(outputPath, text);
|
|
129
|
+
|
|
130
|
+
const result = {
|
|
131
|
+
path: outputPath,
|
|
132
|
+
bytes: Buffer.byteLength(text, "utf8"),
|
|
133
|
+
profile
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
if (badgeOutputPath) {
|
|
137
|
+
const badge = createVerifiedAgentBadgeSvg(profile);
|
|
138
|
+
|
|
139
|
+
await mkdir(dirname(badgeOutputPath), { recursive: true });
|
|
140
|
+
await writeFile(badgeOutputPath, badge);
|
|
141
|
+
result.badge = {
|
|
142
|
+
path: badgeOutputPath,
|
|
143
|
+
bytes: Buffer.byteLength(badge, "utf8"),
|
|
144
|
+
badgeHash: hashObject({
|
|
145
|
+
version: VERIFIED_AGENT_BADGE_VERSION,
|
|
146
|
+
profileHash: profile.profileHash,
|
|
147
|
+
svg: badge
|
|
148
|
+
})
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function verifyVerifiedAgentProfile(profile, {
|
|
156
|
+
requireVerified = true,
|
|
157
|
+
expectedBotId = null,
|
|
158
|
+
staleAfterMs = null,
|
|
159
|
+
now = new Date()
|
|
160
|
+
} = {}) {
|
|
161
|
+
const freshness = checkProfileFreshness({
|
|
162
|
+
generatedAt: profile?.generatedAt,
|
|
163
|
+
staleAfterMs,
|
|
164
|
+
now
|
|
165
|
+
});
|
|
166
|
+
const recomputedHash = hashVerifiedAgentProfile(profile);
|
|
167
|
+
const checks = [
|
|
168
|
+
check(
|
|
169
|
+
"Verified agent profile version is supported",
|
|
170
|
+
profile?.version === VERIFIED_AGENT_PROFILE_VERSION,
|
|
171
|
+
profile?.version ?? "missing"
|
|
172
|
+
),
|
|
173
|
+
check(
|
|
174
|
+
"Verified agent profile hash is valid",
|
|
175
|
+
profile?.profileHash === recomputedHash,
|
|
176
|
+
`declared=${profile?.profileHash ?? "missing"} recomputed=${recomputedHash ?? "missing"}`
|
|
177
|
+
),
|
|
178
|
+
check(
|
|
179
|
+
"Verified agent profile excludes secrets",
|
|
180
|
+
profile?.reportSafety?.secretsIncluded === false &&
|
|
181
|
+
profile?.reportSafety?.sourceEvidenceSecretsIncluded !== true,
|
|
182
|
+
`profile=${profile?.reportSafety?.secretsIncluded ?? "missing"} source=${profile?.reportSafety?.sourceEvidenceSecretsIncluded ?? "missing"}`
|
|
183
|
+
),
|
|
184
|
+
check(
|
|
185
|
+
"Verified agent profile has a bot id",
|
|
186
|
+
Boolean(profile?.agent?.botId),
|
|
187
|
+
profile?.agent?.botId ?? "missing"
|
|
188
|
+
),
|
|
189
|
+
check(
|
|
190
|
+
"Verified agent profile matches expected bot id",
|
|
191
|
+
!expectedBotId || profile?.agent?.botId === expectedBotId,
|
|
192
|
+
`expected=${expectedBotId ?? "none"} actual=${profile?.agent?.botId ?? "missing"}`
|
|
193
|
+
),
|
|
194
|
+
check(
|
|
195
|
+
"Verified agent profile is verified",
|
|
196
|
+
!requireVerified || profile?.status?.ok === true && profile?.status?.value === "verified",
|
|
197
|
+
`status=${profile?.status?.value ?? "missing"}`
|
|
198
|
+
),
|
|
199
|
+
check(
|
|
200
|
+
"Verified agent profile includes custom registry proof",
|
|
201
|
+
!requireVerified || profile?.proofs?.receiptRegistrySubmissionVerificationOk === true,
|
|
202
|
+
`ok=${profile?.proofs?.receiptRegistrySubmissionVerificationOk ?? "missing"}`
|
|
203
|
+
),
|
|
204
|
+
check(
|
|
205
|
+
"Verified agent profile includes action record proof",
|
|
206
|
+
!requireVerified || profile?.proofs?.actionRecordVerificationOk === true,
|
|
207
|
+
`ok=${profile?.proofs?.actionRecordVerificationOk ?? "missing"}`
|
|
208
|
+
),
|
|
209
|
+
check(
|
|
210
|
+
"Verified agent profile includes portable set proof",
|
|
211
|
+
!requireVerified || profile?.proofs?.portableSetVerified === true,
|
|
212
|
+
`ok=${profile?.proofs?.portableSetVerified ?? "missing"}`
|
|
213
|
+
)
|
|
214
|
+
];
|
|
215
|
+
|
|
216
|
+
if (staleAfterMs !== null && staleAfterMs !== undefined) {
|
|
217
|
+
checks.push(check(
|
|
218
|
+
"Verified agent profile is fresh",
|
|
219
|
+
!freshness.stale,
|
|
220
|
+
freshness.ageMs === null
|
|
221
|
+
? `generatedAt=${profile?.generatedAt ?? "missing"}`
|
|
222
|
+
: `ageMs=${freshness.ageMs} staleAfterMs=${staleAfterMs}`
|
|
223
|
+
));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const failedChecks = checks.filter((item) => !item.ok);
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
version: VERIFIED_AGENT_PROFILE_VERIFICATION_VERSION,
|
|
230
|
+
ok: failedChecks.length === 0,
|
|
231
|
+
status: failedChecks.length === 0 ? "verified" : freshness.stale ? "stale" : "failed",
|
|
232
|
+
checkedAt: now instanceof Date ? now.toISOString() : new Date(now).toISOString(),
|
|
233
|
+
found: Boolean(profile),
|
|
234
|
+
profileHash: profile?.profileHash ?? null,
|
|
235
|
+
computedProfileHash: recomputedHash,
|
|
236
|
+
botId: profile?.agent?.botId ?? null,
|
|
237
|
+
badgeText: profile?.display?.badgeText ?? null,
|
|
238
|
+
stale: freshness.stale,
|
|
239
|
+
ageMs: freshness.ageMs,
|
|
240
|
+
staleAfterMs,
|
|
241
|
+
failedCheckCount: failedChecks.length,
|
|
242
|
+
failedChecks,
|
|
243
|
+
checks
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function createVerifiedAgentBadgeSvg(profile, {
|
|
248
|
+
width = 188,
|
|
249
|
+
height = 28
|
|
250
|
+
} = {}) {
|
|
251
|
+
const label = profile?.display?.badgeText ?? "SVS Not Verified";
|
|
252
|
+
const botId = profile?.agent?.botId ?? "agent";
|
|
253
|
+
const color = profile?.display?.badgeColor ?? "#ef4444";
|
|
254
|
+
const textColor = profile?.display?.badgeTextColor ?? "#08111f";
|
|
255
|
+
const leftWidth = 56;
|
|
256
|
+
const rightWidth = width - leftWidth;
|
|
257
|
+
|
|
258
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" role="img" aria-label="${escapeXml(label)}">
|
|
259
|
+
<title>${escapeXml(label)}: ${escapeXml(botId)}</title>
|
|
260
|
+
<linearGradient id="svs-gradient" x1="0%" x2="100%" y1="0%" y2="0%">
|
|
261
|
+
<stop offset="0%" stop-color="#9945ff"/>
|
|
262
|
+
<stop offset="52%" stop-color="#14f195"/>
|
|
263
|
+
<stop offset="100%" stop-color="#00c2ff"/>
|
|
264
|
+
</linearGradient>
|
|
265
|
+
<rect width="${width}" height="${height}" rx="6" fill="#08111f"/>
|
|
266
|
+
<rect width="${leftWidth}" height="${height}" rx="6" fill="url(#svs-gradient)"/>
|
|
267
|
+
<rect x="${leftWidth - 6}" width="6" height="${height}" fill="url(#svs-gradient)"/>
|
|
268
|
+
<rect x="${leftWidth}" width="${rightWidth}" height="${height}" fill="${escapeXml(color)}"/>
|
|
269
|
+
<text x="28" y="18" text-anchor="middle" font-family="Inter, ui-sans-serif, system-ui, sans-serif" font-size="11" font-weight="800" fill="#08111f">SVS</text>
|
|
270
|
+
<text x="${leftWidth + Math.floor(rightWidth / 2)}" y="18" text-anchor="middle" font-family="Inter, ui-sans-serif, system-ui, sans-serif" font-size="11" font-weight="800" fill="${escapeXml(textColor)}">${escapeXml(label.replace(/^SVS\\s+/, ""))}</text>
|
|
271
|
+
</svg>
|
|
272
|
+
`;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function hashVerifiedAgentProfile(profile) {
|
|
276
|
+
if (!profile || typeof profile !== "object") {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const { profileHash: _profileHash, ...unsigned } = profile;
|
|
281
|
+
|
|
282
|
+
return hashObject(unsigned);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function checkProfileFreshness({
|
|
286
|
+
generatedAt,
|
|
287
|
+
staleAfterMs,
|
|
288
|
+
now = new Date()
|
|
289
|
+
} = {}) {
|
|
290
|
+
if (staleAfterMs === null || staleAfterMs === undefined) {
|
|
291
|
+
return {
|
|
292
|
+
stale: false,
|
|
293
|
+
ageMs: null
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const generatedTime = Date.parse(generatedAt);
|
|
298
|
+
const nowTime = now instanceof Date ? now.getTime() : Date.parse(now);
|
|
299
|
+
|
|
300
|
+
if (!Number.isFinite(generatedTime) || !Number.isFinite(nowTime)) {
|
|
301
|
+
return {
|
|
302
|
+
stale: true,
|
|
303
|
+
ageMs: null
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const ageMs = Math.max(0, nowTime - generatedTime);
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
stale: ageMs > staleAfterMs,
|
|
311
|
+
ageMs
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
function check(name, ok, detail) {
|
|
316
|
+
return {
|
|
317
|
+
name,
|
|
318
|
+
ok: Boolean(ok),
|
|
319
|
+
detail
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function escapeXml(value) {
|
|
324
|
+
return String(value ?? "")
|
|
325
|
+
.replaceAll("&", "&")
|
|
326
|
+
.replaceAll("<", "<")
|
|
327
|
+
.replaceAll(">", ">")
|
|
328
|
+
.replaceAll("\"", """);
|
|
329
|
+
}
|