Skip to content

Commit 34755dd

Browse files
authored
test: add ZKP test (#130)
Signed-off-by: Allain Magyar <[email protected]>
1 parent 21cb994 commit 34755dd

File tree

12 files changed

+603
-120
lines changed

12 files changed

+603
-120
lines changed

.github/workflows/e2e.yml

+36
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ jobs:
1919
runs-on: macos-13
2020

2121
steps:
22+
- name: Mask apikey
23+
env:
24+
APIKEY: ${{ inputs.apiKey || secrets.APIKEY }}
25+
run: echo "::add-mask::${{env.APIKEY}}"
26+
2227
- name: Checkout Code
2328
uses: actions/checkout@v3
2429

@@ -35,6 +40,37 @@ jobs:
3540
- name: Adding Known Hosts
3641
run: ssh-keyscan -H github.com >> ~/.ssh/known_hosts
3742

43+
- name: Create properties file
44+
working-directory: E2E/e2eTests/Resources
45+
env:
46+
MEDIATOR_OOB_URL: ${{ inputs.mediatorOobUrl || vars.MEDIATOR_OOB_URL }}
47+
PRISM_AGENT_URL: ${{ inputs.prismAgentUrl || vars.PRISM_AGENT_URL }}
48+
PUBLISHED_DID: ${{ inputs.publishedDid || vars.PUBLISHED_DID }}
49+
JWT_SCHEMA_GUID: ${{ inputs.jwtSchemaGuid || vars.JWT_SCHEMA_GUID }}
50+
ANONCRED_DEFINITION_GUID: ${{ inputs.anoncredDefinitionGuid || vars.ANONCRED_DEFINITION_GUID }}
51+
APIKEY: ${{ inputs.apiKey || secrets.APIKEY }}
52+
run: |
53+
cat <<EOL > properties.plist
54+
<?xml version="1.0" encoding="UTF-8"?>
55+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
56+
<plist version="1.0">
57+
<dict>
58+
<key>MEDIATOR_OOB_URL</key>
59+
<string>${{env.MEDIATOR_OOB_URL}}</string>
60+
<key>PRISM_AGENT_URL</key>
61+
<string>$${{env.PRISM_AGENT_URL}}</string>
62+
<key>APIKEY</key>
63+
<string>$${{env.APIKEY}}</string>
64+
<key>PUBLISHED_DID</key>
65+
<string>${{env.PUBLISHED_DID}}</string>
66+
<key>JWT_SCHEMA_GUID</key>
67+
<string>${{env.JWT_SCHEMA_GUID}}</string>
68+
<key>ANONCRED_DEFINITION_GUID</key>
69+
<string>${{env.ANONCRED_DEFINITION_GUID}}</string>
70+
</dict>
71+
</plist>
72+
EOL
73+
3874
- name: Run tests
3975
working-directory: E2E
4076
env:

E2E/e2eTests/Source/Abilities/OpenEnterpriseAPI.swift

+71-21
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class OpenEnterpriseAPI: Ability {
6161
return body
6262
}
6363
default:
64-
throw Error.WrongResponse
64+
throw Error.WrongResponse(response)
6565
}
6666
}
6767

@@ -87,7 +87,7 @@ class OpenEnterpriseAPI: Ability {
8787
return body
8888
}
8989
default:
90-
throw Error.WrongResponse
90+
throw Error.WrongResponse(response)
9191
}
9292
}
9393

@@ -100,7 +100,7 @@ class OpenEnterpriseAPI: Ability {
100100
return body
101101
}
102102
default:
103-
throw Error.WrongResponse
103+
throw Error.WrongResponse(response)
104104
}
105105
}
106106

@@ -127,7 +127,7 @@ class OpenEnterpriseAPI: Ability {
127127
return body
128128
}
129129
default:
130-
throw Error.WrongResponse
130+
throw Error.WrongResponse(response)
131131
}
132132
}
133133

@@ -167,7 +167,7 @@ class OpenEnterpriseAPI: Ability {
167167
return body
168168
}
169169
default:
170-
throw Error.WrongResponse
170+
throw Error.WrongResponse(response)
171171
}
172172
}
173173

@@ -194,7 +194,7 @@ class OpenEnterpriseAPI: Ability {
194194
return body
195195
}
196196
default:
197-
throw Error.WrongResponse
197+
throw Error.WrongResponse(response)
198198
}
199199
}
200200

@@ -208,7 +208,8 @@ class OpenEnterpriseAPI: Ability {
208208
"issuerId": issuerId,
209209
"attrNames": [
210210
"name",
211-
"age"
211+
"age",
212+
"gender"
212213
]
213214
]
214215

@@ -230,7 +231,7 @@ class OpenEnterpriseAPI: Ability {
230231
return body
231232
}
232233
default:
233-
throw Error.WrongResponse
234+
throw Error.WrongResponse(response)
234235
}
235236
}
236237

@@ -244,7 +245,7 @@ class OpenEnterpriseAPI: Ability {
244245
author: issuerId,
245246
schemaId: "\(Config.agentUrl)/schema-registry/schemas/\(anoncredSchemaGuid)/schema",
246247
signatureType: "CL",
247-
supportRevocation: true
248+
supportRevocation: false
248249
)
249250

250251
let response = try await client!.createCredentialDefinition(body: .json(anoncredDefinition))
@@ -255,7 +256,7 @@ class OpenEnterpriseAPI: Ability {
255256
return body
256257
}
257258
default:
258-
throw Error.WrongResponse
259+
throw Error.WrongResponse(response)
259260
}
260261
}
261262

@@ -269,7 +270,7 @@ class OpenEnterpriseAPI: Ability {
269270
return response
270271
}
271272
default:
272-
throw Error.WrongResponse
273+
throw Error.WrongResponse(response)
273274
}
274275
}
275276

@@ -283,7 +284,7 @@ class OpenEnterpriseAPI: Ability {
283284
return response
284285
}
285286
default:
286-
throw Error.WrongResponse
287+
throw Error.WrongResponse(response)
287288
}
288289
}
289290

@@ -298,7 +299,7 @@ class OpenEnterpriseAPI: Ability {
298299
return body
299300
}
300301
default:
301-
throw Error.WrongResponse
302+
throw Error.WrongResponse(response)
302303
}
303304
}
304305

@@ -323,15 +324,16 @@ class OpenEnterpriseAPI: Ability {
323324
return body
324325
}
325326
default:
326-
throw Error.WrongResponse
327+
throw Error.WrongResponse(response)
327328
}
328329
}
329330

330331
func offerAnonymousCredential(_ connectionId: String) async throws -> Components.Schemas.IssueCredentialRecord {
331332
var claims: OpenAPIValueContainer = try OpenAPIValueContainer()
332333
claims.value = [
333334
"name" : "automation",
334-
"age" : "99"
335+
"age" : "99",
336+
"gender": "M"
335337
]
336338

337339
let body = Components.Schemas.CreateIssueCredentialRecordRequest(
@@ -351,7 +353,7 @@ class OpenEnterpriseAPI: Ability {
351353
return body
352354
}
353355
default:
354-
throw Error.WrongResponse
356+
throw Error.WrongResponse(response)
355357
}
356358
}
357359

@@ -364,7 +366,7 @@ class OpenEnterpriseAPI: Ability {
364366
return body
365367
}
366368
default:
367-
throw Error.WrongResponse
369+
throw Error.WrongResponse(response)
368370
}
369371
}
370372

