@aporthq/aport-agent-guardrails 1.0.8
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 +217 -0
- package/README.md +481 -0
- package/bin/agent-guardrails +133 -0
- package/bin/aport-create-passport.sh +444 -0
- package/bin/aport-cursor-hook.sh +90 -0
- package/bin/aport-guardrail-api.sh +108 -0
- package/bin/aport-guardrail-bash.sh +394 -0
- package/bin/aport-guardrail-v2.sh +5 -0
- package/bin/aport-guardrail.sh +5 -0
- package/bin/aport-resolve-paths.sh +71 -0
- package/bin/aport-status.sh +276 -0
- package/bin/frameworks/crewai.sh +49 -0
- package/bin/frameworks/cursor.sh +95 -0
- package/bin/frameworks/langchain.sh +48 -0
- package/bin/frameworks/n8n.sh +36 -0
- package/bin/frameworks/openclaw.sh +19 -0
- package/bin/lib/allowlist.sh +18 -0
- package/bin/lib/common.sh +28 -0
- package/bin/lib/config.sh +46 -0
- package/bin/lib/constants.sh +232 -0
- package/bin/lib/detect.sh +65 -0
- package/bin/lib/error.sh +269 -0
- package/bin/lib/passport.sh +19 -0
- package/bin/lib/templates/.gitkeep +1 -0
- package/bin/lib/templates/config.yaml +6 -0
- package/bin/lib/validation.sh +206 -0
- package/bin/openclaw +660 -0
- package/docs/ADDING_A_FRAMEWORK.md +87 -0
- package/docs/AGENTS.md.example +40 -0
- package/docs/CODE_REVIEW.md +192 -0
- package/docs/DEPLOYMENT_READINESS.md +81 -0
- package/docs/FAQ_SECURITY_SCANNERS.md +373 -0
- package/docs/FRAMEWORK_ROADMAP.md +41 -0
- package/docs/HOSTED_PASSPORT_SETUP.md +362 -0
- package/docs/IMPLEMENTING_YOUR_OWN_EVALUATOR.md +433 -0
- package/docs/OPENCLAW_COMPATIBILITY.md +73 -0
- package/docs/OPENCLAW_LOCAL_INTEGRATION.md +596 -0
- package/docs/OPENCLAW_TOOLS_AND_POLICIES.md +54 -0
- package/docs/QUICKSTART.md +470 -0
- package/docs/QUICKSTART_OPENCLAW_PLUGIN.md +470 -0
- package/docs/README.md +28 -0
- package/docs/RELEASE.md +87 -0
- package/docs/REPO_LAYOUT.md +47 -0
- package/docs/SKILLS_ECOSYSTEM_ANALYSIS_FEB17.md +1260 -0
- package/docs/TOOL_POLICY_MAPPING.md +46 -0
- package/docs/UPGRADE.md +46 -0
- package/docs/VERIFICATION_METHODS.md +97 -0
- package/docs/assets/README.md +8 -0
- package/docs/assets/porter.svg +54 -0
- package/docs/development/ERROR_CODES.md +616 -0
- package/docs/frameworks/GITHUB_ISSUE_PROPOSALS.md +1105 -0
- package/docs/frameworks/crewai.md +114 -0
- package/docs/frameworks/cursor.md +159 -0
- package/docs/frameworks/langchain.md +72 -0
- package/docs/frameworks/n8n.md +40 -0
- package/docs/frameworks/openclaw.md +40 -0
- package/docs/launch/ADD_APORT_AWESOME_LISTS_INSTRUCTIONS.md +146 -0
- package/docs/launch/ANNOUNCEMENT_GUIDE.md +266 -0
- package/docs/launch/AWESOME_REPOS.md +53 -0
- package/docs/launch/CURSOR_VSCODE_HOOKS_RESEARCH.md +77 -0
- package/docs/launch/DEMO_TERMINAL_OUTPUT.txt +48 -0
- package/docs/launch/DRY_AND_PLAN_CHECKLIST.md +47 -0
- package/docs/launch/EVIDENCE_README.md +61 -0
- package/docs/launch/EVIDENCE_TERMINAL_CAPTURE.txt +10 -0
- package/docs/launch/FRAMEWORK_SUPPORT_PLAN.md +1640 -0
- package/docs/launch/LAUNCH_READINESS_CHECKLIST.md +237 -0
- package/docs/launch/LAUNCH_STRATEGY_SUMMARY.md +464 -0
- package/docs/launch/OPENCLAW_FEEDBACK_AND_FIXES.md +85 -0
- package/docs/launch/POST_1_VALENTINE_IMPROVED.md +233 -0
- package/docs/launch/POST_2_GUARDRAIL_IMPROVED.md +369 -0
- package/docs/launch/PRE_LAUNCH_FIXES.md +766 -0
- package/docs/launch/QUICK_LAUNCH_CHECKLIST.md +400 -0
- package/docs/launch/READINESS_SUMMARY.md +262 -0
- package/docs/launch/README.md +68 -0
- package/docs/launch/USER_STORIES.md +327 -0
- package/docs/launch/scripts/add-aport-awesome-pr.sh +69 -0
- package/docs/operations/MONITORING.md +588 -0
- package/docs/reviews/2026-02-18-staff-review.md +268 -0
- package/extensions/openclaw-aport/README.md +415 -0
- package/extensions/openclaw-aport/index.js +625 -0
- package/extensions/openclaw-aport/openclaw-aport.js +7 -0
- package/extensions/openclaw-aport/openclaw.plugin.json +46 -0
- package/extensions/openclaw-aport/package.json +36 -0
- package/extensions/openclaw-aport/test.js +307 -0
- package/external/aport-policies/README.md +363 -0
- package/external/aport-policies/agent.session.create.v1/README.md +345 -0
- package/external/aport-policies/agent.session.create.v1/policy.json +162 -0
- package/external/aport-policies/agent.tool.register.v1/README.md +361 -0
- package/external/aport-policies/agent.tool.register.v1/policy.json +172 -0
- package/external/aport-policies/code.release.publish.v1/README.md +51 -0
- package/external/aport-policies/code.release.publish.v1/policy.json +121 -0
- package/external/aport-policies/code.repository.merge.v1/README.md +287 -0
- package/external/aport-policies/code.repository.merge.v1/express.example.js +332 -0
- package/external/aport-policies/code.repository.merge.v1/fastapi.example.py +370 -0
- package/external/aport-policies/code.repository.merge.v1/policy.json +162 -0
- package/external/aport-policies/data.export.create.v1/README.md +226 -0
- package/external/aport-policies/data.export.create.v1/express.example.js +172 -0
- package/external/aport-policies/data.export.create.v1/fastapi.example.py +165 -0
- package/external/aport-policies/data.export.create.v1/policy.json +133 -0
- package/external/aport-policies/data.report.ingest.v1/README.md +134 -0
- package/external/aport-policies/data.report.ingest.v1/express.example.js +105 -0
- package/external/aport-policies/data.report.ingest.v1/minimal-example.js +68 -0
- package/external/aport-policies/data.report.ingest.v1/policy.json +174 -0
- package/external/aport-policies/finance.crypto.trade.v1/README.md +146 -0
- package/external/aport-policies/finance.crypto.trade.v1/express.example.js +109 -0
- package/external/aport-policies/finance.crypto.trade.v1/minimal-example.js +65 -0
- package/external/aport-policies/finance.crypto.trade.v1/policy.json +176 -0
- package/external/aport-policies/finance.payment.charge.v1/README.md +326 -0
- package/external/aport-policies/finance.payment.charge.v1/express.example.js +250 -0
- package/external/aport-policies/finance.payment.charge.v1/fastapi.example.py +227 -0
- package/external/aport-policies/finance.payment.charge.v1/minimal-example.js +64 -0
- package/external/aport-policies/finance.payment.charge.v1/policy.json +224 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/contexts.jsonl +12 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/expected.jsonl +12 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/passport.instance.json +42 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/passport.template.json +40 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/payments-charge-policy.test.js +817 -0
- package/external/aport-policies/finance.payment.charge.v1/tests/test_payments_charge_policy.py +486 -0
- package/external/aport-policies/finance.payment.payout.v1/README.md +78 -0
- package/external/aport-policies/finance.payment.payout.v1/policy.json +181 -0
- package/external/aport-policies/finance.payment.refund.v1/README.md +275 -0
- package/external/aport-policies/finance.payment.refund.v1/express.example.js +167 -0
- package/external/aport-policies/finance.payment.refund.v1/fastapi.example.py +136 -0
- package/external/aport-policies/finance.payment.refund.v1/minimal-example.js +183 -0
- package/external/aport-policies/finance.payment.refund.v1/policy.json +216 -0
- package/external/aport-policies/finance.payment.refund.v1/tests/refunds-policy.test.js +924 -0
- package/external/aport-policies/finance.payment.refund.v1/tests/test_refunds_policy.py +778 -0
- package/external/aport-policies/finance.transaction.execute.v1/README.md +309 -0
- package/external/aport-policies/finance.transaction.execute.v1/express.example.js +261 -0
- package/external/aport-policies/finance.transaction.execute.v1/fastapi.example.py +231 -0
- package/external/aport-policies/finance.transaction.execute.v1/minimal-example.js +78 -0
- package/external/aport-policies/finance.transaction.execute.v1/policy.json +189 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/contexts.jsonl +12 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/expected.jsonl +12 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/passport.instance.json +42 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/passport.template.json +42 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/test_transactions_policy.py +214 -0
- package/external/aport-policies/finance.transaction.execute.v1/tests/transactions-policy.test.js +306 -0
- package/external/aport-policies/governance.data.access.v1/README.md +292 -0
- package/external/aport-policies/governance.data.access.v1/express.example.js +321 -0
- package/external/aport-policies/governance.data.access.v1/fastapi.example.py +279 -0
- package/external/aport-policies/governance.data.access.v1/minimal-example.js +65 -0
- package/external/aport-policies/governance.data.access.v1/policy.json +208 -0
- package/external/aport-policies/governance.data.access.v1/tests/contexts.jsonl +12 -0
- package/external/aport-policies/governance.data.access.v1/tests/data-access-policy.test.js +308 -0
- package/external/aport-policies/governance.data.access.v1/tests/expected.jsonl +12 -0
- package/external/aport-policies/governance.data.access.v1/tests/passport.instance.json +56 -0
- package/external/aport-policies/governance.data.access.v1/tests/passport.template.json +56 -0
- package/external/aport-policies/governance.data.access.v1/tests/test_data_access_policy.py +214 -0
- package/external/aport-policies/legal.contract.review.v1/README.md +109 -0
- package/external/aport-policies/legal.contract.review.v1/policy.json +378 -0
- package/external/aport-policies/legal.contract.review.v1/tests/legal-contract-review-policy.test.js +609 -0
- package/external/aport-policies/legal.contract.review.v1/tests/passport.template.json +49 -0
- package/external/aport-policies/mcp.tool.execute.v1/README.md +301 -0
- package/external/aport-policies/mcp.tool.execute.v1/policy.json +141 -0
- package/external/aport-policies/messaging.message.send.v1/README.md +230 -0
- package/external/aport-policies/messaging.message.send.v1/express.example.js +183 -0
- package/external/aport-policies/messaging.message.send.v1/fastapi.example.py +193 -0
- package/external/aport-policies/messaging.message.send.v1/policy.json +144 -0
- package/external/aport-policies/policy-template.json +107 -0
- package/external/aport-policies/system.command.execute.v1/README.md +275 -0
- package/external/aport-policies/system.command.execute.v1/policy.json +146 -0
- package/external/aport-spec/CONTRIBUTING.md +273 -0
- package/external/aport-spec/LICENSE +21 -0
- package/external/aport-spec/README.md +168 -0
- package/external/aport-spec/conformance/README.md +294 -0
- package/external/aport-spec/conformance/cases/data.export.v1/contexts/allow_users.json +6 -0
- package/external/aport-spec/conformance/cases/data.export.v1/contexts/deny_pii.json +6 -0
- package/external/aport-spec/conformance/cases/data.export.v1/expected/allow_users.decision.json +19 -0
- package/external/aport-spec/conformance/cases/data.export.v1/expected/deny_pii.decision.json +19 -0
- package/external/aport-spec/conformance/cases/data.export.v1/passports/template.json +29 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/allow_50usd.json +9 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/deny_150usd.json +9 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/contexts/deny_currency.json +9 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/allow_50usd.decision.json +19 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/deny_150usd.decision.json +19 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/expected/deny_currency.decision.json +19 -0
- package/external/aport-spec/conformance/cases/payments.refunds.v1/passports/template.json +42 -0
- package/external/aport-spec/conformance/package.json +44 -0
- package/external/aport-spec/conformance/pnpm-lock.yaml +642 -0
- package/external/aport-spec/conformance/src/cases.ts +371 -0
- package/external/aport-spec/conformance/src/ed25519.ts +167 -0
- package/external/aport-spec/conformance/src/jcs.ts +85 -0
- package/external/aport-spec/conformance/src/runner.ts +533 -0
- package/external/aport-spec/conformance/src/validators.ts +185 -0
- package/external/aport-spec/conformance/test-runner.js +315 -0
- package/external/aport-spec/conformance/tsconfig.json +21 -0
- package/external/aport-spec/error-schema.json +192 -0
- package/external/aport-spec/index.json +12 -0
- package/external/aport-spec/integrations/clawmoat/README.md +12 -0
- package/external/aport-spec/integrations/shield/README.md +245 -0
- package/external/aport-spec/integrations/shield/adapters/index.js +116 -0
- package/external/aport-spec/integrations/shield/adapters/system-command-execute.js +133 -0
- package/external/aport-spec/integrations/shield/test/README.md +58 -0
- package/external/aport-spec/integrations/shield/test/shield.md +40 -0
- package/external/aport-spec/integrations/shield/test/test-shield-to-verify.js +274 -0
- package/external/aport-spec/metrics-schema.json +504 -0
- package/external/aport-spec/oap/CHANGELOG.md +54 -0
- package/external/aport-spec/oap/VERSION.md +40 -0
- package/external/aport-spec/oap/capability-registry.md +229 -0
- package/external/aport-spec/oap/conformance.md +257 -0
- package/external/aport-spec/oap/decision-schema.json +114 -0
- package/external/aport-spec/oap/examples/context.refund.usd.50.json +9 -0
- package/external/aport-spec/oap/examples/decision.allow.sample.json +20 -0
- package/external/aport-spec/oap/examples/decision.deny.sample.json +23 -0
- package/external/aport-spec/oap/examples/passport.instance.v1.json +50 -0
- package/external/aport-spec/oap/examples/passport.template.v1.json +71 -0
- package/external/aport-spec/oap/oap-spec.md +426 -0
- package/external/aport-spec/oap/passport-schema.json +396 -0
- package/external/aport-spec/oap/security.md +213 -0
- package/external/aport-spec/oap/vc/context-oap-v1.jsonld +137 -0
- package/external/aport-spec/oap/vc/examples/oap-decision-vc.json +37 -0
- package/external/aport-spec/oap/vc/examples/oap-passport-vc.json +68 -0
- package/external/aport-spec/oap/vc/tools/INTEGRATION.md +375 -0
- package/external/aport-spec/oap/vc/tools/README.md +278 -0
- package/external/aport-spec/oap/vc/tools/examples/decision-to-vc.js +66 -0
- package/external/aport-spec/oap/vc/tools/examples/passport-to-vc.js +83 -0
- package/external/aport-spec/oap/vc/tools/examples/vc-to-decision.js +77 -0
- package/external/aport-spec/oap/vc/tools/examples/vc-to-passport.js +94 -0
- package/external/aport-spec/oap/vc/tools/package.json +38 -0
- package/external/aport-spec/oap/vc/tools/pnpm-lock.yaml +472 -0
- package/external/aport-spec/oap/vc/tools/src/cli.ts +226 -0
- package/external/aport-spec/oap/vc/tools/src/crypto-utils.ts +427 -0
- package/external/aport-spec/oap/vc/tools/src/index.ts +653 -0
- package/external/aport-spec/oap/vc/tools/src/test.ts +148 -0
- package/external/aport-spec/oap/vc/tools/src/vp.ts +382 -0
- package/external/aport-spec/oap/vc/tools/test-simple.js +214 -0
- package/external/aport-spec/oap/vc/tools/tsconfig.json +19 -0
- package/external/aport-spec/oap/vc/vc-mapping.md +443 -0
- package/external/aport-spec/passport-schema.json +586 -0
- package/external/aport-spec/rate-limiting.md +136 -0
- package/external/aport-spec/transport-profile.md +325 -0
- package/external/aport-spec/webhook-spec.md +314 -0
- package/package.json +70 -0
- package/skills/aport-agent-guardrail/SKILL.md +314 -0
- package/src/evaluator.js +252 -0
- package/src/server/index.js +72 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Simple test of OAP VC conversion tools
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Mock the conversion functions for demonstration
|
|
8
|
+
function exportPassportToVC(passport, registryKey) {
|
|
9
|
+
return {
|
|
10
|
+
"@context": [
|
|
11
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
12
|
+
"https://raw.githubusercontent.com/aporthq/aport-spec/refs/heads/main/oap/vc/context-oap-v1.jsonld",
|
|
13
|
+
],
|
|
14
|
+
type: ["VerifiableCredential", "OAPPassportCredential"],
|
|
15
|
+
credentialSubject: passport,
|
|
16
|
+
issuer: registryKey.issuer,
|
|
17
|
+
issuanceDate: passport.created_at,
|
|
18
|
+
expirationDate: new Date(
|
|
19
|
+
new Date(passport.created_at).getTime() + 365 * 24 * 60 * 60 * 1000
|
|
20
|
+
).toISOString(),
|
|
21
|
+
proof: {
|
|
22
|
+
type: "Ed25519Signature2020",
|
|
23
|
+
created: passport.created_at,
|
|
24
|
+
verificationMethod: `${registryKey.issuer}/.well-known/oap/keys.json#${registryKey.kid}`,
|
|
25
|
+
proofPurpose: "assertionMethod",
|
|
26
|
+
jws: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function exportDecisionToVC(decision, registryKey) {
|
|
32
|
+
return {
|
|
33
|
+
"@context": [
|
|
34
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
35
|
+
"https://raw.githubusercontent.com/aporthq/aport-spec/refs/heads/main/oap/vc/context-oap-v1.jsonld",
|
|
36
|
+
],
|
|
37
|
+
type: ["VerifiableCredential", "OAPDecisionReceipt"],
|
|
38
|
+
credentialSubject: decision,
|
|
39
|
+
issuer: registryKey.issuer,
|
|
40
|
+
issuanceDate: decision.created_at,
|
|
41
|
+
expirationDate: new Date(
|
|
42
|
+
new Date(decision.created_at).getTime() + decision.expires_in * 1000
|
|
43
|
+
).toISOString(),
|
|
44
|
+
proof: {
|
|
45
|
+
type: "Ed25519Signature2020",
|
|
46
|
+
created: decision.created_at,
|
|
47
|
+
verificationMethod: `${registryKey.issuer}/.well-known/oap/keys.json#${registryKey.kid}`,
|
|
48
|
+
proofPurpose: "assertionMethod",
|
|
49
|
+
jws: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function importVCToPassport(vc) {
|
|
55
|
+
return vc.credentialSubject;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function importVCToDecision(vc) {
|
|
59
|
+
return vc.credentialSubject;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Test data
|
|
63
|
+
const samplePassport = {
|
|
64
|
+
agent_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
65
|
+
kind: "template",
|
|
66
|
+
spec_version: "oap/1.0",
|
|
67
|
+
owner_id: "org_12345678",
|
|
68
|
+
owner_type: "org",
|
|
69
|
+
assurance_level: "L2",
|
|
70
|
+
status: "active",
|
|
71
|
+
capabilities: [
|
|
72
|
+
{
|
|
73
|
+
id: "finance.payment.refund",
|
|
74
|
+
params: { currency_limits: { USD: { max_per_tx: 5000 } } },
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
limits: {
|
|
78
|
+
"finance.payment.refund": {
|
|
79
|
+
currency_limits: { USD: { max_per_tx: 5000, daily_cap: 50000 } },
|
|
80
|
+
reason_codes: ["customer_request"],
|
|
81
|
+
idempotency_required: true,
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
regions: ["US", "CA"],
|
|
85
|
+
metadata: { name: "Customer Support AI" },
|
|
86
|
+
created_at: "2024-01-01T00:00:00Z",
|
|
87
|
+
updated_at: "2024-01-15T10:30:00Z",
|
|
88
|
+
version: "1.0.0",
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const sampleDecision = {
|
|
92
|
+
decision_id: "550e8400-e29b-41d4-a716-446655440002",
|
|
93
|
+
policy_id: "finance.payment.refund.v1",
|
|
94
|
+
agent_id: "550e8400-e29b-41d4-a716-446655440000",
|
|
95
|
+
owner_id: "org_12345678",
|
|
96
|
+
assurance_level: "L2",
|
|
97
|
+
allow: true,
|
|
98
|
+
reasons: [{ code: "oap.allowed", message: "Transaction within limits" }],
|
|
99
|
+
created_at: "2024-01-15T10:30:00Z",
|
|
100
|
+
expires_in: 3600,
|
|
101
|
+
passport_digest:
|
|
102
|
+
"sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef",
|
|
103
|
+
signature: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
104
|
+
kid: "oap:registry:key-2025-01",
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const registryKey = {
|
|
108
|
+
issuer: "https://aport.io",
|
|
109
|
+
kid: "key-2025-01",
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Run tests
|
|
113
|
+
console.log("🧪 Testing OAP VC Conversion Tools\n");
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
// Test 1: Passport → VC
|
|
117
|
+
console.log("1. Converting Passport → VC...");
|
|
118
|
+
const passportVC = exportPassportToVC(samplePassport, registryKey);
|
|
119
|
+
console.log(" ✅ Success");
|
|
120
|
+
console.log(` 📄 Type: ${passportVC.type.join(", ")}`);
|
|
121
|
+
console.log(` 🏢 Issuer: ${passportVC.issuer}`);
|
|
122
|
+
console.log(` 📅 Issuance: ${passportVC.issuanceDate}`);
|
|
123
|
+
console.log(` ⏰ Expiration: ${passportVC.expirationDate}`);
|
|
124
|
+
console.log(" 📄 Sample VC Data:");
|
|
125
|
+
console.log(
|
|
126
|
+
" " +
|
|
127
|
+
JSON.stringify(passportVC, null, 2)
|
|
128
|
+
.split("\n")
|
|
129
|
+
.slice(0, 10)
|
|
130
|
+
.join("\n ") +
|
|
131
|
+
"\n ...\n"
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
// Test 2: Decision → VC
|
|
135
|
+
console.log("2. Converting Decision → VC...");
|
|
136
|
+
const decisionVC = exportDecisionToVC(sampleDecision, registryKey);
|
|
137
|
+
console.log(" ✅ Success");
|
|
138
|
+
console.log(` 📄 Type: ${decisionVC.type.join(", ")}`);
|
|
139
|
+
console.log(` 🏢 Issuer: ${decisionVC.issuer}`);
|
|
140
|
+
console.log(` 📅 Issuance: ${decisionVC.issuanceDate}`);
|
|
141
|
+
console.log(` ⏰ Expiration: ${decisionVC.expirationDate}`);
|
|
142
|
+
console.log(" 📄 Sample VC Data:");
|
|
143
|
+
console.log(
|
|
144
|
+
" " +
|
|
145
|
+
JSON.stringify(decisionVC, null, 2)
|
|
146
|
+
.split("\n")
|
|
147
|
+
.slice(0, 10)
|
|
148
|
+
.join("\n ") +
|
|
149
|
+
"\n ...\n"
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Test 3: VC → Passport
|
|
153
|
+
console.log("3. Converting VC → Passport...");
|
|
154
|
+
const importedPassport = importVCToPassport(passportVC);
|
|
155
|
+
console.log(" ✅ Success");
|
|
156
|
+
console.log(` 🆔 Agent ID: ${importedPassport.agent_id}`);
|
|
157
|
+
console.log(` 📋 Kind: ${importedPassport.kind}`);
|
|
158
|
+
console.log(` 🔐 Assurance: ${importedPassport.assurance_level}`);
|
|
159
|
+
console.log(" 📄 Sample Passport Data:");
|
|
160
|
+
console.log(
|
|
161
|
+
" " +
|
|
162
|
+
JSON.stringify(importedPassport, null, 2)
|
|
163
|
+
.split("\n")
|
|
164
|
+
.slice(0, 8)
|
|
165
|
+
.join("\n ") +
|
|
166
|
+
"\n ...\n"
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
// Test 4: VC → Decision
|
|
170
|
+
console.log("4. Converting VC → Decision...");
|
|
171
|
+
const importedDecision = importVCToDecision(decisionVC);
|
|
172
|
+
console.log(" ✅ Success");
|
|
173
|
+
console.log(` 🆔 Decision ID: ${importedDecision.decision_id}`);
|
|
174
|
+
console.log(` 📋 Policy ID: ${importedDecision.policy_id}`);
|
|
175
|
+
console.log(` ✅ Allow: ${importedDecision.allow}`);
|
|
176
|
+
console.log(" 📄 Sample Decision Data:");
|
|
177
|
+
console.log(
|
|
178
|
+
" " +
|
|
179
|
+
JSON.stringify(importedDecision, null, 2)
|
|
180
|
+
.split("\n")
|
|
181
|
+
.slice(0, 8)
|
|
182
|
+
.join("\n ") +
|
|
183
|
+
"\n ...\n"
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
// Test 5: Round-trip
|
|
187
|
+
console.log("5. Testing round-trip conversion...");
|
|
188
|
+
const roundTripPassport = importVCToPassport(
|
|
189
|
+
exportPassportToVC(samplePassport, registryKey)
|
|
190
|
+
);
|
|
191
|
+
const isEqual =
|
|
192
|
+
JSON.stringify(samplePassport) === JSON.stringify(roundTripPassport);
|
|
193
|
+
console.log(
|
|
194
|
+
` ${isEqual ? "✅" : "❌"} Round-trip ${
|
|
195
|
+
isEqual ? "preserved" : "modified"
|
|
196
|
+
} data\n`
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
console.log(
|
|
200
|
+
"🎉 All tests passed! OAP VC conversion tools are working correctly."
|
|
201
|
+
);
|
|
202
|
+
console.log("\n📚 Next steps:");
|
|
203
|
+
console.log(" • Install dependencies: npm install");
|
|
204
|
+
console.log(" • Build TypeScript: npm run build");
|
|
205
|
+
console.log(
|
|
206
|
+
" • Use CLI: npx oap-vc export --type passport --input passport.json --output passport.vc.json --key registry-key.json"
|
|
207
|
+
);
|
|
208
|
+
console.log(
|
|
209
|
+
' • Use SDK: import { exportPassportToVC } from "@oap/vc-tools"'
|
|
210
|
+
);
|
|
211
|
+
} catch (error) {
|
|
212
|
+
console.error("❌ Test failed:", error.message);
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"declarationMap": true,
|
|
14
|
+
"sourceMap": true,
|
|
15
|
+
"types": ["node"]
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist"]
|
|
19
|
+
}
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
# Open Agent Passport Verifiable Credential Mapping
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document defines how Open Agent Passport (OAP) objects can be exported and imported as W3C Verifiable Credentials (VCs) for interoperability with existing VC ecosystems.
|
|
6
|
+
|
|
7
|
+
## Design Principles
|
|
8
|
+
|
|
9
|
+
- **Optional VC Support**: VCs are optional for OAP v1 - native OAP JSON remains the source of truth
|
|
10
|
+
- **Deterministic Mapping**: Export/import mappings are deterministic and reversible
|
|
11
|
+
- **Minimal VC Dependencies**: Avoid forcing VC adoption in OAP v1 implementations
|
|
12
|
+
- **Future Compatibility**: Design for future VC integration without breaking changes
|
|
13
|
+
|
|
14
|
+
## Passport to VC Mapping
|
|
15
|
+
|
|
16
|
+
### OAP Passport Credential
|
|
17
|
+
|
|
18
|
+
An OAP passport can be exported as a Verifiable Credential with the following structure:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"@context": [
|
|
23
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
24
|
+
"https://raw.githubusercontent.com/aporthq/aport-spec/refs/heads/main/oap/vc/context-oap-v1.jsonld"
|
|
25
|
+
],
|
|
26
|
+
"type": ["VerifiableCredential", "OAPPassportCredential"],
|
|
27
|
+
"credentialSubject": {
|
|
28
|
+
"agent_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
29
|
+
"kind": "template",
|
|
30
|
+
"spec_version": "oap/1.0",
|
|
31
|
+
"owner_id": "org_12345678",
|
|
32
|
+
"owner_type": "org",
|
|
33
|
+
"assurance_level": "L2",
|
|
34
|
+
"status": "active",
|
|
35
|
+
"capabilities": ["finance.payment.refund", "data.export"],
|
|
36
|
+
"limits": {
|
|
37
|
+
"finance.payment.refund": {
|
|
38
|
+
"currency_limits": {
|
|
39
|
+
"USD": {
|
|
40
|
+
"max_per_tx": 5000,
|
|
41
|
+
"daily_cap": 50000
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"reason_codes": ["customer_request", "defective_product"],
|
|
45
|
+
"idempotency_required": true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"regions": ["US", "CA"],
|
|
49
|
+
"metadata": {
|
|
50
|
+
"name": "Customer Support AI",
|
|
51
|
+
"description": "AI agent for customer support operations"
|
|
52
|
+
},
|
|
53
|
+
"created_at": "2024-01-01T00:00:00Z",
|
|
54
|
+
"updated_at": "2024-01-15T10:30:00Z",
|
|
55
|
+
"version": "1.0.0"
|
|
56
|
+
},
|
|
57
|
+
"issuer": "https://aport.io",
|
|
58
|
+
"issuanceDate": "2024-01-01T00:00:00Z",
|
|
59
|
+
"expirationDate": "2025-01-01T00:00:00Z",
|
|
60
|
+
"proof": {
|
|
61
|
+
"type": "Ed25519Signature2020",
|
|
62
|
+
"created": "2024-01-01T00:00:00Z",
|
|
63
|
+
"verificationMethod": "https://aport.io/.well-known/oap/keys.json#key-2025-01",
|
|
64
|
+
"proofPurpose": "assertionMethod",
|
|
65
|
+
"jws": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Mapping Rules
|
|
71
|
+
|
|
72
|
+
1. **Context**: Include OAP context and W3C VC context
|
|
73
|
+
2. **Type**: Use `["VerifiableCredential", "OAPPassportCredential"]`
|
|
74
|
+
3. **Credential Subject**: Map all OAP passport fields directly
|
|
75
|
+
4. **Issuer**: Use registry URL or owner domain
|
|
76
|
+
5. **Dates**: Map `created_at` to `issuanceDate`, set `expirationDate` based on policy
|
|
77
|
+
6. **Proof**: Use Ed25519Signature2020 over JCS-canonicalized credential subject
|
|
78
|
+
|
|
79
|
+
## Decision to VC Mapping
|
|
80
|
+
|
|
81
|
+
### OAP Decision Receipt
|
|
82
|
+
|
|
83
|
+
An OAP decision can be exported as a Verifiable Credential receipt:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"@context": [
|
|
88
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
89
|
+
"https://raw.githubusercontent.com/aporthq/aport-spec/refs/heads/main/oap/vc/context-oap-v1.jsonld"
|
|
90
|
+
],
|
|
91
|
+
"type": ["VerifiableCredential", "OAPDecisionReceipt"],
|
|
92
|
+
"credentialSubject": {
|
|
93
|
+
"decision_id": "550e8400-e29b-41d4-a716-446655440002",
|
|
94
|
+
"policy_id": "finance.payment.refund.v1",
|
|
95
|
+
"agent_id": "550e8400-e29b-41d4-a716-446655440000",
|
|
96
|
+
"owner_id": "org_12345678",
|
|
97
|
+
"assurance_level": "L2",
|
|
98
|
+
"allow": true,
|
|
99
|
+
"reasons": [
|
|
100
|
+
{
|
|
101
|
+
"code": "oap.allowed",
|
|
102
|
+
"message": "Transaction within limits"
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"created_at": "2024-01-15T10:30:00Z",
|
|
106
|
+
"expires_in": 3600,
|
|
107
|
+
"passport_digest": "sha256:abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx1234yzab5678cdef"
|
|
108
|
+
},
|
|
109
|
+
"issuer": "https://aport.io",
|
|
110
|
+
"issuanceDate": "2024-01-15T10:30:00Z",
|
|
111
|
+
"expirationDate": "2024-01-15T11:30:00Z",
|
|
112
|
+
"proof": {
|
|
113
|
+
"type": "Ed25519Signature2020",
|
|
114
|
+
"created": "2024-01-15T10:30:00Z",
|
|
115
|
+
"verificationMethod": "https://aport.io/.well-known/oap/keys.json#key-2025-01",
|
|
116
|
+
"proofPurpose": "assertionMethod",
|
|
117
|
+
"jws": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Decision Mapping Rules
|
|
123
|
+
|
|
124
|
+
1. **Context**: Include OAP context and W3C VC context
|
|
125
|
+
2. **Type**: Use `["VerifiableCredential", "OAPDecisionReceipt"]`
|
|
126
|
+
3. **Credential Subject**: Map all OAP decision fields directly
|
|
127
|
+
4. **Issuer**: Use registry URL
|
|
128
|
+
5. **Dates**: Map `created_at` to `issuanceDate`, compute `expirationDate` from `expires_in`
|
|
129
|
+
6. **Proof**: Use Ed25519Signature2020 over JCS-canonicalized credential subject
|
|
130
|
+
|
|
131
|
+
## Import/Export Rules
|
|
132
|
+
|
|
133
|
+
### Export Rules
|
|
134
|
+
|
|
135
|
+
#### Requirements
|
|
136
|
+
|
|
137
|
+
1. **Deterministic**: Same OAP object always produces same VC
|
|
138
|
+
2. **Complete**: All OAP fields are included in VC
|
|
139
|
+
3. **Valid**: Generated VCs are valid according to VC specification
|
|
140
|
+
4. **Signed**: VCs include proper Ed25519 signatures
|
|
141
|
+
5. **Context**: Include proper JSON-LD context
|
|
142
|
+
|
|
143
|
+
### Import Rules
|
|
144
|
+
|
|
145
|
+
#### Import Requirements
|
|
146
|
+
|
|
147
|
+
1. **Advisory Only**: VC import is advisory, not authoritative
|
|
148
|
+
2. **Validation**: Validate VC structure and signatures
|
|
149
|
+
3. **Mapping**: Map VC fields back to OAP format
|
|
150
|
+
4. **Source of Truth**: Native OAP JSON remains authoritative
|
|
151
|
+
5. **Error Handling**: Handle invalid or malformed VCs gracefully
|
|
152
|
+
|
|
153
|
+
### Implementation Example
|
|
154
|
+
|
|
155
|
+
#### Code
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
// Export OAP passport to VC
|
|
159
|
+
function exportPassportToVC(passport, registryKey) {
|
|
160
|
+
const vc = {
|
|
161
|
+
"@context": [
|
|
162
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
163
|
+
"https://raw.githubusercontent.com/aporthq/aport-spec/refs/heads/main/oap/vc/context-oap-v1.jsonld"
|
|
164
|
+
],
|
|
165
|
+
"type": ["VerifiableCredential", "OAPPassportCredential"],
|
|
166
|
+
"credentialSubject": passport,
|
|
167
|
+
"issuer": "https://aport.io",
|
|
168
|
+
"issuanceDate": passport.created_at,
|
|
169
|
+
"expirationDate": computeExpirationDate(passport),
|
|
170
|
+
"proof": {
|
|
171
|
+
"type": "Ed25519Signature2020",
|
|
172
|
+
"created": passport.created_at,
|
|
173
|
+
"verificationMethod": `${registryKey.issuer}#${registryKey.kid}`,
|
|
174
|
+
"proofPurpose": "assertionMethod",
|
|
175
|
+
"jws": signCredential(passport, registryKey)
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
return vc;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Import VC to OAP passport
|
|
182
|
+
function importVCToPassport(vc) {
|
|
183
|
+
// Validate VC structure
|
|
184
|
+
if (!isValidVC(vc)) {
|
|
185
|
+
throw new Error("Invalid VC structure");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Verify signature
|
|
189
|
+
if (!verifyCredentialSignature(vc)) {
|
|
190
|
+
throw new Error("Invalid VC signature");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Extract passport from credential subject
|
|
194
|
+
const passport = vc.credentialSubject;
|
|
195
|
+
|
|
196
|
+
// Validate OAP passport structure
|
|
197
|
+
if (!isValidOAPPassport(passport)) {
|
|
198
|
+
throw new Error("Invalid OAP passport structure");
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return passport;
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Interoperability Considerations
|
|
206
|
+
|
|
207
|
+
### VC Ecosystem Integration
|
|
208
|
+
|
|
209
|
+
- **Wallet Support**: OAP VCs can be stored in standard VC wallets
|
|
210
|
+
- **Presentation**: OAP VCs can be presented using standard VC presentation protocols
|
|
211
|
+
- **Verification**: OAP VCs can be verified using standard VC verification libraries
|
|
212
|
+
- **Storage**: OAP VCs can be stored in standard VC repositories
|
|
213
|
+
|
|
214
|
+
### OAP Ecosystem Integration
|
|
215
|
+
|
|
216
|
+
- **Native Support**: OAP implementations work with native JSON format
|
|
217
|
+
- **VC Optional**: VC support is optional for OAP compliance
|
|
218
|
+
- **Performance**: Native OAP format is optimized for performance
|
|
219
|
+
- **Simplicity**: Native OAP format is simpler for basic use cases
|
|
220
|
+
|
|
221
|
+
## Future Considerations
|
|
222
|
+
|
|
223
|
+
### VC v2.0 Support
|
|
224
|
+
|
|
225
|
+
Future versions may include:
|
|
226
|
+
|
|
227
|
+
- **BBS+ Signatures**: Support for selective disclosure
|
|
228
|
+
- **ZKP Integration**: Zero-knowledge proof support
|
|
229
|
+
- **Multi-Signature**: Support for multiple signers
|
|
230
|
+
- **Revocation**: Standard VC revocation mechanisms
|
|
231
|
+
|
|
232
|
+
### OAP v2.0 Integration
|
|
233
|
+
|
|
234
|
+
Future OAP versions may:
|
|
235
|
+
|
|
236
|
+
- **Native VC Support**: Make VCs a first-class citizen
|
|
237
|
+
- **DID Integration**: Support for Decentralized Identifiers
|
|
238
|
+
- **Credential Exchange**: Standard credential exchange protocols
|
|
239
|
+
- **Privacy Enhancements**: Enhanced privacy and selective disclosure
|
|
240
|
+
|
|
241
|
+
## Implementation Guide
|
|
242
|
+
|
|
243
|
+
### Export OAP Passport to VC
|
|
244
|
+
|
|
245
|
+
```javascript
|
|
246
|
+
function exportPassportToVC(passport, registryKey) {
|
|
247
|
+
// Validate passport structure
|
|
248
|
+
if (!isValidOAPPassport(passport)) {
|
|
249
|
+
throw new Error("Invalid OAP passport structure");
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Create VC structure
|
|
253
|
+
const vc = {
|
|
254
|
+
"@context": [
|
|
255
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
256
|
+
"https://raw.githubusercontent.com/aporthq/aport-spec/refs/heads/main/oap/vc/context-oap-v1.jsonld"
|
|
257
|
+
],
|
|
258
|
+
"type": ["VerifiableCredential", "OAPPassportCredential"],
|
|
259
|
+
"credentialSubject": {
|
|
260
|
+
// Map all OAP passport fields
|
|
261
|
+
"agent_id": passport.agent_id,
|
|
262
|
+
"kind": passport.kind,
|
|
263
|
+
"spec_version": passport.spec_version,
|
|
264
|
+
"parent_agent_id": passport.parent_agent_id,
|
|
265
|
+
"owner_id": passport.owner_id,
|
|
266
|
+
"owner_type": passport.owner_type,
|
|
267
|
+
"assurance_level": passport.assurance_level,
|
|
268
|
+
"status": passport.status,
|
|
269
|
+
"capabilities": passport.capabilities,
|
|
270
|
+
"limits": passport.limits,
|
|
271
|
+
"regions": passport.regions,
|
|
272
|
+
"metadata": passport.metadata,
|
|
273
|
+
"created_at": passport.created_at,
|
|
274
|
+
"updated_at": passport.updated_at,
|
|
275
|
+
"version": passport.version
|
|
276
|
+
},
|
|
277
|
+
"issuer": registryKey.issuer,
|
|
278
|
+
"issuanceDate": passport.created_at,
|
|
279
|
+
"expirationDate": computeExpirationDate(passport),
|
|
280
|
+
"proof": {
|
|
281
|
+
"type": "Ed25519Signature2020",
|
|
282
|
+
"created": passport.created_at,
|
|
283
|
+
"verificationMethod": `${registryKey.issuer}/.well-known/oap/keys.json#${registryKey.kid}`,
|
|
284
|
+
"proofPurpose": "assertionMethod",
|
|
285
|
+
"jws": signCredential(passport, registryKey)
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
return vc;
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Export OAP Decision to VC
|
|
294
|
+
|
|
295
|
+
```javascript
|
|
296
|
+
function exportDecisionToVC(decision, registryKey) {
|
|
297
|
+
// Validate decision structure
|
|
298
|
+
if (!isValidOAPDecision(decision)) {
|
|
299
|
+
throw new Error("Invalid OAP decision structure");
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Create VC structure
|
|
303
|
+
const vc = {
|
|
304
|
+
"@context": [
|
|
305
|
+
"https://www.w3.org/2018/credentials/v1",
|
|
306
|
+
"https://raw.githubusercontent.com/aporthq/aport-spec/refs/heads/main/oap/vc/context-oap-v1.jsonld"
|
|
307
|
+
],
|
|
308
|
+
"type": ["VerifiableCredential", "OAPDecisionReceipt"],
|
|
309
|
+
"credentialSubject": {
|
|
310
|
+
// Map all OAP decision fields
|
|
311
|
+
"decision_id": decision.decision_id,
|
|
312
|
+
"policy_id": decision.policy_id,
|
|
313
|
+
"agent_id": decision.agent_id,
|
|
314
|
+
"owner_id": decision.owner_id,
|
|
315
|
+
"assurance_level": decision.assurance_level,
|
|
316
|
+
"allow": decision.allow,
|
|
317
|
+
"reasons": decision.reasons,
|
|
318
|
+
"created_at": decision.created_at,
|
|
319
|
+
"expires_in": decision.expires_in,
|
|
320
|
+
"passport_digest": decision.passport_digest,
|
|
321
|
+
"signature": decision.signature,
|
|
322
|
+
"kid": decision.kid,
|
|
323
|
+
"decision_token": decision.decision_token,
|
|
324
|
+
"remaining_daily_cap": decision.remaining_daily_cap
|
|
325
|
+
},
|
|
326
|
+
"issuer": registryKey.issuer,
|
|
327
|
+
"issuanceDate": decision.created_at,
|
|
328
|
+
"expirationDate": new Date(new Date(decision.created_at).getTime() + decision.expires_in * 1000).toISOString(),
|
|
329
|
+
"proof": {
|
|
330
|
+
"type": "Ed25519Signature2020",
|
|
331
|
+
"created": decision.created_at,
|
|
332
|
+
"verificationMethod": `${registryKey.issuer}/.well-known/oap/keys.json#${registryKey.kid}`,
|
|
333
|
+
"proofPurpose": "assertionMethod",
|
|
334
|
+
"jws": signCredential(decision, registryKey)
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
return vc;
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Import VC to OAP Objects
|
|
343
|
+
|
|
344
|
+
```javascript
|
|
345
|
+
function importVCToPassport(vc) {
|
|
346
|
+
// Validate VC structure
|
|
347
|
+
if (!isValidVC(vc)) {
|
|
348
|
+
throw new Error("Invalid VC structure");
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Verify signature
|
|
352
|
+
if (!verifyCredentialSignature(vc)) {
|
|
353
|
+
throw new Error("Invalid VC signature");
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Extract passport from credential subject
|
|
357
|
+
const passport = vc.credentialSubject;
|
|
358
|
+
|
|
359
|
+
// Validate OAP passport structure
|
|
360
|
+
if (!isValidOAPPassport(passport)) {
|
|
361
|
+
throw new Error("Invalid OAP passport structure");
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return passport;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function importVCToDecision(vc) {
|
|
368
|
+
// Validate VC structure
|
|
369
|
+
if (!isValidVC(vc)) {
|
|
370
|
+
throw new Error("Invalid VC structure");
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Verify signature
|
|
374
|
+
if (!verifyCredentialSignature(vc)) {
|
|
375
|
+
throw new Error("Invalid VC signature");
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Extract decision from credential subject
|
|
379
|
+
const decision = vc.credentialSubject;
|
|
380
|
+
|
|
381
|
+
// Validate OAP decision structure
|
|
382
|
+
if (!isValidOAPDecision(decision)) {
|
|
383
|
+
throw new Error("Invalid OAP decision structure");
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return decision;
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Validation Functions
|
|
391
|
+
|
|
392
|
+
```javascript
|
|
393
|
+
function isValidVC(vc) {
|
|
394
|
+
return vc &&
|
|
395
|
+
vc["@context"] &&
|
|
396
|
+
vc.type &&
|
|
397
|
+
vc.credentialSubject &&
|
|
398
|
+
vc.issuer &&
|
|
399
|
+
vc.issuanceDate &&
|
|
400
|
+
vc.proof;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function isValidOAPPassport(passport) {
|
|
404
|
+
return passport &&
|
|
405
|
+
passport.agent_id &&
|
|
406
|
+
passport.kind &&
|
|
407
|
+
passport.spec_version &&
|
|
408
|
+
passport.owner_id &&
|
|
409
|
+
passport.owner_type &&
|
|
410
|
+
passport.assurance_level &&
|
|
411
|
+
passport.status &&
|
|
412
|
+
passport.capabilities &&
|
|
413
|
+
passport.limits &&
|
|
414
|
+
passport.regions &&
|
|
415
|
+
passport.created_at &&
|
|
416
|
+
passport.updated_at &&
|
|
417
|
+
passport.version;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function isValidOAPDecision(decision) {
|
|
421
|
+
return decision &&
|
|
422
|
+
decision.decision_id &&
|
|
423
|
+
decision.policy_id &&
|
|
424
|
+
decision.agent_id &&
|
|
425
|
+
decision.owner_id &&
|
|
426
|
+
decision.assurance_level &&
|
|
427
|
+
typeof decision.allow === 'boolean' &&
|
|
428
|
+
decision.reasons &&
|
|
429
|
+
decision.created_at &&
|
|
430
|
+
decision.expires_in &&
|
|
431
|
+
decision.passport_digest &&
|
|
432
|
+
decision.signature &&
|
|
433
|
+
decision.kid;
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## References
|
|
438
|
+
|
|
439
|
+
- [W3C Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model/)
|
|
440
|
+
- [W3C Verifiable Credentials Implementation Guidelines](https://www.w3.org/TR/vc-imp-guide/)
|
|
441
|
+
- [Ed25519Signature2020](https://w3c-ccg.github.io/lds-ed25519-2020/)
|
|
442
|
+
- [JSON-LD](https://www.w3.org/TR/json-ld11/)
|
|
443
|
+
- [OAP Specification](../oap-spec.md)
|