From 0f1161c8703df331dc688eea63e596223a7cc5e4 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 24 Oct 2024 11:41:13 -0400 Subject: [PATCH 1/5] Clean up the algorithms assertion. --- index.js | 3 ++ suites/algorithms.js | 123 +++++++++++++++++++++---------------------- 2 files changed, 64 insertions(+), 62 deletions(-) diff --git a/index.js b/index.js index 23ea663..f9ebabd 100644 --- a/index.js +++ b/index.js @@ -163,6 +163,8 @@ export * as assertions from './assertions.js'; export {generators} from './vc-generator/generators.js'; export {deriveCloned, issueCloned} from './vc-generator/issuer.js'; export {createDocLoader} from './vc-generator/documentLoader.js'; +// this is just here for backwards compatitility to avoid a major release +// FIXME remove this on next MAJOR release export { dateRegex, expectedMultibasePrefix, isObjectOrArrayOfObjects, shouldBeErrorResponse, shouldBeUrl, isStringOrArrayOfStrings, @@ -170,3 +172,4 @@ export { verificationFail } from './assertions.js'; export {createInitialVc} from './helpers.js'; +export {algorithmsAssertions} from './suites/algorithms.js'; diff --git a/suites/algorithms.js b/suites/algorithms.js index 5213aef..4526814 100644 --- a/suites/algorithms.js +++ b/suites/algorithms.js @@ -8,6 +8,10 @@ export function algorithmsAssertions({ testDescription, vendorName, credential, + features = { + authentication: false, + proofChain: false + } }) { return describe(testDescription, function() { const columnId = testDescription; @@ -54,78 +58,73 @@ and proof.proofPurpose values is not set, an error MUST be raised.', 'type', 'proofPurpose', 'verificationMethod'); } }); - it('If options has a non-null domain item, it MUST be equal to \ -proof.domain or an error MUST be raised.', - function() { - this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20options%20has%20a%20non%2Dnull%20domain%20item%2C%20it%20MUST%20be%20equal%20to%20proof.domain%20or%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; - this.test.cell.skipMessage = 'Pending test.'; - this.skip(); - }); - it('If options has a non-null challenge item, it MUST be equal to \ -proof.challenge or an error MUST be raised.', - function() { - this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20options%20has%20a%20non%2Dnull%20challenge%20item%2C%20it%20MUST%20be%20equal%20to%20proof.challenge%20or%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; - this.test.cell.skipMessage = 'Pending test.'; - this.skip(); - }); - it('Whenever this algorithm encodes strings, it MUST use UTF-8 encoding.', + if(features?.authentication) { + it('If options has a non-null domain item, it MUST be equal to \ + proof.domain or an error MUST be raised.', function() { - this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=(map).-,Whenever%20this%20algorithm%20encodes%20strings%2C%20it%20MUST%20use%20UTF%2D8%20encoding.,-Let%20proof%20be'; - for(const proof of proofs) { - expect(proof.proofValue.isWellFormed()).to.be.true; - } + this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20options%20has%20a%20non%2Dnull%20domain%20item%2C%20it%20MUST%20be%20equal%20to%20proof.domain%20or%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; + this.test.cell.skipMessage = 'Pending test.'; + this.skip(); }); - it('If a proof with id equal to previousProof does not exist in allProofs, \ -an error MUST be raised.', - function() { - this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20a%20proof%20with%20id%20equal%20to%20previousProofdoes%20not%20exist%20in%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; - for(const proof of proofs) { - if('previousProof' in proof) { - if(typeof proof.previousProof === 'string') { - proofs.some( - otherProof => otherProof.id == proof.previousProof). - should.equal(true, - 'Expected previousProof ' + - `${proof.previousProof} ` + - 'to be the id of another included proof.' - ); - } if(Array.isArray(proof.previousProof)) { - for(const previousProof in proof.previousProof) { + it('If options has a non-null challenge item, it MUST be equal to \ + proof.challenge or an error MUST be raised.', + function() { + this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20options%20has%20a%20non%2Dnull%20challenge%20item%2C%20it%20MUST%20be%20equal%20to%20proof.challenge%20or%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; + this.test.cell.skipMessage = 'Pending test.'; + this.skip(); + }); + } + if(features?.proofChain) { + it('If a proof with id equal to previousProof does not exist in ' + + 'allProofs, an error MUST be raised.', function() { + this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20a%20proof%20with%20id%20equal%20to%20previousProofdoes%20not%20exist%20in%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; + for(const proof of proofs) { + if('previousProof' in proof) { + if(typeof proof.previousProof === 'string') { proofs.some( - otherProof => otherProof.id == previousProof). + otherProof => otherProof.id == proof.previousProof). should.equal(true, 'Expected previousProof ' + - `${proof.previousProof} ` + - 'to be the id of another included proof.' + `${proof.previousProof} ` + + 'to be the id of another included proof.' ); + } if(Array.isArray(proof.previousProof)) { + for(const previousProof in proof.previousProof) { + proofs.some( + otherProof => otherProof.id == previousProof). + should.equal(true, + 'Expected previousProof ' + + `${proof.previousProof} ` + + 'to be the id of another included proof.' + ); + } } } } - } - }); - it('If any element of previousProof array has an id attribute \ -that does not match the id attribute of any element of allProofs, \ -an error MUST be raised.', - function() { - this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20any%20element%20of%20previousProof%20array%20has%20an%20id%20attribute%20that%20does%20not%20match%20the%20id%20attribute%20of%20any%20element%20of%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; - const previousProofs = []; - for(const proof of proofs) { - if('previousProof' in proof) { - if(typeof proof.previousProof === 'string') { - previousProofs.push(proof.previousProof); - } if(Array.isArray(proof.previousProof)) { - previousProofs.concat(proof.previousProof); + }); + it('If any element of previousProof array has an id attribute' + + ' that does not match the id attribute of any element of allProofs,' + + ' an error MUST be raised.', function() { + this.test.link = 'https://www.w3.org/TR/vc-data-integrity/#:~:text=If%20any%20element%20of%20previousProof%20array%20has%20an%20id%20attribute%20that%20does%20not%20match%20the%20id%20attribute%20of%20any%20element%20of%20allProofs%2C%20an%20error%20MUST%20be%20raised%20and%20SHOULD%20convey%20an%20error%20type%20of%20PROOF_GENERATION_ERROR.'; + const previousProofs = []; + for(const proof of proofs) { + if('previousProof' in proof) { + if(typeof proof.previousProof === 'string') { + previousProofs.push(proof.previousProof); + } if(Array.isArray(proof.previousProof)) { + previousProofs.concat(proof.previousProof); + } } } - } - for(const previousProof of previousProofs) { - proofs.some( - otherProof => otherProof.id == previousProof).should.equal( - true, - 'Expected all previousProof values to be the id of \ -another included proof.' - ); - } - }); + for(const previousProof of previousProofs) { + proofs.some( + otherProof => otherProof.id == previousProof).should.equal( + true, + 'Expected all previousProof values to be the id of \ + another included proof.' + ); + } + }); + } }); } From 569477dd64f5d976d5fbaa56d83667aa756d6227 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 24 Oct 2024 13:35:39 -0400 Subject: [PATCH 2/5] Add test suite for assertionsSuite. --- index.js | 2 +- suites/algorithms.js | 7 +++-- tests/30-algorithms.js | 62 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 tests/30-algorithms.js diff --git a/index.js b/index.js index f9ebabd..23f1360 100644 --- a/index.js +++ b/index.js @@ -172,4 +172,4 @@ export { verificationFail } from './assertions.js'; export {createInitialVc} from './helpers.js'; -export {algorithmsAssertions} from './suites/algorithms.js'; +export {algorithmsSuite} from './suites/algorithms.js'; diff --git a/suites/algorithms.js b/suites/algorithms.js index 4526814..dd3af26 100644 --- a/suites/algorithms.js +++ b/suites/algorithms.js @@ -1,11 +1,14 @@ +/*! + * Copyright (c) 2024 Digital Bazaar, Inc. + */ import chai from 'chai'; import {createInitialVc} from '../helpers.js'; const expect = chai.expect; -export function algorithmsAssertions({ +export function algorithmsSuite({ endpoints, - testDescription, + testDescription = 'Data Integrity - Algorithms', vendorName, credential, features = { diff --git a/tests/30-algorithms.js b/tests/30-algorithms.js new file mode 100644 index 0000000..3b9174b --- /dev/null +++ b/tests/30-algorithms.js @@ -0,0 +1,62 @@ +/*! + * Copyright (c) 2024 Digital Bazaar, Inc. + */ +import {algorithmsSuite} from '../index.js'; +import {createSuite} from './helpers.js'; +import {cryptosuites} from './fixtures/cryptosuites.js'; +import {documentLoader} from './fixtures/documentLoader.js'; +import {MockIssuer} from './mock-data.js'; +import {versionedCredentials} from './fixtures/credentials/index.js'; + +const tag = 'Test-Issuer-Valid'; +const tags = [tag]; + +describe('should issue all suites', function() { + for(const testDataOptions of cryptosuites) { + for(const [ + vcVersion, + {credential, mandatoryPointers} + ] of versionedCredentials) { + _runSuite({ + vcVersion, + testDataOptions, + credential, + mandatoryPointers + }); + } + } +}); + +function _runSuite({ + vcVersion, testDataOptions, + credential, mandatoryPointers +}) { + const {suiteName, keyType = ''} = testDataOptions; + let title = `VC ${vcVersion} Suite ${suiteName}`; + if(keyType) { + title += `keyType ${keyType}`; + } + return describe(title, + function() { + const implemented = new Map(); + const {cryptosuite, key, derived} = testDataOptions; + const signer = key.signer(); + const suite = createSuite({ + signer, cryptosuite, + mandatoryPointers, derived + }); + // pass the VC's context to the issuer + const {'@context': contexts} = credential; + const issuer = new MockIssuer({ + tags, suite, + contexts, documentLoader + }); + implemented.set(suiteName, {endpoints: [issuer]}); + algorithmsSuite({ + endpoints: [issuer], + tag, + credential, + cryptosuiteName: suiteName, + }); + }); +} From cceb97c4edea43d1e8cf11c49f1967dba61051a7 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Thu, 24 Oct 2024 14:10:26 -0400 Subject: [PATCH 3/5] Move matrix construction code into suites/algorithms. --- suites/algorithms.js | 24 ++++++++++++++++++++---- tests/30-algorithms.js | 2 +- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/suites/algorithms.js b/suites/algorithms.js index dd3af26..03b1667 100644 --- a/suites/algorithms.js +++ b/suites/algorithms.js @@ -7,9 +7,8 @@ import {createInitialVc} from '../helpers.js'; const expect = chai.expect; export function algorithmsSuite({ - endpoints, + implemented, testDescription = 'Data Integrity - Algorithms', - vendorName, credential, features = { authentication: false, @@ -17,11 +16,28 @@ export function algorithmsSuite({ } }) { return describe(testDescription, function() { - const columnId = testDescription; + // this will tell the report + // to make an interop matrix with this suite + this.matrix = true; + this.report = true; + this.rowLabel = 'Test Name'; + this.columnLabel = 'Verifier'; + this.implemented = []; + for(const [vendorName, {endpoints}] of implemented) { + if(!endpoints) { + throw new Error(`Expected ${vendorName} to have endpoints.`); + } + algorithmsAssert({vendorName, credential, endpoints, features}); + } + }); +} + +function algorithmsAssert({vendorName, credential, endpoints, features}) { + return describe(vendorName, function() { const [issuer] = endpoints; beforeEach(function() { this.currentTest.cell = { - columnId, + columnId: vendorName, rowId: this.currentTest.title }; }); diff --git a/tests/30-algorithms.js b/tests/30-algorithms.js index 3b9174b..4c00329 100644 --- a/tests/30-algorithms.js +++ b/tests/30-algorithms.js @@ -53,7 +53,7 @@ function _runSuite({ }); implemented.set(suiteName, {endpoints: [issuer]}); algorithmsSuite({ - endpoints: [issuer], + implemented, tag, credential, cryptosuiteName: suiteName, From b13810f81852c988e76e12093f5727aff35e3a2b Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Sun, 27 Oct 2024 19:37:44 -0400 Subject: [PATCH 4/5] Update tests/30-algorithms.js improve describe title. --- tests/30-algorithms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/30-algorithms.js b/tests/30-algorithms.js index 4c00329..6046217 100644 --- a/tests/30-algorithms.js +++ b/tests/30-algorithms.js @@ -11,7 +11,7 @@ import {versionedCredentials} from './fixtures/credentials/index.js'; const tag = 'Test-Issuer-Valid'; const tags = [tag]; -describe('should issue all suites', function() { +describe('should run with all suites', function() { for(const testDataOptions of cryptosuites) { for(const [ vcVersion, From 734f1c4f9c2d835b0cd8d466cc91ea630192ca44 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Sun, 27 Oct 2024 19:38:22 -0400 Subject: [PATCH 5/5] Update suites/algorithms.js improve language Implementation not Verifier. --- suites/algorithms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suites/algorithms.js b/suites/algorithms.js index 03b1667..049fe11 100644 --- a/suites/algorithms.js +++ b/suites/algorithms.js @@ -21,7 +21,7 @@ export function algorithmsSuite({ this.matrix = true; this.report = true; this.rowLabel = 'Test Name'; - this.columnLabel = 'Verifier'; + this.columnLabel = 'Implementation'; this.implemented = []; for(const [vendorName, {endpoints}] of implemented) { if(!endpoints) {