Skip to content

Commit

Permalink
[MDS-6165] - add object types to jsonld and reference untp context fi…
Browse files Browse the repository at this point in the history
…les (#3241)

* attestation type and use published vocab

* need tupe

* update dcc construction and library to dcc 0.3.10

* update test

* test

* remove/update logging

* ensure query doesn't include regional mines (yet
  • Loading branch information
Jsyro authored Sep 13, 2024
1 parent 2ed8d13 commit 7510526
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 66 deletions.
24 changes: 13 additions & 11 deletions services/core-api/app/api/services/traction_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,22 +188,24 @@ def fetch_current_public_did(self):

def sign_jsonld_credential_deprecated(
self,
did,
verkey,
did: str,
verkey: str,
credential: BaseModel,
) -> dict:
# #verkey suffix is indy's default, but could be aparameter later.
options = {"verificationMethod": did + "#verkey", "proofPurpose": "assertionMethod"}
payload = {
"doc": {
"options": options,
"credential": credential.dict(by_alias=True, exclude_none=True)
},
"verkey": verkey,
}

class Payload(BaseModel):
doc: dict
verkey: str

payload = Payload(doc={"options": options, "credential": credential}, verkey=verkey)

post_resp = requests.post(
traction_deprecated_jsonld_sign, json=payload, headers=self.get_headers())
assert post_resp.status_code == 200, f"post_resp={post_resp.json()}"
traction_deprecated_jsonld_sign,
json=payload.model_dump(by_alias=True, exclude_none=True, mode="json"),
headers=self.get_headers())
assert post_resp.status_code == 200, f"post_resp={post_resp.__dict__}"
return post_resp.json()

def fetch_a_random_did_key(self):
Expand Down
103 changes: 60 additions & 43 deletions services/core-api/app/api/verifiable_credentials/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,13 @@ def process_all_untp_map_for_orgbook():
inner join mine_party_appt mpa on p.party_guid = mpa.party_guid
inner join permit pmt on pmt.permit_id = mpa.permit_id
inner join permit_amendment pa on pa.permit_id = pmt.permit_id
inner join mine m on pa.mine_guid = m.mine_guid
where mpa.permit_id is not null
and mpa.mine_party_appt_type_code = 'PMT'
and mpa.deleted_ind = false
and m.major_mine_ind = true
group by pa.permit_amendment_guid, pa.description, pa.issue_date, pa.permit_amendment_status_code, mpa.deleted_ind, pmt.permit_no, mpa.permit_id, poe.party_guid, p.party_name, poe.name_text, poe.registration_id
order by pmt.permit_no, pa.issue_date;
Expand All @@ -143,7 +145,7 @@ def process_all_untp_map_for_orgbook():
assert public_did.startswith(
"did:web:"
), f"Config.CHIEF_PERMITTING_OFFICER_DID_WEB = {Config.CHIEF_PERMITTING_OFFICER_DID_WEB} is not a did:web"
current_app.logger.warning("public did: " + public_did)
task_logger.info("public did: " + public_did)

records: List[Tuple[W3CCred,
PermitAmendmentOrgBookPublish]] = [] # list of tuples [payload, record]
Expand Down Expand Up @@ -186,13 +188,12 @@ def process_all_untp_map_for_orgbook():
try:
record.save()
except IntegrityError:
current_app.logger.warning(f"ignoring duplicate={str(record.unsigned_payload_hash)}")
task_logger.warning(f"ignoring duplicate={str(record.unsigned_payload_hash)}")
continue
current_app.logger.warning(
"bcreg_uri=" +
str(cred_payload.credentialSubject.issuedTo.identifiers[0].identifierURI) +
", for permit_amendment_guid=" + str(row[0]))
current_app.logger.warning("unsigned_hash=" + str(record.unsigned_payload_hash))
task_logger.info("bcreg_uri=" +
str(cred_payload.credentialSubject.issuedTo.identifiers[0].identifierURI) +
", for permit_amendment_guid=" + str(row[0]))
task_logger.warning("unsigned_hash=" + str(record.unsigned_payload_hash))