@@ -395,7 +397,55 @@ class OpenEnterpriseAPI: Ability {
395397
return body
396398
}
397399
default:
398-
throw Error.WrongResponse
400+
throw Error.WrongResponse(response)
401+
}
402+
}
403+
404+
func requestAnonymousPresentProof(_ connectionId: String) async throws -> Components.Schemas.PresentationStatus {
405+
let credentialDefinitionUrl = Config.agentUrl + "/credential-definition-registry/definitions/" + Config.anoncredDefinitionGuid + "/definition"
406+
let anoncredPresentationRequest = Components.Schemas.AnoncredPresentationRequestV1(
407+
requested_attributes: .init(additionalProperties: [
408+
"gender": .init(
409+
name: "gender",
410+
restrictions: [
411+
.init(additionalProperties: [
412+
"attr::gender::value": "M",
413+
"cred_def_id": credentialDefinitionUrl
414+
])
415+
]
416+
)
417+
]),
418+
requested_predicates: .init(additionalProperties: [
419+
"age": .init(
420+
name: "age",
421+
p_type: ">",
422+
p_value: 18,
423+
restrictions: []
424+
)
425+
]),
426+
name: "proof_req_1",
427+
nonce: Utils.generateNonce(length: 25),
428+
version: "1.0"
429+
)
430+
431+
let body = Components.Schemas.RequestPresentationInput(
432+
connectionId: connectionId,
433+
options: nil,
434+
proofs: [],
435+
anoncredPresentationRequest: anoncredPresentationRequest,
436+
credentialFormat: "AnonCreds"
437+
)
438+
439+
let response = try await client!.requestPresentation(body: .json(body))
440+
441+
switch(response){
442+
case .created(let createdResponse):
443+
switch(createdResponse.body){
444+
case .json(let body):
445+
return body
446+
}
447+
default:
448+
throw Error.WrongResponse(response)
399449
}
400450
}
401451

@@ -408,12 +458,12 @@ class OpenEnterpriseAPI: Ability {
408458
return body
409459
}
410460
default:
411-
throw Error.WrongResponse
461+
throw Error.WrongResponse(response)
412462
}
413463
}
414464

415-
enum Error: Swift.Error, Equatable {
416-
case WrongResponse
465+
enum Error: Swift.Error {
466+
case WrongResponse(_ response: Any)
417467
}
418468
}
419469
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import XCTest
2+
3+
final class AnoncredProofOfRequestFeature: Feature {
4+
override func title() -> String {
5+
"Provide anonymous proof of request"
6+
}
7+
8+
override func description() -> String {
9+
"The Edge Agent should provide anonymous proof to Cloud Agent"
10+
}
11+
12+
func testRespondToProofOfRequest() async throws {
13+
currentScenario = Scenario("Respond to anonymous request proof")
14+
.given("Cloud Agent is connected to Edge Agent")
15+
.and("Edge Agent has '1' anonymous credentials issued by Cloud Agent")
16+
.when("Cloud Agent asks for anonymous present-proof")
17+
.and("Edge Agent sends the present-proof")
18+
.then("Cloud Agent should see the present-proof is verified")
19+
}
20+
}

