Skip to content

Support status checks via workflows. #152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

wes-smith
Copy link

This PR adds two features:

  • Added support for verifyPresentationOptions to appear on exchange steps,
    allowing for more extensible and general step option expression.
  • Added support for verifyPresentationResponseSchema to appear on exchange
    steps, allowing for enforcing validation constraints at the workflow layer.

@codecov-commenter
Copy link

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 82.69%. Comparing base (78fb952) to head (36ca606).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #152      +/-   ##
==========================================
+ Coverage   82.38%   82.69%   +0.31%     
==========================================
  Files          15       15              
  Lines        4529     4611      +82     
==========================================
+ Hits         3731     3813      +82     
  Misses        798      798              
Files with missing lines Coverage Δ
lib/helpers.js 85.32% <100.00%> (+1.60%) ⬆️
lib/oid4/oid4vp.js 83.97% <100.00%> (+0.25%) ⬆️
lib/vcapi.js 76.89% <100.00%> (+0.44%) ⬆️
lib/verify.js 69.12% <100.00%> (+1.71%) ⬆️
schemas/bedrock-vc-workflow.js 100.00% <100.00%> (ø)

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 78fb952...36ca606. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@tminard tminard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few questions / suggestions.

The new tests look a little gnarly but I do not have specific suggestions yet.

Comment on lines +202 to +211
if(verifyPresentationOptions.checks !== undefined) {
for(const check in verifyPresentationOptions.checks) {
if(verifyPresentationOptions.checks[check] == true) {
if(!checks.includes(check)) {
checks.push(check);
}
}
}
}
options.checks = checks;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if(verifyPresentationOptions.checks !== undefined) {
for(const check in verifyPresentationOptions.checks) {
if(verifyPresentationOptions.checks[check] == true) {
if(!checks.includes(check)) {
checks.push(check);
}
}
}
}
options.checks = checks;
const checksSet = new Set(checks);
if(verifyPresentationOptions.checks) {
for(const [check, enabled] of Object.entries(verifyPresentationOptions.checks)) {
if(enabled) {
checksSet.add(check);
}
}
}
options.checks = Array.from(checksSet);

I'm not sure what's being checked with verifyPresentationOptions.checks[check].