task_logger.info("num of records created: " + str(len(records or [])))

Expand Down Expand Up @@ -336,51 +337,61 @@ def produce_untp_cc_map_payload(cls, did: str, permit_amendment: PermitAmendment
current_app.logger.warning("No Orgbook Entity, do not produce Mines Act Permit UNTP CC")
return None

untp_party_cpo = base.Party(
untp_party_cpo = base.Entity(
id="did:web:untp.traceability.site:parties:regulators:CHIEF-PERMITTING-OFFICER",
name="Chief Permitting Officer of Mines",
identifiers=[
base.Identifier(
identifierValue=
"did:web:untp.traceability.site:parties:regulators:CHIEF-PERMITTING-OFFICER")
])
registeredId=
"did:web:untp.traceability.site:parties:regulators:CHIEF-PERMITTING-OFFICER",
idScheme=base.IdentifierScheme(
id="https://w3c-ccg.github.io/did-method-web/", name="DID Web"))
orgbook_cred_url = f"https://orgbook.gov.bc.ca/entity/{orgbook_entity.registration_id}/credential/{orgbook_entity.credential_id}"

#this should have a did:web reference ideally, but orgbook doesn't have those yet.
untp_party_business = base.Party(
untp_party_business = base.Entity(
id=orgbook_cred_url,
name=orgbook_entity.name_text,
identifiers=[
base.Identifier(
scheme=ANONCRED_SCHEME,
identifierValue=str(orgbook_entity.registration_id),
identifierURI=orgbook_cred_url)
])
idScheme=base.IdentifierScheme(id=ANONCRED_SCHEME, name="anoncred"),
registeredId=str(orgbook_entity.registration_id))

facility = cc.Facility(
id="https://mines.nrs.gov.bc.ca/PLACEHOLDER",
name=permit_amendment.mine.mine_name,
geolocation=
f'https://plus.codes/{plus_code_encode(permit_amendment.mine.latitude, permit_amendment.mine.longitude)}',
verifiedByCAB=True)
registeredId="mine_no",
idScheme=base.IdentifierScheme(
id="https://www2.gov.bc.ca/PLACEHOLDER", name="FACILITY_PLACEHOLDER"),
IDverifiedByCAB=True)

products = [
cc.Product(
id="https://unstats.un.org/unsd/classifications/Econ/cpc/PLACEHOLDER",
name=c,
classifications=cc.Classification(
scheme="https://unstats.un.org/unsd/classifications/Econ/cpc",
classifierName=c),
verifiedByCAB=False) for c in permit_amendment.mine.commodities
registeredId=c,
idScheme=base.IdentifierScheme(
id="https://unstats.un.org/unsd/classifications/Econ/cpc",
name="Central Product Classification (UNCEFACT)"),
IDverifiedByCAB=False) for c in permit_amendment.mine.commodities
]

untp_assessments = [
cc.ConformityAssessment(
id="https://mines.nrs.gov.bc.ca/ASSESSMENT_ID_PLACEHOLDER",
referenceRegulation=cc.Regulation(
id="https://www.bclaws.gov.bc.ca/civix/document/id/complete/statreg/96293_01",
name="BC Mines Act",
issuingBody=base.Party(name="Government of British Columbia"),
jurisdictionCountry="CA",
administeredBy=base.Entity(
id="https://www2.gov.bc.ca/gov/content/home",
name="Government of British Columbia",
registeredId="BC-GOV",
idScheme=base.IdentifierScheme(
id="https://www2.gov.bc.ca/gov/content/home", name="BC-GOV")),
effectiveDate=datetime(2024, 5, 14, tzinfo=ZoneInfo("UTC")).isoformat()),
conformityTopic=codes.ConformityTopicCode.Governance_Compliance,
# Is there a did:web that attests to that legistlation?
subjectFacilities=[facility],
subjectProducts=products,
sustainabilityTopic=codes.SustainabilityTopic.Governance_Compliance)
assessedFacilities=[facility],
assessedProducts=products)
]
issue_date = permit_amendment.issue_date
issuance_date_str = datetime(
Expand All @@ -389,24 +400,30 @@ def produce_untp_cc_map_payload(cls, did: str, permit_amendment: PermitAmendment

cred = cc.ConformityAttestation(
id="http://example.com/govdomain/minesactpermit/123",
assessmentLevel=codes.AssessmentAssuranceCode.GovtApproval,
type=codes.AttestationType.Certification,
description=
"This is a conformity attestation for the existence of a mining permit under the Mines Act within British Columbia (a province of Canada).",
type="ConformityAttestation",
assessmentLevel=codes.AssessmentLevelCode.GovtApproval,
attestationType=codes.AttestationType.Certification,
scope=cc.ConformityAssessmentScheme(
id=
"https://github.com/bcgov/bc-vcpedia/blob/main/credentials/bc-mines-act-permit/1.1.1/governance.md",
"https://bcgov.github.io/digital-trust-toolkit/docs/governance/mining/bc-mines-act-permit/1.1.1/governance",
name="BC Mines Act Permit Credential (1.1.1) Governance Documentation"),
issuedBy=untp_party_cpo,
issuedTo=untp_party_business,
validFrom=issuance_date_str, #shouldn't this just be in the w3c wrapper
authorisations=base.Endorsement(
id=
"https://www2.gov.bc.ca/gov/content/industry/mineral-exploration-mining/permitting/mines-contact-info",
name="BC Chief Permitting Officer of Mines",
issuingAuthority=untp_party_cpo),
issuedToParty=untp_party_business,
validFrom=issuance_date_str, #shouldn't this just be in the w3c wrapper
assessments=untp_assessments)

w3c_cred = W3CCred(
context=["https://www.w3.org/2018/credentials/v1", {
"@vocab": "urn:bcgov:attributes#"
}],
type=["VerifiableCredential", "NonProductionCredential"],
context=[
"https://www.w3.org/2018/credentials/v1",
"https://test.uncefact.org/vocabulary/untp/dcc/0/untp-dcc-context-0.3.10.jsonld", {
"name": "https://schema.org/name"
}
],
type=["VerifiableCredential", "DigitalConformityCredential", "NonProductionCredential"],
issuer={"id": did},
issuanceDate=issuance_date_str,
credentialSubject=cred)
Expand Down
4 changes: 2 additions & 2 deletions services/core-api/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,5 @@ opentelemetry-instrumentation-sqlalchemy==0.43b0
opentelemetry-instrumentation-urllib3==0.43b0
Pillow==10.3.0
setuptools==65.5.1
urllib3==2.2.2
untp_models==0.0.1
untp_models==0.0.2
urllib3==2.2.2
11 changes: 1 addition & 10 deletions services/core-api/tests/verifiable_credentials/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,7 @@ def test_produce_untp_cc_map_payload_happy(self, db_session):
pa = permit.permit_amendments[0]

assert pa_cred
assert str(pa_cred.credentialSubject.issuedTo.identifiers[0].identifierValue) == str(
poe.registration_id)
assert pa_cred.credentialSubject.validFrom == datetime(
pa.issue_date.year,
pa.issue_date.month,
pa.issue_date.day,
0,
0,
0,
tzinfo=ZoneInfo("UTC")).isoformat()
assert str(pa_cred.credentialSubject.issuedToParty.registeredId) == str(poe.registration_id)

def test_produce_untp_cc_map_payload_null_if_no_orgbook(self, db_session):
mine, permit = create_mine_and_permit()
Expand Down

0 comments on commit 7510526

Please sign in to comment.