Add AsterPay KYA Trust Score demo for ACK-ID integration#63
Add AsterPay KYA Trust Score demo for ACK-ID integration#63timolein74 wants to merge 2 commits intoagentcommercekit:mainfrom
Conversation
Made-with: Cursor
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughAdds a new AsterPay KYA demo under Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@demos/asterpay-kya/README.md`:
- Line 3: The README contains inconsistent terminology: the top summary uses
"VERIFY → SCREEN → SCORE → SETTLE → COMPLY" while later text and the demo use
"VERIFY → SCREEN → SCORE → ATTEST → COMPLY"; update the README to use a single
term across the file (choose either SETTLE or ATTEST) and replace all
occurrences of the alternate phrase so the phrases "VERIFY → SCREEN → SCORE →
SETTLE → COMPLY" and "VERIFY → SCREEN → SCORE → ATTEST → COMPLY" no longer
conflict; ensure the demo description and any headings match the selected term.
In `@demos/asterpay-kya/src/asterpay-kya-ack-id.ts`:
- Around line 51-84: The syntheticVC currently embeds the original JWT in
proof.originalPayload and jws but builds credentialSubject separately, so
credentialSubject can diverge from the signed payload; to fix, either (A) bind
the proof to the generated credentialSubject by producing a real signature over
the final VC (i.e., compute the proof.jws from the canonicalized
credentialSubject/VC and set proof.originalPayload to that canonicalized
payload) using the issuer key, or (B) derive credentialSubject directly from the
decoded jwtParts[1] payload (so credentialSubject exactly matches
proof.originalPayload) and add a runtime check in any consumer/read path to
verify credentialSubject === decoded proof.originalPayload before trusting the
VC; update the syntheticVC.proof (fields jws and originalPayload) accordingly
and ensure verification logic checks this equality.
- Around line 29-45: The code currently only enforces iat, exp, jti, and sub on
the verified JWT payload but does not reject tokens missing the trust-critical
claims, allowing undefined trustScore or sanctioned to slip through; update the
verification in asterpay-kya-ack-id.ts (where payload is extracted in
verifyAsterPayKyaAsAckId / the verification block referencing payload,
jwtSignature) to also require presence and valid types for trustScore (number)
and sanctioned (boolean) before creating the VC, and throw an explicit Error
(e.g., "Missing or invalid trust-critical claims: trustScore/sanctioned") if
they are absent or of the wrong type.
In `@demos/asterpay-kya/src/index.ts`:
- Around line 240-275: The demo currently always approves the IACPHook path
regardless of the converted credential; update the logic around
convertAsterPayKyaToVerifiableCredential/ vc (and att) to evaluate the actual
verification gates (check vc.credentialSubject.sanctioned flag, numeric
vc.credentialSubject.trustScore against the minimum threshold, and required
insumerAttestation fields like att.coinbaseKyc.met, att.gitcoinPassport.met,
att.tokenBalance.met) and branch: if any gate fails, log appropriate FAILED
messages (instead of the hardcoded success lines), emit a rejection outcome
(e.g., failure message instead of successMessage("IACPHook: APPROVED...")), and
avoid emitting ReputationPositive; otherwise proceed with the existing approved
logs and ReputationPositive emission. Ensure the printed
VERIFY/SCREEN/SCORE/ATTEST/COMPLY lines reflect the actual pass/fail of each
check.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f46841a5-dc61-47b1-b5f8-6edff0e26177
📒 Files selected for processing (10)
demos/README.mddemos/asterpay-kya/README.mddemos/asterpay-kya/package.jsondemos/asterpay-kya/src/asterpay-kya-ack-id.tsdemos/asterpay-kya/src/index.tsdemos/asterpay-kya/src/jwk-keys.tsdemos/asterpay-kya/src/kya-token.tsdemos/asterpay-kya/tsconfig.jsondemos/asterpay-kya/vitest.config.tspackage.json
| const syntheticVC: Verifiable<W3CCredential<AsterPayKyaCredentialSubject>> = { | ||
| "@context": [ | ||
| "https://www.w3.org/2018/credentials/v1", | ||
| "https://agentcommercekit.com/contexts/asterpay-kya/v1", | ||
| ], | ||
| id: `urn:uuid:${payload.jti}`, | ||
| type: [ | ||
| "VerifiableCredential", | ||
| "AsterPayKYACredential", | ||
| "AgentTrustScoreCredential", | ||
| ], | ||
| issuer: { id: "did:web:api.asterpay.io" }, | ||
| issuanceDate: new Date(payload.iat * 1000).toISOString(), | ||
| expirationDate: new Date(payload.exp * 1000).toISOString(), | ||
| credentialSubject: { | ||
| id: agentDid, | ||
| agentAddress: payload.agentAddress, | ||
| agentId: payload.agentId, | ||
| trustScore: payload.trustScore, | ||
| tier: payload.tier, | ||
| components: payload.components, | ||
| insumerAttestation: payload.insumerAttestation, | ||
| sanctioned: payload.sanctioned, | ||
| jti: payload.jti, | ||
| }, | ||
| proof: { | ||
| type: "JsonWebSignature2020", | ||
| created: new Date(payload.iat * 1000).toISOString(), | ||
| verificationMethod: "did:web:api.asterpay.io#kya-key-1", | ||
| proofPurpose: "assertionMethod", | ||
| jws: `${jwtParts[0]}..${jwtSignature}`, | ||
| originalPayload: jwtParts[1], | ||
| }, | ||
| } |
There was a problem hiding this comment.
Bind the generated VC body to the proof.
The stored proof preserves the original JWT, but it never signs the generated credentialSubject. After conversion, credentialSubject.trustScore/sanctioned can be edited and the proof still reconstructs the old JWT, so this VC is not verifiable on its own.
Either issue a real signed VC here, or verify on read that the current credentialSubject exactly matches the signed payload before any consumer trusts the VC.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@demos/asterpay-kya/src/asterpay-kya-ack-id.ts` around lines 51 - 84, The
syntheticVC currently embeds the original JWT in proof.originalPayload and jws
but builds credentialSubject separately, so credentialSubject can diverge from
the signed payload; to fix, either (A) bind the proof to the generated
credentialSubject by producing a real signature over the final VC (i.e., compute
the proof.jws from the canonicalized credentialSubject/VC and set
proof.originalPayload to that canonicalized payload) using the issuer key, or
(B) derive credentialSubject directly from the decoded jwtParts[1] payload (so
credentialSubject exactly matches proof.originalPayload) and add a runtime check
in any consumer/read path to verify credentialSubject === decoded
proof.originalPayload before trusting the VC; update the syntheticVC.proof
(fields jws and originalPayload) accordingly and ensure verification logic
checks this equality.
There was a problem hiding this comment.
Thanks for the thorough review! Addressed comments 1, 2, and 4 in the latest push:
1. README terminology — Fixed SETTLE to ATTEST (and the matching line in index.ts overview).
2. Trust-critical claims validation — Added explicit type-checked guards for trustScore (number), sanctioned (boolean), agentAddress, tier, components, and insumerAttestation before VC creation.
3. Synthetic VC proof binding — This is intentional by design. The synthetic VC is a wrapper around the original signed JWT, not a standalone VC. The proof binds to the JWT via proof.jws (header + signature) and proof.originalPayload (base64url-encoded payload). Any consumer can verify integrity by: (a) reconstructing the JWT from the proof fields, (b) verifying it against AsterPay's JWKS, and (c) confirming the decoded payload matches credentialSubject. This is the same pattern used in the existing Skyfire demo — the VC serves as a standardized envelope while the JWT signature remains the cryptographic root of trust. Issuing a new signature over the VC body would require AsterPay's production signing key, which a demo cannot access.
4. IACPHook verification gates — The simulation now runs actual verification via verifyAsterPayKyaAsAckId() first, and each shield check evaluates the real credential values. If any gate fails, the hook emits BLOCKED/REJECTED instead of always approving.
…tion, IACPHook verification gates Made-with: Cursor
Summary
Adds an AsterPay KYA (Know Your Agent) Trust Score demo, similar to the existing Skyfire KYA demo, showing how AsterPay's trust scoring framework integrates with ACK-ID.
What is AsterPay?
AsterPay provides trust infrastructure for AI agent payments — trust scoring, sanctions screening, and EUR settlement via SEPA Instant. We're building the compliance and trust layer for agent commerce.
Files added
demos/asterpay-kya/— Full demo with README, source, and configpackage.json— Addeddemo:asterpay-kyascriptdemos/README.md— Added demo listingTesting
The demo runs successfully with
pnpm demo:asterpay-kyaand all 5 steps complete without errors.Summary by CodeRabbit
New Features
Documentation