From c05df452b33d884000848b9dfd0c6781a1d99eac Mon Sep 17 00:00:00 2001 From: Allain Magyar Date: Wed, 26 Jun 2024 23:03:39 -0300 Subject: [PATCH 1/2] test: add verification api integration tests (#1201) Signed-off-by: Allain Magyar Signed-off-by: Hyperledger Bot Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Hyperledger Bot --- .github/workflows/integration-tests.yml | 12 +- tests/integration-tests/README.md | 107 ++++++--- tests/integration-tests/build.gradle.kts | 16 +- tests/integration-tests/docs/static/logs.png | Bin 0 -> 21321 bytes .../docs/static/serenity_context.png | Bin 0 -> 176401 bytes tests/integration-tests/serenity.properties | 3 +- .../test/kotlin/common/CredentialSchema.kt | 5 + .../src/test/kotlin/common/DidPurpose.kt | 25 +++ .../kotlin/common/JwtCredentialProblem.kt | 120 ++++++++++ .../test/kotlin/common/SchemaErrorTemplate.kt | 78 +++++++ .../src/test/kotlin/common/TestConstants.kt | 12 - .../src/test/kotlin/common/VerifiableJwt.kt | 132 +++++++++++ .../src/test/kotlin/config/services/Agent.kt | 11 +- .../test/kotlin/config/services/Keycloak.kt | 5 +- .../test/kotlin/config/services/Service.kt | 2 +- .../kotlin/config/services/ServiceBase.kt | 33 ++- .../src/test/kotlin/config/services/Vault.kt | 5 +- ...PrismNode.kt => VerifiableDataRegistry.kt} | 5 +- .../kotlin/interactions/AuthRestExtensions.kt | 15 ++ .../src/test/kotlin/models/JwtCredential.kt | 210 +++++++++++++++++- .../src/test/kotlin/steps/Setup.kt | 10 +- .../test/kotlin/steps/common/CommonSteps.kt | 49 ++-- .../kotlin/steps/common/ParameterSteps.kt | 29 +++ .../steps/connection/ConnectionSteps.kt | 9 +- .../credentials/IssueCredentialsSteps.kt | 14 +- .../credentials/RevokeCredentialSteps.kt | 18 +- .../test/kotlin/steps/did/ManageDidSteps.kt | 6 +- .../test/kotlin/steps/did/PublishDidSteps.kt | 92 ++++---- .../test/kotlin/steps/did/UpdateDidSteps.kt | 144 +++++++----- .../kotlin/steps/proofs/PresentProofSteps.kt | 55 +++-- .../steps/schemas/CredentialSchemasSteps.kt | 122 ++-------- .../steps/verification/VcVerificationSteps.kt | 205 ++++++++++------- .../issue_anoncred_with_published_did.feature | 15 ++ ...e => issue_jwt_with_published_did.feature} | 6 +- ...=> issue_jwt_with_unpublished_did.feature} | 6 +- .../resources/features/did/create_did.feature | 46 ++-- .../resources/features/did/update_did.feature | 40 ++-- .../features/proofs/present_proof.feature | 25 ++- .../proofs/present_proof_anoncred.feature | 4 +- .../revocation/revoke_jwt_credential.feature | 10 +- .../schemas/credential_schemas.feature | 2 +- .../verification/vc_verification.feature | 6 - .../verificationapi/vc_verification.feature | 54 +++++ 43 files changed, 1237 insertions(+), 526 deletions(-) create mode 100644 tests/integration-tests/docs/static/logs.png create mode 100644 tests/integration-tests/docs/static/serenity_context.png create mode 100644 tests/integration-tests/src/test/kotlin/common/DidPurpose.kt create mode 100644 tests/integration-tests/src/test/kotlin/common/JwtCredentialProblem.kt create mode 100644 tests/integration-tests/src/test/kotlin/common/SchemaErrorTemplate.kt create mode 100644 tests/integration-tests/src/test/kotlin/common/VerifiableJwt.kt rename tests/integration-tests/src/test/kotlin/config/services/{PrismNode.kt => VerifiableDataRegistry.kt} (86%) create mode 100644 tests/integration-tests/src/test/kotlin/interactions/AuthRestExtensions.kt create mode 100644 tests/integration-tests/src/test/kotlin/steps/common/ParameterSteps.kt create mode 100644 tests/integration-tests/src/test/resources/features/credentials/issue_anoncred_with_published_did.feature rename tests/integration-tests/src/test/resources/features/credentials/{issue_published_did.feature => issue_jwt_with_published_did.feature} (90%) rename tests/integration-tests/src/test/resources/features/credentials/{issue_unpublished_did.feature => issue_jwt_with_unpublished_did.feature} (73%) delete mode 100644 tests/integration-tests/src/test/resources/features/verification/vc_verification.feature create mode 100644 tests/integration-tests/src/test/resources/features/verificationapi/vc_verification.feature diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 48424e4fff..813af6813e 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -28,6 +28,7 @@ jobs: runs-on: ubuntu-latest if: ${{ !contains(github.event.pull_request.title, '[skip ci]') }} env: + LOGS_DIR: "tests/integration-tests/target/logs" REPORTS_DIR: "tests/integration-tests/target/site/serenity" steps: - name: Checkout @@ -131,12 +132,21 @@ jobs: comment_title: "Integration Test Results" check_name: "Integration Test Results" - - name: Upload artifacts + - name: Upload serenity report if: github.ref_name == 'main' || failure() uses: actions/upload-artifact@v4 with: name: integration-tests-result path: ${{ env.REPORTS_DIR }} + compression-level: 9 + + - name: Upload logs + if: github.ref_name == 'main' || failure() + uses: actions/upload-artifact@v4 + with: + name: docker-logs + path: ${{ env.LOGS_DIR }} + compression-level: 9 - name: Slack Notification if: github.ref_name == 'main' && failure() diff --git a/tests/integration-tests/README.md b/tests/integration-tests/README.md index 91d175e678..a01890699f 100644 --- a/tests/integration-tests/README.md +++ b/tests/integration-tests/README.md @@ -29,9 +29,11 @@ The Screenplay pattern is used to write the tests. The pattern is described in d * Each actor has their own abilities (actions they can perform) and interactions (tasks they can carry out). These interactions encapsulate the steps required to achieve a certain goal in the system. * The Screenplay Pattern promotes the use of high-level, business-oriented language in test scripts, making them more understandable to non-technical stakeholders. -

-Screenplay pattern overview
-Pic. 1. Screenplay pattern overview +

+ + Screenplay pattern overview +
+ Screenplay pattern overview

## Project structure @@ -66,9 +68,11 @@ The main idea of the framework is to test the ICA as a black box. The tests interact with the ICA through the API and webhook messages. -

-Screenplay pattern overview
-Pic. 2. Overview of the system under test. Roles, Agents and Services communication. +

+ + Screenplay pattern overview +
+ Overview of the system under test. Roles, Agents and Services communication.

### ICA Roles in Tests @@ -397,7 +401,7 @@ The following variables must be set before running the tests: * `AGENT_VERSION`: version of the ICA docker image to use. ```shell -TESTS_CONFIG=/configs/basic.conf PRISM_NODE_VERSION=2.3.0 AGENT_VERSION=1.30.1 ./gradlew test +TESTS_CONFIG=/configs/basic.conf PRISM_NODE_VERSION=2.3.0 AGENT_VERSION=1.36.1 ./gradlew test ``` > Please note: there is no need to pass environment variables if you're using already running agents. @@ -414,17 +418,37 @@ To simplify the execution, each configuration file creates a new `gradle` task. It's possible to execute the configuration file as ```shell -PRISM_NODE_VERSION=2.3.0 AGENT_VERSION=1.30.1 ./gradlew test_basic +PRISM_NODE_VERSION=2.3.0 AGENT_VERSION=1.36.1 ./gradlew test_basic ``` -Also, it's possible to execute the integration tests to all configurations files. The task is named `regression`, it should take a lot of time to execute. - -Note: report is not working due constrains in Serenity BDD reporting system. +Also, it's possible to execute the integration tests to all configurations files. The task is named `regression`, it should take a long time to execute. ```shell -PRISM_NODE_VERSION=2.3.0 AGENT_VERSION=1.30.1 ./gradlew regression +PRISM_NODE_VERSION=2.3.0 AGENT_VERSION=1.36.1 ./gradlew regression ``` +#### Regression report + +Running the regression tasks implies running the same features multiple times. +To enable a full report of the regression execution, `context` variable was introduced to the report. + +To run all scenarios, even if there's a failure, it's required to add `--continue` to the execution + +Example +```bash +AGENT_VERSION=v1.36.1 PRISM_NODE_VERSION=v2.3.0 ./gradlew regression --continue +``` + +Each `context` is based on the configuration used for the current execution and will be displayed in the +Serenity report: + +

+ + Serenity Regression report contexts +
+ Serenity Regression report with contexts +

+ ### Running scenarios in IntelliJ IDEA To run the scenarios in IntelliJ IDEA, you need to create a new run configuration. @@ -433,9 +457,11 @@ It is easy to do by executing `IntegrationTestsRunner` class and selecting the r The required configuration will be created, but you have to edit it to set the environment variables. -

-Running tests in IntelliJ IDEA
-Pic. 3. Running tests through IntelliJ IDEA. +

+ + Running tests in IntelliJ IDEA +
+ Running tests through IntelliJ IDEA.

You could edit `@CucumberOptions` annotation to specify the features to run, as well as specify tags to include or exclude: @@ -444,8 +470,9 @@ For example, here is how you can run only connection scenarios: ```kotlin @CucumberOptions( features = ["src/test/resources/features/connection"], - ... + // ... ) +class IntegrationTestsRunner ``` If you would like to run only particular scenarios from the feature or combine multiple scenarios from different feature file, @@ -454,8 +481,9 @@ you could use tags: @CucumberOptions( features = ["src/test/resources/features"], tags = ["@connection and @credentials"], - ... + // ... ) +class IntegrationTestsRunner ``` > Please note: if you use custom tags, you need to specify them in the feature files as well. @@ -488,21 +516,27 @@ You could start by opening `index.html` file in your browser. On the main report page you could see the summary of the test run as well as the functional coverage table: -

-Report summary
-Pic. 4. HTML-report summary example. +

+ + Report summary +
+ HTML-report summary example.

-

-Functional coverage
-Pic. 5. Functional coverage example. +

+ + Functional coverage +
+ Functional coverage example.

Then, you can go deeper to each scenario and open each step to see the details of the test execution: -

-REST requests analysis
-Pic. 6. REST requests analysis example. +

+ + REST requests analysis +
+ REST requests analysis example.

### Summary reports @@ -530,3 +564,24 @@ And summary reports themselves will be available in `./target/site/serenity` fol JUnit XML reports are also generated under `./target/site/serenity` folder with names `SERENITY-JUNIT-*.xml`. > For more information about the reports, please refer to [Serenity BDD reports documentation](https://serenity-bdd.github.io/docs/reporting/the_serenity_reports). + +### Docker logs + +Docker logs are now redirected to `target/logs` folder. + +If you're running the test using the custom config goals it will have the context added +to the path as `target/logs/basic`. + +Example +```bash +AGENT_VERSION=v1.36.1 PRISM_NODE_VERSION=v2.3.0 ./gradlew test_basic +``` + +Will have the logs output as such: + +

+ + Docker logs directory +
+ Docker logs directory +

diff --git a/tests/integration-tests/build.gradle.kts b/tests/integration-tests/build.gradle.kts index 24d137624b..177a614b9c 100644 --- a/tests/integration-tests/build.gradle.kts +++ b/tests/integration-tests/build.gradle.kts @@ -11,8 +11,8 @@ version = "1.0-SNAPSHOT" buildscript { dependencies { - classpath("net.serenity-bdd:serenity-single-page-report:4.1.4") - classpath("net.serenity-bdd:serenity-json-summary-report:4.1.4") + classpath("net.serenity-bdd:serenity-single-page-report:4.0.46") + classpath("net.serenity-bdd:serenity-json-summary-report:4.0.46") } } @@ -33,7 +33,7 @@ dependencies { testImplementation("io.ktor:ktor-server-netty:2.3.0") testImplementation("io.ktor:ktor-client-apache:2.3.0") // RestAPI client - testImplementation("org.hyperledger.identus:cloud-agent-client-kotlin:1.33.1") + testImplementation("org.hyperledger.identus:cloud-agent-client-kotlin:1.36.1") // Test helpers library testImplementation("io.iohk.atala:atala-automation:0.4.0") // Hoplite for configuration @@ -41,6 +41,10 @@ dependencies { testImplementation("com.sksamuel.hoplite:hoplite-hocon:2.7.5") // Kotlin compose testImplementation("org.testcontainers:testcontainers:1.19.1") + // Crypto + testImplementation("com.nimbusds:nimbus-jose-jwt:9.40") + testImplementation("org.bouncycastle:bcprov-jdk18on:1.78.1") + testImplementation("com.google.crypto.tink:tink:1.13.0") } serenity { @@ -54,7 +58,7 @@ tasks.register("cleanTarget") { tasks.test { dependsOn("cleanTarget") - finalizedBy("reports") + finalizedBy("aggregate", "reports") testLogging.showStandardStreams = true systemProperty("cucumber.filter.tags", System.getProperty("cucumber.filter.tags")) } @@ -82,11 +86,13 @@ afterEvaluate { tasks.register("test_$fileName") { group = "verification" testLogging.showStandardStreams = true + systemProperty("context", fileName) systemProperty("TESTS_CONFIG", "/configs/$fileName.conf") systemProperty("PRISM_NODE_VERSION", System.getenv("PRISM_NODE_VERSION") ?: "") systemProperty("AGENT_VERSION", System.getenv("AGENT_VERSION") ?: "") systemProperty("cucumber.filter.tags", System.getProperty("cucumber.filter.tags")) finalizedBy("aggregate", "reports") + outputs.upToDateWhen { false } } } @@ -94,7 +100,7 @@ afterEvaluate { * Runs the integration suite for each config file present * Restrictions: aggregation of all executions doesn't work because of serenity configuration */ - tasks.register("regression") { + tasks.register("regression") { dependsOn("cleanTarget") group = "verification" configFiles.forEach { diff --git a/tests/integration-tests/docs/static/logs.png b/tests/integration-tests/docs/static/logs.png new file mode 100644 index 0000000000000000000000000000000000000000..776e0643d2e20e5f81321002ee09c78047959e45 GIT binary patch literal 21321 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 S&;ggfjN{K2e!`y(xc*-~k?#Tk literal 0 HcmV?d00001 diff --git a/tests/integration-tests/docs/static/serenity_context.png b/tests/integration-tests/docs/static/serenity_context.png new file mode 100644 index 0000000000000000000000000000000000000000..1470f2e2af174e9403bc7bc55f9e1b00ca0744e8 GIT binary patch literal 176401 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≧TU>mO4_OJy*%mW3SxK0DT-DqVBUvx58VjK~h>MrFf+7xgtk%q# zD`Cx4(uNk51aESZ#Wou;qn>O1Eb8Xc_z=0^587mX*z}AGAp#Eas+5w>4#2oIv6-}q zryQ;|o$7`fXbV=cj&&vqFJq7ekpp;`GfYel&X*WJiI*%YC8`LsaD-IgVLc7bFb~I$ z<=3fO7t;@8RgoP$%0N7lvVNWu#KLjMkFrfokrS8Pb~p2n7Z{87O_(}bupNVe}pO`hKzA}5JDGP^b|4C_M`>W>Qnl2 zVV;HY8=}sVXwU>rL}J1sLdjE`t{no(JSBp1xoMt7p~u{Vu72QB7nzYBox$YTu1=D> zM=N%b#wQ~b$~rcuvCe{pJ~-&6=zO%g;!8NVA)%A@4MD{Vj3vTk2}Vq%#^kbCwjPtc zd|^SXh-Iw`lF$o0(4eKJWm;RZ603(>*GQ%I_bXgp_vEfl=@3;nLr;Z*L`Vf*6yX>8 z@<+nHkhZxV#yi^$bAIH4^ZGfKa7nOc7L?npD$LbFcH9@Pfcw#7fn5ps#ug4FzPVQy zW;9IB*<}Zhg+>vaHzETjVVs&A!n)9bzH zC5@`qVs8vR5HcoGU!qk|Dsz#bn4B1%6Gs;!5s$8z-;MS`0DtS+I>@iD9maig@9Zh<`Us+RajvhmhRy>uK z5RMkyNXUTuOg!|7Xs4aG|A)!GYX~B_W9j)QG2@6_cNMH*;Z?5Lo1B6wjeMX<%m2V) z$<37eaEJL`MI24SV?Po7o>~DuIyaHWHBh`%;b{uIzAB@2>812< zN|h%{vJ*Sxu0}d5Y74~DC0@5Gu}l&72k^ZeyoEoM&sQLrdG=sPHzpL+dIr}c6;94z zv)frY1@NgJRp$d(gRJ%$T07k1F`^=tX`z(@=It8>t5#ZI`w{Tb|$pLoVrYqMQV)PgE@Etm}DbU!wo z_MM);u3iEGJ^h6g;axFk8XB|kFQq?SmbTO9vE*Ax-Eq>_$~~DNp;Nq?l>Sy!ZkPm|NSL?y7EW2eq1wYnw-~=0Grj zZ>aGm`W@% zn!H|kNhc_la5^}&;NF>TQ>$#@*w6CO55ilf+@HB7FD@mLJ=+E86hwr_ z$g!1pS_B-?+M2?RyLJD~q`O6~I%vs+M;t`%A39zHiC=7m2f-Sin9(nrv12@xr0vkz zO}^9nhE$3OTn7^{30<#|^s;%vNkP8*8#{cu*U-WS&>+TYt(}dI-9|nR2JM3yf}v(B zXQP%^sL~tYyKYjq3`7;ZByF~845!(9z9i@NJSsrq1Ex2Ql8>SZjEkrGsG6e*sOl4* z@sfz9UdMxD?Q3yg47Qn(mlZJs={8d~G~=Gf->}%zOE%qh#Mq`KtF*Sg ziu39BXV%+E#HZoflZ9A1Rs`LcG;6#|t&5Ed6^(43MO4JRvBE7fDC8Wuy;AMf1&ELd zt`QaG)s`bOo%`trienHyyb^n?!TC-Rx9hyG(Sj;`X`tC6xhPD`Pf9&~YYT_CKi)dg z$!a9PRUwKffy&uBLmpY=Nsnz46ajWr^bBELG}24w41|`hs8+98YgQ-=TR)Q(CQxA^(d3wgRp>a zQ#c)ZjHDXxGO7hdV>r_^3ENuN#Zij^eb+W^e1?T}MXech=``tJ1Ar!O?i1mOs%0Et zj#6(nTyl=b8nx(JM{Zp9ZH78*PUR3aJNsFR;?Wcei#J|PbJ{5Axq{i4a&oik0d<4* z3lh(Qp=wV_VtvF_lkOC&@>!Q|^dsDPRS}v5FE37UX*&sghXEiAIWV?>uwGnAPNmxvZpRQ)Y-8a6NE160&K;m*OlF^n41ubz zv71DXSCO|gk;IjOVYlZLjwy)s=&4!j+VxCIy&W;HfgizKxDjf)Gy{vO6^dIol?V`w zsGlFy@3<*9DhK*;8;neK7QTru+rPm~p}Ah{$HoCFQE8wqOuw!u`sq#&)}`0~=)L`8 z0ZTDgL~TYdG%=5e2ce?!Hc#k4f`8L`vT50lVNYDJD~G4TrRGD^cVjX%9u78dXM5Yp zf8En|WrTTHadNQP$iGTUF(D0f?91lkZ8A~kOumD!_HO1riK1>_+tCtAH8av zNfc^vk)iZ}wF1xZSErh&{z3RpU<+OMj|}CfZrUU6wG}`wcHkpc?Uk}VN@buHsQV_( z3$O8Fs6QJqj%z@j9%I(VRpKUh`5lWjF(7W?xNI5Bb=>cKe1;<0zW-)j@P;su*VKnC zfM`90O$sKfdy(NIDdfw}$9xP0`PM_aa_J3mJ$at|`mC`s2=bmN&%4wdh94&$L#{*? zLa;bM*omr2)%h!t$oAQ}$A8(yd7RCWeF5IWZO8noG~Ox~EO(ooA^}t~_?l zg+&QVE^{HguuC^?m+3o`BNb+_u45)0lTL+2?VM^JH<-IQ9=tDp>E!wW(5j3NQFt_C z9NEi8j2QYsQ?IQ<`G>4Kr{{jd$cKt~kpLVB>;(=3xgCzoWVG&u=?X{YNlSv9wLGrR zPfcy-M!3<)mC1ZNW4bejmdA$E3mjooKL7YSri#D~SPRdtWk<$qJe+5{Xy3gB$pv!4 z`=+H<{F5*^cJxOZfbf)9v-IgmZ9iQbgX1ZR~sIa zx`mD|(vTbKM>(L8Eb@RwI@9MCf60z`^~A;ow$SIEsazUg@twxfQ2(h>miM!xFz7kp z?5{v&+|kXHY+5>n_2Lp7CiN@H$vSHVrp?@vo6ngYXivZUz{Sm9dKP{o)*mW@zG&5VWN%P80c*s#Zr-1Bu!*k&6JWE{-X7Z7=VHnub+P(+AhHh zdLm7ihwfhPJg=a}V(kK7JO;hWbtbg6M4sj>Et%gsKtM^R^XYFwY$77oCa?6E-)oAA?jQ|tN%=!9>&wRWgO_)YwN|kkLW|DE$IVsy z>S9*!Q#k(bh>{;S4R9e;%dqGX{qro&KU=R`N<+h&*ys_DZHaHDRtmD^$$0sI+Rx&! zAVWwiIQ*p=+!`I{6ZiiR^_F2x$L;$t4bmW8BMbxt2?-gU5&}x6Fp=&YIeIcuX=xDY zZs~3q-3=opM&~o{`~Lr)Hyj7N=KNk~UDrqMCAG!S!*2qn^tTaJb~9Im62n5M4@p17 zz1fL&tduw~p2#b2;*))fFV4N&&wZKLAJbc{{^r|=Zvitt*Je7t;!I~lV^dN~^?v7- zSDQh5D_kSCX=N*#gqk{Ki5V*!#q(2x8-%5(A3rDu2BR7(AL&cjLq8VPQOm4@llNvK z)I8ZA{ZpU6<5|!?KQa>Q^dRIxnBx}QBtef}p}K-Wj3c*81XX_1{Prb}X-K`epChD3 z_YXgD>Rosx=`F5Gm+ezkfjmM_x~0BsjgDPhmT^Db7rZ`go*Rz7_brzYZ+~VYUV6Wm zp7^!psQyTY$J=)5CV6n1|4UPx!OlI4czfo5Sw_F@Ec%S_YRfyvIfu5bfuhn>y;83< zKa0x7$A^{C8^1z}rpU51kNR!KL%S{h{_bQ?B%hI{Sm(^r<>Hj6jrR45Q_psj&!>}< zp{b+$+LdK(gS-M%Th40w=swjY1=o`rBqueIty`TL6^&ktoS;$8b@#xKHWdiQ>t zxjL1{3#dek-#Bh0uM`pSG2i@LF*Ks*8;LYS(ar;gquvypo*rmH_74?aD&5iicKXq6eL8W~c6)o{_mAv9~ zXSCk@-q^l(#13`hMvY})FktqRZzA$hTCtwmFKVbdG2~B;_+zS+}x(N zCgYj3^}m}7|5*k{kxzaZMtH{b{XO1vgO}6cw%$zhee3q}ES(+LL+7aReq@|c#+IkG z;g_e`dFc8S(Snx+V0iG1Gr$0A>p^xgT|joI<7Yp1hzTiDp>&?pFIe6+6An~XapLmjFu+& zwW^G!UKEWhS#5rN^~3qq(Z}S1IFGojrpr+BEu#0|DCE9Xid6WNT^P2U^n9y#O8fqO znS_LovbXCS)a8Thu{eU7T7G1(9VXWQt;mBDvAv7*oZQe~W!QL^SxSEy>YTGcg)T+C zMMg_SrrPOFFt67Wm>Fp^M8L_6%qFpH0Wx2nCPlx`;blHbZ*(vFZX#z4X@UAh=J$(T z?jONM6$UOB{dH-d(j4UzfaH+fSBD*N=oIJ0*I%nNx|xB#=tCAM%j`62K7K6EY|?3d z%5`jCTa3@cMM{{SByVYFl9jMThY7^7`uW!{I+eTLKg{UqrC(lOhgMPU3f_4; z*1HR^oRQg659U2qR{OmoXV$mN2c7mcOrO#09C7IsX_C~Y)+bvR$wTE`%|7smQdOYA z2H$!uN(eG+F@kg_-bO1G3H#TZfF5AO?}r0#O)t}KDXnOcSle$uSX2N^c;TltZK+|` z>wSIvAMybU0w!d_e~$?v-okrDZ!b@0K9P#0Pf-13h}<@@sUTn-&f!_7C2}F!F4n(& zsIctzS^4|WW@5}Py0Q&FxWCd0@`K%q-+XEYWiqZNGuTOKx|}(vT8z~lk3ht;V3`Bs z;T30}H`9&4bu_yfJHPA0Y|{0s%~EMV5xg%{*#bEgR_{@Fa`<-96MlFcEE?bY-+e9w zV?w=XPS?UzK70cI0o~TBT(fG@u+z6UYA`=TJ}}c~4zI0{hFjks5|eYxROHKV+M0KV zZxx&}Xz-13OVOV`eH4y*P(KqI)_HDO_Cs;VJX@Y*Q4KZ>hWF9`(vYHu?=YTGb< zMb&wxnpg^1s8oXOp1%Ch7iZe|hbQmC<8<XebywC9`M)CR&tfg%7k_#b)1 zUzGE=I;S(C>XHfoORU>Cy-;Yx-JdQ|-P)2{$)wyk(mEsZA;Z&X1eq|K9SdQ~rl6*! z(zY(FjW<=ozxE@QKYjZHbDWJh$m~pPZ=i2t_zm({t?=|521tKF5d8>#K{D%la+zF9 z^C|dd^w3P@$vo+N;28RY>GBSyo}TW9jeP$YKhi03pYpve0Cw3K(Tm6W9mThgJTDH0 zChJaSBja*=B}a;$f0WXeuGW4{FR7^`8@I(rx+ZP#)_*q2eZK`Q_vliasSFyef06jf zh;W$;k=1KiqPc=**YCSHs`(A;bkd44p^Rt#^xrvf>HF^-OqnHTI_p3L_`} zw|nXw;|^#Drty00LoSfi*s|Y^_MTTf<#*bazodqp?ute`IXgBnYAkqCz;S4E;@=2) z*>>HorlExT!@HO*+6%#~Gx8UY)GY}_T8Li99_VJ=Eeos*R!Z8Z%Qts?B zhS-YoT=LFBL>%HhQxb3>R&D&|gJ&yYdZMF)toYx-mt~O`OHCk>)fKt`G00s^E{uwk zPz?N$HX1zoR9MJGv@x5Y_04ajVF}FpYL3$ZD3#Ye3md*hn^B9VU2O_+2}I`aq61$# zXLMXo0@28dWS9&IDD@5At_Upv209Q=vrF=1NPExMTyjQ#M=nOQTqcUFpr^uObf{G+ z0z`rb*F>Ho{fkRHx7lyVNlR_=ZJaEcGH_aEJxf!lktDyRauL;Q7HU7PMY;3l&(xHS z#XU9{SvNz_B2NN5nC(P+w#H)xck%Me-O*wCIF8SXP)(`YM#e3X?{p8X5xRq`VXF3* zoBcod!1_;QC(3yg4`)N6#)~-6ef_9pabGVEe+QG3=qmiumx(LWvA#zRiJ6go-Kaw- z?+*d7`86u5T2JPo(>e~c5Vf8Shl0<@ZPnznua=r)q3p(^A|MUAb^O{jTySZQqP@(S z)W{#Vg#^^+g0!=u#))m&O;mFA$v9DDsSFc zd8rSYZ(m~z<5(~6IFhcx(tun(FTp%U`qE0#YlK#m^R(OHBi0ym+fAbO{kqpbp&#=r(}Pg|*u>2P z_t$0nNq>84kkVM_ahpV*jQupQ1`=_yIX8jNMZv6ZpHKY}?-^x0p6*x=$(6q@S)wit z-fQr8L0N*~3|uUzI&p04TcZHmlG`9=Ty!ZU2WddHt=?a8Pm1_{Gv<`y0UCx_Y7DvF zf@(B6Hs~TgR^IbJ3T$7f+GFisTefcYQdP5zTTU9w0w;ZHAUnc!IYk%>hasMfdp({3 zU-IrTKBr3>)JIbU$kET^Kz8aSCISL*Fzv4e%5NA6$ON?O|Y?#%EwmcDJqOY60HJ@Dl7fpfzT zvJ<+?C&u;Ifx(56%!FXaCR5ST=gbk9BN@0Yfnj}S1UwO8hB6T7G zX>sVVsHM;)k+CI~{@azhY>7Cj)~3uEBC>cVwQV57eN*yn#l^RzF2*q%nte9#ajMq# zJfz7RBmKQhy1q%lDzf%a^M=GCrc7r3FVZ6$CgU_Z1^z@`(%sfvz@F{S4|;Vxmokyu z#CukcSwi;`H6tVXf0MPJ-<%f}@Kx++rKROav~A!z+ivtN&z*Cga?l$QvFL54~zd9S$O>)=S68?&i z3gpOmwcxxQ{dlha%o60c=3Dq#1Lw|{-VV1yEei!vu$ZYSNo?@jGEUE&bYRg* zV$$|da$0{50ilJT2!DJOUcae{#YpNv9Leeubbqdflku3$1cq-_Vw`EU7xe44;M4D~ zynD3%C42ODZ`piy!*2ZuW#bgOY{gq>NXxYtT%A(#P&pgIb?%3q zQuqw1DrpDaYF}U`s};#F2XQD?{y7_9K&D0NOhQ#bRw_$oE3XHfYvYni*6F8Hn)+)tg{17t9kyKuAsj2ocSG7u)3`9%-O8P9Kx2K z5(Cq6r7PAwI3Joqyi6rUPa=EO>CCj2MW_K5hJi0T09SN& zFI@8b(z}pnPs`v;f!dQS&%$J>dYLV)ya*Yn=LhWwtYZ8c?94-ihvf>t9l_ z(8h*~kaVdl9&wN)$X!0!CHii9Ri~6d_}9)SIzZs}saHK<60_@3oe5Et?#+H9aOA(= z50@yGWZtUA7Oeus_dfY6l46W?(S5#u#Sw^YqWCSP6uuaslqT8zq3RhOXn zXx@h!Uvy*AoYBdeKA3bA^8EUyDxQaURs7d(qb1oT-~)oki=A{!- zX|ax!*Pssf_!pi}Kl-II<4V(Pu$4O(Iv2whFp0pCIDoqx{R)FT(V<(I7xf8Hv7;k1 zL?=j#0STnZ?cCp*h|jRi+s|HHBR=t&3m4M)&055gXY_8n_sDMW?L=Q6es^JJJFald z73rH_#JOuL+zOEQ0(up^Z4d=VM5wr*KM(|)>>_g1`ZD&y? znH2qfz@X3l`G5*jXzym+tKE}2M|j6%1N-+Ry{jjZU)wOyh7A%}rRcLUj+6)KP~x+@!(=s9)&1|p}G$erYXX71r-vd>U| z`kmZX5Br`(9gO$6Wz|pzyx0JpV4l#gIxII#F^1)am37vMsgGYDz`9le6tJ?>H-uC( zj58A#M4&PMI`)flwRp@VtYFUFs9H)PX1=J%y|{EC`HEH7f=j}0Mo?>IB$po??vjbY zJm2v#d_aU3CAIb-senE;E(1xyHP`s180s1I1;P`J%gb84c?qidbRhHEiJR5A1%d^* zSEC>yl>xz`I+c=N2SO){V|7^sDvGhPA}92wrNuXAE_N6wen49@p;Nj;S-Tt;>z=}u z?viX1GG8WvHR^C8=hSTtW~n_4g6ikF{#B1k9IC(GW6wN^4b_^|{6<7pB_c*uLJhOj zT*b(zx9bs+rm%UPhiJ{R ze>RvH)xV8V67}T0e@}C!+#*lFhT%a*H>Y!iD|gHqINSV=ijj&e@GU^LBPNP3wa4YX zErTQ>$!>jm3b890CFGf>(X&At4?ymSIUC3$K7xOUmcu1`6t&9UCe1mLh?2G@aAPrI zS*dM{cSdg@a%N2?ip_>hJJh1Crf9OWF?px#U8w!mjor5Hvzj(>fo$&W)_;`wREmmd zmt%VGnvpJf!F3tKsIKzXG=TD!(5fWm$Y2gIfYRct;z8h`(I+E+#OrF-{e}phI33K3 zXKrZRI=t32#;LFgx&;D|-kcL;i_BCmjCWfAxz@%uD;myuCP+xME=@PcL1vRv%u{0Q zl44N-Y>aiI6{;Qa9CAzfd-o4^ux*P!l41FOWPDzLwH`y(h1lFI<7^ASb&_msE0eoa zu8M670r1GY%jR~OM;+UuyP=QAhz;9skG@U$O<7J60I(7vsuX;@YH;2Ct^$TwIxJ5A ztQ#=;>9tn78g^jEXrP<}{{adVoUH(P@97@vncMXikyoSpJwrGXV(2qVFI+G(z7qMB zmY*33m^(KNs@b1@0ZZf>Q51k;MCBjqJD_!-Ay)nfHCs}{_e2;o?x){jKp{-Gae{3Z zyA!`(?h6&GaT_<0Ql5Y)P&)UGG+k+A!duig${H@=$aCI=nWc)P;it-1Abp*!C-vvZ z{t$6Y(_|9Sz(?kJ5>E~Mi8@Cl6mKDBk4vR(>6aOJk=o$G2c~H9W)ktLXN9ld!w^`& z&Yl+h?ptB8)8&(8@1tL}uXM3!TRwvH34*sA(_2lDzAuc{%Cx0iQAW;xVNY2N=Q)WQ z1ef-8;G)qQP@fZv(zAEeQ zet6xV2WuV8#olJPUisnOxisZ^MfW4@f1;kjjV!P#Pbg?07L5#B zD^!v~HsKZNl@ zcW@*|TtKX?BUI@bhh>f!n9Np$u0*~!xUK!XEBhmkCRSDEl5w>dxI8AvuV{BTFu&So z>BK?NCG|JLuTetUaNG-n>&~e)RCdVib1A$Mo$AC4?kAG{k}BNtox%%jUNT_YDJzz< zYFUWo_)d&X_ebxG?R| z+n5{O_2~9n!b)0&!(oFj!Pm)h{LsMJ5qO!FFc(2aRW{x-Z@DCN6w|*3?K|*yK_6~I z>;(K}^#kjf4W5??ci`>h_oZF$l<+O|=EOZM@-UNz^dGb zdJ=0dGTpPbdjgFHw`GF-Sv*(bAyIeZ%oq=~Zjxd{A%*5GXsz5RYlfeHVT#(X52YaF ziL0h-6b(^-+(MU$RC_b-jL9YaYPXOub!yLsDqC9FqIW||&(4fwZLC1}Ext*S_RwX? zUlQ|Gxu?S7wi6;)GsGs*tIqF;VHas05;$Cx`|IyBebJ;FwqLQnka3}K49St%(08Qc z!J7(U!Oz`{(OHSr6vhQ(@crFNC2Oh8K*_UakKqo z9+H!e9{Hz zN%H*j>%(#$S>K`>(rm@CukSyfZoW^h{6{IsNT-FBxGlGfNP4P&cwxa=_b98;mk|Tp zrJtC+Sm(K;t16H53`60UgwLx{J75)_>X&5DW|_}_SAjRnF_*+47S_;G{R}H&zsuPs zk^8zpn!9smu9m4Y8uMNg&f8G@dEMNSTgUFX1GPXy}zb)fvg6 z>ehsZJ4kXR$A#8PAABWnCx+0g+!&}=c~?IxakH>@j12g)+y5x~<7H0|taY%uKMD9h zVf>Xh*x$zio5K>}TWiE-YE2;&!gek-+auU#1N9?drrvtem;Wy2?c!DO0GK z#QdAJr!OibYWc6Eil+C34mb~VCQd(VP)TR!31NO=`)jeY56vvT*8O`oV}24g3E^&P zGb6SIFff%y7^y$|WM;f7D8;np8rg@RoHPNC2Dh;512J?zy#Ahmgv!ko<8rM_=6aX@ zSTNz)VS{279%3<=3sHen0~|wLdXZlvn%Gk-d~rl5kgsOQe%|UanD-MSIBmm*^0%zv zLc$zjLD?ejaCo5T48KxCdUb;>p??giK+;HxfLmYoqRR;V<7?TjuOGY@`7~@309{JAv=1j;lyzQKweS9xmXDH9MVPf?AB5?wG&n8s8ds zX0^h*kO9*~%nvy{7)&HP8>Y)cu%sxFMCuYrd=jg7Ce~j}jM2I_o*ZsEb4B(F>yg$Z zVV~R^BE9h_#9pN^S{8h$Zxh;=jcgRvi z(-@QSOBXc|N$@;j?`aYjMFYy1ieqJ&)LQ??63=6Z#4qKTFmB+xDGuCeFug6*GWk8g zlH$rm6id_~F59^6Jn>ttD38S}q4qb^74Af3hG;2n)D;Y1`j*ks_2B+?0-dW3wS-i- zd$(at=rjFue-P9W{3N*&EWw;8)%}fC>d)^>cWaZUFY^|%eG8WY1tDk46}|>aX0I^d zS>Cs&)XsuR{HVWrYE$gSu#IfV(cEqS)GBy)veAU1UpOjh?`kvw()6wx@|lWb+qEF3 zvHt**Nmo5rLp3oHXksM}>cKb1hU*KkS_GpRiU&b^WJiHj{yJx0sh7>?$^mG!*lScij{e+sWn?nW)% z_ikN&+Vw6|Q~g!;=XizBZPQe0VKV6dO-CvEbr@`h*;jpAW1axQ> zGvOr|_QF#wy$O|lsH#m)K?L&*Q!eW%2QLFs0=E1}4eB#lX>++5dGPD>ux+q0<|Dmj z`YSkn;~VuPF?M=WTa~l#3m0Kt!i?)VwbAVi)TevGTtV`4Tm%=CPp6p=t(Pk^M}TWI z8oDA5T&JE)NzpNYz&E1?gxe~wf8RDOigM&tIDTtLA6%kSRGyUL=pL|JmbeN0TSdh| zBt1I~l=G=LF)Z}CV#QkRrikIJ;qr$wzi^xh3~Bd5SVRpCUVe`1A<(0mVNW0-5W1>& zGejB&+T_AgjvZRuX}ssCU!qflsj8_^YB=#s+SA0YQFgn70KAJCW^VNDcpFm#*F(r08e~ z__7|YPSgj?0_hfKIow(w_xyQwE#hE`-FYO}YT%RG*c=b~mH|hIC{y>|n+o!AS+CN^ZmD)>qh&RVvthV1z2|zJTZ&9aX3l~_%cUnl>g>w<_N6l&c z?%udHExa2KU`xUFSJ=SQ=g8;xc`%C&&?$T1o|O#mh__h)lc4ONw6TGS6~4Z4E@9YI;Q{QEs&L?UgaUabGA<0klQJIn0YbmA2wlXS6zAf0Si=A_xYR_iYgUcV9Pl1Ad5hN0+HeH)vQQ=$$`wS4mHaP{8 zU&e~*Vvg}G-;-5Zgu$ViMCj`K1z|{`{YM$zFL6QC-W<}{SR4soC@7gV$3}iAN~UKH zXEQ>^ewkA$YOwe>W32AWd+O5d2MWSK6)j7IF{RQ=G5nwo=F2j9VfjjCDt6{@zHHNn zDQa*0UM$IALpu^!UWNF;Zlt4MWpT| z*+v&0bahz65^lmQZ_^Al96T3fMWt}-!DpfSz31K8BYWc4i>#+Mv!&#Wzf~86Z)ARq zSXDge6HqNWE(Yx8Vw-PW)rDNIK`QB>&cb2ch)KpO!ArcH#D2QS+$ z<+iIyPhhy;p56fE)VgbKn@Y3^<+SgrUQ2UxaYu3F3R5%iv*9-0|2M1KyRoMu|9dv*y|msg*XLoUOBz zDT0;gTc%v<4##TyhmUBRJM!E5QK2ShQxOpPY!aA-t9_*J7F(us)%F&mAX_kNG|Y#_ zrNSobn1QxM9llo)?0%exN7IKOt*8+n3wO$PL)kLCFEYMj=|m~L1@%M>2;QOfOW+l1 z7H3TR3f%FvVfvvFEtrw{3E3?tar{0{*qX25EbtmhwX^$-ez!AvE~5+ap$kHyM-KVy z9Jg!U3>#d};KUY_If>#7_S9e5FBCXt-g2MsO(X~Z0jr=^$iM+@Q zHJ@(f2~ZrPf5`zomu1;&C}C8{77Ku?+}aB@isfA$#G~Vkn2XC%b!B=qp{Iwg2E9&k~r%b+}`9F<#Bjc^&TG)NZn3LgRQJ{l;2;6;= z9rFM&p-SLp`E-n!2U(u=CtYbPkIBovFR5c<*0oBLW0n?DIDxf0Tfdev*ta;vvQx}7 zRG@9gkp}kxeweI0>%jb25|#}x7~94sFwY+4r0ImV(X9GGZlsr_*gul)#@}i*yRI~t z6yUC_zh*Ho6%l&#@CPo~J1(N+)Vw2Hj8cPl*00SYC!)^(*bsXHitXZQg;_ncN zC3SdboX|$Ym%&aWowu@+pFe<-BY&wzoqc=gsC>3^TisIWSiR=2&&R=>7{GRiv8W)E zBF`=ce*JpgYIDIsQSx;VclfxA5y4-!wLyB)pw4^B#}K?H=x;V!kB+D6k>tBhQxitAV@> zkN<%ypiCK(Ba4Z*uV1Qlxglw5$R;haQUo$l$PbaX;Hi>~L9n+_yR3{Wt|)0}I^Ofi zX#6afWZvxL56kOa4Utt`Kg-go?3W^Jjn%mqri{dC~Ou2lC;N2cZ`}mwS zX|I{^k{S5P$`91T`j10ae;WI{*vyIa`G)w?RA#j--`=6MjJs?hpjNcX14QQ<>vHD` z-8{UBpbN_RR(GSU>L9xKy8=&hg3?bxzw(RI3o-e*lbL~*6Ao-Uv?E-9kJU18cUuxM zDl4G*PlDp~E>vk=<){&^q%s1qOx{*$Z=;z~;a=7h?Cjq5yl}z;KWvgXh7nL(xNZme{sLdQ6S7V#O zf??MK$}_vAX-bPEGc)3`3&)>M zwkabn^s>+G)W|9te&Iz`KA|I{D zo~@i5DD?W*X6>l@~GJrX9hb&UCRA zuC*|nTKa3KEA+wehEWm9jW_$xx;Jube&4PmCaf7nUFU~4glrZxq{C)u;;_zmcau%K8d&0?akw5TN3aSYXn&?r&TZ3U4D$CHJQ zt8L46UFNLYe*wrIDgfaoVJ-kg_@U}1dx8vq5^TEfllD6e$@d6+J^KH`PnckMCOE#^ zq2(oD3S+d+OZLA8HGkEBRLgql=|#fQ-YPy{uNYr8RiQ*Grb1n>8K$knxvp7x63(a{ zgK7F@ckGz~?}vY!>{B{wbjf~RuM}&p`y^p4T|CK$CV>|Ugi-Mf+_e?J-O&AV5kPbQ zFIwSWroZm~`DqVoUR6*h1_nMN&PabX88b_Uy+bw9jQZcnbO*~vz)&gfFR%+}*H=KG)f za+OzfM{fzz(goW64dET3h6h}w8UrJ%z7$pzu zNnn>*xATbz;WP!6alf+z4o8-s$&jm!I+hToYd-8e-DxGPDEO z6Bg6G%2WxX!k?IGO&~wN7m&?(ZNM{{Q7^79NV4d0b)^-zVAYxsluJbe^f!N~7SV5xSw-E~3tU=uk^V9o5g|3Go5 z9P>_ukzi4J9`%lqs+`jH4H!;W3U8plpYq>WrWAenXIvhTn71XZpTClf8MLI z=KR}BsC={I64Y6fvy~V?eY-|y)fm{2PED(7?46f_1Ak|$@WlpI8*{b(8+K=o1M#CB zXYQ~8hc0~FHty^t_)FBBs%9XTa4O8tr+u|g3TfSehyS+`bUMjd&vDfH=vQ-4I+8{i zz<)>2SG&ZT3L~Ql0ZQYyaDSo3?}IY(lU<%v zG(q3m%;XL*h^9X{C&+L1Sk$|<%1KUd0StP>Gl|Foe;M9EmZ#jr-HH!MtHS^iDqCd= zd_60A4YpN?a4Y#S`7SW`poX+lbEms(>C6MQjD$|~2J!g`P1icUoiZ82b3g~tZ%R~+ zNOR<{JvGaXI!mLgLRb=sYDR#4+ks^!)@|9fUKvj#X$j&eWo_WZsNN3@oQit5kGsKL z?D1#?U*X{OQ#<<6U>1Kdf&=^I##rl@+jzq{tJi#+2n)I8mSWk-uYN*3tV*gvk)8J> z2)zkfBQ(FvO`3d*yP86WyQDzDpp_<4-k;RfK~@t3JW+2PsC}aw`A%KQxU5>Q*4|fc z->sOR#+goZuUO2RsgV6IH^h8sdYAt)5I~RtVFM>nR_nd%dul<`M{uPgjHmHc;@l@u=09WBry+$7$Zd9YZ*X>bQ2xF4?@U5+$+R3l)m!XNuNEx=mAr4fx z2uv{qP-*qgWlq{U~>Xh`Hoo+yyw{7^J3rjE*sup9;-5?v}8Qsc#f zuQ7n!pupA<^d&L9-A~jSrszMmpX7TQmN5^y=pWviy&EVWiAOy=by%;BMwVN%EID)N z`sKVlCfs~5Tk)uGbW4vEAz&vI{F%EK@w0oU37i0T3dvtijk=Xo>~z6SFY0IobFYh_ zYxuFag!wy&kWpX!O)$!;@EL~S&1Tt00#m~tJc}hDs0r{kJ_lYO_LVBR z?D*I2-EWh&Ruy`2ywqS~jvR~yK#EkU-`*D_C4p|dHb|)|4#hwuwnO;K)rU;oEOVRPmUadv-28}^}xxm`+5Uyr+4h(}admdCA zKc=RaifhESp^JP4l`nL`f<-VipVtv6n8Z*(omc>0Dzn+)Tv=u-P@E!{59#?K;-i7w z&%}p2HOzVa1Q;dx2*AvB+lM5lbjn(C2xgKfB|YT?PMO$TZLDlw7m;RaTM1vz_)?9S z*o+CJtRW5}9^1|Fd$91*Z~S4%?aRxw%hr+7i|rfNbWVcJT6Nsg<~&ZQ>n)FR^sgw) z{AWdG+_5Jl0ZTZR`&(#OYs6Uo>Q-N$wNZn4cVB|@2vN=5c_T-_@OS< zt{aSP0r8P0CxY;<4ZhE7n2EiHnP9Z}HeZ}o2Iur9P*@yeEhr#)dic1eEt}4EqoREy zTmr5U&R$%;nzoV3e*JXEm1oX zhNIU%PrTZ)ly~uVq3RhkkB)Yvkw1}07ww`Ra;o#-!#|^l4CTHV7Jx)&-G58*dB8}# z(xG&*wB%L*Iy5yUu{}CmABO>To1zZ?-p7~rJ-tMujpnMC-zE=ccAL|^d3FbO-iNdl z4p{z7Y746JqIpxSXQC~>RC3P#hi&G?#l}hWb4$#4i)8mF^Hmn3O7ZO^S1B)XSaX~j zyq@jp3vgJnt-m#q5Jzy)K=?Agf-%i1ooc_TtTu<)?1*fjD6lzRW<$8Zx3m@Tn; zlSlQRA@hq8YA&XC z--&L>vfu30YgnD7ZS@veB`H^@LoQfk-6OvlaN(fK{w3T3->xZYf+Ixij)ZQjGMv{% zf^uZ|@-z0^S+R#?QgK-`2fCANs!_6XDQU2`$E*1`5T9{SZpSB!eBn$r2g$ZKirJ(DAY~QF&$b-0M=?nvOu&3lXL)z9DFvjDO^P z9xo)_#WCr4sbLu9X*p>!vs2DAL3ie4nFx$gX_m;=bTrSF(DH(FmreJfVGH}*5FCi& z*u0uZpit+y1={7C;os*0tOYfcNMFud8QQDHu7M)kA+p(@%>Ygsn3oC~0f~Tvo&cSA z+x>GY5x}UR*YI0u0SWr99tD;jXrO} zl^;Q@xce|%=!&Tqj$oWO&{^xZ?%P&8 z>VznLiB@s@wf!&rdLrQLt5*gF%h?Syq^b?RH=PG#o$YaN2$r^1YSA%?7~@$Z{YGn|y6yp}R>)u^qx`v01jEs4>{&N7S`9~-Q)!^fy4sNpws^LP`#;#e zh;CU}*V9KPZNueeP<8jb@e|^5#V?jkJeFeMNzn&=_&)%P-Cda$GJ1x=-p^kdVDR*f z@c?K$o37TZPL~=UU$T9y3zK+Xy39lT#zKYgJY%6diK3e2UC}e@w&*h`2hj;RhK7m& z>z1UBX3Y-D|97g)}%e#(eX679a8{BsT|dllNG=J5LGmZ`OfRY@{i5?LPFL9X9L%@Ckk`JMbwCteYASiVT*-w~+8$^hE<{rZa_qRT^57-d@YbN)~cj`k})erL74(cyDgm z*(Ro`p@6w-J)C=${m;y-VNJ?x z(w?-Q=;)FFc?mg_Xt6(7t^x1i6-99o;t`N<-ci z;z7XMKVC(!)sJ>R+>xvmv)A%*z9j$Js4oFo?(AE#YpU)Bl zTNdVrkGs)p|bxTu=x7gj0*N>&CqqAt$Q4_NGL$YVQ0YIh$7@aEOh ziGPdN4M)%mm6FGkkqecw43Y=b*vx#{6X>BqdgY9I>Bi~c$QqYe@TT#Wg?nMcfvD!p zIb$I8$_dg}Y=h8lOwNZvj(#mb z5&r0JQge>ie(CgbOmOu`su(qZ0<4$bIHBKt-90ZJcAyktWvR+;3=m?+I{oR}mT zBWj10(OgVC$|kiw91bf)0Mhl)9*9!66_%5{q;{X!`lOAe7)vOsrBsGs?XeGBmaSik zQQs1G8rXp@0aS?YS|dlFgqWH~x=lB-znYiXyMVdrd~;Yu9NT%Um0Ou7rcJOEmrSRI zL7jGgq)olF{+DFf`3Ta1_r5tDS9e6oC&EbDZAX6u65W-eVUi1;rz9OmY*rV8*=^0aBaga$?< zICLU%%!$L-VE|@Jd=iV?m3}FY>ZnbgH{J3}fE>Ga%GF)1KSwnBC!$oJ2uf zZv@FvK)_KLr2J3c<#b?!HVx^dx%>5~HypqJ&q(*JjGnNU5S3Xz8WX0A)H2dN*$;|s z+k}S(lddOj@(-?V!j?f#H`#X2rC!+#@R8$lNd}?Gfxbm&QO#x~{J&DT2py$i@-@Ns z@4dF@la!aCN^w`F#>h=FScDP59rL$74Sk)ef4*i7;EufzY#jiQX^5&qRGNfHFR%c1 zoG1hCu5LeHt<^_l8u2i^Zbo?!mR(=RK1k6Q!(??!u^*xev)^+8aX46cw&_KU9+M7{PSuhl6s^zr{_Qj>Ia6 zQeplSs0gX$JuVI8d1-acN=NHId=aVh%5uZ^Locd7cvpB%|8(PKHS5dvTE>^$J?)B% z4u4cGuGTvGvq$~k(uS23{pyb$x~w-itfiE4;~RY*=2&(RzzLc88!BvKNxZ(Nd(3H@ za_C{t&|@*+%q&UP_gt2keHIMnl=+#cp2D)80r!_|X`FIlER9$6_fqICR{5L`=>@n(aT@X}g!yM-c+HX1 zFcI*4kE_5OO^mlkYD3yLD#nGED1w5E+PDL1oSmJ+AMkPZ?h4UoJ&PBmUz|ytIpJCF z=+tb=xA_txK1?)}Q3RX>v|tsGU6N9{8=&*FVSo|zu}0TE6lo6W%FO#VUTCml*E^X) z*%bVHt{jf}nQLXb^T2zvEV%;_G`qB>3l(ehxRH4CsC%WA&m8(S7%WdQ{11d3)ut^{ z&~Dh%L1%O9T;m)m8|OaMatf_)kIVTa_8&T1-T)G>2cX;AjfA3kI~ zE6K{3bB^+kcZ@-aA}N+siNKhCnlChtuc^4p&1Xuyg4|FB2$tx~buVHh{XuUfMj!HA zv6sLH_QAIwu4sh3COw&zFOZOn8|>gqMO(NB;ogbb+nSVQP5uGXOnv=1HDb2u8{8aC zF;|~uU1hqg=w27eF8X}?Trk{(ue&T_wi_5I`{gCl@Svvq#gjvs+=2y2R6Du|8ba!1h7p`4z$ z7sEX*SON7Y?*43HA;)cZGm|bEfTVdy-iU3Cc}|wCPc}W|4y-)WmoC)^QDhNAf`!`H zC*#7R=bMc$gx8iGL(z4JK`BO(@XOYw^spDNMEO=ck0H)MZLYg($EtOJ#REgB{N=v5 zTrIyRM(BQf#T)X79p#VdEQ2R+=tF=Bg5r)WTFKHGms=c6tRkdGYWNd8_nM$|vV&9e4DY{J0dlFni*Deh z01v_mwbDcVr=vJlZ%>wuJ>i*PpE|;)#8!rPlb`8GG9A+r;7dbL|{ce$TQ`a`kkE%ACL{ zr<%V}j10VYCKYxf5F;J->bKXVE__YTc{BmDc` zNSj@(P1Z-Ei|C*&zW6YL3G==2z5A;+39H@73?Qm&AgKu3?Lba^JNAlQ=V!tr+$b~i z4{7RCIs9wZ~R%X&R9Ps@e*ghL7PZ&SzJgPc88Ec)vs$%6PBDoN~S; zf)xDDqQI$jl1E1W?RCZs&NQ^zXQy}m0aKPZpt2A!EoJobZvc!_m>IxwRT>=;;?p!9 z);=>@XkL)51J5eKe=xI-eb}F-Wai5%=Z^O%@o|`9B{H$q&o|KzL!7~`-)p>Zvb*o& zu`V^jRzN2)xv`vw7CCGWIAS_dGW5FU&rgfL-O|c*N04 zOXk$pk@B711o1-XQ!91lL4j(p*@UB`bPb1*7M)44Bk(J`7v2=6VN$L-n_-gDav zc_^-&xg6eW?2_Z#E+$@+Tv{CnFk1O%Xq_8?JOBOPRNt=(%5xP2wX<`4_ZD^~?HW4? zNjNW$^P@^6ll>HDkdC2b%QX`Tdih zyX?8T)p>v0&abjEB7RDPe5(?=QmW`783R9UxPd7d-|t$}OV}wp(cc62w{fo`D-e>{ z$KTVQZPqXsl$N@mWUSDes35GD=PT!e`nPnt#0~;@WyTtWCV>>^a|;9%6qiDbe2)L9 zq`k~THTkVUsy(QDlTa%)xAo>SEfXu#;6ESuw}_Xkta{!i<%drOLrvWze798YK(91b z9QgF)V2zG0?hbl&uKy{de=i5{SL1t{KDuH1d+z~?RW7$kF6Lte6uxIGcCcZ`@0@jT zuz(q>ADCGg$d0zY!v)uMBssHj_Gkb3j{p2L=PLlF#>_nR`+?fOAfl||NuLJBlS@?V zQk!<~xve~Q<_A@5VAr(q7AyI`cJ?c@h{nt9O&Rvc27d(cgX97b$K4&3Jv(@t+<9IC~t?|2M_bYu1h9NxjNWs=3-w z3VLwI^1xzyHv!C#i=vnuJy5FVWAXi9)blqB{)ey{b^a6#E^g~*SMlP{K9jD41*L~C zIEmng!Hw5L%T3e%z0?2tSMPezzmDB;QHW3C2K@Gw1m8V@i-#I+T#uA}6hH3#_i_ZX zHF19~+49Ywb0e_l0CTkO7~*|M{iD3ij=vKu?b?f?%->tVB9t+jN5IBu$EX(Kd_BgJ zb-+@-aNM&BdzYVl&=;&ZMXMLK>jU=a$Qq=KRohvT-Kj}FO1>To*hq!IPl85~&2vKz zhg=k8$XgmI^`c9}8O8)RXIbwzI@f4DQ`E|x*hb&hdqRunS1UTYD$u)xvwBf-3N@dY z+4~JvFza1^cY=Nk)cMjMTSQXYrA%NS45@*&Koek6z(byTrD8!v=gB>`Lo*F0F1?^W zs&YzSEnY@7RmfDq(#U(#n@yRL{u-joOF<)zu&;hoiof=y{@?ZU53&Z z(%Mz|9{nkm#41km(^LMu?$tSYXmqAqV~UFl`RStgi>tH&uiO1{SbZOC6XDbGv;0>9 zkdA)p_{;!MqKP!dH{X?Hy(6d!i*CG`XcKm`~^@g}iR=&7c z7*f66TyXXQDm1{PJ~pJ9Mweaes*rj}3EXNO`Mru7W5o=l?=TPQZjfz%8iZ(PaG{@m z9^XV6KR)Ly4&7_zDM0To=ATX2L3}(f94EjNxTE_Tm<(i0>g@sQH?NXushCE?k>`2C^+{Y&XFDKpR4X;5aNaX+4|ho#{2bHSjmg-JFU@zwxW}P zf-&4QjGl9KQyU`V>0J`(uY0lC~_6zVE3UOTsp}R@J$0*+JC$qZ){eNomqt@GllfW;ouDvip?4n{= zET~tE4itSVAVWI`uiXXnt1H}%_*sL#k%3Z416(l$;>jQF+aME2d|n0Rz1)x+eGO>A zU14t~;lLIK`1yegvyYaNGer)lkv!!~>p7Np<$i5OSmk?d zHVnpSI)|mRq&E4){Wh0wvBzdZCy&jRG7ms~KJ_Y5D&8s2oCtI3D;$R}4Z~jyAHu&4 zbnuTbu5-I@pwA`cWX_+GAiIkj`r29n>&=#GO-VKDDqB#G0YJKI1K?5a9;VCyaGjrw zjNgWa8-8O|Qvs9~o0fNK=+cr-vV7`vt*?Ubwuf|#Ky(L)`x>GIoL>nqTn`uqN>*d? z4AM6j1fmS^;x2F)dHPS^QDI;p6@f6aFMEMWw5NWN_jTh}U?|xIJjGbt?1&jP@a4+f zlN|Y|;|LzIGVZ$Z%OH)djAC|C%g#l+&y?VXSmGe-kVqv6sK-+D$BplH?@Rlxsk&7y z-acwN#7?8Z^aJU<^B zWg%IY)hc|Ld8MOC_~*k)pW{5}y&2vVc;1DLc`Or~h8p2tzKO@?hTM5Rn_$*&gfDfx zN1To-(d3?Cynd!qlyK4z`D=ZWQOvrzzoJIit{zO6@3TE6e!k1JCqJF#IEmDX$m|I6 zi^Hy#XuL87nE>%?12+4pgE?3SX!FBzN;0V@6J?i*cpXVL1Gq5aMOY$6qbZC0bR-Ab zzj)ky1C?k8I=#>lT^do)6L+&OTb!mhC9#=pkz%V=K|60dyPu42n4JH3?y_hPfapuV zQ7!Vk^}(O8Ig=vGz_8n&ATC$uUn-@?rmSjF1F_iNY{0(g4)F!|J#?Dw#)h4G0tW{4 zYRUYX3*+IJ^Ky#rUY>Xp_{Mz*8E<*)Hm)aOtn!LFtI=@T`zv1<6{!K5_ni=dx1`lS zV5@Gdg{4y;Gr@Fc1fm|ScUmpvvW&Tv5u0~bftm^zCw`seQ%(37e(fTSZd3lCI#+-Q zQHS6PTpL~8nLdB{d&gA7omZIJ+s}q!?K@2R=XL?MLrkyJg+| zS(E!FyKSW?!yqG#2e^|w-`JZZRrBbav)7G_|56BlIgkIt&x0K7Jkb0^e!iPO3b#^T zRD`cwkzCH9+R{2%o()_oZ<9(*%+;O#yiB0>MQp8E8Tz0JpTi_Z)%oSQyOf=(Qp z6|!5e3)(AM`iv4)Ote#>Enc%TJ9kMOdHtflo*m{~W$S#sVj5^nmCd7=;wwzx?JW{uli z?Y|)B^@H78`Fe`H?_+-GI|2%-1TZq=DtTB~?_291-FDJChXts|F;Waa^l$nvX?hDq zM^xN6<&3PBymC%hI;!y~S5LfX&!Ukc5K@e8DW@X*wu1tScLkZ*M7}O}cqWN^>+pl# zVdP}RNc7TqiBj#G3Mpe^#wTcPUfy4L5BV&hCfuV|@;Z)@mamJEVpSa*-|pMFA9VDD zb^DdYb>qsd7agDe))+5i?g8%c?cAe|%c6N6hOaQ*aXh6OlZlWyL(^eHK@&pT=kt}Z z;J&FeEfa74eZV;o6uii5PssYXFjpUObt6;ad`wv>t6_@9veUYzA{bhIW;bbsx{z&= zzwIXiv|t+oX89G4=B;*!5OUT8ABuSR;AE)*flB3=E|8Zpn2EPQ&pX3O-}pz%(Wct zYPruWtQ#w-z#rvc@!`wqoBlvgj4q%zmH1GuQ87{005VnS;j6l#c4TX^!p8cQ?P%MX z-KC!ROwyYmW`Mb&+<|w@5A^nUS(qER-6fD;32RVD*gmA%OtGgJ4F#Il-kJi@sjgfU zx5?htpOW#`Dfj7`*IabeSA(nsu$}Ck>FTtJ0g_xX=dCrN>nFqcCU7#inpe z@!%K3`rp)!xb=m?j+a4JHK6)iCdi4G02#W;E4)?#z`D+tS(dW57l<&}zWArZr1+cc zYB~5O+g}7IXx`iaMo(SsTNS$I;F}9LFr~1Gn71F^SF5Zo1@sU+^0v=Cn7D7p`G7N% z_|wHu$3h5A-@!AyV;%%G_qck|=W_{q{ClhZxmBeiTdl`VYJ;;L2WkZ=g#7mywn~|D z>HdmbxJW?Ya{NWtL=(Sl_O7~y^%$~Lt^k;u7^CI)vt@>5Og63Yf~H|A1(YDq1Vrxn z@i_DVf7nSLEubmxC#^I^g=^S(>Hxr45!7Soti9n70u-U@PBkZp=RGF9vh7_pDz(%Z zJ9Kep61Vg0#If!he4sD4_+kwUStiqVoZvYg@M+1o6wo9QgrKPL`mQEAMSfbQAIb-pdIk$d~R=+}9Sd@cR!+ z+L~1u3zl^Aa_P+lW(R;_&SrIN$>?s4q}nv)JIfyC9UmBun-UK3CFT4CCg53b{|tDu z)8D`IEYa_g??qrr_R3u$)=WLzvqQ(W`B*Z=YR-4Ofn||QngBXBWG`6~$!0&poBe)4+^Bo8UcEDPi4Wv z&u8V=zq#)G@fDyBO{BB6&0|FKF1vYk0*w~GKFUWQ?)bHFUzW-4$!a_-~uIBS4& zD8+e`ZB75otn0FuWU)qzh$e|t$Eb&q^QsfA0MjLqCt_httlZHN_I@JOX|Py9j-XRq z+jGlN0s_S2jBQ)TE z*6fOv`zu@3Oc7ZWC;7r-_lf>bQa`}&3yNIM*^K6|T0b!fAivoNP@?%9J9Z;#M^P8T zZ}f%8fJv;1d+GIDr?d9!k1+6@&_7}ybbT(_3qPGOS~pZ~txT%r0=$gg#izV^D)wqT z&z~N2$8OpyweJnO1!r|c=@X7h7Z1V0Dg8quWxV%#ZUgO=3~<}e!v5Kssr+HhFlUV% zBK2ul<1#hOm$49OpgHcQr4Vu_+vR2{@3u!L+y(J9-TdlP_MDq2U;qpwM1iDS{><6i zZEjrINn#@?H8Pd7-|~E@?mEq60S=;`qxDeZObC9l%BH{?3dC3ZWY4*Ead>a|h#lps z%nZSzpf`WkAhwd0br##H%&RANf8Vryg^~Z}>6@8NWPxZ zz-ORykTC>^p@lvbF6;Wh?_c(!a}3j{cSfZ??@yl0-@atA2h20k$;r|NCIpF|%cK|T z4WR|#>>|lMiw4q(u3D#F+^);IqSP(%lZ>i$y=khh`y5S|#;mG2z9aTaaUe}8Nz)&H z@SvdB0a0AMC>WCCYCiHPUhP5$BwoZUaeB22ywjrm=A^a5+cDo{1%KHwh66L41U>O* zm4lHG^J$mH04EyIsXwbmx~%Fb5^B5X$8zDFpd#Ab=pS8n{O@Aik&tSp+S{jwWEZLX z9a*}rzgOVn=iU%Jt?%pS_raa0jNV#j^(+J%&G39^L7Dl=d&+kM=%Eg5)?22IYAZd$ zt-vk{>13~u?7wdU91gw|GzJbVf|7{ro4WXFDKm#CMdXT(O_%1BfWP5YDaL4h zs=}>+YYF~4)bP)JjHGeAMC*b;w9pXLt0eP(y8htI#42qaiK3vnG@ zt3g3xw17gED<3<8HoBKikL}HPqxu%Wm6D(+jW)hg zrj`#ybt0;#5!=4Lt;rz^^B4kgVTf{35o+6zi@1jjQPlfvDJlSZ59vBIlptd&6$%SF z_G?O!VcV^eun zOP~8kT?K8a!~L83b%rUCw_lX(MgLp>PSdOq0k$FvlS*KfY%17otq+P+^qogSK8>$^C zzOUt__6qenlI_Jd1262}v2nLxTA+E=_$DJSvON9&ST;q?Pak)+%Qs=QAX62lSpHgo!2LfFKp3R3J5@ovY0OoyE zQ^M1cQP~6i0XsN1FScj)}ZahOu3`%K;=m|5mZz zcBUaLk+*N!qBsh;?)r~xaf}@(k)Jqt`YSx%&XLP{R;tR+{+ar^op;8dl}T@#PT7*8h1j;bAai8USi($ghuKOGoW3Nl(Pk>D>0GV z3RyjLy)7+Z`++sb6w4vwB~WMYDQjBifXNDPZ#SS^`2KU2)l)`QkQcw2mAA=>SiNnh zC*wt;;`_0Bc_99g+?=d;j3p7~y=dM0gxAdM`XjszYmf_^&YeBFv4~=@(F|oDU1d!^ zD-dmj>-d2byOHkI@ygmf{)3{^bnWw14gYn%Qs})s%*M1q9VLT8*N@AZ%g~3YLeTPL zdT(*hxToEp1;=E^qm!MrMOCz3s3r0JDmC5pv^Gzb@vlE4lZs0(wYSikgms?A@KvtM zh-R*QN#c6=H)fVbqTu<>+GDE(SwyPySucBe7~rV(V8FX2uO>ENPp3>~M(8!?|=_6LJSY_)Bq@+j7=%&P!+cnA&5x*{3ECvGAd^#yqEN zrCBeo1`L0~1L%_4_9z4C2M}RIL=;$O@>jUj{m$c_{$Q&zDW;opns1*>K$XTNz@I>@ z{f!X&`VHtnNzqFeIc}IX+ExarUWz(&C;&SKL{D-Md@DHwSP_i^%jO80zz1{i*EbB^4KUy{GO-%#< z17ADKuceU!4)0G!1K`_OCE$cg>8YC-11Uzwhd{&cfmEdj_dl!iG+$=uW8~cm3$Sk2 zNjC&9zCIidD_%;<`9~MV{dZqaySt>Au{^+qVONqb?d;`Ky1Mk?&Giv;1nzLzr8AzL zd5_DPrp!RIy`OEISh5L`$54ELH`D)cog?6j7U1u+Y!tH#brg|Kyp(Yjufnc-^XON@ zPlnu?I+mY25ZwI>bEcADp#ffCh0A>G!qw}-pOXc;h$Sd~2hjtStHqo&T2|#1RyNgW zE|9vW5fSi5uJ+*A`>nUnWekN#T1+-LgM_HXNYRc1DO6E`Q|Q&grNgW|3L0D}ApVWT zgsYt};cywXTWTI8e>RRFKaU;d<7`K!&ohM8na@Dr9T?pKPDof8@IM7tH9 z+b$>gu#LX%g~%jKYHX#Hr=-orQl+7)}W(w6XP4kVt>2!8=Gh-bbDnw%jSs_ z*4szDQXVol$n{T`d)9ezmr2_hVaTS-B;CGk?qjt0E%4aXp zEUKSQy%WoG{KZ-zYUpNOy@>3nPk$ds0rGYEcbw!rg=0#&LaN7)^G-Uz5bqg5PS?a) zsaLP))-Z1{lSaK3n@@kCwVjRW2LiLEL_#$5z-oJO)rB8)n)Bi%&h+pBrp)IR=H&DD z;mfuIm$(vwHM&Xb7=OWAD$~mt-=UgAJh<*yVIgGPqo#+<+4{#S8q+#JmQgVPmr%b( zJ4IH~V0k#F#QstgcpY$dWDNQu*PHF)MZuaFj*xG0j6mV5@FyQ3Z1a#P@8|njiC5gp zmw^T(;$ySTjQj2@MUxee(R|4bt_$sB^8DWbsM=l;=#fSXEwq_4U9S{@;U%W5{ZBW( z9O`#15-l~Wsjk<)=JqDbCe)(A%WxzS6Y0L(pYJ3bk$m!LYL+7?RlctLpPhdH-zUcR zE(ri1uL2$3@69xa1FmU~?wxGvi{`m^#w@->AVrY3rYmT2)GMzEsf4}DL+Sr&&s;?t=cPc`fG4RhTyY4It0=nXG%j%e)VgsQHSID zxla0nn^0-H{n1*#FC|6JXc-w3JzSQL_TRg`*OBXFow}>8Nd`D@86SH zE4O`aOP4RnW_R&pqlxWN&YQjfJTitkWhS|OOVxx86x`j<*~dO_t5t%51qhBs(KLOv zH^2=a^XEJBfD`vUS*D_J-}p=_P^9JAz|<1{jB_|5Gc**72mtpLW=chcy*91Ht(09E z^XS~&lS&Jt%e=e}voEtk<40lKEH>;r%ALzNnWrtU7Aa4>oPN5~oq8abz2(`q)z)pL zbi=Li!~qSaABi|ZHT`-d`ugxx^dOtXms7+83O%U+$y-F2=}Yxi?OZPZNs9#hDgw9m z-dg3?pUyDvINQD%4~8UkcLe4q{8MoDuXU26A-kUd*jHdgD&--?uYFdF2xAt_8WqFI z)<5=z+7C8)4 z3b?69Ac1*+T0j(c?PD2Hs_SrxKGDWO$Eb(;CB*Bi`q0AhpS28OBbk;!dPuGs7+v9_ zmDdib=9WXQHaTEM3p=9S+rvtIdhdr?h6@Tf1)4o}~L3t5x1oqnPlXg_(KmJQJ23Z~72$g&mX?UEY} zwz33bymA1p|E$X5a`N8jT6MAA#Mnu0FUAejQjj_B}>Q!9MO!U9fZ%J7t6r+wXp zb=zDU0aP25qe8*()EeD{L#eY`Nv;?pD7^m6(50dLD){AksTzZkA)8aNfq*ZQuu#zU zGGd2C@!(ghrc#Lh$pmxuOD><+k={nHzfO{dSr)E-CBWJ*aXb!pa z!%o$Ee4A<86IGXH2l|bUoSHNt#4u*QR`R_g)JvHN@w(`e!u!O*LhB0cPi-JW@B&ZZ z|MklbT>fh>%?6-Z2G^Id&NyF;;#5dJ{Qzg&2(*Q0ak?liB(|s*_Zb&--EU!eSIgpq z9AAq)cY>hLBAIyz|B^uof3-3<8vvX?(wO@OZTlRyD z*PHuRu@m&++{KuuE-y!N19i!ScL}@qpRn3WtkRY6pE%@Gxd<&%7pJ_2qsQ{_(^(adagtCQyr_X%+!ey~n&x*rn0oi_hPKVf1bLk5V z$ScKv68{YYD8%e;o`zvSwH1ouud0AjuU6DphHG|Smjjepte1nF@*l!x@gl97#ok$m z&_iW%DlR7}1*S&5n3mf6mdJRya=dT);)U3{UGvX5@6JWbhZD)O-3whnyFwwvgLU1L z7HisLx22Os+%cP9%`J~aF(ce)nVMD7B*!^PxpsiIxJ#l@pU`?=a8{VJV{eRD2EAN9F~MdZS6APBe^w zCo>5sb`(mI@bvMJLXsJr#`!(%rdXR2C8 zeA4JUdrjx^wWv(#@XLZHWs`qANVa*L$zYUb)3croR;aR{7@3=!BeXG|@h-mPg)wMV zB$>b?<{sUoRv|2l_4T8W8Jgb&ef(V|dNOIR>bbO`U~BWb6U+i%X5>_D5G^atPnN9C5z+T?J#p!lcJzF-<7| z{~2~?qUct6fhdYdRI^qbf((0&_ld5Vkq98ACf<6V)qpJ|ic&2$@b)a&aLOy=dpS{e zhBu6n+b4bRC84A{AoF{@&A9a@L#KpGtHiD8q+Bx${Rm(V& z3|7uJzm{yF_-ky;8wE8Ba3#8l{%pVuPR~C;Eifl&WXRsScDK#wG3~L$j!?KH{ zCLO%&-=$z2FTehFK6_Svf8UO}j@ub1?V5DAi3nvR5bzCn>c^}wVS}#q=|<0{n&LGq zqQoez^475?^o+ma`mWUO+marGhR_(YT1W6~81VxEE^H*a8&~M%N%A}wsM|AGmhCuH zHYM?>g~k8Iq5qIMU9Gnd#n*f@G3ZXvTmZEd^K89qzimVgQhKI#Qxj)@(KJpJTCIEP z&YPg)4pH$1hK2KG8vvP6Ou_Wq&xHJeB?O$}X)XJopGZfy@N*yS%9qYEZB-KJUO(Yw zf46L}LaFG;xAm{Z%R`N@#z}h=tVxgWCv7{5ab@jpR50h_31>m_x(TU`#5LiZpN$2^ z{v3b()b?iFz`{Lcj#~9VLaS6;#zTh)Z2@j!LvG@Ottpt2AX^}jQGp0;%C)o4s#c`F ztO?j}0KNmwrf8H9H8l0@X`rAF8OT1eA*-Q}lVt`jQBv`loz$6AfZlFBCh&Nx5gfJ8k!XDdp1c_|5#zlYe<*Ey))U z=`maSFEJ1bE)DcLSb+beVXoB=CdkqiLyYY{_{&@A-o^Yr0!J(1 zBnonVL9}0I2;Rg(=TU|m;cCNkA^n`7BtYKn=;0;iwzaXs2!O5324qG=Qz6T%&nA0% zB3Q>u1VzAg#&)cK`Q-0fzkpxUTM%^TFPDKA??QpEeEq*&50V-9L*D;&|Mz6{AFKOc z*Pry`{t(xHUB89?QyTwu{R>W>Dlc-R@-Mp)xTn`Q70S(icNTw~BSqMFQ$~P>%+#tFBPFU)8yY=(9kve)koNta{)dJMmQfokQjk~B z)2~9-{8h)hIM?rDa-OyQfEK?hC6%p=C|y5kK};`y`Q+3eN8>vX=F+q3hm43XH8b)Q zz5J_E{Wn}O;dH)pk9*iw(cLiTdYxzl-ox5qc|rz>oYEzR%mhDCzmRe5`& z1K8`7kxa+7Q0&G{%h`bJ36Eb|uA~NJtZ&fbTCrIhEGFJBDz(8hK{4LP)-QJ-e`1Y@ z0JA%Ir3o#UDjFZm2scE)eKuo&0h==h@=eQ6wr2ALBCgn!=r1?>aPEa!<#qj7?P*%* zMfcTtSP^}SvOH63U5abBva8Kv?mXZ$KZyzN|`!A_k`?33B?JjnR_Lit)lN)5olzwxVW#XL( zf}+UOc%@@}Nj%B35ua9T3<24WkMh(%QpzWp0~_d;9G8M$Er6NPtH=RqT-SrWvV17G z(IcZ=#2YZ0!(t*9Fk`y~r|Cw+MD)6IB35o7RZg#wO7U;QvQbNX=HGTihH?9S^;ydo zh(yQBgNrN(cU^aksi8GZu~H zeq>uF>ZTC4@8aA%kb}6%2Eykp^`J1?IQ&8`0cPEkJHLwn3$xwu$=$;^Ly@Fpu-|Ii zv!#ObZ8U#+*)>lm?Ta7Qra!er%Q+LTM=Fk{taWVG;cSE**M49e-4{DEX6xGGKW5=n z5=Fhu-(?L{UtHRfJCS0x;7`RjY(fb;1M7=j3sob;oPlwr_=oYxQYjs>s7MyZ)P>SA z`K+y*@DTCICe=6BXW=~}5*R(RqbQZuVJA02Y~PYu3n<35xDP1E`KJ11dpmuh?i|e4 zJw@U{5zbEDBo0VS?Eq1R66TAAaMinPndh(!il&SZWl9fKwDp-G{0aK4$s=&;9CB9d zd2&baxOlG@zv-K}rP62>q<2rr3wxfdl+ES^?_phyG|X2b^DP8Mj_OqQq(dqHRZ-aP zGDYd869h^1zROGVyLyR1)h*^!!WE7P>XHCfir7jTKkp22E81H|4p|!CmU=1e@}i*h zU^1jQcGdkYW3El2GYEce@$r-K=q=8wBuBoEI<>o&D6BSR5@f^w#N}Xh6_h0+G zprnfx!HF~Yd<@iXWUhNhWOkOaG%7|}XlYhNxzL7P-asYB?*ZK8CfW;=J z1|@XUs_PS4*m0WC0r7b`pV>1FXyeSTgTwUdc2=Q&E`7cJa~_&k z)1y1+Lr5JE>T%f;=Xw?5X=j3MB9<=8fP)gPda0 zZYk7aiDi*8ocmniBTww065Erv!TS?8v1(LU`LuSp5xHaPnH$M zOw=_EbANI45dBDWipOeu-f^Cks7fx5K{%!0H&B8%6w%;4q?{*0KklK8 zNS9#Ik3`ha;us%dLY{x9XF%%R)l}tB5%=}s{mfNJeU~)h_EfP2sd=%E{C3!;z#Yy| z5?JqGlM|?P2W0thSZtlLyw$SkeS(FF=M{rEaXYAC@@*k9GSBpLT3?~TA37f}khEqyr! zyXL&YkdlyQST8^EgucvFe5{#G=3rTk!#0_9e@VW^D|5K|eSs;-t$q+<0;d*sZ)aX8 zGO9(Y7hoyd_pIwI4v+#;gn}><@x|FdHNOG7ByTPSuwB-GFjox^BvnbEZLkoZ2ZF~? zcC9$_sxdJtBV&d2jRZMC?h%-yAMsvdE=e$reRqwhVpQ*3{HHZF0Y??w(Hp;R4RUrz0n^xFc5Y zN%iV+3BT@;P0>KbykKanVXh*6X-J0vj%2&JaqdQRds+054*k`J0Gr2qkPrTR3c5Kx z={q9ig8t@{gz4`y^F&Mq%@4bOO<%ztsdMvd5ywgk5cY`)17i8o_DK7aP+-Z7fBl5# zMnKtGMNC^MD)FS;H75W3PkEvQr=1CZ(lPe;bcX=g7CB;2oNxJSBT`;(O{RyW^@>|84TKU(0R&s%H zup1BfJi)0qP$uMz9VE7=c@bsOhQJv)e?Azs#huDZLVwu4q74UMcEp@Lt zLa5po$xp*6jz3;+S{2u|wjp;m0MnkI?fdum_uzN!zQ<&Xr z%*)GH!oy<1^D|kh_~CiKg@7qW;+92hu)+C9WZT^}gV?2qh+j@h=X|yv6^5)jH*Wc1 zaRzCIJcItfZsk)_3dNL04mmpJVTE-)Wt@}F))?_=Qx7f&_Cw^uh4P4QjK^(Rkv22Z z(Ws|89D`9~N6t1$IU@#a5@PP@SZ0{l9}xy6@0CkLGY}UKTS64h?w&sCHy-eg6-#Sn+T6$F#Iqf#+WLeg`NFE*0@|HASQ5x4w1s2 zKA-f>CN8`!74Lc-zy4L$+hS~w8Ic&>#|hnjH5*xTy4Wbgqjb7>-BIM-s=?k;|P8h zo9*LBz=hzQr%~>!t3nGjKRz6Bn?>{2DsV1pNgLz<&}v6ZOkQHEuKGsUW^PB@`cMnS zD!T|w)y;9-9!qfhIm81h+TGvYx$X$o$^2P(7^WB<5&&JQo9LgEf&v8ANkWA$Ndb&11-2@$mjOUqx}{Ng{gFB1jAdZdEUHq( zSxQ6MOl{1jBk4)(@kQ?S1Pnx_TYHpop?p+8e+!AcR=`^%aP)_-2W+@(-qHO{ljSaM_Pp0NM&4fp ze2(6Bfu4{W=yezCqcI}+VdJAZw@8%L5X{O0lii{c@}c%+#$>m zZ@Pt~+2N_%$KpJSJ^ZLiOH9N(5d)Qv-brmd+=+flOpU~y1h#<=3t^Rx^pfT1k)6fR zy@dSos)4jDWzXb+0c=457vO+6B$o&XXWJ?HmXRal?&Z7sGQIUrs?|}L<0HchRQ-{% zTezt6u=AGqYKtFM_mGPtDGYM*WzV3iO^SOuyY6_Q?mDI+SCac7r#!l1p@5F1g2dXI z1`gX(CVs4*Y0#Hh{v2r#fu<@)*@;qtFMB(aYm=<7FH=stWNAm_T!r2U!|{u#o;Mg) zzmU5#=)*w!&jvmCAtRRB=;r3!pq@z4Ch0Me{t^AIwXA5x8;;TUTwP}CjtBV+G9kjU=Pwm4jqZH58zKb>(I2s*xybI4UI8F&imbz#k5SDKy z3E^t*)*wPt75AP2O7LCgKon_@OAQf(S6^4UQ8nU~Utd}Ckb!)|-D8%}G2v|I!_)#W zULHE0_rcvc6V0=FDTvT~+Rs!ac^0Hm*9C-{4||5v8DB>=ri@_kx_*1LGPQtl1NN+^ zFP11TnSQl;#5DmJ11+MzuaGLt4n(rUYCCc^0YdH43}%POgCneNv8XJOLm2BAgba`V zg4${BD8#drn)99bJM(-P>0^%(z0!^|^;JOfq$djdU>$$Q@f=K~c)j(YUPAhMstTJm zgF^qPqMG=O%8za|6A8_bVF7oo8r1=DZ{3mcTMLJl3@>qieQ*FPfQ>KN-2z;gVtT0I zaa~rc<|ydnA~|Bu{B9r>WNqp;Zy)&a7;gv7n^`|RHBg-Lg~_wCS#RWuF_Kf-H(vtl zpH@vRGY~;FjwRLPYu4O*c{Wd!T`nqF7(igA3KiEJ6Tgz*G9w}^)Cbs+tZC~_r8vY? z=-bvKm7(yu+m`Y|XlFQ!mGH zmuaX#hcnMxflZQ5xL<081RHr4>&?}wID_=DH6Vcy4k=VOboSF#KcB_kSW85 z!;Qqu%^{DHA(=wQ8Sn1v{e*>0)~zmPi-8)?H%;6F61!#=gt0WD0z>;2eCt(WSrq5ae(Ins1s10zI1$ zW;oah&9Bkc-@R3(Cw)T)_seUB72_#?YcS{X%B^$X-mU9}Yao*;#XPo1idUYprFlE^ z%~QY)h0aErK4fNuVLOu03 zZYwN*9trf@ynAw1(E>>~O;_YXt`#o?LX>w$8?!pzggX1?XmhcohNFA)(tPVB znjUJ@F|*>+WM?2w56?Y$?AcxmpMR21IaqEo2)j=V~F z9zX4Syx1S$lchb;%U$FbHkD6`W=`b3l?SD z7b`kv7L*iR=RoV85^*f70hKy51X^Sc5(dEJBKCkCU+Usp?KX8%{p;n#uWPH!94BoM zd`tuykUB|Me=l%V;Q$ksft zy*6qY+-ZDG-l(kMJ>!sjU~v@DDA@?TFRg%gz_6x)4X_Ib+H+N;AmAu4fP&tB?l>wW`QK-+`@Fm>FUAEEy^MO~AhNgU85|*XyW&5jpPl zO@T^hAdc)jc`z&k^xO$_0W}f|VX$g$miOkDNb+K%XVNN2Q%~Q!uQB_fT{yMIW2-NDQf>KS-x- zihEK991DT@>#0Yw2PAK$19=f0_enK&yv6UaRlnIH7!D1Z4Hn1H$pj)lIpH2=bw5o#b1h-*V3p)1$h;{ zgg;v%H6eCXpwk1|88R0={LfFkUDr*E93dUIjjkW)|FI?at~v-$10ZvSR|9-E*&XuJgCeZHnc{n3~ly?NR^;y+N|J>TZWPuAD z%!UU`LF0Rk9HyY+9`Gtb$K~8_#V+)KuozmT%mIZtZ@S-V@1zP!+GIR%#Jmc_ui%TO zJL1kC%bV^cnTe;rZA&$RAKfhXSUn}x6k4Z5ZHXT;8K`n;R?(XVlt3>>FwB}I+7-?s zH7Ec7Pz@B}{k0A(z8Z*On065f9B zxnmCXlA9PF4?}s(#+9w7rCQ9&_I^oBTtTuZrMnGE8=5KgPPB0DOGN|ERHUk(mM7Ga zs@A^zz#sfF`GZE(zXbHYB|weY@338(0~BfhcMuLJm*isF8b~7&P^a9Yw#ejsQF-%* znRR_6dazK;t*y$ahVjc4gE&z-7Yz)2(EBq*tS$+1Q=Nr!F-w!XWZ*Tlyze&t2DcubMPmq|tQ7C2Acb^_!+qFxB-8hgcU*??j zmwMD0cBsXLtPL9OR{!*yLGS@u3L z!(W3jW}U+w^fi+`ow;S6n)rh=V+RtPXJ2MVpfI7l`7yE2km45l(HuAX}HQoD(?Ur1s#cTMx?f*^cWH_E6QB?4na;g`*)3P z#~=KvShWiWOw3Z(a$g?oNLAHGm|H;VqV|>B71l1|2eMarrglo$jZjSVrzm3O8hiM} zxg?xc^!^?&kl1cs0c`&ahjwc=Tz4?0(J8s0Z7hBZ_vdzShA1a*t!}Mq6khd4qUhdU zIdkC*z^ed1di)hxuCPYhV1{me)He2qsHi6|ny(cF((Iu{1{2^wR}Hm>shf%cGU{@6V<^;Pd7#%J=+z5YH;_m74YKN+7 zBC}kpBdYfeBMIamg>8M46|kK?Q_|`*jtYe)+e(dpq-=+a1YYA?uPoTzUj6p+S}DAu zuWXLH8F+@S0quvD)==4U&=CRjmpjFgxvEMw%JkUVS2wZ+c^KUsFn?*Eyk^}$;_Ltq zC-b;c(Ci(IbU#E6yrXyYT#&*xJN_31ykFh`&6h_*UnCg453 zaDc2|hnAnPp1y9Rf)%klockZ^qx&|Ox1CSn*@Do`Z;(fKzc{i-W~-2u*@c|4f{MJx zD(_*as11v=`pzBGUhsHdYxYoiRdL}8Wc+@7&RK5B?Sr*o0i{TqWdr27X{m;Yb^2 z#?mFprt>c<076Y7k@H8Z4(L=^JiQqajq>P=?39$ zjfTy2v(eXg1mksKVnJ!|5j0*oB-xuvxTfd4>Lu%yom#Fr&@}?rS&LZ0RWM3GpBHgu zLz>U3AhSBALy#i{oe{04;l+XPnvz*|)T`VNjQl&K+@n`dgTucd#Uk|T@T+WvnVd3# zNL~7`y3}ZV#~J?T8<9lyV92+IPRZ!#Xlml&R@2=esrm|%S*~Qk>VnXlG^pABwfKWG z6ks1(S*uT_Yh!2r>g|6bUd7dB!K2V$&H?=8E6;h)$0dQW^rD?ZVk5`X7xzjuO%EN? zZ!_Sm6^zRQp?9`LpU$2AjX}iSlN&1vT8YZ={8XG@68kA;h?AKfw!5i5k?~OB- zFh(~Zvr#$QB|CtFF(MjIqdW5bxn3mFXlOvG!`^YSvz$hoqt&QXXx7#8lu9SJScY!}OIjQjS*LW$Gd7lj*tS=yWBD<8K<}p73z$gG{@D2q9N} z?a?$kXsuH4A)=!K6jGP+^-6~hYpTI7?r%Q?WRQ)wG=-g&;q;XZv+2*)Fk+)RXA#ZwBbd@ayI&yf3ATAuCvh+ZV^IPFOMXG`t)m#$(E zZ@O_cNVVs~D^93?1mB~|ylEDF=c>HOY4~O9>IoPA0?HRBRDs<+?Tx-|&}CqDCmCd= zIf&DYmxjf}H=Z?#b|ck|stTBB!AudV>jowQb(O9mx%pKSRR*e(^MXqDxN6vYg$b~8 zUh`m3esUbY^}rb6w(D8@c{X0y(br8+i+p_IX`)2h)Q&|?gi{7;oSyYu!?9eTaO*mIGWoOq)^)1x{Y>dRJueGT`ezQ2cnF_rrv+qLHBP#eEi{2ZP&49tDfWeWMy;&ZG zKDDjrlMMgn)JBOL+#C7c@}VkfdnBQh@hY9AAONS{0Z? zL2>j={6TSE0Y$z+BItuzp2Mvc=hm{a-9Rk1wq9?kaV)+V=x79^si2`qwTO`zp#l-n zraM_GnaltyNcg;Iwh{+O5DV|N9rQL#3K_gZ=iH=)+A0)zHSHyLUf_4UZ&j_e z-IU?=Jy83gX>qYe)~X-nNAjbp`4ZHnr1rE0DZ2l6n?OW_{pf35zx>`;6c;AQSaV%^ zcHVk?ASxrrOP_i$9l|Tzb1oGcl7OxO2=+4Ja^Ev5X!gtrQ1Mma`ora zR@`2|ycV7Obu5vmzCkxw__3QBuv4(|kdcFFt%Cca!9~vLrDdFz9CyH&FO2!YIzt^! zVKx~C)(uQ4F7H>&zfzG)jP0C63ZG8xA8zR-n7AHOu_bHRY>(;xQy{7M+F1GT{O(`H zoIk;+6x%6lb6@n!K;hqdE?EQ8<{5c#2AD7~H*j>gPhgv8y}bj16y!a9iG2zZUP@ zmxF2`TFb`A?EW+I1K&uy30?sritmI=MJ)Q{^LsP$ql8r!E_)palq1B$aAeGH|?a1=! z@QN$SZZwZ&#A=;uy$K{@z@Ov)n-(i$TJ&>lqEj|}-hs&Ztu+%Ja^EJRIH65#H)5Tz5%rVh|JLoiPa3z@ zZo6P-+}`%`+Sa=K@7`s2ppe5>_nhWHiPS%C!Bc>_-^3(2)+kXA6md*t|80eLuYWc? z$P5!8(_hBYbm7D?s?ZNW77%;^zwKoThtCK2Wc#b%;t#$va3A(QGPs!Z+~$t@EOE&&=5Z<@gnewIi`x}HWFl#q?%u6KX?zn6wi;p~`4 z0HIFHq~8m3;>ig72W&qPp~ljAna~1!FLmCpW7?jh?>ZJ%@Y1T9l|YQJ91BNeH$Ku) z&wR3cZHDVbHZzA?s|OzT)02&_iPc^+<*L7dCj^-Btr;4aL2xPPchN(mj5bY289Qgw z#aRDYLU>L+D$eHV8LFure?D zfaB-hz~PMH`Zj-Un8tqN&gvvPV=Z8HblbP8siV!|!t7QwWcp{d&i3m*b&lXa43YxC zAjtr#p2e@2kXbhzO0dkhFWY{CW>hw;E>wv_oL`VhUmphEXg!Hw z$=bb=eDI1@682v2-^LU;rgby|c0W(_4McjRT;SS+lF6YlEW}_6*W*Vxu*>YcZ4xyf z&mFi*t7`J0r8;_ntcdN$nr<(QXwE8rRJbc%UL}Rzx`CPhCvjn{Y&am#A!7jUc`QL; z7VX|kre-mpE5tHGjH^H9ROv{b_bY>m4CPz}TAe`B-39YJv!%-cgnd!*6d7$Ya=Z2G z3$Sy}mTh_0!e~(HVB%rdGdAbbV$lxqo?M|z?ONyBO^!QKG41dH&*O}81$DGnw20w0 z$h+)-QRv$~$efqe%lfH6?$r-=?3vs7i+P(gk46+a}DCI|J% zRe9DMNLRI1O6Az7IgZh*^~Npg8u7hDFIf_jMg1U$)J(+2cj0f?MZ5EvN`U@R(p2am}fd zSq|-VFKLTe{g>Av!&a;?iuiJ!5KkKMEhCa=MEA{L!Yk(TAN}Ib9UyQ{Qd=E{6ufpH z*|~q;3(WrfE~l*TnSVGUNP_SiB&_r@i5*dPm2RQvoM>&^;>I;kOk|LQ@D2V zudN&CadG4s2RRX+x0NyUsX*t93EHo&W#|T2jS|x+zurRWYAB7laXelRFj`4{y9&xe zI;=~GnaGUYDxx^-G%1TuAans=oeujWx&`a zOkaC*>+5gmva(#J{^ZK1b-^baed~#h_t0rgY1SvNH2AU{xEEyH3+8U{B`+hshL(~7 zW-=X?iT^wJKiRkAl%n7+;;I)72*}BUpxNz^&yW4(4o}C8O8+f2R%Y;zQ=YAvQzBN= zQ4CxMwaVE+shkWRXNi6`X{1){uM9st$GFs?2xK{SRI+O#qYEgm`u2cmme=VQLY%t} z+w2<;C@M2JJWbr%(4GO%U3;%3SAAUPqwCaXa!G3Lk&Cd8b8fjOcsS;w57<4n9-C8F zj!t42>#ZL&htC$mwl|+u((woErk>W4PI(i2fGhL+-`V?fBGHh0HzhcyR}=nIDBQT9 zT+UIsX4@M=`PdN5OFz&U;2$>CWh2`9R{ z^eqQ5OS{JLMi-chLXM;qofH86r)^$rki&9jNsPNgZ@Jnyy;yWnwvb(-Eis%5(UpQT zw)(aobo+Jw$#zgwiN=j1T+uYjF4*RZKmyVJT>NJrDUsJ$*Ki45X^ftEiEd>XGEhD*}E`=+OUd0f$ zf+ck|BLS81ky!Ya+s!Y=@p9~$@r)HK;Ry0Ia*622 zOuKs;+)6N9R5W@>mENE%90YSQ;d_l%U~c4!9RBQm{Mt~RV|7IJqdPh)|CMvY!`h2` z{=ec^^QY2ePA=0lJ9whC5+*Qag&J};Kd_r^>m@sLi@@04o>c39dxo<8GyZxUY_wjA zCu^nYJGFqsZF7Aia>UGO<|>UTpH>={rc7))_w2GaZ&)(lZQGX2pr_Yl zJAOdiNqrN?dC|4dzaOJgGW)<(m$ujENsfGUj zd#&50eIdS+>CwaoKV@8X`(|-`U0GC2n><&fH#az_XzSk038@{`K2pX`q?z@G1pzBs z{YqHz=D}aQ(iR7F4#Ueo3VB@4%|L;9M8cNb=qkLlRBzL^Lu+i~>8(TT^+d5(HA>~-y3_1o5* zE`YyOpZ_LNkh;hLbv(R8PXr=H*uB)_vFDtlLrVp-Lz2PlxW#qaT6(A9adz z64y8QE|X&Er{a+w)5saqkqZ~s89$Ip623VVviexXyyy^w@4KdeewaS)Kwf;DtKMzc zRA_ZGJkQXgl3hSMd8i%t9!Qjt98UdG=YW@dW@zg*1@c(ojH`=2>T3HpuXoH7gnZSh zl}=bd;L;@-L^=s~Jg%$-e5zca_|EeSNehbc!$Lm>EXFZtJlUbI^{*l{gCD9<{5*p1I5OSMy6Wrn zmS3Rv^KO-WYNjFW6kq0a4?C0hWN%<1!i5!thf9UYAWnlmg z*Un53nQ}_?M0o=$RF7X!;>sO$ai6FH;*u6P2w%Q`B8{d+O!nFj1CPOOIW$tcf^@u` zd$Gck+vEVmPccFwp~>!~mJK77V9J%CH?1K7N)et|^50sKTka#3XyVga^@56AP`-EG zcNA@<0BcnpKF>>fV!|o1K0x1hzef%aQ}+zo>Tr8!>m018bMzy}!4M z!didV*q2@{x*lCm8L-zo5oUf!29?SCzUDsaqiO*VA_n9;WMqEwJ@Dk^T}88-qvH95 zjQbPG-HKPLlI(Ng#2~guiSYztGUs@7%pjMJn|_cb6Du-9U-5s#?OxfoBpa-dv5;4RBy0;z$C69$hq`OI=CPQu+J=( zW;x|DoAP(&`-xfHy3FGes_8#?ghJIQuooXS?Pz(S_{zJX8*qhZ)ex9A%1LBTO0}>C zp0k1h5|s$uG4#!6ee?c)ag+vF#Hi3PIFfRAsnB_rmq^tT)9~>eIL!faiS(O>7*6X& zSv}SP9K*d$n9if74i1j*kOTRjkk*Yn6-)n36Ay}XMS{FP?UbycThQi6o_dm@83?p1 zu;bV>T>4dL!=HTB33gc|>JhJJRq=b3CMl5J?&X{c!_ex*tm9pkz^&#Cw-y<;`5OT5 z?|i-)yEz6Hf#=;BJ!*+F8Oh`KM04;uB8Idjx)7h=cEbyoOWn)$Us{!7C)1e0KYyg9 zJ+k(zP)aAeYHIA#>@m399LXvnMt@qDx|91>sFWn4el3f0#{ZpTs=a_RL7_-x-;bG# z4{k9TLkf+h^jo{=G$xX)$LBSbo=v%WUa?_XM<+h`9!B0;4i>IDdeD?rcKDlPH>k6i z;n`^4B#X(!Ovei(ZNg^H(O+)=JjxY^p+OEH$1FKMkC{TEPYm9z3S=(h2tOZANmWl({lXu>#(1lnunUQ`s8bc@p?amHY=P1LU#by>p4lpF z*zL40CdhG!{kSaBN-TbP`##_3<2g$gH^MF)RV%v3Rbi_Ylr%&pMAZwG;=365Xvu+z0b->cmtbLcJ-?vH|3n$_

lL+?-B9csAu>EGbW6z<1k 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%0A%91+URtV+=v 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 literal 0 HcmV?d00001 diff --git a/tests/integration-tests/serenity.properties b/tests/integration-tests/serenity.properties index c8682e00d5..7cde73aebd 100644 --- a/tests/integration-tests/serenity.properties +++ b/tests/integration-tests/serenity.properties @@ -1,8 +1,9 @@ -serenity.project.name=Open Enterprise Agent Integration tests +serenity.project.name=Identus Integration tests jira.url=https://input-output.atlassian.net jira.project=ATL serenity.reports.show.step.details=true serenity.report.show.manual.tests=false +serenity.verbose.steps=true serenity.simplified.stack.traces=false serenity.report.accessibility=true json.pretty.printing=true diff --git a/tests/integration-tests/src/test/kotlin/common/CredentialSchema.kt b/tests/integration-tests/src/test/kotlin/common/CredentialSchema.kt index 972f806069..05a6bbf37c 100644 --- a/tests/integration-tests/src/test/kotlin/common/CredentialSchema.kt +++ b/tests/integration-tests/src/test/kotlin/common/CredentialSchema.kt @@ -30,10 +30,15 @@ enum class CredentialSchema { tags = listOf("school", "students"), version = "1.0.0", ) + override val claims: Map = linkedMapOf( + "name" to "Name", + "age" to 18, + ) }, ; abstract val credentialSchema: CredentialSchemaInput abstract val schema: JsonSchema abstract val credentialSchemaType: String abstract val schemaType: String + abstract val claims: Map } diff --git a/tests/integration-tests/src/test/kotlin/common/DidPurpose.kt b/tests/integration-tests/src/test/kotlin/common/DidPurpose.kt new file mode 100644 index 0000000000..dee1243f98 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/common/DidPurpose.kt @@ -0,0 +1,25 @@ +package common + +import org.hyperledger.identus.client.models.* + +enum class DidPurpose { + EMPTY { + override val publicKeys = emptyList() + override val services = emptyList() + }, + JWT { + override val publicKeys = listOf( + ManagedDIDKeyTemplate("auth-1", Purpose.AUTHENTICATION, Curve.SECP256K1), + ManagedDIDKeyTemplate("auth-2", Purpose.AUTHENTICATION, Curve.ED25519), + ManagedDIDKeyTemplate("assertion-1", Purpose.ASSERTION_METHOD, Curve.SECP256K1), + ) + override val services = emptyList() + }, + ANONCRED { + override val publicKeys = emptyList() + override val services = emptyList() + }, ; + + abstract val publicKeys: List + abstract val services: List +} diff --git a/tests/integration-tests/src/test/kotlin/common/JwtCredentialProblem.kt b/tests/integration-tests/src/test/kotlin/common/JwtCredentialProblem.kt new file mode 100644 index 0000000000..eb9435d881 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/common/JwtCredentialProblem.kt @@ -0,0 +1,120 @@ +package common + +import com.nimbusds.jose.JWSAlgorithm +import com.nimbusds.jose.jwk.Curve +import models.JwtCredential +import org.hyperledger.identus.client.models.VcVerification +import java.time.OffsetDateTime + +enum class JwtCredentialProblem { + ALGORITHM_VERIFICATION { + override fun jwt(): String { + val jwt = VerifiableJwt.jwtVCv1() + return jwt.sign(JWSAlgorithm.HS256, null) + } + override val verification = VcVerification.ALGORITHM_VERIFICATION + }, + AUDIENCE_CHECK { + override fun jwt(): String { + val jwt = VerifiableJwt.jwtVCv1() + jwt.audience("did:wrong") + return jwt.sign(DEFAULT_ALGORITHM, DEFAULT_CURVE) + } + override val verification = VcVerification.AUDIENCE_CHECK + }, + COMPLIANCE_WITH_STANDARDS { + override fun jwt(): String { + TODO("Not supported yet") + } + + override val verification = VcVerification.COMPLIANCE_WITH_STANDARDS + }, + EXPIRATION_CHECK { + override fun jwt(): String { + val jwt = VerifiableJwt.jwtVCv1() + jwt.expirationTime(OffsetDateTime.now().plusYears(10)) + return jwt.sign(DEFAULT_ALGORITHM, DEFAULT_CURVE) + } + + override val verification = VcVerification.EXPIRATION_CHECK + }, + INTEGRITY_OF_CLAIMS { + override fun jwt(): String { + TODO("Not supported yet") + } + override val verification = VcVerification.INTEGRITY_OF_CLAIMS + }, + ISSUER_IDENTIFICATION { + override fun jwt(): String { + val jwt = VerifiableJwt.jwtVCv1() + jwt.issuer("did:wrong") + return jwt.sign(DEFAULT_ALGORITHM, DEFAULT_CURVE) + } + override val verification = VcVerification.ISSUER_IDENTIFICATION + }, + NOT_BEFORE_CHECK { + override fun jwt(): String { + val jwt = VerifiableJwt.jwtVCv1() + jwt.notBefore(OffsetDateTime.now().minusYears(10)) + return jwt.sign(DEFAULT_ALGORITHM, DEFAULT_CURVE) + } + override val verification = VcVerification.NOT_BEFORE_CHECK + }, + REVOCATION_CHECK { + override fun jwt(): String { + TODO("Not supported yet") + } + override val verification = VcVerification.REVOCATION_CHECK + }, + SCHEMA_CHECK { + override fun jwt(): String { + TODO("Not supported yet") + } + override val verification = VcVerification.SCHEMA_CHECK + }, + SEMANTIC_CHECK_OF_CLAIMS { + override fun jwt(): String { + val jwt = VerifiableJwt.jwtVCv1() + val jwtCredential = JwtCredential() + val claims = mutableMapOf() + claims.putAll(jwt.claimSetBuilder.claims) + claims.remove("iss") + jwtCredential.claims(claims) + return jwt.sign(DEFAULT_ALGORITHM, DEFAULT_CURVE) + } + override val verification = VcVerification.SEMANTIC_CHECK_OF_CLAIMS + }, + SIGNATURE_VERIFICATION { + override fun jwt(): String { + val jwt = VerifiableJwt.jwtVCv1() + return jwt.sign(DEFAULT_ALGORITHM, DEFAULT_CURVE) + } + override val verification = VcVerification.SIGNATURE_VERIFICATION + }, + SUBJECT_VERIFICATION { + override fun jwt(): String { + TODO("Not yet implemented") + } + override val verification = VcVerification.SUBJECT_VERIFICATION + }, ; + + companion object { + init { + // forcefully check if JwtCredentialProblems has all VcVerification + // cases since it's not possible to inherit final class + VcVerification.entries.forEach { + try { + JwtCredentialProblem.valueOf(it.name) + } catch (e: IllegalArgumentException) { + throw IllegalArgumentException("JwtCredentialProblem does not contain the new ${it.name} VcVerification case") + } + } + } + } + + protected val DEFAULT_ALGORITHM = JWSAlgorithm.ES256K + protected val DEFAULT_CURVE = Curve.SECP256K1 + + abstract fun jwt(): String + abstract val verification: VcVerification +} diff --git a/tests/integration-tests/src/test/kotlin/common/SchemaErrorTemplate.kt b/tests/integration-tests/src/test/kotlin/common/SchemaErrorTemplate.kt new file mode 100644 index 0000000000..c76c614113 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/common/SchemaErrorTemplate.kt @@ -0,0 +1,78 @@ +package common + +import com.google.gson.Gson +import com.google.gson.JsonObject +import common.CredentialSchema.STUDENT_SCHEMA +import net.serenitybdd.screenplay.Actor + +enum class SchemaErrorTemplate { + TYPE_AND_PROPERTIES_WITHOUT_SCHEMA_TYPE { + override fun inner_schema(): String { + return """ + { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "age": { + "type": "integer" + } + }, + "required": ["name"] + } + """.trimIndent() + } + }, + CUSTOM_WORDS_NOT_DEFINED { + override fun inner_schema(): String { + return """ + { + "${"$"}schema": "http://json-schema.org/draft-2020-12/schema#", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "age": { + "type": "integer" + } + }, + "customKeyword": "value" + } + """.trimIndent() + } + }, + MISSING_REQUIRED_FOR_MANDATORY_PROPERTY { + override fun inner_schema(): String { + return """ + { + "${"$"}schema": "http://json-schema.org/draft-2020-12/schema#", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "age": { + "type": "integer" + } + } + } + """ + } + }, ; + + abstract fun inner_schema(): String + + fun schema(actor: Actor): String { + val innerSchema = Gson().fromJson(inner_schema(), JsonObject::class.java) + val json = getJson(actor) + json.add("schema", innerSchema) + return json.toString() + } + + private fun getJson(actor: Actor): JsonObject { + val jsonString = Gson().toJson(STUDENT_SCHEMA.credentialSchema.copy(author = actor.recall("shortFormDid"))) + return Gson().fromJson(jsonString, JsonObject::class.java) + } +} diff --git a/tests/integration-tests/src/test/kotlin/common/TestConstants.kt b/tests/integration-tests/src/test/kotlin/common/TestConstants.kt index 56a81a0a73..15fed21943 100644 --- a/tests/integration-tests/src/test/kotlin/common/TestConstants.kt +++ b/tests/integration-tests/src/test/kotlin/common/TestConstants.kt @@ -18,18 +18,6 @@ object TestConstants { ), ) - val PRISM_DID_AUTH_KEY = ManagedDIDKeyTemplate("auth-1", Purpose.AUTHENTICATION) - val PRISM_DID_SERVICE_FOR_UPDATE = Service( - "https://update.com", - listOf("LinkedDomains"), - Json("https://update.com/"), - ) - val PRISM_DID_UPDATE_NEW_SERVICE_URL = "https://bar.foo.com/" - val PRISM_DID_UPDATE_NEW_SERVICE = Service( - "https://new.service.com", - listOf("LinkedDomains"), - Json("https://new.service.com/"), - ) val EVENT_TYPE_CONNECTION_UPDATED = "ConnectionUpdated" val EVENT_TYPE_ISSUE_CREDENTIAL_RECORD_UPDATED = "IssueCredentialRecordUpdated" val EVENT_TYPE_PRESENTATION_UPDATED = "PresentationUpdated" diff --git a/tests/integration-tests/src/test/kotlin/common/VerifiableJwt.kt b/tests/integration-tests/src/test/kotlin/common/VerifiableJwt.kt new file mode 100644 index 0000000000..4aa5d2483e --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/common/VerifiableJwt.kt @@ -0,0 +1,132 @@ +package common + +import com.google.gson.JsonArray +import com.google.gson.JsonObject +import com.google.gson.annotations.SerializedName +import com.google.gson.reflect.TypeToken +import io.iohk.atala.automation.restassured.CustomGsonObjectMapperFactory +import models.JwtCredential +import java.time.OffsetDateTime + +object VerifiableJwt { + fun schemaVCv1(): JwtCredential { + val favoriteColorEnum = JsonArray() + listOf("red", "orange", "green", "blue", "yellow", "purple").forEach { + favoriteColorEnum.add(it) + } + + val favoriteColor = JsonObject() + favoriteColor.addProperty("type", "string") + favoriteColor.add("enum", favoriteColorEnum) + + val jsonSchemaPropertiesCredentialSubjectProperties = JsonObject() + jsonSchemaPropertiesCredentialSubjectProperties.add("favoriteColor", favoriteColor) + + val required = JsonArray() + required.add("favoriteColor") + + val jsonSchemaPropertiesCredentialSubject = JsonObject() + jsonSchemaPropertiesCredentialSubject.addProperty("type", "object") + jsonSchemaPropertiesCredentialSubject.add("properties", jsonSchemaPropertiesCredentialSubjectProperties) + jsonSchemaPropertiesCredentialSubject.add("required", required) + + val jsonSchemaProperties = JsonObject() + jsonSchemaProperties.add("credentialSubject", jsonSchemaPropertiesCredentialSubject) + + val jsonSchema = JsonObject() + jsonSchema.addProperty("${"$"}id", "https://example.com/schemas/favorite-color-schema.json") + jsonSchema.addProperty("${"$"}schema", "https://json-schema.org/draft/2020-12/schema") + jsonSchema.addProperty("title", "Favorite Color Schema") + jsonSchema.addProperty("description", "Favorite Color using JsonSchemaCredential") + jsonSchema.addProperty("type", "object") + jsonSchema.add("properties", jsonSchemaProperties) + + val credentialSubject = JsonObject() + credentialSubject.addProperty("id", "https://example.com/schemas/favorite-color-schema.json") + credentialSubject.addProperty("type", "JsonSchema") + credentialSubject.add("jsonSchema", jsonSchema) + + val credentialSchema = JsonObject() + credentialSchema.addProperty( + "id", + "https://www.w3.org/2022/credentials/v2/json-schema-credential-schema.json", + ) + credentialSchema.addProperty("type", "JsonSchema") + credentialSchema.addProperty( + "digestSRI", + "sha384-S57yQDg1MTzF56Oi9DbSQ14u7jBy0RDdx0YbeV7shwhCS88G8SCXeFq82PafhCrW", + ) + + val verifiableSchema = VerifiableSchemaV1( + credentialSubject = credentialSubject, + credentialSchema = credentialSchema, + type = listOf("VerifiableCredential", "JsonSchemaCredential"), + context = listOf("https://www.w3.org/ns/credentials/v2", "https://www.w3.org/ns/credentials/examples/v2"), + id = "https://example.com/credentials/3734", + issuer = "https://example.com/issuers/14", + issuanceDate = OffsetDateTime.now(), + ) + + val typeToken = object : TypeToken>() {}.type + val gson = CustomGsonObjectMapperFactory().create(null, null) + val json = gson.toJsonTree(verifiableSchema) + val claims = gson.fromJson>(json, typeToken) + val jwt = JwtCredential().claims(claims) + return jwt + } + + fun jwtVCv1(): JwtCredential { + val credentialSubject = JsonObject() + credentialSubject.addProperty("id", "did:subject") + credentialSubject.addProperty("firstName", "John") + credentialSubject.addProperty("lastName", "Doe") + + val vc = VerifiableCredentialV1( + credentialSubject = credentialSubject, + type = listOf("VerifiableCredential", "VerifiablePresentation"), + context = listOf("https://www.w3.org/2018/credentials/v1"), + credentialStatus = CredentialStatus( + statusPurpose = "Revocation", + statusListIndex = 1, + id = "https://example.com/credential-status/4a6ad192-14b5-4804-8c78-8873c82d2250#1", + type = "StatusList2021Entry", + statusListCredential = "https://example.com/credential-status/4a6ad192-14b5-4804-8c78-8873c82d2250", + ), + ) + + val jwt = JwtCredential().issuer("did:prism:issuer").jwtID("jti").subject("did:subject") + .audience("did:prism:verifier").issueTime(OffsetDateTime.now()).expirationTime(OffsetDateTime.now()) + .notBefore(OffsetDateTime.now()).claim("vc", vc) + + return jwt + } + + // --- Types to mimic JWT-VC + + // https://www.w3.org/2018/credentials/v1 + // https://www.w3.org/TR/2023/WD-vc-jwt-20230501/ + data class VerifiableCredentialV1( + val credentialSubject: Any, + val type: Collection, + @SerializedName("@context") val context: Collection, + val credentialStatus: CredentialStatus, + ) + + data class CredentialStatus( + val statusPurpose: String, + val statusListIndex: Int, + val id: String, + val type: String, + val statusListCredential: String, + ) + + data class VerifiableSchemaV1( + @SerializedName("@context") val context: Collection, + val id: String, + val type: Collection, + val issuer: String, + val issuanceDate: OffsetDateTime, + val credentialSchema: Any, + val credentialSubject: Any, + ) +} diff --git a/tests/integration-tests/src/test/kotlin/config/services/Agent.kt b/tests/integration-tests/src/test/kotlin/config/services/Agent.kt index 52e3072e44..f4d7cc0962 100644 --- a/tests/integration-tests/src/test/kotlin/config/services/Agent.kt +++ b/tests/integration-tests/src/test/kotlin/config/services/Agent.kt @@ -4,7 +4,7 @@ import com.sksamuel.hoplite.ConfigAlias import config.VaultAuthType import org.testcontainers.containers.ComposeContainer import org.testcontainers.containers.wait.strategy.Wait -import java.io.File +import java.io.* data class Agent( val version: String, @@ -13,12 +13,13 @@ data class Agent( @ConfigAlias("didcomm_service_url") val didcommServiceUrl: String?, @ConfigAlias("rest_service_url") val restServiceUrl: String?, @ConfigAlias("auth_enabled") val authEnabled: Boolean, - @ConfigAlias("prism_node") val prismNode: PrismNode?, + @ConfigAlias("prism_node") val prismNode: VerifiableDataRegistry?, val keycloak: Keycloak?, val vault: Vault?, @ConfigAlias("keep_running") override val keepRunning: Boolean = false, -) : ServiceBase { +) : ServiceBase() { + override val logServices = listOf("identus-cloud-agent") override val container: ComposeContainer init { @@ -50,9 +51,7 @@ data class Agent( env["VAULT_APPROLE_SECRET_ID"] = "agent-secret" } - container = ComposeContainer( - File("src/test/resources/containers/agent.yml"), - ) + container = ComposeContainer(File("src/test/resources/containers/agent.yml")) .withEnv(env) .waitingFor("identus-cloud-agent", Wait.forHealthcheck()) } diff --git a/tests/integration-tests/src/test/kotlin/config/services/Keycloak.kt b/tests/integration-tests/src/test/kotlin/config/services/Keycloak.kt index 289cb1cc68..e3a2d8475d 100644 --- a/tests/integration-tests/src/test/kotlin/config/services/Keycloak.kt +++ b/tests/integration-tests/src/test/kotlin/config/services/Keycloak.kt @@ -18,13 +18,14 @@ data class Keycloak( @ConfigAlias("client_id") val clientId: String = "prism-agent", @ConfigAlias("client_secret") val clientSecret: String = "prism-agent-demo-secret", @ConfigAlias("keep_running") override val keepRunning: Boolean = false, -) : ServiceBase { +) : ServiceBase() { private val logger = Logger.get() private val keycloakComposeFile = "src/test/resources/containers/keycloak.yml" private val keycloakEnvConfig: Map = mapOf( "KEYCLOAK_HTTP_PORT" to httpPort.toString(), ) - private val keycloakClientRoles: List = AgentRole.values().map { it.roleName } + override val logServices: List = listOf("keycloak") + private val keycloakClientRoles: List = AgentRole.entries.map { it.roleName } override val container: ComposeContainer = ComposeContainer(File(keycloakComposeFile)).withEnv(keycloakEnvConfig) .waitingFor("keycloak", Wait.forLogMessage(".*Running the server.*", 1)) diff --git a/tests/integration-tests/src/test/kotlin/config/services/Service.kt b/tests/integration-tests/src/test/kotlin/config/services/Service.kt index cef1310379..ee897f6e91 100644 --- a/tests/integration-tests/src/test/kotlin/config/services/Service.kt +++ b/tests/integration-tests/src/test/kotlin/config/services/Service.kt @@ -3,7 +3,7 @@ package config.services import com.sksamuel.hoplite.ConfigAlias data class Service( - @ConfigAlias("prism_node") val prismNode: PrismNode?, + @ConfigAlias("prism_node") val prismNode: VerifiableDataRegistry?, val keycloak: Keycloak?, val vault: Vault?, ) diff --git a/tests/integration-tests/src/test/kotlin/config/services/ServiceBase.kt b/tests/integration-tests/src/test/kotlin/config/services/ServiceBase.kt index af1b7b0b0d..8c598b61d6 100644 --- a/tests/integration-tests/src/test/kotlin/config/services/ServiceBase.kt +++ b/tests/integration-tests/src/test/kotlin/config/services/ServiceBase.kt @@ -1,25 +1,46 @@ package config.services -import com.sksamuel.hoplite.ConfigAlias import org.testcontainers.containers.ComposeContainer import org.testcontainers.lifecycle.Startable +import java.io.* -interface ServiceBase : Startable { +abstract class ServiceBase : Startable { + companion object { + private val context = System.getProperties().getOrDefault("context", "") + private val logDir = File("target/logs/$context") + init { + logDir.deleteRecursively() + logDir.mkdirs() + } + } - val container: ComposeContainer + abstract val container: ComposeContainer + abstract val keepRunning: Boolean - @ConfigAlias("keep_running") - val keepRunning: Boolean + open val logServices: List = emptyList() + private val logWriters: MutableList = mutableListOf() override fun start() { + logServices.forEach { + val output = File(logDir, "$it.log") + output.createNewFile() + val writer = FileOutputStream(output, true).bufferedWriter() + logWriters.add(writer) + container.withLogConsumer(it) { logLine -> + writer.append(logLine.utf8String) + } + } container.start() postStart() } - fun postStart() { + open fun postStart() { } override fun stop() { + logWriters.forEach { + it.close() + } if (!keepRunning) { container.stop() } diff --git a/tests/integration-tests/src/test/kotlin/config/services/Vault.kt b/tests/integration-tests/src/test/kotlin/config/services/Vault.kt index ebd7234de6..85f1a02b27 100644 --- a/tests/integration-tests/src/test/kotlin/config/services/Vault.kt +++ b/tests/integration-tests/src/test/kotlin/config/services/Vault.kt @@ -13,10 +13,11 @@ import java.io.File data class Vault( @ConfigAlias("http_port") val httpPort: Int, - @ConfigAlias("keep_running") override val keepRunning: Boolean = false, @ConfigAlias("vault_auth_type") val authType: VaultAuthType = VaultAuthType.APP_ROLE, -) : ServiceBase { + @ConfigAlias("keep_running") override val keepRunning: Boolean = false, +) : ServiceBase() { private val logger = Logger.get() + override val logServices: List = listOf("vault") private val vaultComposeFile: String = "src/test/resources/containers/vault.yml" override val container: ComposeContainer = ComposeContainer(File(vaultComposeFile)).withEnv( mapOf( diff --git a/tests/integration-tests/src/test/kotlin/config/services/PrismNode.kt b/tests/integration-tests/src/test/kotlin/config/services/VerifiableDataRegistry.kt similarity index 86% rename from tests/integration-tests/src/test/kotlin/config/services/PrismNode.kt rename to tests/integration-tests/src/test/kotlin/config/services/VerifiableDataRegistry.kt index b9e712bea7..2997f567cc 100644 --- a/tests/integration-tests/src/test/kotlin/config/services/PrismNode.kt +++ b/tests/integration-tests/src/test/kotlin/config/services/VerifiableDataRegistry.kt @@ -5,11 +5,12 @@ import org.testcontainers.containers.ComposeContainer import org.testcontainers.containers.wait.strategy.Wait import java.io.File -data class PrismNode( +data class VerifiableDataRegistry( @ConfigAlias("http_port") val httpPort: Int, val version: String, @ConfigAlias("keep_running") override val keepRunning: Boolean = false, -) : ServiceBase { +) : ServiceBase() { + override val logServices: List = listOf("prism-node") private val vdrComposeFile = "src/test/resources/containers/vdr.yml" override val container: ComposeContainer = ComposeContainer(File(vdrComposeFile)).withEnv( mapOf( diff --git a/tests/integration-tests/src/test/kotlin/interactions/AuthRestExtensions.kt b/tests/integration-tests/src/test/kotlin/interactions/AuthRestExtensions.kt new file mode 100644 index 0000000000..19318c0c5a --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/interactions/AuthRestExtensions.kt @@ -0,0 +1,15 @@ +package interactions + +import net.serenitybdd.screenplay.rest.interactions.RestInteraction + +fun Post.body(obj: Any): RestInteraction { + return this.with { + it.header("Content-Type", "application/json").body(obj) + } +} + +fun Patch.body(obj: Any): RestInteraction { + return this.with { + it.header("Content-Type", "application/json").body(obj) + } +} diff --git a/tests/integration-tests/src/test/kotlin/models/JwtCredential.kt b/tests/integration-tests/src/test/kotlin/models/JwtCredential.kt index 741f3f4c5f..e4395e27e0 100644 --- a/tests/integration-tests/src/test/kotlin/models/JwtCredential.kt +++ b/tests/integration-tests/src/test/kotlin/models/JwtCredential.kt @@ -1,20 +1,210 @@ package models -import com.jayway.jsonpath.DocumentContext -import com.jayway.jsonpath.JsonPath +import com.google.gson.Gson +import com.nimbusds.jose.* +import com.nimbusds.jose.crypto.* +import com.nimbusds.jose.crypto.impl.* +import com.nimbusds.jose.jwk.* +import com.nimbusds.jose.jwk.gen.ECKeyGenerator +import com.nimbusds.jose.jwk.gen.OctetKeyPairGenerator +import com.nimbusds.jose.util.Base64URL +import com.nimbusds.jwt.JWTClaimsSet +import com.nimbusds.jwt.SignedJWT +import org.bouncycastle.jce.provider.BouncyCastleProvider +import org.hyperledger.identus.client.models.VerificationMethod +import java.io.Serializable +import java.security.Provider +import java.security.SecureRandom +import java.time.OffsetDateTime import java.util.Base64 +import java.util.Date +import kotlin.reflect.KClass -class JwtCredential(base64: String) { - private val payload: DocumentContext +class JwtCredential { + // helper classes + interface Key { + val value: T + } + + class EC(override val value: ECKey) : Key + class OKP(override val value: OctetKeyPair) : Key + class Secret(override val value: ByteArray) : Key + + // properties + var header: JWSHeader? = null + var payload: Payload? = null + var signature: Base64URL? = null + var claimSetBuilder = JWTClaimsSet.Builder() + + companion object { + val provider: Provider = BouncyCastleProvider() + val keys: MutableMap> = mutableMapOf() + + fun parseBase64(base64: String): JwtCredential { + return JwtCredential().parseBase64(base64) + } + + fun parseJwt(jwt: String): JwtCredential { + return JwtCredential().parseJwt(jwt) + } + + fun verify(jwt: String, verification: List): Boolean { + val signedJWT = SignedJWT.parse(jwt) + verification + .map { Gson().toJson(it.publicKeyJwk) } + .forEach { + val result = signedJWT.verify(verifier(it)) + if (result) return true + } + return false + } + + fun verify(jwt: String, verifier: JWSVerifier): Boolean { + verifier.jcaContext.provider = provider + val signedJWT = SignedJWT.parse(jwt) + val result = signedJWT.verify(verifier) + return result + } + + private fun type(algorithm: JWSAlgorithm): KClass { + if (MACProvider.SUPPORTED_ALGORITHMS.contains(algorithm)) { + return MACProvider::class + } + if (ECDSAProvider.SUPPORTED_ALGORITHMS.contains(algorithm)) { + return ECDSAProvider::class + } + + if (EdDSAProvider.SUPPORTED_ALGORITHMS.contains(algorithm)) { + return EdDSAProvider::class + } + throw RuntimeException("Requested [$algorithm] not supported.") + } + + private fun generateBytes(bytes: Int): ByteArray { + val randomBytes = ByteArray(bytes) + SecureRandom().nextBytes(randomBytes) + return randomBytes + } + + private fun key(algorithm: JWSAlgorithm, curve: Curve?): Key { + val key = keys + .getOrPut("${algorithm.name}-${curve?.name}") { + when (type(algorithm)) { + MACProvider::class -> Secret( + generateBytes(128), + ) + + ECDSAProvider::class -> EC( + ECKeyGenerator(curve).provider(provider).keyUse(KeyUse.SIGNATURE).generate(), + ) + + EdDSAProvider::class -> OKP( + OctetKeyPairGenerator(curve).provider(provider).keyUse(KeyUse.SIGNATURE).generate(), + ) + + else -> throw RuntimeException("Requested [$algorithm] not supported.") + } + } + return key + } + + fun signer(algorithm: JWSAlgorithm, curve: Curve?): JWSSigner { + val signer: JWSSigner = when (val key = key(algorithm, curve)) { + is Secret -> MACSigner(key.value) + is EC -> ECDSASigner(key.value) + is OKP -> Ed25519Signer(key.value) + else -> throw RuntimeException("Unsupported key algorithm: $algorithm and curve: $curve") + } + signer.jcaContext.provider = provider + return signer + } + + private fun parseKey(key: String): JWK { + try { return ECKey.parse(key) } catch (_: Error) { } + try { return OctetKeyPair.parse(key) } catch (_: Error) { } + throw RuntimeException("Invalid key [$key]") + } + + private fun verifier(key: String): JWSVerifier { + val verifier: JWSVerifier = when (val jwk = parseKey(key)) { + is ECKey -> ECDSAVerifier(jwk) + is OctetKeyPair -> Ed25519Verifier(jwk) + else -> throw RuntimeException("Invalid key [$key]") + } + verifier.jcaContext.provider = provider + return verifier + } + } + + fun sign(algorithm: JWSAlgorithm, curve: Curve?): String { + val jwt = SignedJWT( + JWSHeader.Builder(algorithm).build(), + claimSetBuilder.build(), + ) + jwt.sign(signer(algorithm, curve)) + return jwt.serialize() + } - init { + fun parseBase64(base64: String): JwtCredential { val jwt = String(Base64.getDecoder().decode(base64)) - val parts = jwt.split(".") - payload = JsonPath.parse(String(Base64.getUrlDecoder().decode(parts[1]))) + return parseJwt(jwt) + } + + fun parseJwt(jwt: String): JwtCredential { + val signedJWT = SignedJWT.parse(jwt) + claimSetBuilder = JWTClaimsSet.Builder(signedJWT.jwtClaimsSet) + header = signedJWT.header + payload = signedJWT.payload + signature = signedJWT.signature + return this + } + + fun issuer(iss: String): JwtCredential { + claimSetBuilder.issuer(iss) + return this + } + + fun jwtID(jti: String): JwtCredential { + claimSetBuilder.jwtID(jti) + return this + } + + fun audience(aud: String): JwtCredential { + claimSetBuilder.audience(aud) + return this + } + + fun issueTime(iat: OffsetDateTime): JwtCredential { + claimSetBuilder.issueTime(Date.from(iat.toInstant())) + return this + } + + fun subject(sub: String): JwtCredential { + claimSetBuilder.subject(sub) + return this + } + + fun expirationTime(exp: OffsetDateTime): JwtCredential { + claimSetBuilder.expirationTime(Date.from(exp.toInstant())) + return this + } + + fun notBefore(nbf: OffsetDateTime): JwtCredential { + claimSetBuilder.notBeforeTime(Date.from(nbf.toInstant())) + return this + } + + fun claim(key: String, data: Any): JwtCredential { + claimSetBuilder.claim(key, Gson().fromJson(Gson().toJson(data), Object::class.java)) + return this + } + + fun claims(claims: Map): JwtCredential { + claims.forEach { (key, value) -> claimSetBuilder.claim(key, value) } + return this } - fun statusListId(): String { - val listUrl = payload.read("$.vc.credentialStatus.statusListCredential") - return listUrl.split("/credential-status/")[1] + fun serialize(): String { + return SignedJWT(header!!.toBase64URL(), payload!!.toBase64URL(), signature!!).serialize() } } diff --git a/tests/integration-tests/src/test/kotlin/steps/Setup.kt b/tests/integration-tests/src/test/kotlin/steps/Setup.kt index ce1034a63e..57b035ab9d 100644 --- a/tests/integration-tests/src/test/kotlin/steps/Setup.kt +++ b/tests/integration-tests/src/test/kotlin/steps/Setup.kt @@ -20,7 +20,15 @@ import org.hyperledger.identus.client.models.CreateWebhookNotification import java.util.UUID object Setup { - val config = ConfigLoader().loadConfigOrThrow(TestConstants.TESTS_CONFIG) + private val config: Config + + init { + try { + config = ConfigLoader().loadConfigOrThrow(TestConstants.TESTS_CONFIG) + } catch (e: Exception) { + throw RuntimeException(e) + } + } /** * This function starts all services and actors before all tests. diff --git a/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt b/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt index e9883293c9..bc885b15ee 100644 --- a/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/common/CommonSteps.kt @@ -1,46 +1,55 @@ package steps.common +import common.CredentialSchema +import common.DidPurpose import interactions.Get -import io.cucumber.java.ParameterType import io.cucumber.java.en.Given import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor -import net.serenitybdd.screenplay.actors.OnStage import org.apache.http.HttpStatus -import org.hyperledger.identus.client.models.* +import org.hyperledger.identus.client.models.Connection +import org.hyperledger.identus.client.models.ConnectionsPage import steps.connection.ConnectionSteps import steps.credentials.IssueCredentialsSteps import steps.did.PublishDidSteps -import java.lang.IllegalArgumentException +import steps.schemas.CredentialSchemasSteps class CommonSteps { - @ParameterType(".*") - fun actor(actorName: String): Actor { - return OnStage.theActorCalled(actorName) - } + @Given("{actor} has a jwt issued credential from {actor}") + fun holderHasIssuedCredentialFromIssuer(holder: Actor, issuer: Actor) { + actorsHaveExistingConnection(issuer, holder) - @ParameterType(".*") - fun curve(value: String): Curve { - return Curve.decode(value) ?: throw IllegalArgumentException("$value is not a valid Curve value") - } + val publishDidSteps = PublishDidSteps() + publishDidSteps.agentHasAnUnpublishedDID(holder, DidPurpose.JWT) + publishDidSteps.agentHasAPublishedDID(issuer, DidPurpose.JWT) - @ParameterType(".*") - fun purpose(value: String): Purpose { - return Purpose.decode(value) ?: throw IllegalArgumentException("$value is not a valid Purpose value") + val issueSteps = IssueCredentialsSteps() + issueSteps.issuerOffersACredential(issuer, holder, "short") + issueSteps.holderReceivesCredentialOffer(holder) + issueSteps.holderAcceptsCredentialOfferForJwt(holder) + issueSteps.acmeIssuesTheCredential(issuer) + issueSteps.bobHasTheCredentialIssued(holder) } - @Given("{actor} has an issued credential from {actor}") - fun holderHasIssuedCredentialFromIssuer(holder: Actor, issuer: Actor) { + @Given("{actor} has a jwt issued credential with {} schema from {actor}") + fun holderHasIssuedCredentialFromIssuerWithSchema( + holder: Actor, + schema: CredentialSchema, + issuer: Actor, + ) { actorsHaveExistingConnection(issuer, holder) val publishDidSteps = PublishDidSteps() - publishDidSteps.createsUnpublishedDid(holder) - publishDidSteps.agentHasAPublishedDID(issuer) + publishDidSteps.agentHasAnUnpublishedDID(holder, DidPurpose.JWT) + publishDidSteps.agentHasAPublishedDID(issuer, DidPurpose.JWT) + + val schemaSteps = CredentialSchemasSteps() + schemaSteps.agentHasAPublishedSchema(issuer, schema) val issueSteps = IssueCredentialsSteps() - issueSteps.issuerOffersACredential(issuer, holder, "short") + issueSteps.issuerOffersCredentialToHolderUsingSchema(issuer, holder, "short", schema) issueSteps.holderReceivesCredentialOffer(holder) issueSteps.holderAcceptsCredentialOfferForJwt(holder) issueSteps.acmeIssuesTheCredential(issuer) diff --git a/tests/integration-tests/src/test/kotlin/steps/common/ParameterSteps.kt b/tests/integration-tests/src/test/kotlin/steps/common/ParameterSteps.kt new file mode 100644 index 0000000000..d580395788 --- /dev/null +++ b/tests/integration-tests/src/test/kotlin/steps/common/ParameterSteps.kt @@ -0,0 +1,29 @@ +package steps.common + +import io.cucumber.java.DataTableType +import io.cucumber.java.ParameterType +import net.serenitybdd.screenplay.Actor +import net.serenitybdd.screenplay.actors.OnStage +import org.hyperledger.identus.client.models.* + +class ParameterSteps { + @ParameterType(".*") + fun actor(actorName: String): Actor { + return OnStage.theActorCalled(actorName) + } + + @ParameterType(".*") + fun curve(value: String): Curve { + return Curve.decode(value) ?: throw IllegalArgumentException("$value is not a valid Curve value") + } + + @ParameterType(".*") + fun purpose(value: String): Purpose { + return Purpose.decode(value) ?: throw IllegalArgumentException("$value is not a valid Purpose value") + } + + @DataTableType + fun vcVerification(cell: String): VcVerification { + return VcVerification.valueOf(cell) + } +} diff --git a/tests/integration-tests/src/test/kotlin/steps/connection/ConnectionSteps.kt b/tests/integration-tests/src/test/kotlin/steps/connection/ConnectionSteps.kt index 99d0ed603e..886bb64b86 100644 --- a/tests/integration-tests/src/test/kotlin/steps/connection/ConnectionSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/connection/ConnectionSteps.kt @@ -3,6 +3,7 @@ package steps.connection import abilities.ListenToEvents import interactions.Get import interactions.Post +import interactions.body import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get @@ -22,13 +23,9 @@ class ConnectionSteps { // Acme(Issuer) initiates a connection // and sends it to Bob(Holder) out-of-band, e.g. using QR-code val connectionLabel = "Connection with ${invitee.name}" + inviter.attemptsTo( - Post.to("/connections") - .with { - it.body( - CreateConnectionRequest(label = connectionLabel), - ) - }, + Post.to("/connections").body(CreateConnectionRequest(label = connectionLabel)), ) val connection = SerenityRest.lastResponse().get() diff --git a/tests/integration-tests/src/test/kotlin/steps/credentials/IssueCredentialsSteps.kt b/tests/integration-tests/src/test/kotlin/steps/credentials/IssueCredentialsSteps.kt index 147e5989cf..1688e3a585 100644 --- a/tests/integration-tests/src/test/kotlin/steps/credentials/IssueCredentialsSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/credentials/IssueCredentialsSteps.kt @@ -3,6 +3,7 @@ package steps.credentials import abilities.ListenToEvents import common.CredentialSchema import interactions.Post +import interactions.body import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get @@ -50,10 +51,7 @@ class IssueCredentialsSteps { ) issuer.attemptsTo( - Post.to("/issue-credentials/credential-offers") - .with { - it.body(credentialOfferRequest) - }, + Post.to("/issue-credentials/credential-offers").body(credentialOfferRequest), ) } @@ -85,11 +83,8 @@ class IssueCredentialsSteps { format: String, schema: CredentialSchema, ) { - val schemaGuid = issuer.recall(schema.name)!! - val claims = linkedMapOf( - "name" to "Name", - "age" to 18, - ) + val schemaGuid = issuer.recall(schema.name) + val claims = schema.claims sendCredentialOffer(issuer, holder, format, schemaGuid, claims) saveCredentialOffer(issuer, holder) } @@ -217,6 +212,7 @@ class IssueCredentialsSteps { it.data.thid == issuer.recall("thid") } issuer.remember("issuedCredential", credentialEvent!!.data) + credentialEvent != null && credentialEvent!!.data.protocolState == IssueCredentialRecord.ProtocolState.CREDENTIAL_SENT } diff --git a/tests/integration-tests/src/test/kotlin/steps/credentials/RevokeCredentialSteps.kt b/tests/integration-tests/src/test/kotlin/steps/credentials/RevokeCredentialSteps.kt index fcad462ec7..ab8d16d289 100644 --- a/tests/integration-tests/src/test/kotlin/steps/credentials/RevokeCredentialSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/credentials/RevokeCredentialSteps.kt @@ -4,6 +4,7 @@ import interactions.* import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get +import io.iohk.atala.automation.extensions.toJsonPath import io.iohk.atala.automation.serenity.ensure.Ensure import io.iohk.atala.automation.utils.Wait import models.JwtCredential @@ -17,8 +18,8 @@ class RevokeCredentialSteps { @When("{actor} revokes the credential issued to {actor}") fun issuerRevokesCredentialsIssuedToHolder(issuer: Actor, holder: Actor) { val issuedCredential = issuer.recall("issuedCredential") - val jwtCred = JwtCredential(issuedCredential.credential!!) - val statusListId = jwtCred.statusListId() + val jwtCred = JwtCredential.parseBase64(issuedCredential.credential!!) + val statusListId = statusListId(jwtCred) issuer.remember("statusListId", statusListId) issuer.attemptsTo( @@ -59,7 +60,6 @@ class RevokeCredentialSteps { Get.resource("/credential-status/$statusListId"), ) val actualEncodedList: String = SerenityRest.lastResponse().jsonPath().get("credentialSubject.encodedList") - println("actual encoded $actualEncodedList | before encoded $encodedStatusList") actualEncodedList != encodedStatusList } } @@ -67,12 +67,18 @@ class RevokeCredentialSteps { @Then("{actor} should see the credential is not revoked") fun issuerShouldSeeTheCredentialIsNotRevoked(issuer: Actor) { val issuedCredential = issuer.recall("issuedCredential") - val jwtCred = JwtCredential(issuedCredential.credential!!) - val statusListId = jwtCred.statusListId() + val jwtCred = JwtCredential.parseBase64(issuedCredential.credential!!) + val statusListId = statusListId(jwtCred) issuer.remember("statusListId", statusListId) - issuer.attemptsTo( Get.resource("/credential-status/$statusListId"), ) } + + private fun statusListId(jwtCredential: JwtCredential): String { + val listUrl = jwtCredential.payload!! + .toJSONObject().toJsonPath() + .read("$.vc.credentialStatus.statusListCredential") + return listUrl.split("/credential-status/")[1] + } } diff --git a/tests/integration-tests/src/test/kotlin/steps/did/ManageDidSteps.kt b/tests/integration-tests/src/test/kotlin/steps/did/ManageDidSteps.kt index b77cf8fe74..b9589a8754 100644 --- a/tests/integration-tests/src/test/kotlin/steps/did/ManageDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/did/ManageDidSteps.kt @@ -2,6 +2,7 @@ package steps.did import interactions.Get import interactions.Post +import interactions.body import io.cucumber.java.en.* import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure @@ -31,10 +32,7 @@ class ManageDidSteps { val createDidRequest = createPrismDidRequest(curve, purpose) actor.attemptsTo( - Post.to("/did-registrar/dids") - .with { - it.body(createDidRequest) - }, + Post.to("/did-registrar/dids").body(createDidRequest), ) if (SerenityRest.lastResponse().statusCode() == SC_CREATED) { diff --git a/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt b/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt index 0b766d65b4..cd4302d194 100644 --- a/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/did/PublishDidSteps.kt @@ -1,9 +1,10 @@ package steps.did import abilities.ListenToEvents -import common.TestConstants +import common.DidPurpose import interactions.Get import interactions.Post +import interactions.body import io.cucumber.java.en.* import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure @@ -17,28 +18,44 @@ import org.hyperledger.identus.client.models.* import kotlin.time.Duration.Companion.seconds class PublishDidSteps { + + @Given("{actor} has a published DID for {}") + fun agentHasAPublishedDID(agent: Actor, didPurpose: DidPurpose) { + if (agent.recallAll().containsKey("hasPublishedDid") && actualDidHasSamePurpose(agent, didPurpose)) { + return + } + agentHasAnUnpublishedDID(agent, didPurpose) + hePublishesDidToLedger(agent) + } + + @Given("{actor} has an unpublished DID for {}") + fun agentHasAnUnpublishedDID(agent: Actor, didPurpose: DidPurpose) { + if (agent.recallAll().containsKey("shortFormDid") || agent.recallAll().containsKey("longFormDid")) { + // is not published and has the same purpose + if (!agent.recallAll().containsKey("hasPublishedDid") && actualDidHasSamePurpose(agent, didPurpose)) { + return + } + } + agentCreatesUnpublishedDid(agent, didPurpose) + } + + private fun actualDidHasSamePurpose(agent: Actor, didPurpose: DidPurpose): Boolean { + val actualPurpose: DidPurpose = agent.recall("didPurpose") ?: return false + return actualPurpose == didPurpose + } + @Given("{actor} creates unpublished DID") - fun createsUnpublishedDid(actor: Actor) { + fun agentCreatesEmptyUnpublishedDid(actor: Actor) { + agentCreatesUnpublishedDid(actor, DidPurpose.EMPTY) + } + + @Given("{actor} creates unpublished DID for {}") + fun agentCreatesUnpublishedDid(actor: Actor, didPurpose: DidPurpose) { val createDidRequest = CreateManagedDidRequest( - CreateManagedDidRequestDocumentTemplate( - publicKeys = listOf( - ManagedDIDKeyTemplate("auth-1", Purpose.AUTHENTICATION, Curve.SECP256K1), - ManagedDIDKeyTemplate("auth-2", Purpose.AUTHENTICATION, Curve.ED25519), - ManagedDIDKeyTemplate("assertion-1", Purpose.ASSERTION_METHOD, Curve.SECP256K1), - ManagedDIDKeyTemplate("comm-1", Purpose.KEY_AGREEMENT, Curve.X25519), - ), - services = listOf( - Service("https://foo.bar.com", listOf("LinkedDomains"), Json("https://foo.bar.com/")), - Service("https://update.com", listOf("LinkedDomains"), Json("https://update.com/")), - Service("https://remove.com", listOf("LinkedDomains"), Json("https://remove.com/")), - ), - ), + CreateManagedDidRequestDocumentTemplate(didPurpose.publicKeys, services = didPurpose.services), ) actor.attemptsTo( - Post.to("/did-registrar/dids") - .with { - it.body(createDidRequest) - }, + Post.to("/did-registrar/dids").body(createDidRequest), Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), ) @@ -54,42 +71,18 @@ class PublishDidSteps { actor.remember("longFormDid", managedDid.longFormDid) actor.remember("shortFormDid", did.did) + actor.remember("didPurpose", didPurpose) actor.forget("hasPublishedDid") } - @Given("{actor} has a published DID") - fun agentHasAPublishedDID(agent: Actor) { - if (agent.recallAll().containsKey("hasPublishedDid")) { - return - } - if (!agent.recallAll().containsKey("shortFormDid") && - !agent.recallAll().containsKey("longFormDid") - ) { - createsUnpublishedDid(agent) - } - hePublishesDidToLedger(agent) - } - - @Given("{actor} has an unpublished DID") - fun agentHasAnUnpublishedDID(agent: Actor) { - if (agent.recallAll().containsKey("shortFormDid") || - agent.recallAll().containsKey("longFormDid") - ) { - // is not published - if (!agent.recallAll().containsKey("hasPublishedDid")) { - return - } - } - createsUnpublishedDid(agent) - } - @When("{actor} publishes DID to ledger") fun hePublishesDidToLedger(actor: Actor) { + val shortFormDid = actor.recall("shortFormDid") actor.attemptsTo( - Post.to("/did-registrar/dids/${actor.recall("shortFormDid")}/publications"), + Post.to("/did-registrar/dids/$shortFormDid/publications"), ) - val didOperationResponse = SerenityRest.lastResponse().get() + val didOperationResponse = SerenityRest.lastResponse().get() actor.attemptsTo( Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_ACCEPTED), Ensure.that(didOperationResponse.scheduledOperation.didRef).isNotEmpty(), @@ -115,7 +108,7 @@ class PublishDidSteps { Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK), Ensure.that(didDocument.id).isEqualTo(actor.recall("shortFormDid")), ) - + actor.remember("didVerification", didDocument.verificationMethod) actor.remember("hasPublishedDid", true) } @@ -126,9 +119,6 @@ class PublishDidSteps { val shortFormDid = actor.recall("shortFormDid") actor.attemptsTo( Ensure.that(didDocument.id).isEqualTo(shortFormDid), - Ensure.that(didDocument.authentication!![0]) - .isEqualTo("$shortFormDid#${TestConstants.PRISM_DID_AUTH_KEY.id}"), - Ensure.that(didDocument.verificationMethod!![0].controller).isEqualTo(shortFormDid), Ensure.that(didResolutionResult.didDocumentMetadata.deactivated!!).isFalse(), ) } diff --git a/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt b/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt index cb3ddf0131..b2a73bf072 100644 --- a/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/did/UpdateDidSteps.kt @@ -1,8 +1,8 @@ package steps.did -import common.TestConstants import interactions.Get import interactions.Post +import interactions.body import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get @@ -19,85 +19,75 @@ class UpdateDidSteps { @When("{actor} updates PRISM DID by adding new key with {curve} curve and {purpose} purpose") fun actorUpdatesPrismDidByAddingNewKeys(actor: Actor, curve: Curve, purpose: Purpose) { val newDidKeyId = UUID.randomUUID().toString() - val didKey = ManagedDIDKeyTemplate( - id = newDidKeyId, - purpose = purpose, - curve = curve, - ) val updatePrismDidAction = UpdateManagedDIDRequestAction( actionType = ActionType.ADD_KEY, - addKey = didKey, + addKey = ManagedDIDKeyTemplate( + id = newDidKeyId, + purpose = purpose, + curve = curve, + ), ) actor.remember("newDidKeyId", newDidKeyId) - actor.remember("updatePrismDidAction", updatePrismDidAction) + actorSubmitsPrismDidUpdateOperation(actor, updatePrismDidAction) } @When("{actor} updates PRISM DID by removing keys") fun actorUpdatesPrismDidByRemovingKeys(actor: Actor) { + val didKeyId = actor.recall("newDidKeyId") val updatePrismDidAction = UpdateManagedDIDRequestAction( actionType = ActionType.REMOVE_KEY, - removeKey = RemoveEntryById(TestConstants.PRISM_DID_AUTH_KEY.id), + removeKey = RemoveEntryById(didKeyId), ) - actor.remember("updatePrismDidAction", updatePrismDidAction) + actorSubmitsPrismDidUpdateOperation(actor, updatePrismDidAction) } @When("{actor} updates PRISM DID with new services") fun actorUpdatesPrismDidWithNewServices(actor: Actor) { + val serviceId = UUID.randomUUID().toString() val updatePrismDidAction = UpdateManagedDIDRequestAction( actionType = ActionType.ADD_SERVICE, - addService = TestConstants.PRISM_DID_UPDATE_NEW_SERVICE, + addService = Service( + id = serviceId, + type = listOf("LinkedDomains"), + serviceEndpoint = Json("https://service.com/"), + ), ) - actor.remember("updatePrismDidAction", updatePrismDidAction) + actor.remember("newServiceId", serviceId) + actorSubmitsPrismDidUpdateOperation(actor, updatePrismDidAction) } @When("{actor} updates PRISM DID by removing services") fun actorUpdatesPrismDidByRemovingServices(actor: Actor) { + val serviceId = actor.recall("newServiceId") val updatePrismDidAction = UpdateManagedDIDRequestAction( actionType = ActionType.REMOVE_SERVICE, - removeService = RemoveEntryById(TestConstants.PRISM_DID_UPDATE_NEW_SERVICE.id), + removeService = RemoveEntryById(serviceId), ) - actor.remember("updatePrismDidAction", updatePrismDidAction) + actorSubmitsPrismDidUpdateOperation(actor, updatePrismDidAction) } @When("{actor} updates PRISM DID by updating services") fun actorUpdatesPrismDidByUpdatingServices(actor: Actor) { - val newService = UpdateManagedDIDServiceAction( - id = TestConstants.PRISM_DID_SERVICE_FOR_UPDATE.id, - type = TestConstants.PRISM_DID_SERVICE_FOR_UPDATE.type, - serviceEndpoint = Json( - TestConstants.PRISM_DID_UPDATE_NEW_SERVICE_URL, - ), - ) + val serviceId = actor.recall("newServiceId") + val newServiceUrl = "https://update.com" val updatePrismDidAction = UpdateManagedDIDRequestAction( actionType = ActionType.UPDATE_SERVICE, - updateService = newService, + updateService = UpdateManagedDIDServiceAction( + id = serviceId, + type = listOf("LinkedDomains"), + serviceEndpoint = Json(newServiceUrl), + ), ) - actor.remember("updatePrismDidAction", updatePrismDidAction) - } - @When("{actor} submits PRISM DID update operation") - fun actorSubmitsPrismDidUpdateOperation(actor: Actor) { - actor.attemptsTo( - Post.to("/did-registrar/dids/${actor.recall("shortFormDid")}/updates") - .with { - it.body(UpdateManagedDIDRequest(listOf(actor.recall("updatePrismDidAction")))) - }, - ) - val didOperationResponse = SerenityRest.lastResponse().get() - actor.attemptsTo( - Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_ACCEPTED), - Ensure.that(didOperationResponse.scheduledOperation.didRef).isNotEmpty(), - Ensure.that(didOperationResponse.scheduledOperation.id).isNotEmpty(), - ) + actor.remember("newServiceUrl", newServiceUrl) + actorSubmitsPrismDidUpdateOperation(actor, updatePrismDidAction) } @Then("{actor} sees PRISM DID was successfully updated with new keys of {purpose} purpose") fun actorSeesDidSuccessfullyUpdatedWithNewKeys(actor: Actor, purpose: Purpose) { val newDidKeyId = actor.recall("newDidKeyId") - var i = 0 - Wait.until( - errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!", - ) { + + Wait.until(errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!") { actor.attemptsTo( Get.resource("/dids/${actor.recall("shortFormDid")}"), ) @@ -115,27 +105,30 @@ class UpdateDidSteps { } } - @Then("{actor} sees PRISM DID was successfully updated and keys removed") - fun actorSeesDidSuccessfullyUpdatedAndKeysRemoved(actor: Actor) { - Wait.until( - errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!", - ) { + @Then("{actor} sees PRISM DID was successfully updated and keys removed with {purpose} purpose") + fun actorSeesDidSuccessfullyUpdatedAndKeysRemoved(actor: Actor, purpose: Purpose) { + val newDidKeyId = actor.recall("newDidKeyId") + Wait.until(errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!") { actor.attemptsTo( Get.resource("/dids/${actor.recall("shortFormDid")}"), ) - val authUris = SerenityRest.lastResponse().get().didDocument!!.authentication!! - val verificationMethods = SerenityRest.lastResponse() - .get().didDocument!!.verificationMethod!!.map { it.id } - authUris.none { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_AUTH_KEY.id}" - } && verificationMethods.none { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_AUTH_KEY.id}" + val didKey = "${actor.recall("shortFormDid")}#$newDidKeyId" + val didDocument = SerenityRest.lastResponse().get().didDocument!! + val verificationMethodNotPresent = didDocument.verificationMethod!!.map { it.id }.none { it == didKey } + + verificationMethodNotPresent && when (purpose) { + Purpose.ASSERTION_METHOD -> didDocument.assertionMethod!!.none { it == didKey } + Purpose.AUTHENTICATION -> didDocument.authentication!!.none { it == didKey } + Purpose.CAPABILITY_DELEGATION -> didDocument.capabilityDelegation!!.none { it == didKey } + Purpose.CAPABILITY_INVOCATION -> didDocument.capabilityInvocation!!.none { it == didKey } + Purpose.KEY_AGREEMENT -> didDocument.keyAgreement!!.none { it == didKey } } } } - @Then("{actor} sees PRISM DID was successfully updated with new services") + @Then("{actor} sees that PRISM DID should have the new service") fun actorSeesDidSuccessfullyUpdatedWithNewServices(actor: Actor) { + val serviceId = actor.recall("newServiceId") Wait.until( errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!", ) { @@ -145,13 +138,14 @@ class UpdateDidSteps { val serviceIds = SerenityRest.lastResponse().get().didDocument!!.service!!.map { it.id } serviceIds.any { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_UPDATE_NEW_SERVICE.id}" + it == "${actor.recall("shortFormDid")}#$serviceId" } } } - @Then("{actor} sees PRISM DID was successfully updated by removing services") + @Then("{actor} sees the PRISM DID should have the service removed") fun actorSeesDidSuccessfullyUpdatedByRemovingServices(actor: Actor) { + val serviceId = actor.recall("newServiceId") Wait.until( errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!", ) { @@ -161,13 +155,14 @@ class UpdateDidSteps { val serviceIds = SerenityRest.lastResponse().get().didDocument!!.service!!.map { it.id } serviceIds.none { - it == "${actor.recall("shortFormDid")}#${TestConstants.PRISM_DID_UPDATE_NEW_SERVICE.id}" + it == "${actor.recall("shortFormDid")}#$serviceId" } } } - @Then("{actor} sees PRISM DID was successfully updated by updating services") + @Then("{actor} sees the PRISM DID should have the service updated") fun actorSeesDidSuccessfullyUpdatedByUpdatingServices(actor: Actor) { + val serviceUrl = actor.recall("newServiceUrl") Wait.until( errorMessage = "ERROR: DID UPDATE operation did not succeed on the ledger!", ) { @@ -175,7 +170,36 @@ class UpdateDidSteps { Get.resource("/dids/${actor.recall("shortFormDid")}"), ) val service = SerenityRest.lastResponse().get().didDocument!!.service!! - service.any { it.serviceEndpoint.value.contains(TestConstants.PRISM_DID_UPDATE_NEW_SERVICE_URL) } + service.any { it.serviceEndpoint.value.contains(serviceUrl) } } } + + private fun actorSubmitsPrismDidUpdateOperation(actor: Actor, updatePrismDidAction: UpdateManagedDIDRequestAction) { + actor.attemptsTo( + Post.to("/did-registrar/dids/${actor.recall("shortFormDid")}/updates") + .body(UpdateManagedDIDRequest(listOf(updatePrismDidAction))), + ) + } + + @Then("{actor} sees the PRISM DID should have been updated successfully") + fun checkIfUpdateWasSuccessful(actor: Actor) { + val didOperationResponse = SerenityRest.lastResponse().get() + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_ACCEPTED), + Ensure.that(didOperationResponse.scheduledOperation.didRef).isNotEmpty(), + Ensure.that(didOperationResponse.scheduledOperation.id).isNotEmpty(), + ) + } + + @Then("{actor} sees the PRISM DID was not successfully updated") + fun checkIfUpdateWasNotSuccessful(actor: Actor) { + val detail: String = SerenityRest.lastResponse().get("detail") + actor.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_BAD_REQUEST), + Ensure.that(detail) + .contains( + "Ed25519 must be used in [Authentication, AssertionMethod]. X25519 must be used in [KeyAgreement]", + ), + ) + } } diff --git a/tests/integration-tests/src/test/kotlin/steps/proofs/PresentProofSteps.kt b/tests/integration-tests/src/test/kotlin/steps/proofs/PresentProofSteps.kt index d6452a45e8..b0599b7627 100644 --- a/tests/integration-tests/src/test/kotlin/steps/proofs/PresentProofSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/proofs/PresentProofSteps.kt @@ -3,6 +3,7 @@ package steps.proofs import abilities.ListenToEvents import interactions.Patch import interactions.Post +import interactions.body import io.cucumber.java.en.Then import io.cucumber.java.en.When import io.iohk.atala.automation.extensions.get @@ -11,16 +12,17 @@ import io.iohk.atala.automation.utils.Wait import models.PresentationStatusAdapter import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor -import org.apache.http.HttpStatus.SC_CREATED +import org.apache.http.HttpStatus.* import org.hyperledger.identus.client.models.* import kotlin.time.Duration.Companion.seconds class PresentProofSteps { @When("{actor} sends a request for proof presentation to {actor}") - fun faberSendsARequestForProofPresentationToBob(faber: Actor, bob: Actor) { + fun verifierSendsARequestForProofPresentationToHolder(verifier: Actor, holder: Actor) { + val verifierConnectionToHolder = verifier.recall("connection-with-${holder.name}").connectionId val presentationRequest = RequestPresentationInput( - connectionId = faber.recall("connection-with-${bob.name}").connectionId, + connectionId = verifierConnectionToHolder, options = Options( challenge = "11c91493-01b3-4c4d-ac36-b336bab5bddf", domain = "https://example-verifier.com", @@ -32,54 +34,47 @@ class PresentProofSteps { ), ), ) - faber.attemptsTo( - Post.to("/present-proof/presentations") - .with { - it.body( - presentationRequest, - ) - }, - ) - faber.attemptsTo( + verifier.attemptsTo( + Post.to("/present-proof/presentations").body(presentationRequest), Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), ) val presentationStatus = SerenityRest.lastResponse().get() - faber.remember("thid", presentationStatus.thid) - bob.remember("thid", presentationStatus.thid) + verifier.remember("thid", presentationStatus.thid) + holder.remember("thid", presentationStatus.thid) } - @When("{actor} receives the request") - fun bobReceivesTheRequest(bob: Actor) { + @When("{actor} receives the presentation proof request") + fun holderReceivesTheRequest(holder: Actor) { Wait.until( timeout = 30.seconds, errorMessage = "ERROR: Bob did not achieve any presentation request!", ) { - val proofEvent = ListenToEvents.with(bob).presentationEvents.lastOrNull { - it.data.thid == bob.recall("thid") + val proofEvent = ListenToEvents.with(holder).presentationEvents.lastOrNull { + it.data.thid == holder.recall("thid") } - bob.remember("presentationId", proofEvent?.data?.presentationId) + holder.remember("presentationId", proofEvent?.data?.presentationId) proofEvent?.data?.status == PresentationStatusAdapter.Status.REQUEST_RECEIVED } } - @When("{actor} makes the presentation of the proof to {actor}") - fun bobMakesThePresentationOfTheProof(bob: Actor, faber: Actor) { + @When("{actor} makes the presentation of the proof") + fun holderMakesThePresentationOfTheProofToVerifier(holder: Actor) { val requestPresentationAction = RequestPresentationAction( - proofId = listOf(bob.recall("issuedCredential").recordId), + proofId = listOf(holder.recall("issuedCredential").recordId), action = RequestPresentationAction.Action.REQUEST_MINUS_ACCEPT, ) - - bob.attemptsTo( - Patch.to("/present-proof/presentations/${bob.recall("presentationId")}").with { - it.body(requestPresentationAction) - }, + val presentationId: String = holder.recall("presentationId") + holder.attemptsTo( + Patch.to("/present-proof/presentations/$presentationId").body(requestPresentationAction), + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK), ) } @When("{actor} rejects the proof") - fun bobRejectsProof(bob: Actor) { - bob.attemptsTo( - Patch.to("/present-proof/presentations/${bob.recall("presentationId")}").with { + fun holderRejectsProof(holder: Actor) { + val presentationId: String = holder.recall("presentationId") + holder.attemptsTo( + Patch.to("/present-proof/presentations/$presentationId").with { it.body( RequestPresentationAction(action = RequestPresentationAction.Action.REQUEST_MINUS_REJECT), ) diff --git a/tests/integration-tests/src/test/kotlin/steps/schemas/CredentialSchemasSteps.kt b/tests/integration-tests/src/test/kotlin/steps/schemas/CredentialSchemasSteps.kt index 3fecf2e436..ae14368831 100644 --- a/tests/integration-tests/src/test/kotlin/steps/schemas/CredentialSchemasSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/schemas/CredentialSchemasSteps.kt @@ -1,14 +1,9 @@ package steps.schemas -import com.google.gson.Gson -import com.google.gson.JsonObject -import common.CredentialSchema +import common.* import common.CredentialSchema.STUDENT_SCHEMA -import interactions.Get -import interactions.Post -import io.cucumber.java.en.Given -import io.cucumber.java.en.Then -import io.cucumber.java.en.When +import interactions.* +import io.cucumber.java.en.* import io.iohk.atala.automation.extensions.get import io.iohk.atala.automation.serenity.ensure.Ensure import models.JsonSchema @@ -32,22 +27,16 @@ class CredentialSchemasSteps { @When("{actor} creates a new credential {} schema") fun agentCreatesANewCredentialSchema(actor: Actor, schema: CredentialSchema) { actor.attemptsTo( - Post.to("/schema-registry/schemas").with { - it.body( - schema.credentialSchema.copy(author = actor.recall("shortFormDid")), - ) - }, + Post.to("/schema-registry/schemas").body( + schema.credentialSchema.copy(author = actor.recall("shortFormDid")), + ), ) actor.remember(schema.name, SerenityRest.lastResponse().get("guid")) } @When("{actor} creates a schema containing '{}' issue") fun agentCreatesASchemaContainingIssue(actor: Actor, schema: SchemaErrorTemplate) { - actor.attemptsTo( - Post.to("/schema-registry/schemas").with { - it.body(schema.schema(actor)) - }, - ) + actor.attemptsTo(Post.to("/schema-registry/schemas").body(schema.schema(actor))) } @Then("{actor} sees new credential schema is available") @@ -76,22 +65,17 @@ class CredentialSchemasSteps { fun acmeCreatesMultipleSchemas(actor: Actor, numberOfSchemas: Int) { val createdSchemas: MutableList = mutableListOf() repeat(numberOfSchemas) { i: Int -> - actor.attemptsTo( - Post.to("/schema-registry/schemas").with { - it.body( - CredentialSchemaInput( - author = actor.recall("shortFormDid"), - name = "${UUID.randomUUID()} $i", - description = "Simple student credentials schema", - type = STUDENT_SCHEMA.credentialSchemaType, - schema = STUDENT_SCHEMA.schema, - tags = listOf("school", "students"), - version = "1.0.0", - ), - ) - }, + val credentialSchemaInput = CredentialSchemaInput( + author = actor.recall("shortFormDid"), + name = "${UUID.randomUUID()} $i", + description = "Simple student credentials schema", + type = STUDENT_SCHEMA.credentialSchemaType, + schema = STUDENT_SCHEMA.schema, + tags = listOf("school", "students"), + version = "1.0.0", ) actor.attemptsTo( + Post.to("/schema-registry/schemas").body(credentialSchemaInput), Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED), ) createdSchemas.add(SerenityRest.lastResponse().get()) @@ -104,8 +88,6 @@ class CredentialSchemasSteps { actor.recall>("createdSchemas").forEach { schema -> actor.attemptsTo( Get.resource("/schema-registry/schemas/${schema.guid}"), - ) - actor.attemptsTo( Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK), ) } @@ -118,75 +100,3 @@ class CredentialSchemasSteps { ) } } - -enum class SchemaErrorTemplate { - TYPE_AND_PROPERTIES_WITHOUT_SCHEMA_TYPE { - override fun inner_schema(): String { - return """ - { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "age": { - "type": "integer" - } - }, - "required": ["name"] - } - """.trimIndent() - } - }, - CUSTOM_WORDS_NOT_DEFINED { - override fun inner_schema(): String { - return """ - { - "${"$"}schema": "http://json-schema.org/draft-2020-12/schema#", - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "age": { - "type": "integer" - } - }, - "customKeyword": "value" - } - """.trimIndent() - } - }, - MISSING_REQUIRED_FOR_MANDATORY_PROPERTY { - override fun inner_schema(): String { - return """ - { - "${"$"}schema": "http://json-schema.org/draft-2020-12/schema#", - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "age": { - "type": "integer" - } - } - } - """ - } - }, ; - - abstract fun inner_schema(): String - - fun schema(actor: Actor): String { - val innerSchema = Gson().fromJson(inner_schema(), JsonObject::class.java) - val json = getJson(actor) - json.add("schema", innerSchema) - return json.toString() - } - - private fun getJson(actor: Actor): JsonObject { - val jsonString = Gson().toJson(STUDENT_SCHEMA.credentialSchema.copy(author = actor.recall("shortFormDid"))) - return Gson().fromJson(jsonString, JsonObject::class.java) - } -} diff --git a/tests/integration-tests/src/test/kotlin/steps/verification/VcVerificationSteps.kt b/tests/integration-tests/src/test/kotlin/steps/verification/VcVerificationSteps.kt index fa3addf6ef..32f285a197 100644 --- a/tests/integration-tests/src/test/kotlin/steps/verification/VcVerificationSteps.kt +++ b/tests/integration-tests/src/test/kotlin/steps/verification/VcVerificationSteps.kt @@ -1,106 +1,139 @@ package steps.verification -import com.google.gson.Gson -import io.cucumber.java.en.When +import com.nimbusds.jose.JWSAlgorithm +import com.nimbusds.jose.jwk.Curve +import common.* +import interactions.Post +import interactions.body +import io.cucumber.datatable.DataTable +import io.cucumber.java.en.* +import io.iohk.atala.automation.extensions.getList import io.iohk.atala.automation.serenity.ensure.Ensure -import io.restassured.http.Header +import models.JwtCredential import net.serenitybdd.rest.SerenityRest import net.serenitybdd.screenplay.Actor -import net.serenitybdd.screenplay.rest.interactions.Post +import org.apache.http.HttpStatus.SC_BAD_REQUEST import org.apache.http.HttpStatus.SC_OK import org.hyperledger.identus.client.models.* +import org.hyperledger.identus.client.models.VcVerification.* import java.time.OffsetDateTime +typealias Verification = ParameterizableVcVerification + class VcVerificationSteps { - @When("{actor} verifies VcVerificationRequest") - fun agentVerifiesVerifiableCredential(actor: Actor) { - val signedJwtCredential = - "eyJhbGciOiJFUzI1NksifQ.eyJpc3MiOiJkaWQ6cHJpc206NDE1ODg1OGI1ZjBkYWMyZTUwNDdmMjI4NTk4OWVlMzlhNTNkZWJhNzY0NjFjN2FmMDM5NjU0ZGYzYjU5MjI1YyIsImF1ZCI6ImRpZDpwcmlzbTp2ZXJpZmllciIsIm5iZiI6MTI2MjMwNDAwMCwiZXhwIjoxMjYzMjU0NDAwLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vd3d3LnczLm9yZy8yMDE4L2NyZWRlbnRpYWxzL2V4YW1wbGVzL3YxIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJVbml2ZXJzaXR5RGVncmVlQ3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU2NoZW1hIjp7ImlkIjoiZGlkOndvcms6TURQOEFzRmhIemh3VXZHTnVZa1g3VDtpZD0wNmUxMjZkMS1mYTQ0LTQ4ODItYTI0My0xZTMyNmZiZTIxZGI7dmVyc2lvbj0xLjAiLCJ0eXBlIjoiSnNvblNjaGVtYVZhbGlkYXRvcjIwMTgifSwiY3JlZGVudGlhbFN1YmplY3QiOnsidXNlck5hbWUiOiJCb2IiLCJhZ2UiOjQyLCJlbWFpbCI6ImVtYWlsIn0sImNyZWRlbnRpYWxTdGF0dXMiOnsiaWQiOiJkaWQ6d29yazpNRFA4QXNGaEh6aHdVdkdOdVlrWDdUO2lkPTA2ZTEyNmQxLWZhNDQtNDg4Mi1hMjQzLTFlMzI2ZmJlMjFkYjt2ZXJzaW9uPTEuMCIsInR5cGUiOiJTdGF0dXNMaXN0MjAyMUVudHJ5Iiwic3RhdHVzUHVycG9zZSI6IlJldm9jYXRpb24iLCJzdGF0dXNMaXN0SW5kZXgiOjAsInN0YXR1c0xpc3RDcmVkZW50aWFsIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9jcmVkZW50aWFscy9zdGF0dXMvMyJ9LCJyZWZyZXNoU2VydmljZSI6eyJpZCI6Imh0dHBzOi8vZXhhbXBsZS5lZHUvcmVmcmVzaC8zNzMyIiwidHlwZSI6Ik1hbnVhbFJlZnJlc2hTZXJ2aWNlMjAxOCJ9fSwianRpIjoiaHR0cDovL2V4YW1wbGUuZWR1L2NyZWRlbnRpYWxzLzM3MzIifQ.HBxrn8Nu6y1RvUAU8XcwUDPOiiHhC1OgHN757lWai6i8P-pHL4TBzIDartYtrMiZUKpNx9Onb19sJYywtqFkpg" - - val request = - arrayOf( - VcVerificationRequest( - signedJwtCredential, - listOf( - ParameterizableVcVerification( - VcVerification.NOT_BEFORE_CHECK, - DateTimeParameter(dateTime = OffsetDateTime.parse("2010-01-01T00:00:00Z")), - ), - ParameterizableVcVerification( - VcVerification.EXPIRATION_CHECK, - DateTimeParameter(dateTime = OffsetDateTime.parse("2010-01-01T00:00:00Z")), - ), - ParameterizableVcVerification( - VcVerification.AUDIENCE_CHECK, - DidParameter(did = "did:prism:verifier"), - ), - ParameterizableVcVerification( - VcVerification.ISSUER_IDENTIFICATION, - DidParameter(did = "did:prism:4158858b5f0dac2e5047f2285989ee39a53deba76461c7af039654df3b59225c"), - ), - ), - ), - VcVerificationRequest( - signedJwtCredential, - listOf( - ParameterizableVcVerification( - VcVerification.EXPIRATION_CHECK, - DateTimeParameter(dateTime = OffsetDateTime.parse("2010-01-13T00:00:00Z")), - ), - ParameterizableVcVerification( - VcVerification.NOT_BEFORE_CHECK, - DateTimeParameter(dateTime = OffsetDateTime.parse("2009-01-01T00:00:00Z")), - ), - ParameterizableVcVerification( - VcVerification.AUDIENCE_CHECK, - DidParameter(did = "BAD AUDIENCE"), - ), - ParameterizableVcVerification( - VcVerification.ISSUER_IDENTIFICATION, - DidParameter(did = "BAD ISSUER"), - ), - ), - ), - ) + @Given("{actor} uses that JWT VC issued from {actor} for Verification API") + fun holderUsesThatJWTVCForVerificationAPI(holder: Actor, issuer: Actor) { + val issuedCredential = holder.recall("issuedCredential") + val jwt = JwtCredential.parseBase64(issuedCredential.credential!!).serialize() + val issuerDid = issuer.recall("shortFormDid") + holder.remember("jwt", jwt) + holder.remember("issuerDid", issuerDid) + } - val post = - Post.to("/verification/credential").with { - it.header(Header("apiKey", "pylnapbvyudwmfrt")) - it.body(request) - } + @Given("{actor} has a JWT VC for Verification API") + fun holderHasAJWTVCForVerificationAPI(holder: Actor) { + val jwtCredential = VerifiableJwt.jwtVCv1() + val jwt = jwtCredential.sign(JWSAlgorithm.ES256K, Curve.SECP256K1) + holder.remember("jwt", jwt) + holder.remember("issuerDid", "did:prism:issuer") + } + + @Given("{actor} has a Verifiable Schema for Verification API") + fun holderHasAVerifiableSchemaForVerificationAPI(holder: Actor) { + val jwtCredential = VerifiableJwt.schemaVCv1() + val jwt = jwtCredential.sign(JWSAlgorithm.ES384, Curve.SECP256K1) + holder.remember("jwt", jwt) + holder.remember("issuerDid", "did:prism:issuer") + } - actor.attemptsTo( - post, + @Given("{actor} has a {} problem in the Verifiable Credential") + fun holderHasProblemInTheVerifiableCredential(holder: Actor, problem: JwtCredentialProblem) { + val jwt = problem.jwt() + holder.remember("jwt", jwt) + holder.remember("issuerDid", "did:prism:issuer") + } + + @When("{actor} sends the JWT Credential to {actor} Verification API") + fun holderSendsJwtCredentialToVerificationAPI(holder: Actor, verifier: Actor, dataTable: DataTable) { + // add type to datatable + val checks = dataTable.asMap(VcVerification::class.java, Boolean::class.java) + val jwt: String = holder.recall("jwt") + val issuerDid: String = holder.recall("issuerDid") + verifyJwt(verifier, jwt, issuerDid, checks) + holder.remember("checks", checks) + } + + @Then("{actor} should see that verification has failed with {} problem") + fun holderShouldSeeThatVerificationHasFailedWithProblem(holder: Actor, problem: JwtCredentialProblem) { + } + + @Then("{actor} should see that all checks have passed") + fun holderShouldSeeThatVerificationHasPassed(holder: Actor) { + val jwt: String = holder.recall("jwt") + analyzeResponse(holder, jwt) + } + + @Then("{actor} should see the check has failed") + fun holderShouldSeeTheCheckHasFailed(holder: Actor) { + holder.attemptsTo( + Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_BAD_REQUEST), ) + } - val expected = listOf( - VcVerificationResponse( - signedJwtCredential, - listOf( - VcVerificationResult(VcVerification.NOT_BEFORE_CHECK, true), - VcVerificationResult(VcVerification.EXPIRATION_CHECK, true), - VcVerificationResult(VcVerification.AUDIENCE_CHECK, true), - VcVerificationResult(VcVerification.ISSUER_IDENTIFICATION, true), - ), - ), - VcVerificationResponse( - signedJwtCredential, - listOf( - VcVerificationResult(VcVerification.EXPIRATION_CHECK, false), - VcVerificationResult(VcVerification.NOT_BEFORE_CHECK, false), - VcVerificationResult(VcVerification.AUDIENCE_CHECK, false), - VcVerificationResult(VcVerification.ISSUER_IDENTIFICATION, false), - ), - ), + private fun verifyJwt( + verifier: Actor, + jwt: String, + issuerDid: String, + verifications: Map, + ) { + val now = OffsetDateTime.now() + + // creates the checks based on the data table from feature file + val checks = verifications.map { (key, value) -> + when (key) { + ALGORITHM_VERIFICATION -> Verification(key) to value + AUDIENCE_CHECK -> Verification(key, DidParameter(did = "did:prism:verifier")) to value + COMPLIANCE_WITH_STANDARDS -> Verification(key) to value + EXPIRATION_CHECK -> Verification(key, DateTimeParameter(dateTime = now.minusDays(5))) to value + INTEGRITY_OF_CLAIMS -> Verification(key) to value + ISSUER_IDENTIFICATION -> Verification(key, DidParameter(did = issuerDid)) to value + NOT_BEFORE_CHECK -> Verification(key, DateTimeParameter(dateTime = now.plusDays(5))) to value + REVOCATION_CHECK -> Verification(key) to value + SCHEMA_CHECK -> Verification(key) to value + SEMANTIC_CHECK_OF_CLAIMS -> Verification(key) to value + SIGNATURE_VERIFICATION -> Verification(key) to value + SUBJECT_VERIFICATION -> Verification(key, DidParameter(did = "did:prism:something")) to value + } + }.toMap() + + val vcVerificationRequest = VcVerificationRequest(jwt, checks.keys.toList()) + val payload = listOf(vcVerificationRequest) + + verifier.attemptsTo( + Post.to("/verification/credential").body(payload), ) - actor.attemptsTo( + } + + private fun analyzeResponse(holder: Actor, jwt: String) { + val checks = holder.recall>("checks") + val actual = SerenityRest.lastResponse().getList() + + holder.attemptsTo( Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK), - Ensure.that( - SerenityRest.lastResponse().body().asString(), - ).isEqualTo( - Gson().toJson(expected), - ), + Ensure.that(actual[0].credential).isEqualTo(jwt), ) + + // check each verification result from the requested checks + actual[0].result!!.forEach { + val expected = checks.getOrElse(it.verification) { + throw RuntimeException("Couldn't find ${it.verification} in verification request.") + } + + holder.attemptsTo( + Ensure.that(it.success).isEqualTo(expected) + .withReportedError("Expected [${it.verification}] to be [$expected] but got [${it.success}]"), + ) + } } } diff --git a/tests/integration-tests/src/test/resources/features/credentials/issue_anoncred_with_published_did.feature b/tests/integration-tests/src/test/resources/features/credentials/issue_anoncred_with_published_did.feature new file mode 100644 index 0000000000..051e8df412 --- /dev/null +++ b/tests/integration-tests/src/test/resources/features/credentials/issue_anoncred_with_published_did.feature @@ -0,0 +1,15 @@ +@RFC0453 @AIP20 @credentials +Feature: Issue Anoncred with published DID + + Background: + Given Issuer and Holder have an existing connection + And Issuer has a published DID for ANONCRED + And Holder has an unpublished DID for ANONCRED + + Scenario: Issuing anoncred with published PRISM DID + Given Issuer has an anoncred schema definition + When Issuer offers anoncred to Holder + And Holder receives the credential offer + And Holder accepts credential offer for anoncred + And Issuer issues the credential + Then Holder receives the issued credential diff --git a/tests/integration-tests/src/test/resources/features/credentials/issue_published_did.feature b/tests/integration-tests/src/test/resources/features/credentials/issue_jwt_with_published_did.feature similarity index 90% rename from tests/integration-tests/src/test/resources/features/credentials/issue_published_did.feature rename to tests/integration-tests/src/test/resources/features/credentials/issue_jwt_with_published_did.feature index c44fa3c948..e54fd17c2d 100644 --- a/tests/integration-tests/src/test/resources/features/credentials/issue_published_did.feature +++ b/tests/integration-tests/src/test/resources/features/credentials/issue_jwt_with_published_did.feature @@ -1,11 +1,11 @@ @RFC0453 @AIP20 @credentials -Feature: Issue Credentials Protocol with published DID +Feature: Issue JWT Credentials with published DID Background: Given Issuer and Holder have an existing connection - And Issuer has a published DID + And Issuer has a published DID for JWT And Issuer has published STUDENT_SCHEMA schema - And Holder has an unpublished DID + And Holder has an unpublished DID for JWT Scenario: Issuing credential with published PRISM DID When Issuer offers a credential to Holder with "short" form DID diff --git a/tests/integration-tests/src/test/resources/features/credentials/issue_unpublished_did.feature b/tests/integration-tests/src/test/resources/features/credentials/issue_jwt_with_unpublished_did.feature similarity index 73% rename from tests/integration-tests/src/test/resources/features/credentials/issue_unpublished_did.feature rename to tests/integration-tests/src/test/resources/features/credentials/issue_jwt_with_unpublished_did.feature index e9ac6e44f0..a658a0c453 100644 --- a/tests/integration-tests/src/test/resources/features/credentials/issue_unpublished_did.feature +++ b/tests/integration-tests/src/test/resources/features/credentials/issue_jwt_with_unpublished_did.feature @@ -1,10 +1,10 @@ @RFC0453 @AIP20 @credentials -Feature: Issue Credentials Protocol with unpublished DID +Feature: Issue JWT Credentials with unpublished DID Background: Given Issuer and Holder have an existing connection - And Issuer has an unpublished DID - And Holder has an unpublished DID + And Issuer has an unpublished DID for JWT + And Holder has an unpublished DID for JWT Scenario: Issuing credential with unpublished PRISM DID And Issuer offers a credential to Holder with "long" form DID diff --git a/tests/integration-tests/src/test/resources/features/did/create_did.feature b/tests/integration-tests/src/test/resources/features/did/create_did.feature index 3879305102..55ebe81a21 100644 --- a/tests/integration-tests/src/test/resources/features/did/create_did.feature +++ b/tests/integration-tests/src/test/resources/features/did/create_did.feature @@ -1,28 +1,28 @@ @DLT @did @create Feature: Create and publish DID -Scenario Outline: Create PRISM DID - When Issuer creates PRISM DID with key having purpose - Then He sees PRISM DID was created successfully - And He sees PRISM DID data was stored correctly with and -Examples: - | curve | purpose | - | secp256k1 | authentication | - | secp256k1 | assertionMethod | - | Ed25519 | authentication | - | Ed25519 | assertionMethod | - | X25519 | keyAgreement | + Scenario Outline: Create PRISM DID + When Issuer creates PRISM DID with key having purpose + Then He sees PRISM DID was created successfully + And He sees PRISM DID data was stored correctly with and + Examples: + | curve | purpose | + | secp256k1 | authentication | + | secp256k1 | assertionMethod | + | Ed25519 | authentication | + | Ed25519 | assertionMethod | + | X25519 | keyAgreement | -Scenario Outline: Create PRISM DID with disallowed key purpose - When Issuer creates PRISM DID with key having purpose - Then He sees PRISM DID was not successfully created - Examples: - | curve | purpose | - | Ed25519 | keyAgreement | - | X25519 | authentication | - | X25519 | assertionMethod | + Scenario Outline: Create PRISM DID with disallowed key purpose + When Issuer creates PRISM DID with key having purpose + Then He sees PRISM DID was not successfully created + Examples: + | curve | purpose | + | Ed25519 | keyAgreement | + | X25519 | authentication | + | X25519 | assertionMethod | -Scenario: Successfully publish DID to ledger - When Issuer creates unpublished DID - And He publishes DID to ledger - Then He resolves DID document corresponds to W3C standard + Scenario: Successfully publish DID to ledger + Given Issuer creates unpublished DID + When He publishes DID to ledger + Then He resolves DID document corresponds to W3C standard diff --git a/tests/integration-tests/src/test/resources/features/did/update_did.feature b/tests/integration-tests/src/test/resources/features/did/update_did.feature index 67760dc1b6..9aeb2e122f 100644 --- a/tests/integration-tests/src/test/resources/features/did/update_did.feature +++ b/tests/integration-tests/src/test/resources/features/did/update_did.feature @@ -2,27 +2,27 @@ Feature: Update DID Background: Published DID is created - Given Issuer has a published DID + Given Issuer has a published DID for JWT - Scenario: Update PRISM DID by adding new services + Scenario: Update PRISM DID services When Issuer updates PRISM DID with new services - And He submits PRISM DID update operation - Then He sees PRISM DID was successfully updated with new services + Then He sees the PRISM DID should have been updated successfully + And He sees that PRISM DID should have the new service - Scenario: Update PRISM DID by removing services - When Issuer updates PRISM DID by removing services - And He submits PRISM DID update operation - Then He sees PRISM DID was successfully updated by removing services - - Scenario: Update PRISM DID by updating services When Issuer updates PRISM DID by updating services - And He submits PRISM DID update operation - Then He sees PRISM DID was successfully updated by updating services + Then He sees the PRISM DID should have been updated successfully + And He sees the PRISM DID should have the service updated - Scenario Outline: Update PRISM DID by adding new keys + When Issuer updates PRISM DID by removing services + Then He sees the PRISM DID should have been updated successfully + And He sees the PRISM DID should have the service removed + + Scenario Outline: Update PRISM DID keys When Issuer updates PRISM DID by adding new key with curve and purpose - And He submits PRISM DID update operation Then He sees PRISM DID was successfully updated with new keys of purpose + + When Issuer updates PRISM DID by removing keys + Then He sees PRISM DID was successfully updated and keys removed with purpose Examples: | curve | purpose | | secp256k1 | authentication | @@ -31,7 +31,11 @@ Feature: Update DID | Ed25519 | assertionMethod | | X25519 | keyAgreement | - Scenario: Update PRISM DID by removing keys - When Issuer updates PRISM DID by removing keys - And He submits PRISM DID update operation - Then He sees PRISM DID was successfully updated and keys removed + Scenario Outline: Update PRISM DID with disallowed key purpose + When Issuer updates PRISM DID by adding new key with curve and purpose + Then He sees the PRISM DID was not successfully updated + Examples: + | curve | purpose | + | Ed25519 | keyAgreement | + | X25519 | authentication | + | X25519 | assertionMethod | diff --git a/tests/integration-tests/src/test/resources/features/proofs/present_proof.feature b/tests/integration-tests/src/test/resources/features/proofs/present_proof.feature index f19b73090d..c2fa51b80d 100644 --- a/tests/integration-tests/src/test/resources/features/proofs/present_proof.feature +++ b/tests/integration-tests/src/test/resources/features/proofs/present_proof.feature @@ -3,24 +3,25 @@ Feature: Present Proof Protocol Scenario: Holder presents credential proof to verifier Given Verifier and Holder have an existing connection - And Holder has an issued credential from Issuer + And Holder has a jwt issued credential from Issuer When Verifier sends a request for proof presentation to Holder - And Holder receives the request - And Holder makes the presentation of the proof to Verifier + And Holder receives the presentation proof request + And Holder makes the presentation of the proof Then Verifier has the proof verified + Scenario: Holder presents proof to verifier which is the issuer itself + Given Issuer and Holder have an existing connection + And Holder has a jwt issued credential from Issuer + When Issuer sends a request for proof presentation to Holder + And Holder receives the presentation proof request + And Holder makes the presentation of the proof + Then Issuer has the proof verified + Scenario: Verifier rejects holder proof Given Verifier and Holder have an existing connection - And Holder has an issued credential from Issuer + And Holder has a jwt issued credential from Issuer When Verifier sends a request for proof presentation to Holder - And Holder receives the request + And Holder receives the presentation proof request And Holder rejects the proof Then Holder sees the proof is rejected - Scenario: Holder presents proof to verifier which is the issuer itself - Given Issuer and Holder have an existing connection - And Holder has an issued credential from Issuer - When Issuer sends a request for proof presentation to Holder - And Holder receives the request - And Holder makes the presentation of the proof to Issuer - Then Issuer has the proof verified diff --git a/tests/integration-tests/src/test/resources/features/proofs/present_proof_anoncred.feature b/tests/integration-tests/src/test/resources/features/proofs/present_proof_anoncred.feature index 102140b1fa..77c52dc572 100644 --- a/tests/integration-tests/src/test/resources/features/proofs/present_proof_anoncred.feature +++ b/tests/integration-tests/src/test/resources/features/proofs/present_proof_anoncred.feature @@ -4,8 +4,8 @@ Feature: Present Proof Protocol Scenario: Holder presents anoncreds credential proof to verifier Given Issuer and Holder have an existing connection And Verifier and Holder have an existing connection - And Issuer has a published DID - And Holder has an unpublished DID + And Issuer has a published DID for ANONCRED + And Holder has an unpublished DID for ANONCRED And Issuer has an anoncred schema definition And Issuer offers anoncred to Holder And Holder receives the credential offer diff --git a/tests/integration-tests/src/test/resources/features/revocation/revoke_jwt_credential.feature b/tests/integration-tests/src/test/resources/features/revocation/revoke_jwt_credential.feature index 2ac02f447b..b60e7d7bf9 100644 --- a/tests/integration-tests/src/test/resources/features/revocation/revoke_jwt_credential.feature +++ b/tests/integration-tests/src/test/resources/features/revocation/revoke_jwt_credential.feature @@ -2,20 +2,20 @@ Feature: Credential revocation - JWT Background: - Given Holder has an issued credential from Issuer + Given Holder has a jwt issued credential from Issuer Scenario: Revoke issued credential When Issuer revokes the credential issued to Holder Then Issuer should see the credential was revoked When Issuer sends a request for proof presentation to Holder - And Holder receives the request - And Holder makes the presentation of the proof to Issuer + And Holder receives the presentation proof request + And Holder makes the presentation of the proof Then Issuer sees the proof returned verification failed Scenario: Holder tries to revoke credential from issuer When Holder tries to revoke credential from Issuer And Issuer sends a request for proof presentation to Holder - And Holder receives the request - And Holder makes the presentation of the proof to Issuer + And Holder receives the presentation proof request + And Holder makes the presentation of the proof Then Issuer has the proof verified And Issuer should see the credential is not revoked diff --git a/tests/integration-tests/src/test/resources/features/schemas/credential_schemas.feature b/tests/integration-tests/src/test/resources/features/schemas/credential_schemas.feature index fb65e1682d..fdbbbc911f 100644 --- a/tests/integration-tests/src/test/resources/features/schemas/credential_schemas.feature +++ b/tests/integration-tests/src/test/resources/features/schemas/credential_schemas.feature @@ -2,7 +2,7 @@ Feature: Credential schemas Background: - When Issuer creates unpublished DID + Given Issuer creates unpublished DID Scenario: Successful schema creation When Issuer creates a new credential STUDENT_SCHEMA schema diff --git a/tests/integration-tests/src/test/resources/features/verification/vc_verification.feature b/tests/integration-tests/src/test/resources/features/verification/vc_verification.feature deleted file mode 100644 index c09163f1b8..0000000000 --- a/tests/integration-tests/src/test/resources/features/verification/vc_verification.feature +++ /dev/null @@ -1,6 +0,0 @@ -@verification @api -Feature: Vc Verification schemas - -Scenario: Successful Verifies VcVerificationRequest - Given Issuer and Holder have an existing connection - When Issuer verifies VcVerificationRequest diff --git a/tests/integration-tests/src/test/resources/features/verificationapi/vc_verification.feature b/tests/integration-tests/src/test/resources/features/verificationapi/vc_verification.feature new file mode 100644 index 0000000000..3db147f66d --- /dev/null +++ b/tests/integration-tests/src/test/resources/features/verificationapi/vc_verification.feature @@ -0,0 +1,54 @@ +@verification @api +Feature: Vc Verification schemas + + Scenario: Receive a jwt vc from cloud-agent and verify it + Given Holder has a jwt issued credential with STUDENT_SCHEMA schema from Issuer + And Holder uses that JWT VC issued from Issuer for Verification API + And Holder sends the JWT Credential to Issuer Verification API + | ALGORITHM_VERIFICATION | true | + | EXPIRATION_CHECK | true | + | ISSUER_IDENTIFICATION | true | + | NOT_BEFORE_CHECK | true | + | SCHEMA_CHECK | true | + | SIGNATURE_VERIFICATION | true | + | SEMANTIC_CHECK_OF_CLAIMS | true | + Then Holder should see that all checks have passed + + Scenario: Expected checks for generated JWT VC + Given Holder has a JWT VC for Verification API + When Holder sends the JWT Credential to Issuer Verification API + | ALGORITHM_VERIFICATION | true | + | AUDIENCE_CHECK | true | + | EXPIRATION_CHECK | true | + | ISSUER_IDENTIFICATION | true | + | NOT_BEFORE_CHECK | true | + | SIGNATURE_VERIFICATION | false | + | SEMANTIC_CHECK_OF_CLAIMS | true | + Then Holder should see that all checks have passed + + Scenario Outline: Expected failures + Given Holder has a problem in the Verifiable Credential + When Holder sends the JWT Credential to Issuer Verification API + | | false | + Then Holder should see that verification has failed with problem + Examples: + | problem | + | ALGORITHM_VERIFICATION | + | AUDIENCE_CHECK | + | EXPIRATION_CHECK | + | ISSUER_IDENTIFICATION | + | NOT_BEFORE_CHECK | + | SIGNATURE_VERIFICATION | + | SEMANTIC_CHECK_OF_CLAIMS | + + Scenario Outline: Unsupported verification check should fail + Given Holder has a JWT VC for Verification API + When Holder sends the JWT Credential to Issuer Verification API + | | false | + Then Holder should see the check has failed + Examples: + | verification | + | COMPLIANCE_WITH_STANDARDS | + | INTEGRITY_OF_CLAIMS | + | REVOCATION_CHECK | + | SUBJECT_VERIFICATION | From e5e341139ba4a93a748cfb8af10928c6d45ba310 Mon Sep 17 00:00:00 2001 From: Allain Magyar Date: Thu, 27 Jun 2024 08:26:51 -0300 Subject: [PATCH 2/2] chore: fix image centering in integration test (#1229) Signed-off-by: Allain Magyar --- tests/integration-tests/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/integration-tests/README.md b/tests/integration-tests/README.md index a01890699f..2fef57bf71 100644 --- a/tests/integration-tests/README.md +++ b/tests/integration-tests/README.md @@ -29,7 +29,7 @@ The Screenplay pattern is used to write the tests. The pattern is described in d * Each actor has their own abilities (actions they can perform) and interactions (tasks they can carry out). These interactions encapsulate the steps required to achieve a certain goal in the system. * The Screenplay Pattern promotes the use of high-level, business-oriented language in test scripts, making them more understandable to non-technical stakeholders. -

+

Screenplay pattern overview
@@ -68,7 +68,7 @@ The main idea of the framework is to test the ICA as a black box. The tests interact with the ICA through the API and webhook messages. -

+

Screenplay pattern overview
@@ -442,7 +442,7 @@ AGENT_VERSION=v1.36.1 PRISM_NODE_VERSION=v2.3.0 ./gradlew regression --continue Each `context` is based on the configuration used for the current execution and will be displayed in the Serenity report: -

+

Serenity Regression report contexts
@@ -457,7 +457,7 @@ It is easy to do by executing `IntegrationTestsRunner` class and selecting the r The required configuration will be created, but you have to edit it to set the environment variables. -

+

Running tests in IntelliJ IDEA
@@ -516,14 +516,14 @@ You could start by opening `index.html` file in your browser. On the main report page you could see the summary of the test run as well as the functional coverage table: -

+

Report summary
HTML-report summary example.

-

+

Functional coverage
@@ -532,7 +532,7 @@ On the main report page you could see the summary of the test run as well as the Then, you can go deeper to each scenario and open each step to see the details of the test execution: -

+

REST requests analysis
@@ -579,7 +579,7 @@ AGENT_VERSION=v1.36.1 PRISM_NODE_VERSION=v2.3.0 ./gradlew test_basic Will have the logs output as such: -

+

Docker logs directory