E2E/e2eTests/Source/Features/ProofOfRequestFeature.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ final class ProofOfRequestFeature: Feature {
1212
func testRespondToProofOfRequest() async throws {
1313
currentScenario = Scenario("Respond to request proof")
1414
.given("Cloud Agent is connected to Edge Agent")
15-
.and("Edge Agent has 1 credentials issued by Cloud Agent")
15+
.and("Edge Agent has '1' credentials issued by Cloud Agent")
1616
.when("Cloud Agent asks for present-proof")
1717
.and("Edge Agent sends the present-proof")
1818
.then("Cloud Agent should see the present-proof is verified")

E2E/e2eTests/Source/Steps/CloudAgentSteps.swift

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ class CloudAgentSteps: Steps {
1010
var cloudAgentAsksForPresentProof = { (cloudAgent: Actor) in
1111
try await CloudAgentWorkflow.asksForPresentProof(cloudAgent: cloudAgent)
1212
}
13+
14+
@Step("{actor} asks for anonymous present-proof")
15+
var cloudAgentAsksForAnonymousPresentProof = { (cloudAgent: Actor) in
16+
try await CloudAgentWorkflow.asksForAnonymousPresentProof(cloudAgent: cloudAgent)
17+
}
1318

1419
@Step("{actor} should see the present-proof is verified")
1520
var cloudAgentShouldSeeThePresentProofIsVerified = { (cloudAgent: Actor) in

E2E/e2eTests/Source/Steps/EdgeAgentSteps.swift

+6-1
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@ class EdgeAgentSteps: Steps {
77
try await EdgeAgentWorkflow.presentProof(edgeAgent: edgeAgent)
88
}
99

10-
@Step("{actor} has {int} credentials issued by {actor}")
10+
@Step("{actor} has '{int}' credentials issued by {actor}")
1111
var edgeAgentHasCredentialsIssuedByCloudAgent = { (edgeAgent: Actor, numberOfCredentials: Int, cloudAgent: Actor) in
1212
try await EdgeAgentWorkflow.hasIssuedCredentials(edgeAgent: edgeAgent, numberOfCredentialsIssued: numberOfCredentials, cloudAgent: cloudAgent)
1313
}
1414

15+
@Step("{actor} has '{int}' anonymous credentials issued by {actor}")
16+
var edgeAgentHasAnonymousCredentialsIssuedByCloudAgent = { (edgeAgent: Actor, numberOfCredentials: Int, cloudAgent: Actor) in
17+
try await EdgeAgentWorkflow.hasIssuedAnonymousCredentials(edgeAgent: edgeAgent, numberOfCredentialsIssued: numberOfCredentials, cloudAgent: cloudAgent)
18+
}
19+
1520
@Step("{actor} accepts {int} credential offer sequentially from {actor}")
1621
var edgeAgentAcceptsCredentialsOfferSequentiallyFromCloudAgent = { (edgeAgent: Actor, numberOfCredentials: Int, cloudAgent: Actor) in
1722
var recordIdList: [String] = []

E2E/e2eTests/Source/Utils.swift

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import Foundation
2+
import XCTest
3+
4+
class Utils {
5+
static func generateNonce(length: Int) -> String {
6+
var result: String = ""
7+
8+
while (result.count < length) {
9+
var randomByte: UInt8 = 0
10+
_ = SecRandomCopyBytes(kSecRandomDefault, 1, &randomByte)
11+
if (randomByte >= 250) {
12+
continue
13+
}
14+
let randomDigit = randomByte % 10
15+
result += String(randomDigit)
16+
}
17+
return result
18+
}
19+
}
20+

E2E/e2eTests/Source/Workflows/CloudAgentWorkflow.swift

+9
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ class CloudAgentWorkflow {
5959
try cloudAgent.remember(key: "presentationId", value: presentation.presentationId)
6060
}
6161

62+
static func asksForAnonymousPresentProof(cloudAgent: Actor) async throws {
63+
let connectionId: String = try cloudAgent.recall(key: "connectionId")
64+
let presentation = try await cloudAgent.using(
65+
ability: OpenEnterpriseAPI.self,
66+
action: "ask an anonymous presentation proof to \(connectionId)"
67+
).requestAnonymousPresentProof(connectionId)
68+
try cloudAgent.remember(key: "presentationId", value: presentation.presentationId)
69+
}
70+
6271
static func verifyCredentialState(cloudAgent: Actor, recordId: String, expectedState: Components.Schemas.IssueCredentialRecord.protocolStatePayload) async throws {
6372
try await cloudAgent.waitUsingAbility(
6473
ability: OpenEnterpriseAPI.self,

E2E/e2eTests/Source/Workflows/EdgeAgentWorkflow.swift

+12
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,18 @@ class EdgeAgentWorkflow {
3939
}
4040
}
4141

42+
static func hasIssuedAnonymousCredentials(edgeAgent: Actor, numberOfCredentialsIssued: Int, cloudAgent: Actor) async throws {
43+
for _ in 0..<numberOfCredentialsIssued {
44+
try await CloudAgentWorkflow.offersAnonymousCredential(cloudAgent: cloudAgent)
45+
try await EdgeAgentWorkflow.waitToReceiveCredentialsOffer(edgeAgent: edgeAgent, numberOfCredentials: 1)
46+
try await EdgeAgentWorkflow.acceptsTheCredentialOffer(edgeAgent: edgeAgent)
47+
let recordId: String = try cloudAgent.recall(key: "recordId")
48+
try await CloudAgentWorkflow.verifyCredentialState(cloudAgent: cloudAgent, recordId: recordId, expectedState: .CredentialSent)
49+
try await EdgeAgentWorkflow.waitToReceiveIssuedCredentials(edgeAgent: edgeAgent, numberOfCredentials: 1)
50+
try await EdgeAgentWorkflow.processIssuedCredentials(edgeAgent: edgeAgent, numberOfCredentials: 1)
51+
}
52+
}
53+
4254
static func acceptsTheCredentialOffer(edgeAgent: Actor) async throws {
4355
let message: Message = try edgeAgent.using(
4456
ability: Sdk.self,

0 commit comments

Comments
 (0)