Skip to content
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

test: add ZKP test #130

Merged
merged 5 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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
Loading