Skip to content

Commit

Permalink
Merge pull request #16 from petridishdev/feature/w3c
Browse files Browse the repository at this point in the history
feat: add support for cardinality in credential type registration
  • Loading branch information
esune authored Nov 25, 2024
2 parents eeaf4c3 + b3377b7 commit 8f97ed2
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 13 deletions.
3 changes: 2 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"--reload"
],
"env": {
"ARIES_VCR_URL": "http://host.docker.internal:8008",
"ISSER_REGISTRY_URL": "https://bcgov.github.io/digital-trust-toolkit/registrations/issuers/dev.json",
"ARIES_VCR_URL": "http://host.docker.internal:8080",
},
"jinja": true
},
Expand Down
3 changes: 2 additions & 1 deletion schemas/credential_type.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Annotated

from fastapi import Body
from schemas import CredentialMapping, CredentialTopic, Options
from schemas import CredentialMapping, CredentialTopic, Options, Path
from pydantic import BaseModel


Expand All @@ -18,3 +18,4 @@ class CredentialType(Options, BaseModel):
oca_bundle: Annotated[dict | None, Body(validation_alias="ocaBundle")] = None
topic: CredentialTopic
mappings: list[CredentialMapping] | None = None
cardinality: list[Path] | None = None
6 changes: 6 additions & 0 deletions schemas/mappings/vcr_credential_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,10 @@ def serialize_model(self) -> dict[str, Any]:
mapping.model_dump(mode="json") for mapping in secured_document.mappings
]

if secured_document.cardinality:
model_dump["cardinality"] = [
cardinality.model_dump(mode="json")
for cardinality in secured_document.cardinality
]

return model_dump
26 changes: 18 additions & 8 deletions tests/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
"path": "$.path.to.credential.expiry_date",
}

credential_subject_cardinality_spec = {
"path": "$.path.to.credentialSubject.id",
}

credential_type_spec = {
"format": "vc_di",
"type": "BCPetroleum&NaturalGasTitle",
Expand All @@ -25,6 +29,9 @@
effective_date_mapping_spec,
expiry_date_mapping_spec,
],
"cardinality": [
credential_subject_cardinality_spec,
],
}

secured_credential_type_spec = {
Expand All @@ -34,16 +41,19 @@
"name": "BC Petroleum & Natural Gas Title",
"version": "0.0.3",
"verificationMethods": [
"did:web:untp.traceability.site:parties:regulators:director-of-petroleum-lands#multikey"
"did:web:registry-dev.apps.silver.devops.gov.bc.ca:petroleum-and-natural-gas-act:director-of-petroleum-lands#multikey"
],
"topic": {
"type": "my-registration.city-of-vancouver",
"type": "registration.bc-registries",
"sourceId": {"path": "$.credentialSubject.issuedTo.identifier"},
},
"mappings": [
{"type": "effective_date", "name": "effective_date", "path": "$.validFrom"},
{"type": "expiry_date", "name": "expiry_date", "path": "$.validUntil"},
],
"cardinality": [
{"path": "$.credentialSubject.issuedTo.id"},
],
"resources": [
{
"type": "OverlayCaptureBundle",
Expand All @@ -57,7 +67,7 @@
{
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-jcs-2022",
"verificationMethod": "did:web:untp.traceability.site:parties:regulators:director-of-petroleum-lands#multikey",
"verificationMethod": "did:web:registry-dev.apps.silver.devops.gov.bc.ca:petroleum-and-natural-gas-act:director-of-petroleum-lands#multikey",
"proofPurpose": "authentication",
"proofValue": "z17CzsxiNiugmX9CYseEkoXxjMqBDxyasiwWwZ58AD5ctKJLjSeoEmSBvj5VVxzATFfpwKdfRmjqLn2wRMhb9jHV",
}
Expand All @@ -75,24 +85,24 @@
"securedDocument": {
"@context": ["https://www.w3.org/ns/credentials/v2"],
"type": ["VerifiableCredential", "BCPetroleum&NaturalGasTitle"],
"id": "https://localhost:8080/api/vc/topic/0f95da2f-1485-4848-a93c-8abebc223e41/credential/123456",
"id": "https://localhost:8080/api/vc/topic/d6499ae0-4f9f-453b-93e7-07f4585ff703/credential/123456",
"issuer": {
"id": "did:web:untp.traceability.site:parties:regulators:director-of-petroleum-lands#multikey"
"id": "did:web:registry-dev.apps.silver.devops.gov.bc.ca:petroleum-and-natural-gas-act:director-of-petroleum-lands#multikey"
},
"validFrom": "2024-08-12T05:44:20+00:00",
"validUntil": "2025-08-12T05:44:20+00:00",
"credentialSubject": {
"issuedTo": {
"id": "https://orgbook.gov.bc.ca/api/vc/topic/0f95da2f-1485-4848-a93c-8abebc223e41",
"id": "https://orgbook.gov.bc.ca/api/vc/topic/d6499ae0-4f9f-453b-93e7-07f4585ff703-2",
"legalName": "PACIFIC CANBRIAM ENERGY LIMITED",
"identifier": "0f95da2f-1485-4848-a93c-8abebc223e41",
"identifier": "d6499ae0-4f9f-453b-93e7-07f4585ff703",
}
},
"proof": [
{
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-jcs-2022",
"verificationMethod": "did:web:untp.traceability.site:parties:regulators:director-of-petroleum-lands#multikey",
"verificationMethod": "did:web:registry-dev.apps.silver.devops.gov.bc.ca:petroleum-and-natural-gas-act:director-of-petroleum-lands#multikey",
"proofPurpose": "assertionMethod",
"proofValue": "z2Nr9eDUfBzircv484R3u7vzdxARh5D8vsbj4ohFRQZhkq2PTdJ9YsLfF18mafaPMtchV5EefmovvFoFbFNmLqrWW",
}
Expand Down
1 change: 0 additions & 1 deletion tests/test_credential_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ def test_issue_credential():
response = client.post(
"/credential-types/", json=copy.deepcopy(secured_credential_type_spec)
)
print(response.json())
assert response.status_code == 201

response = client.post("/credentials/", json=copy.deepcopy(secured_credential_spec))
Expand Down
7 changes: 5 additions & 2 deletions tests/test_mappings.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ def test_valid_vcr_credential_type_output():
"format": "vc_di",
"schema": "BCPetroleum&NaturalGasTitle",
"version": "0.0.3",
"origin_did": "did:web:untp.traceability.site:parties:regulators:director-of-petroleum-lands",
"origin_did": "did:web:registry-dev.apps.silver.devops.gov.bc.ca:petroleum-and-natural-gas-act:director-of-petroleum-lands",
"topic": {
"type": "my-registration.city-of-vancouver",
"type": "registration.bc-registries",
"source_id": {"path": "$.credentialSubject.issuedTo.identifier"},
},
"mappings": [
Expand All @@ -35,6 +35,9 @@ def test_valid_vcr_credential_type_output():
"path": "$.validUntil",
},
],
"cardinality": [
{"path": "$.credentialSubject.issuedTo.id"},
],
"credential": {
"effective_date": {
"name": "effective_date",
Expand Down
73 changes: 73 additions & 0 deletions tests/test_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ def test_valid_credential_type_schema():
"source_id": topic_spec.get("sourceId"),
},
"mappings": credential_type_spec.get("mappings"),
"cardinality": credential_type_spec.get("cardinality"),
}


Expand All @@ -240,6 +241,7 @@ def test_valid_credential_type_schema_no_mappings():
"type": topic_spec.get("type"),
"source_id": topic_spec.get("sourceId"),
},
"cardinality": credential_type_spec.get("cardinality"),
}
assert "mappings" not in credential_type_output

Expand All @@ -263,7 +265,9 @@ def test_valid_credential_type_schema_empty_mappings():
"source_id": topic_spec.get("sourceId"),
},
"mappings": [],
"cardinality": credential_type_spec.get("cardinality"),
}
assert "mappings" in credential_type_output


def test_invalid_credential_type_schema_missing_format():
Expand Down Expand Up @@ -416,3 +420,72 @@ def test_invalid_credential_type_schema_invalid_mappings():
assert errors.get("msg") == "Input should be a valid list"
assert "mappings" in errors.get("loc")
assert errors.get("type") == "list_type"


def test_invalid_credential_type_schema_invalid_cardinality():
"""Test invalid CredentialType schema invalid cardinality"""

test_data = {
**credential_type_spec.copy(),
"cardinality": "invalid",
}

with pytest.raises(ValidationError) as exc_info:
CredentialType(**test_data)

errors = exc_info.value.errors()[0]

assert errors.get("msg") == "Input should be a valid list"
assert "cardinality" in errors.get("loc")
assert errors.get("type") == "list_type"


def test_valid_credential_type_schema_cardinality_missing():
"""Test valid CredentialType schema cardinality missing"""

test_data = {
**credential_type_spec.copy(),
"cardinality": None,
}

credential_type = CredentialType(**test_data)
credential_type_output = credential_type.model_dump(exclude_none=True)

assert credential_type_output == {
"format": str(credential_type_spec.get("format")),
"type": credential_type_spec.get("type"),
"version": credential_type_spec.get("version"),
"verification_methods": credential_type_spec.get("verificationMethods"),
"topic": {
"type": topic_spec.get("type"),
"source_id": topic_spec.get("sourceId"),
},
"mappings": credential_type_spec.get("mappings"),
}
assert "cardinality" not in credential_type_output


def test_valid_credential_type_schema_cardinality_empty():
"""Test valid CredentialType schema valid cardinality empty list"""

test_data = {
**credential_type_spec.copy(),
"cardinality": [],
}

credential_type = CredentialType(**test_data)
credential_type_output = credential_type.model_dump(exclude_none=True)

assert credential_type_output == {
"format": str(credential_type_spec.get("format")),
"type": credential_type_spec.get("type"),
"version": credential_type_spec.get("version"),
"verification_methods": credential_type_spec.get("verificationMethods"),
"topic": {
"type": topic_spec.get("type"),
"source_id": topic_spec.get("sourceId"),
},
"mappings": credential_type_spec.get("mappings"),
"cardinality": [],
}
assert "cardinality" in credential_type_output

0 comments on commit 8f97ed2

Please sign in to comment.