uncefact / spec-untp

UN Transparency Protocol
https://uncefact.github.io/spec-untp/
GNU General Public License v3.0
10 stars 9 forks source link

Expanding UNTP Credentials based on the Proposed JSON-LD Context File Structure #109

Open ashleythedeveloper opened 2 weeks ago

ashleythedeveloper commented 2 weeks ago

Based on my understanding, it has been proposed that we have a more "compact" JSON-LD structure than what we are currently producing via Jargon.

For example:

Compact JSON-LD context file

{
  "@context": {
    "@protected": true,

    "untp": "https://test.uncefact.org/vocabulary/untp/",

    "ConformityCredential": {
      "@id": "untp:ConformityCredential",
      "@context": {
        "@protected": true,

        "id": "@id",
        "type": "@type"
      }
    },

    "ConformityAttestation": {
      "@id": "untp:ConformityCredential#conformityattestation",
      "@context": {
        "@protected": true,

        "id": "@id",
        "type": "@type",

        "untp": "https://uncefact.github.io/spec-untp/docs/specification/",

        "assessments": "untp:ConformityCredential#conformityassessment"
      }
    },

    "ConformityAssessment": {
      "@id": "untp:ConformityCredential#conformityassessment",
      "@context": {
        "@protected": true,

        "id": "@id",
        "type": "@type",

        "untp": "https://uncefact.github.io/spec-untp/docs/specification/",

        "topic": "untp:ConformityCredential#sustainabilitytopic",
        "level": "untp:ConformityCredential#assessmentAssuranceCode",
        "regulation": "untp:ConformityCredential#regulation",
        "products": "untp:ConformityCredential#product", 
        "entities": "untp:ConformityCredential#party",
        "facilities": "untp:ConformityCredential#facility"
      }
    },
    ...
  }
}

"Inline" JSON-LD context file

{
  "@context": {
    "@version": 1.1,
    "description": "xsd:string",
    "validFrom": "xsd:string",
    "validTo": "xsd:string",
    "scope": {
      "@id": "xsd:string",
      "@context": {
        "id": "xsd:string",
        "name": "xsd:string",
        "dateOfIssue": "xsd:string",
        "issuingBody": {
          "@id": "xsd:string",
          "@context": {
            "id": "xsd:string",
            "name": "xsd:string",
            "type": "xsd:string"
          }
        },
        "criteria": {
          "@id": "xsd:string",
          "@container": "@list",
          "@context": {
            "id": "xsd:string",
            "description": "xsd:string",
            "type": "xsd:string",
            "validationService": "xsd:string"
          }
        }
      }
    },
    "issuedBy": {
      "@id": "xsd:string",
      "@context": {
        "id": "xsd:string",
        "name": "xsd:string",
        "type": "xsd:string"
      }
    },
   ....
}

One of the issues I have had previously using the compact context file structure (logically grouped terms in classes), as opposed to an "inline" context file structure (defines all of the terms at the root level of the context file), is that when a Verifiable Credential is produced with such a context file (logically grouped terms in classes) in the context array, the resulting VC fails to expand.

That is, if we either have not defined the "@vocab": "https://www.w3.org/ns/credentials/issuer-dependent#" term, which will resolve any undefined terms, or we pollute the VC with "type" properties mapping to the corresponding term defined in the context file.

For example:

With vocab

{
  "@context": {
    "@protected": true,

    "@vocab": "https://www.w3.org/ns/credentials/issuer-dependent#",

    "untp": "https://test.uncefact.org/vocabulary/untp/",

    "ConformityCredential": {
      "@id": "untp:ConformityCredential",
      "@context": {
        "@protected": true,

        "id": "@id",
        "type": "@type"
      }
    },

    "ConformityAttestation": {
      "@id": "untp:ConformityCredential#conformityattestation",
      "@context": {
        "@protected": true,

        "id": "@id",
        "type": "@type",

        "untp": "https://uncefact.github.io/spec-untp/docs/specification/",

        "assessments": "untp:ConformityCredential#conformityassessment"
      }
    },

    "ConformityAssessment": {
      "@id": "untp:ConformityCredential#conformityassessment",
      "@context": {
        "@protected": true,

        "id": "@id",
        "type": "@type",

        "untp": "https://uncefact.github.io/spec-untp/docs/specification/",

        "topic": "untp:ConformityCredential#sustainabilitytopic",
        "level": "untp:ConformityCredential#assessmentAssuranceCode",
        "regulation": "untp:ConformityCredential#regulation",
        "products": "untp:ConformityCredential#product", 
        "entities": "untp:ConformityCredential#party",
        "facilities": "untp:ConformityCredential#facility"
      }
    },
    ...
  }
}

With type

{
  "id": "http://university.example/credentials/3732",
  "type": ["VerifiableCredential", "ConformityCredential"],
  "issuer": "did:web:api.vckit.showthething.com",
  "validFrom": "2010-01-01T19:23:24Z",
  "credentialSubject": {
    "id": "http://example.com/D1013",
    "type": "ConformityAttestation",
    "assessorLevel": "3rdParty",
    "assessmentLevel": "Accredited",
    "description": "The provided certificate is issued to Alrite Steel and Services NZ, Ltd by the Australasian Certification Authority for Reinforcing and Structural Steels Ltd (ACRS). It certifies that the company complies with the ACRS Traceability Scheme and relevant ACRS Quality and Operations Evaluation Procedures. The certification covers the purchase, supply, and utilization of sub-contracted services for steel reinforcing materials, hot-rolled plates, floorplates, slabs, flat products, bars, and sections as per various AS/NZS standards.",
    "scope": {
    "type": "ConformityAssessmentScheme",
      "id": "https://www.steelcertification.com/traceability-certification",
      "name": "Traceability Certification Scheme",
      "issuingBody": {
        "type": "Party",
        "name": "AUSTRALASIAN CERTIFICATION AUTHORITY FOR REINFORCING AND STRUCTURAL STEELS LTD",
        "identifiers": [
          {
           "type": "Identifier",
            "scheme": "https://abr.business.gov.au",
            "identifierValue": "40096692545",
            "identifierURI": "https://abr.business.gov.au/ABN/View?abn=40096692545"
          }
        ]
      },
      "dateOfIssue": "2000-01-01T10:00:00.000Z"
    },
    ....
}

My question is, if we proceed with the proposed shape of the context file (logically grouped terms in classes), is it sufficient to pollute the credential with "type" properties for the Credential to expand, or is there another way to map the properties defined in the credential with the terms within the context file?

If the solution to allow the credential to expand is to pollute the credential with "type" properties pointing to the correct term in the context file, I believe we have a conflict within the Conformity Credential data model as it contains a property "type", and there will be a conflict with the "type" property pointing to the correct term within the Conformity Credential Context file.

PatStLouis commented 2 weeks ago

@ashleythedeveloper this was inspired by the citizenship vocab. The credential will fail to expand if its not properly constructed. You will need to replace https://test.uncefact.org/vocabulary/untp/ with https://uncefact.github.io/spec-untp/docs/specification/ for terms to map properly (as it was in the original example I provided). Ultimatly if the json-ld doesn't expand it's probably because there's a mapping error. Could you provide an example of the errors you were running into?

Most of this should be resolved with vcdm v2.0 since they include an @vocab in the base context (which is allegedly a bad idea since its a footgun, I don't believe @vocab should be in context files)

The use case here was to demonstrate how context can be extended, please have a look at this ConformityCredential example, where I provide 2 additional context files (1 for the critical raw material pilot and one for the bc gov tenure governance)

You can see it's expanded properly. I like using types as it allows to add specificity to objects, ex: I have a ConformityAssessment which is a TenureTitle I have an Organization which is also a TitleHolder

This allows BC to define terms based on legal documents. So a TitleHolder can link to a definition right on the legal act governing the ConformityAssessment

PatStLouis commented 2 weeks ago

I initially had all terms defined at the root, I find grouping them by type makes it easier to read:

{
  "@context": {
    "@protected": true,

    "untp": "https://test.uncefact.org/vocabulary/untp/",

    "ConformityCredential": {
      "@id": "untp:ConformityCredential",
      "@context": {
        "@protected": true,

        "id": "@id",
        "type": "@type"
      }
    },

    "ConformityAttestation": {
      "@id": "untp:ConformityCredential#conformityattestation",
      "@context": {
        "@protected": true,

        "id": "@id",
        "type": "@type",

        "assessments": "untp:ConformityCredential#conformityassessment"
      }
    },

    "ConformityAssessment": {
      "@id": "untp:ConformityCredential#conformityassessment",
      "@context": {
        "@protected": true,

        "id": "@id",
        "type": "@type",

        "topic": "untp:ConformityCredential#sustainabilitytopic",
        "level": "untp:ConformityCredential#assessmentAssuranceCode",
        "regulation": "untp:ConformityCredential#regulation",
        "products": "untp:ConformityCredential#product", 
        "entities": "untp:ConformityCredential#party",
        "facilities": "untp:ConformityCredential#facility"
      }
    }
  }
}

vs

{
  "@context": {
    "@protected": true,

    "untp": "https://test.uncefact.org/vocabulary/untp/",

    "ConformityCredential": "untp:ConformityCredential",
    "ConformityAttestation": "untp:ConformityCredential#conformityattestation",
    "ConformityAssessment": "untp:ConformityCredential#conformityassessment",

    "topic": "untp:ConformityCredential#sustainabilitytopic",
    "level": "untp:ConformityCredential#assessmentAssuranceCode",
    "regulation": "untp:ConformityCredential#regulation",
    "products": "untp:ConformityCredential#product", 
    "entities": "untp:ConformityCredential#party",
    "facilities": "untp:ConformityCredential#facility",
    "assessments": "untp:ConformityCredential#conformityassessment"
  }
}

In the first option, its clear what properties belong where

PatStLouis commented 2 weeks ago

@ashleythedeveloper we also need to be careful about redefining protected terms in context files. With the VCDM 2.0 the terms name and description are protected which causes an issue with the jargon link provided. See here

ashleythedeveloper commented 2 weeks ago

Hi @PatStLouis, thank you for your comments.

@ashleythedeveloper this was inspired by the citizenship vocab. The credential will fail to expand if its not properly constructed.

Yep, I was merely using the context files and credentials to convoy the structure I was referring to, which, in hindsight, I feel caused more confusion :) Yep, I understand that the credential will fail to expand, and I manually created a credential/context for my testing.

You will need to replace https://test.uncefact.org/vocabulary/untp/ with https://uncefact.github.io/spec-untp/docs/specification/ for terms to map properly (as it was in the original example I provided).

This should be "untp": "https://test.uncefact.org/vocabulary/untp/", no? As this URI points to the location of the vocabulary or ontology that provides the semantic meanings of the terms in a machine-readable form.

Ultimatly if the json-ld doesn't expand it's probably because there's a mapping error. Could you provide an example of the errors you were running into?

Yep, in my testing, the issue I had with the JSON-LD not expanding was due to the absence of the "type" properties within the objects of the credential.

Most of this should be resolved with vcdm v2.0 since they include an @vocab in the base context (which is allegedly a bad idea since its a footgun, I don't believe @vocab should be in context files)

Right, but this is only a catch-all, right? I can see two scenarios where this vocab is used: either the term is not defined within the context, so the vocab term is used as the IRI for the term missing the definition. The other is due to the expansion mechanism not knowing that the "credentialSubject" is of type "ConformityAttestiontion, " which uses the process mentioned above. The latter is silly as we have the term defined, but we are not using it, so we might as well not be using JSON-LD.

I've recently learned that to overcome this discrepancy between the name of the properties defined in the credential "credentialSubject" and the term defined in the context file "ConformityAttestation," by adding the "type" property within the object of the credential, for example, "type": "ConformityAttestiontion", just as you have in your example.

You can see it's expanded properly. I like using types as it allows to add specificity to objects, ex: I have a ConformityAssessment which is a TenureTitle I have an Organization which is also a TitleHolder

Yes, but would it expand without the types added? That is the essence of my question. Is it the standard to pollute the credential with "type" properties for the credential to expand, or is there another way? If it is the former, we have a conflict with the "type" attribute defined in the Conformity Credential data model.

I initially had all terms defined at the root, I find grouping them by type makes it easier to read

I agree. I've just always had issues with the resulting credential expanding if the "@vocab" term or the "type" property is not defined, which is why we typically used the previous shape.

@ashleythedeveloper we also need to be careful about redefining protected terms in context files.

Yep, I agree.

Fak3 commented 2 weeks ago

we have a conflict with the "type" attribute defined in the Conformity Credential data model.

There is no conflict. Credential can have more specific subtype declared: type: [ConformityCredential, CarbonEmissionsCredential]

nissimsan commented 2 weeks ago

https://test.uncefact.org/spec-untp/untp-v1 is aligns with @PatStLouis's "grouped" approach. Seems like there's agreement here.

ashleythedeveloper commented 2 weeks ago

Hey @Fak3,

There is no conflict. Credential can have more specific subtype declared: type: [ConformityCredential, CarbonEmissionsCredential]

If one creates a Conformity Credential and would like to type the credentialSubject "type": "ConformityAttestation", so that the credentialSubject is not expanding to the issuer dependent IRI and is instead expanding to the actual term defined within the context file "ConformityAttestation", how do we also define the "type" (attestationType) property that the data model expects?

When I have attempted to do so, I get errors on the JSON-LD playground when attempting to expand the credential.

Fak3 commented 2 weeks ago

Hey @Fak3,

There is no conflict. Credential can have more specific subtype declared: type: [ConformityCredential, CarbonEmissionsCredential]

If one creates a Conformity Credential and would like to type the credentialSubject "type": "ConformityAttestation", so that the credentialSubject is not expanding to the issuer dependent IRI and is instead expanding to the actual term defined within the context file "ConformityAttestation", how do we also define the "type" (attestationType) property that the data model expects?

When I have attempted to do so, I get errors on the JSON-LD playground when attempting to expand the credential.

Here is the playground example: link

First context that i have inlined is ours (untp), second is extended by 3d party.

PatStLouis commented 2 weeks ago

@nissimsan Happy to see we seem to be thinking alike on this. Any thoughts on calling it a DigitalProductPassport instead of a UNTPDigitalProductPassport (and the same for any UNTP specific thing)? I feel that by linking it to UNTP definition of a product passport trough the context is sufficient to indicate what we are talking about and would make the VC look cleaner. This is also exactly what context and linked data is for.

I'd also like to open discussion on renaming: https://test.uncefact.org/vocabulary/untp/cc/Facility to: https://test.uncefact.org/vocabulary/untp/cc/Location

I can provide some details as to why if needed bu I left a comment on another issue about this. Basically some assessment would be about an area of land rather than a facility. A location can be typed as a facility or an area, the other way around isn't possible.

I'd also like to flag these 3 attributes as potential footguns:

https://test.uncefact.org/vocabulary/untp/cc/id https://test.uncefact.org/vocabulary/untp/cc/name https://test.uncefact.org/vocabulary/untp/cc/description

For the id I would rather see identifier as the term used. a ressource.id should be a uri according to the VC spec as I understand it. I tend to stay away from redefining the terms 'type' and 'id' as it's just polluting terminology.

For description/name its fine as long as these aren't being redefined as terms in the vc since they are protected term under VCDM 2.0.

Good: assessmentName: https://test.uncefact.org/vocabulary/untp/cc/name Bad: name: https://test.uncefact.org/vocabulary/untp/cc/name

Just something implementers will need to be cautious about...

@ashleythedeveloper the vocabulary link is a new resource using a slightly different architecture than the spec and linking to terms on there would use a slightly different syntax:

{
  "@context": {
    "@protected": true,

    "untp": "https://test.uncefact.org/vocabulary/untp/",
    "evidence": "untp:cc/evidence"

  }
}

instead of

{
  "@context": {
    "@protected": true,

    "untp": "https://test.uncefact.org/vocabulary/untp/",
    "evidence": "untp:ConformityCredential#evidence"

  }
}
onthebreeze commented 1 week ago

Very good discussion here

We can and should easily remove the footguns like property names that collide with VCDM so that we don't need to figure out workarounds. We just avoid the problem instead.

It does seem like a group of increasingly specific context files is a very elegant way to handle UNTP extensions : VCDM -> UNTP -> CRM -> BCGov

ashleythedeveloper commented 1 week ago

@Fak3, please see an example below with the conflicting "type" property. If we are to add a "type" property to the credentialSubject to link the credential subject to the term defined in the context "ConformityAttestation", there will be a conflict with the "type" property defined in the Conformity Credential data model:

Data model

Screenshot 2024-06-17 at 12 08 34 PM Screenshot 2024-06-17 at 12 10 37 PM

Example credential (not complete, only to convey the "type" property conflict)

{
    "@context": [
      "https://www.w3.org/ns/credentials/v2",
      {
        "@context": {
          "@protected": true,

          "untp": "https://test.uncefact.org/vocabulary/untp/",

          "ConformityCredential": {
            "@id": "untp:ConformityCredential",
            "@context": {
              "@protected": true,

              "id": "@id",
              "type": "@type"
            }
          },

          "ConformityAttestation": {
            "@id": "untp:ConformityCredential#ConformityAttestation",
            "@context": {
              "@protected": true,

              "id": "@id",
              "type": "@type",

              "untp": "https://test.uncefact.org/vocabulary/untp/",

              "assessorLevel": {
                "@id": "untp:ConformityCredential#assessorLevel",
                "@type": "@id"
              },
              "assessmentLevel": {
                "@id": "untp:ConformityCredential#assessmentLevel",
                "@type": "@id"
              },
              "description": {
                "@id": "untp:ConformityCredential#description",
                "@type": "@id"
              },
              "scope": {
                "@id": "untp:ConformityCredential#scope",
                "@type": "@id"
              },
              "issuedTo": {
                "@id": "untp:ConformityCredential#issuedTo",
                "@type": "@id"
              },
              "assessments": {
                "@id": "untp:ConformityCredential#assessments",
                "@type": "@id"
              },
              "evidence": {
                "@id": "untp:ConformityCredential#evidence",
                "@type": "@id"
              },
              "accreditation": {
                "@id": "untp:ConformityCredential#accreditation",
                "@type": "@id"
              },
              "regulatoryApproval": {
                "@id": "untp:ConformityCredential#regulatoryApproval",
                "@type": "@id"
              },
              "certificate": {
                "@id": "untp:ConformityCredential#certificate",
                "@type": "@id"
              }
            }
          }
        }
      }
    ],
    "type": [
      "VerifiableCredential",
      "ConformityCredential"
    ],
    "issuer": {
      "id": "did:web:example.com"
    },
    "credentialSubject": {
        "id": "http://example.com/C9876",
        "type": ["ConformityAttestation"],
        "assessorLevel": "3rdParty",
        "assessmentLevel": "Accredited",
        "type": "certification",
        "description": "This certificate is awarded to Quality Alloys Inc by the North American Steel Quality Assurance Association (NASQAA). It attests that the company has met the requirements of the NASQAA Quality Management System for the production and distribution of stainless steel alloys, titanium alloys, and nickel superalloys in accordance with relevant ASTM and SAE aerospace material specifications.",
        "scope": {
          "id": "https://www.nasqaa.org/quality-system-certification",
          "name": "Quality Management System Certification",
          "issuingBody": {
            "name": "NORTH AMERICAN STEEL QUALITY ASSURANCE ASSOCIATION",
            "identifiers": [
              {
                "scheme": "https://www.dnb.com",
                "identifierValue": "081658292",
                "identifierURI": "https://www.dnb.com/business-directory/company-profiles.north_american_steel_quality_assurance_association.081658292.html"
              }
            ]
          },
          "dateOfIssue": "1995-07-01T09:30:00.000Z"
        },
        "issuedBy": {
          "name": "NORTH AMERICAN STEEL QUALITY ASSURANCE ASSOCIATION",
          "identifiers": [
            {
              "scheme": "https://www.dnb.com",
              "identifierValue": "081658292",
              "identifierURI": "https://www.dnb.com/business-directory/company-profiles.north_american_steel_quality_assurance_association.081658292.html"
            }
          ]
        },
        "issuedTo": {
          "name": "QUALITY ALLOYS INCORPORATED",
          "identifiers": [
            {
              "scheme": "https://www.sec.gov/edgar",
              "identifierValue": "0000950170-98-000024",
              "identifierURI": "https://www.sec.gov/Archives/edgar/data/1037055/0000950170-98-000024.txt"
            }
          ]
        },
        "validFrom": "2023-01-15T09:30:00.000Z",
        "validTo": "2025-01-14T09:30:00.000Z",
        "status": "valid",
        "assessments": [
          {
            "referenceStandard": {
              "id": "https://www.astm.org/a0276_a0276m-17.html",
              "name": "ASTM A276/A276M-17",
              "issuingBody": {
                "name": "ASTM INTERNATIONAL",
                "identifiers": [
                  {
                    "scheme": "https://www.dnb.com",
                    "identifierValue": "002803951",
                    "identifierURI": "https://www.dnb.com/business-directory/company-profiles.astm_international.002803951.html"
                  }
                ]
              },
              "issueDate": "2017-01-01T09:30:00.000Z"
            },
            "compliance": true
          },
          {
            "referenceStandard": {
              "id": "https://www.sae.org/standards/content/ams4911l",
              "name": "AMS4911L",
              "issuingBody": {
                "name": "SAE INTERNATIONAL",
                "identifiers": [
                  {
                    "scheme": "https://www.dnb.com",
                    "identifierValue": "001696030",
                    "identifierURI": "https://www.dnb.com/business-directory/company-profiles.sae_international.001696030.html"
                  }
                ]
              },
              "issueDate": "2018-07-01T09:30:00.000Z"
            },
            "compliance": true
          },
          {
            "referenceStandard": {
              "id": "https://www.astm.org/b0265_b0265m-15.html",
              "name": "ASTM B265-15",
              "issuingBody": {
                "name": "ASTM INTERNATIONAL",
                "identifiers": [
                  {
                    "scheme": "https://www.dnb.com",
                    "identifierValue": "002803951",
                    "identifierURI": "https://www.dnb.com/business-directory/company-profiles.astm_international.002803951.html"
                  }
                ]
              },
              "issueDate": "2015-01-01T09:30:00.000Z"
            },
            "compliance": true
          }
        ],
        "evidence": {
          "description": "Quality Management System Certification evidence",
          "evidenceRootHash": "",
          "evidenceData": [
            {
              "fileHash": "",
              "fileLocation": "http://example.com/C9876.pdf",
              "fileType": "application/pdf",
              "EncryptionMethod": "RSA"
            }
          ],
          "decryptionKeyRequest": ""
        },
        "accreditation": {
          "number": "1107Q",
          "authorityEvidence": {
            "format": "webpage",
            "credentialReference": "https://anab.qualityplussoftware.com/accreditation/1107"
          },
          "trustmark": {
            "fileHash": "",
            "fileLocation": "https://www.qualityplussoftware.com/wp-content/uploads/2018/09/anab-accredited-logo-rgb-hi-res.jpg",
            "fileType": "image/jpeg",
            "EncryptionMethod": "none"
          },
          "authority": {
            "name": "ANSI NATIONAL ACCREDITATION BOARD",
            "identifiers": [
              {
                "scheme": "https://www.dnb.com",
                "identifierValue": "117034251",
                "identifierURI": "https://www.dnb.com/business-directory/company-profiles.ansi_national_accreditation_board_inc.117034251.html"
              }
            ]
          }
        },
        "certificate": {
          "fileHash": "",
          "fileLocation": "https://certs.qualityalloys.com/C9876.pdf",
          "fileType": "application/pdf",
          "EncryptionMethod": "none"
        }
      }

  }
ashleythedeveloper commented 1 week ago

Hey @PatStLouis,

@nissimsan Happy to see we seem to be thinking alike on this. Any thoughts on calling it a DigitalProductPassport instead of a UNTPDigitalProductPassport (and the same for any UNTP specific thing)? I feel that by linking it to UNTP definition of a product passport trough the context is sufficient to indicate what we are talking about and would make the VC look cleaner

Yep, I agree.

@ashleythedeveloper the vocabulary link is a new resource using a slightly different architecture than the spec and linking to terms on there would use a slightly different syntax

Ah, ok. Thanks for the heads up.

Fak3 commented 1 week ago

@ashleythedeveloper you specified "type" property twice in single json object, it only picks last one. To fix this list types in json array: instead of this:

    "credentialSubject": {
        "id": "http://example.com/C9876",
        "type": ["ConformityAttestation"],
        "type": "certification"        
      }

do this:

    "credentialSubject": {
        "id": "http://example.com/C9876",
        "type": ["ConformityAttestation", "untp:certification"]
      }

playground example Also your context overrides protected terms from VC context - description and evidence, it is not allowed.