result = await zcapClient.write({
capability,
json: {
options: {
// FIXME: support multi-proof presentations?
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this FIXME need to be preserved?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, no, I'd say we can remove it. If we want to support that in the future we can figure out where to add it (which may even be in a different spot or something).

// validate against the verify presentation result schema, if applicable
if(verifyPresentationResultSchema) {
const {jsonSchema: schema} = verifyPresentationResultSchema;
const validate = compile({schema});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be compiled prior to make the zcap call to ensure it fails as early as possible if there's something invalid here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how much earlier it can actually be compiled. Only once the step executes are you guaranteed to have all the variables to construct the step (if it is a template itself, which is common). Therefore, there might not be any earlier time this can happen. We do want, in the future, some better "test" tools for this sort of thing if we can figure out how to accomplish that nicely.

const validate = compile({schema});
const {valid, error} = validate(result.data);
if(!valid) {
throw error;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be wrapped or provide some logging in case of failure here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard to tell from the diff so I'll need to go look at the source, but I believe this follows the pattern we have with the presentation schema, which is wrapped/handled properly now (IIRC). If this is in the same code path/outer wrapper somewhere then this is ok. Will need to go look and confirm.

Copy link
Member

@dlongley dlongley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed most of this modulo the test, will take a look at that later, LGTM so far.

Comment on lines +201 to +211
// update 'checks' with anything additional from 'verifyPresentationOptions'
if(verifyPresentationOptions.checks !== undefined) {
for(const check in verifyPresentationOptions.checks) {
if(verifyPresentationOptions.checks[check] == true) {
if(!checks.includes(check)) {
checks.push(check);
}
}
}
}
options.checks = checks;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I like Tyler's suggestion better (seems more readable), but if you were looking for a functional way to do it, it could look like this:

Suggested change
// update 'checks' with anything additional from 'verifyPresentationOptions'
if(verifyPresentationOptions.checks !== undefined) {
for(const check in verifyPresentationOptions.checks) {
if(verifyPresentationOptions.checks[check] == true) {
if(!checks.includes(check)) {
checks.push(check);
}
}
}
}
options.checks = checks;
options.checks = checks;
// update 'checks' with anything additional from 'verifyPresentationOptions'
if(verifyPresentationOptions.checks) {
options.checks = [...new Set([
...options.checks,
...Object.entries(verifyPresentationOptions.checks)
.filter(([, v]) => v).map(([k]) => k)]
])];
}

result = await zcapClient.write({
capability,
json: {
options: {
// FIXME: support multi-proof presentations?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, no, I'd say we can remove it. If we want to support that in the future we can figure out where to add it (which may even be in a different spot or something).

// validate against the verify presentation result schema, if applicable
if(verifyPresentationResultSchema) {
const {jsonSchema: schema} = verifyPresentationResultSchema;
const validate = compile({schema});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how much earlier it can actually be compiled. Only once the step executes are you guaranteed to have all the variables to construct the step (if it is a template itself, which is common). Therefore, there might not be any earlier time this can happen. We do want, in the future, some better "test" tools for this sort of thing if we can figure out how to accomplish that nicely.

const validate = compile({schema});
const {valid, error} = validate(result.data);
if(!valid) {
throw error;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard to tell from the diff so I'll need to go look at the source, but I believe this follows the pattern we have with the presentation schema, which is wrapped/handled properly now (IIRC). If this is in the same code path/outer wrapper somewhere then this is ok. Will need to go look and confirm.

Copy link
Member

@dlongley dlongley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nits here -- I think all style / maintenance related. Will approve and merge in once those are addressed. Thanks!

let workflowId;
let workflowRootZcap;
beforeEach(async () => {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Comment on lines +350 to +351
describe('exchange with `verifyPresentationResultSchema` checking correct' +
' usage of `verifyPresentationOptions`', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
describe('exchange with `verifyPresentationResultSchema` checking correct' +
' usage of `verifyPresentationOptions`', () => {
describe('exchange with `verifyPresentationResultSchema` checking correct ' +
'usage of `verifyPresentationOptions`', () => {

Comment on lines +513 to +514
it('should fail when `verifyPresentationOptions` does not match' +
' `verifyPresentationResultSchema`', async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style is off here, but the test name doesn't make sense to me. The result schema isn't used to check the presentation options ... well, perhaps for some definition of "match". Maybe this instead:

Suggested change
it('should fail when `verifyPresentationOptions` does not match' +
' `verifyPresentationResultSchema`', async () => {
it('should fail when status checks are disabled but required by ' +
'`verifyPresentationResultSchema`', async () => {

Comment on lines +539 to +540
// DID Authn step, additionally require VC that was issued from
// workflow 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// DID Authn step, additionally require VC that was issued from
// workflow 1
// DID Authn step, additionally require VC that was issued from
// workflow 1

Comment on lines +393 to +395
it('should pass when `verifyPresentationOptions` matches ' +
'`verifyPresentationResultSchema`', async () => {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
it('should pass when `verifyPresentationOptions` matches ' +
'`verifyPresentationResultSchema`', async () => {
it('should pass when `verifyPresentationOptions` enables status check ' +
'and `verifyPresentationResultSchema` requires is', async () => {

See comments on test name language in the other test below.

let workflowId;
let workflowRootZcap;
beforeEach(async () => {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Comment on lines +419 to +420
// DID Authn step, additionally require VC that was issued from
// workflow 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// DID Authn step, additionally require VC that was issued from
// workflow 1
// DID Authn step, additionally require VC that was issued from
// workflow 1

Comment on lines +421 to +450
didAuthn: {
createChallenge: true,
verifiablePresentationRequest: {
query: [{
type: 'DIDAuthentication',
acceptedMethods: [{method: 'key'}]
}, {
type: 'QueryByExample',
credentialQuery: [{
reason: 'We require a verifiable credential to pass this test',
example: {
'@context': [
'https://www.w3.org/ns/credentials/v2'
],
}
}]
}],
domain: baseUrl
},
verifyPresentationOptions: {
checks: {
credentialStatus: true
}
},
verifyPresentationResultSchema: {
type: 'JsonSchema',
jsonSchema: checksIncludeStatusVerificationResultSchema
}
}
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of repetition with all this in various tests here, could use a helper function to DRY it up. I'll just file an issue on this because I expect this to be common throughout the test suite.

Comment on lines +211 to +229
{
"@context": [
"https://www.w3.org/ns/credentials/v2"
],
"id": credentialId,
"type": [
"VerifiableCredential"
],
"credentialStatus: {
"id": "https://example.com/credentials/status/3#94567",
"type": "BitstringStatusListEntry",
"statusPurpose": "revocation",
"statusListIndex": "94567",
"statusListCredential": "https://example.com/credentials/status/3"
},
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21"
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary indentation when using a big string interpolation block; though perhaps this would be better added with an eslint disable block before and after instead. There should be examples of that in various test suites.

Suggested change
{
"@context": [
"https://www.w3.org/ns/credentials/v2"
],
"id": credentialId,
"type": [
"VerifiableCredential"
],
"credentialStatus: {
"id": "https://example.com/credentials/status/3#94567",
"type": "BitstringStatusListEntry",
"statusPurpose": "revocation",
"statusListIndex": "94567",
"statusListCredential": "https://example.com/credentials/status/3"
},
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21"
}
}
{
"@context": [
"https://www.w3.org/ns/credentials/v2"
],
"id": credentialId,
"type": [
"VerifiableCredential"
],
"credentialStatus: {
"id": "https://example.com/credentials/status/3#94567",
"type": "BitstringStatusListEntry",
"statusPurpose": "revocation",
"statusListIndex": "94567",
"statusListCredential": "https://example.com/credentials/status/3"
},
"credentialSubject": {
"id": "did:example:ebfeb1f712ebc6f1c276e12ec21"
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants