Skip to content

Commit

Permalink
test: add ZKP test (#130)
Browse files Browse the repository at this point in the history
Signed-off-by: Allain Magyar <[email protected]>
  • Loading branch information
amagyar-iohk authored Mar 29, 2024
1 parent 21cb994 commit 34755dd
Show file tree
Hide file tree
Showing 12 changed files with 603 additions and 120 deletions.
36 changes: 36 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ jobs:
runs-on: macos-13

steps:
- name: Mask apikey
env:
APIKEY: ${{ inputs.apiKey || secrets.APIKEY }}
run: echo "::add-mask::${{env.APIKEY}}"

- name: Checkout Code
uses: actions/checkout@v3

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

- name: Create properties file
working-directory: E2E/e2eTests/Resources
env:
MEDIATOR_OOB_URL: ${{ inputs.mediatorOobUrl || vars.MEDIATOR_OOB_URL }}
PRISM_AGENT_URL: ${{ inputs.prismAgentUrl || vars.PRISM_AGENT_URL }}
PUBLISHED_DID: ${{ inputs.publishedDid || vars.PUBLISHED_DID }}
JWT_SCHEMA_GUID: ${{ inputs.jwtSchemaGuid || vars.JWT_SCHEMA_GUID }}
ANONCRED_DEFINITION_GUID: ${{ inputs.anoncredDefinitionGuid || vars.ANONCRED_DEFINITION_GUID }}
APIKEY: ${{ inputs.apiKey || secrets.APIKEY }}
run: |
cat <<EOL > properties.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>MEDIATOR_OOB_URL</key>
<string>${{env.MEDIATOR_OOB_URL}}</string>
<key>PRISM_AGENT_URL</key>
<string>$${{env.PRISM_AGENT_URL}}</string>
<key>APIKEY</key>
<string>$${{env.APIKEY}}</string>
<key>PUBLISHED_DID</key>
<string>${{env.PUBLISHED_DID}}</string>
<key>JWT_SCHEMA_GUID</key>
<string>${{env.JWT_SCHEMA_GUID}}</string>
<key>ANONCRED_DEFINITION_GUID</key>
<string>${{env.ANONCRED_DEFINITION_GUID}}</string>
</dict>
</plist>
EOL
- name: Run tests
working-directory: E2E
env:
Expand Down
92 changes: 71 additions & 21 deletions E2E/e2eTests/Source/Abilities/OpenEnterpriseAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

Expand All @@ -87,7 +87,7 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

Expand All @@ -100,7 +100,7 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

Expand All @@ -127,7 +127,7 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

Expand Down Expand Up @@ -167,7 +167,7 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

Expand All @@ -194,7 +194,7 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

Expand All @@ -208,7 +208,8 @@ class OpenEnterpriseAPI: Ability {
"issuerId": issuerId,
"attrNames": [
"name",
"age"
"age",
"gender"
]
]

Expand All @@ -230,7 +231,7 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

Expand All @@ -244,7 +245,7 @@ class OpenEnterpriseAPI: Ability {
author: issuerId,
schemaId: "\(Config.agentUrl)/schema-registry/schemas/\(anoncredSchemaGuid)/schema",
signatureType: "CL",
supportRevocation: true
supportRevocation: false
)

let response = try await client!.createCredentialDefinition(body: .json(anoncredDefinition))
Expand All @@ -255,7 +256,7 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

Expand All @@ -269,7 +270,7 @@ class OpenEnterpriseAPI: Ability {
return response
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

Expand All @@ -283,7 +284,7 @@ class OpenEnterpriseAPI: Ability {
return response
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

Expand All @@ -298,7 +299,7 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

Expand All @@ -323,15 +324,16 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

func offerAnonymousCredential(_ connectionId: String) async throws -> Components.Schemas.IssueCredentialRecord {
var claims: OpenAPIValueContainer = try OpenAPIValueContainer()
claims.value = [
"name" : "automation",
"age" : "99"
"age" : "99",
"gender": "M"
]

let body = Components.Schemas.CreateIssueCredentialRecordRequest(
Expand All @@ -351,7 +353,7 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

Expand All @@ -364,7 +366,7 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

Expand Down Expand Up @@ -395,7 +397,55 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

func requestAnonymousPresentProof(_ connectionId: String) async throws -> Components.Schemas.PresentationStatus {
let credentialDefinitionUrl = Config.agentUrl + "/credential-definition-registry/definitions/" + Config.anoncredDefinitionGuid + "/definition"
let anoncredPresentationRequest = Components.Schemas.AnoncredPresentationRequestV1(
requested_attributes: .init(additionalProperties: [
"gender": .init(
name: "gender",
restrictions: [
.init(additionalProperties: [
"attr::gender::value": "M",
"cred_def_id": credentialDefinitionUrl
])
]
)
]),
requested_predicates: .init(additionalProperties: [
"age": .init(
name: "age",
p_type: ">",
p_value: 18,
restrictions: []
)
]),
name: "proof_req_1",
nonce: Utils.generateNonce(length: 25),
version: "1.0"
)

let body = Components.Schemas.RequestPresentationInput(
connectionId: connectionId,
options: nil,
proofs: [],
anoncredPresentationRequest: anoncredPresentationRequest,
credentialFormat: "AnonCreds"
)

let response = try await client!.requestPresentation(body: .json(body))

switch(response){
case .created(let createdResponse):
switch(createdResponse.body){
case .json(let body):
return body
}
default:
throw Error.WrongResponse(response)
}
}

Expand All @@ -408,12 +458,12 @@ class OpenEnterpriseAPI: Ability {
return body
}
default:
throw Error.WrongResponse
throw Error.WrongResponse(response)
}
}

enum Error: Swift.Error, Equatable {
case WrongResponse
enum Error: Swift.Error {
case WrongResponse(_ response: Any)
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions E2E/e2eTests/Source/Features/AnoncredProofOfRequestFeature.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import XCTest

final class AnoncredProofOfRequestFeature: Feature {
override func title() -> String {
"Provide anonymous proof of request"
}

override func description() -> String {
"The Edge Agent should provide anonymous proof to Cloud Agent"
}

func testRespondToProofOfRequest() async throws {
currentScenario = Scenario("Respond to anonymous request proof")
.given("Cloud Agent is connected to Edge Agent")
.and("Edge Agent has '1' anonymous credentials issued by Cloud Agent")
.when("Cloud Agent asks for anonymous present-proof")
.and("Edge Agent sends the present-proof")
.then("Cloud Agent should see the present-proof is verified")
}
}
2 changes: 1 addition & 1 deletion E2E/e2eTests/Source/Features/ProofOfRequestFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ final class ProofOfRequestFeature: Feature {
func testRespondToProofOfRequest() async throws {
currentScenario = Scenario("Respond to request proof")
.given("Cloud Agent is connected to Edge Agent")
.and("Edge Agent has 1 credentials issued by Cloud Agent")
.and("Edge Agent has '1' credentials issued by Cloud Agent")
.when("Cloud Agent asks for present-proof")
.and("Edge Agent sends the present-proof")
.then("Cloud Agent should see the present-proof is verified")
Expand Down
5 changes: 5 additions & 0 deletions E2E/e2eTests/Source/Steps/CloudAgentSteps.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ class CloudAgentSteps: Steps {
var cloudAgentAsksForPresentProof = { (cloudAgent: Actor) in
try await CloudAgentWorkflow.asksForPresentProof(cloudAgent: cloudAgent)
}

@Step("{actor} asks for anonymous present-proof")
var cloudAgentAsksForAnonymousPresentProof = { (cloudAgent: Actor) in
try await CloudAgentWorkflow.asksForAnonymousPresentProof(cloudAgent: cloudAgent)
}

@Step("{actor} should see the present-proof is verified")
var cloudAgentShouldSeeThePresentProofIsVerified = { (cloudAgent: Actor) in
Expand Down
7 changes: 6 additions & 1 deletion E2E/e2eTests/Source/Steps/EdgeAgentSteps.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ class EdgeAgentSteps: Steps {
try await EdgeAgentWorkflow.presentProof(edgeAgent: edgeAgent)
}

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

@Step("{actor} has '{int}' anonymous credentials issued by {actor}")
var edgeAgentHasAnonymousCredentialsIssuedByCloudAgent = { (edgeAgent: Actor, numberOfCredentials: Int, cloudAgent: Actor) in
try await EdgeAgentWorkflow.hasIssuedAnonymousCredentials(edgeAgent: edgeAgent, numberOfCredentialsIssued: numberOfCredentials, cloudAgent: cloudAgent)
}

@Step("{actor} accepts {int} credential offer sequentially from {actor}")
var edgeAgentAcceptsCredentialsOfferSequentiallyFromCloudAgent = { (edgeAgent: Actor, numberOfCredentials: Int, cloudAgent: Actor) in
var recordIdList: [String] = []
Expand Down
20 changes: 20 additions & 0 deletions E2E/e2eTests/Source/Utils.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Foundation
import XCTest

class Utils {
static func generateNonce(length: Int) -> String {
var result: String = ""

while (result.count < length) {
var randomByte: UInt8 = 0
_ = SecRandomCopyBytes(kSecRandomDefault, 1, &randomByte)
if (randomByte >= 250) {
continue
}
let randomDigit = randomByte % 10
result += String(randomDigit)
}
return result
}
}

9 changes: 9 additions & 0 deletions E2E/e2eTests/Source/Workflows/CloudAgentWorkflow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ class CloudAgentWorkflow {
try cloudAgent.remember(key: "presentationId", value: presentation.presentationId)
}

static func asksForAnonymousPresentProof(cloudAgent: Actor) async throws {
let connectionId: String = try cloudAgent.recall(key: "connectionId")
let presentation = try await cloudAgent.using(
ability: OpenEnterpriseAPI.self,
action: "ask an anonymous presentation proof to \(connectionId)"
).requestAnonymousPresentProof(connectionId)
try cloudAgent.remember(key: "presentationId", value: presentation.presentationId)
}

static func verifyCredentialState(cloudAgent: Actor, recordId: String, expectedState: Components.Schemas.IssueCredentialRecord.protocolStatePayload) async throws {
try await cloudAgent.waitUsingAbility(
ability: OpenEnterpriseAPI.self,
Expand Down
12 changes: 12 additions & 0 deletions E2E/e2eTests/Source/Workflows/EdgeAgentWorkflow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ class EdgeAgentWorkflow {
}
}

static func hasIssuedAnonymousCredentials(edgeAgent: Actor, numberOfCredentialsIssued: Int, cloudAgent: Actor) async throws {
for _ in 0..<numberOfCredentialsIssued {
try await CloudAgentWorkflow.offersAnonymousCredential(cloudAgent: cloudAgent)
try await EdgeAgentWorkflow.waitToReceiveCredentialsOffer(edgeAgent: edgeAgent, numberOfCredentials: 1)
try await EdgeAgentWorkflow.acceptsTheCredentialOffer(edgeAgent: edgeAgent)
let recordId: String = try cloudAgent.recall(key: "recordId")
try await CloudAgentWorkflow.verifyCredentialState(cloudAgent: cloudAgent, recordId: recordId, expectedState: .CredentialSent)
try await EdgeAgentWorkflow.waitToReceiveIssuedCredentials(edgeAgent: edgeAgent, numberOfCredentials: 1)
try await EdgeAgentWorkflow.processIssuedCredentials(edgeAgent: edgeAgent, numberOfCredentials: 1)
}
}

static func acceptsTheCredentialOffer(edgeAgent: Actor) async throws {
let message: Message = try edgeAgent.using(
ability: Sdk.self,
Expand Down
Loading

0 comments on commit 34755dd

Please sign in to comment.