From b87467cc920abbd0fea9fbc43ffaea140d823d99 Mon Sep 17 00:00:00 2001
From: Douglas Lowe <10961945+douglowe@users.noreply.github.com>
Date: Mon, 15 Sep 2025 16:21:52 +0100
Subject: [PATCH 01/18] 5s-crate profile file
---
.../profiles/five-safes-crate/profile.ttl | 81 +++++++++++++++++++
1 file changed, 81 insertions(+)
create mode 100644 rocrate_validator/profiles/five-safes-crate/profile.ttl
diff --git a/rocrate_validator/profiles/five-safes-crate/profile.ttl b/rocrate_validator/profiles/five-safes-crate/profile.ttl
new file mode 100644
index 00000000..75946bfe
--- /dev/null
+++ b/rocrate_validator/profiles/five-safes-crate/profile.ttl
@@ -0,0 +1,81 @@
+# Copyright (c) 2024-2025 CRS4, University of Manchester
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+@prefix dct: .
+@prefix prof: .
+@prefix role: .
+@prefix rdfs: .
+
+
+ a prof:Profile ;
+
+ # the Profile's label
+ rdfs:label "Five Safes RO-Crate 0.4" ;
+
+ # regular metadata, a basic description of the Profile
+ rdfs:comment """Five Safes RO-Crate Metadata Specification 0.4"""@en ;
+
+ # URI of the publisher of the Metadata Specification
+ dct:publisher ;
+
+ # This profile is an extension of Workflow Run Crate for use in Trusted Research Environments (TRE)
+ prof:isProfileOf ;
+
+ # This profile is a transitive profile of the RO-Crate Metadata Specification
+ prof:isTransitiveProfileOf ,
+ ,
+ ;
+
+ # this profile has a JSON-LD context resource
+ prof:hasResource [
+ a prof:ResourceDescriptor ;
+
+ # it's in JSON-LD format
+ dct:format ;
+
+ # it conforms to JSON-LD, here refered to by its namespace URI as a Profile
+ dct:conformsTo ;
+
+ # this profile resource plays the role of "Vocabulary"
+ # described in this ontology's accompanying Roles vocabulary
+ prof:hasRole role:Vocabulary ;
+
+ # this profile resource's actual file
+ prof:hasArtifact ;
+ ] ;
+
+ # this profile has a human-readable documentation resource
+ prof:hasResource [
+ a prof:ResourceDescriptor ;
+
+ # it's in HTML format
+ dct:format ;
+
+ # it conforms to HTML, here refered to by its namespace URI as a Profile
+ dct:conformsTo ;
+
+ # this profile resource plays the role of "Specification"
+ # described in this ontology's accompanying Roles vocabulary
+ prof:hasRole role:Specification ;
+
+ # this profile resource's actual file
+ prof:hasArtifact ;
+
+ # this profile is inherited from Workflow Run profile
+ prof:isInheritedFrom ;
+ ] ;
+
+ # a short code to refer to the Profile with when a URI can't be used
+ prof:hasToken "five-safes-crate" ;
+.
From 7ab6b6de00ead4c16aeed7729eafd32efdb6ecad Mon Sep 17 00:00:00 2001
From: Douglas Lowe <10961945+douglowe@users.noreply.github.com>
Date: Thu, 18 Sep 2025 13:10:16 +0100
Subject: [PATCH 02/18] 5-safes crate first req
---
.../must/0_root_data_entity_metadata.ttl | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 rocrate_validator/profiles/five-safes-crate/must/0_root_data_entity_metadata.ttl
diff --git a/rocrate_validator/profiles/five-safes-crate/must/0_root_data_entity_metadata.ttl b/rocrate_validator/profiles/five-safes-crate/must/0_root_data_entity_metadata.ttl
new file mode 100644
index 00000000..2cac720c
--- /dev/null
+++ b/rocrate_validator/profiles/five-safes-crate/must/0_root_data_entity_metadata.ttl
@@ -0,0 +1,37 @@
+# Copyright (c) 2024-2025 CRS4
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+@prefix ro: <./> .
+@prefix ro-crate: .
+@prefix rdf: .
+@prefix schema_org: .
+@prefix sh: .
+@prefix validator: .
+@prefix xsd: .
+
+
+ro-crate:RootDataEntityRequiredProperties
+ a sh:NodeShape ;
+ sh:name "Five Safes Crate Root Data Entity REQUIRED properties" ;
+ sh:description "The Root Data Entity MUST have a `funding`" ;
+ sh:targetClass ro-crate:RootDataEntity ;
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "Root Data Entity: `funding` property" ;
+ sh:description """Check if the Root Data Entity includes a `funding` property (as specified by schema.org).""" ;
+ sh:minCount 1 ;
+ sh:nodeKind sh:Literal ;
+ sh:path schema_org:funding;
+ sh:message "The Root Data Entity MUST have a `funding` property (as specified by schema.org)" ;
+ ] .
From 5f45864b59df58902fd163212a70cbc971e53876 Mon Sep 17 00:00:00 2001
From: Douglas Lowe <10961945+douglowe@users.noreply.github.com>
Date: Thu, 18 Sep 2025 13:51:20 +0100
Subject: [PATCH 03/18] adding 5-safe ro-crate example json
---
.../ro-crate-metadata.json | 160 ++++++
.../ro-crate-metadata.json | 392 +++++++++++++++
.../ro-crate-metadata.json | 461 ++++++++++++++++++
3 files changed, 1013 insertions(+)
create mode 100644 tests/data/crates/valid/five-safes-crate-request/ro-crate-metadata.json
create mode 100644 tests/data/crates/valid/five-safes-crate-result/ro-crate-metadata.json
create mode 100644 tests/data/crates/valid/five-safes-profile-crate/ro-crate-metadata.json
diff --git a/tests/data/crates/valid/five-safes-crate-request/ro-crate-metadata.json b/tests/data/crates/valid/five-safes-crate-request/ro-crate-metadata.json
new file mode 100644
index 00000000..b8a84271
--- /dev/null
+++ b/tests/data/crates/valid/five-safes-crate-request/ro-crate-metadata.json
@@ -0,0 +1,160 @@
+{
+ "@context": "https://w3id.org/ro/crate/1.2-DRAFT/context",
+ "@graph": [
+ {
+ "@type": "CreativeWork",
+ "@id": "ro-crate-metadata.json",
+ "about": {
+ "@id": "./"
+ },
+ "conformsTo": {
+ "@id": "https://w3id.org/ro/crate/1.2-DRAFT"
+ }
+ },
+ {
+ "@id": "./",
+ "@type": "Dataset",
+ "conformsTo": {
+ "@id": "https://w3id.org/5s-crate/0.4"
+ },
+ "hasPart": [
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ {
+ "@id": "input1.txt"
+ }
+ ],
+ "mainEntity": {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ "mentions": {
+ "@id": "#query-37252371-c937-43bd-a0a7-3680b48c0538"
+ },
+ "sourceOrganization": {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70"
+ }
+ },
+ {
+ "@id": "https://w3id.org/5s-crate/0.4",
+ "@type": "Profile",
+ "name": "Five Safes RO-Crate profile"
+ },
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1",
+ "@type": "Dataset",
+ "name": "CWL Protein MD Setup tutorial with mutations",
+ "conformsTo": {
+ "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0"
+ },
+ "distribution": {
+ "@id": "https://workflowhub.eu/workflows/289/ro_crate?version=1"
+ }
+ },
+ {
+ "@id": "https://workflowhub.eu/workflows/289/ro_crate?version=1",
+ "@type": "DataDownload",
+ "conformsTo": {
+ "@id": "https://w3id.org/ro/crate"
+ },
+ "encodingFormat": "application/zip"
+ },
+ {
+ "@id": "#query-37252371-c937-43bd-a0a7-3680b48c0538",
+ "@type": "CreateAction",
+ "actionStatus": "http://schema.org/PotentialActionStatus",
+ "agent": {
+ "@id": "https://orcid.org/0000-0001-9842-9718"
+ },
+ "instrument": {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ "name": "Execute query 12389 on workflow ",
+ "object": [
+ {
+ "@id": "input1.txt"
+ },
+ {
+ "@id": "#enableFastMode"
+ }
+ ]
+ },
+ {
+ "@id": "https://orcid.org/0000-0001-9842-9718",
+ "@type": "Person",
+ "name": "Stian Soiland-Reyes",
+ "affiliation": {
+ "@id": "https://ror.org/027m9bs27"
+ },
+ "memberOf": [
+ {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70"
+ }
+ ]
+ },
+ {
+ "@id": "https://ror.org/027m9bs27",
+ "@type": "Organization",
+ "name": "The University of Manchester"
+ },
+ {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70",
+ "@type": "Project",
+ "name": "Investigation of cancer (TRE72 project 81)",
+ "identifier": [
+ {
+ "@id": "_:localid:tre72:project81"
+ }
+ ],
+ "funding": {
+ "@id": "https://gtr.ukri.org/projects?ref=10038961"
+ },
+ "member": [
+ {
+ "@id": "https://ror.org/027m9bs27"
+ },
+ {
+ "@id": "https://ror.org/01ee9ar58"
+ }
+ ]
+ },
+ {
+ "@id": "_:localid:tre72:project81",
+ "@type": "PropertyValue",
+ "name": "tre72",
+ "value": "project81"
+ },
+ {
+ "@id": "https://gtr.ukri.org/projects?ref=10038961",
+ "@type": "Grant",
+ "name": "EOSC4Cancer"
+ },
+ {
+ "@id": "input1.txt",
+ "@type": "File",
+ "name": "input1",
+ "exampleOfWork": {
+ "@id": "#sequence"
+ }
+ },
+ {
+ "@id": "#enableFastMode",
+ "@type": "PropertyValue",
+ "name": "--fast-mode",
+ "value": "True",
+ "exampleOfWork": {
+ "@id": "#fast"
+ }
+ },
+ {
+ "@id": "#sequence",
+ "@type": "FormalParameter",
+ "name": "input-sequence"
+ },
+ {
+ "@id": "#fast",
+ "@type": "FormalParameter",
+ "name": "fast-mode"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/data/crates/valid/five-safes-crate-result/ro-crate-metadata.json b/tests/data/crates/valid/five-safes-crate-result/ro-crate-metadata.json
new file mode 100644
index 00000000..3b43f636
--- /dev/null
+++ b/tests/data/crates/valid/five-safes-crate-result/ro-crate-metadata.json
@@ -0,0 +1,392 @@
+{
+ "@context": "https://w3id.org/ro/crate/1.2-DRAFT/context",
+ "@graph": [
+ {
+ "@type": "CreativeWork",
+ "@id": "ro-crate-metadata.json",
+ "about": {
+ "@id": "./"
+ },
+ "conformsTo": {
+ "@id": "https://w3id.org/ro/crate/1.2-DRAFT"
+ }
+ },
+ {
+ "@id": "./",
+ "@type": "Dataset",
+ "conformsTo": {
+ "@id": "https://w3id.org/5s-crate/0.4"
+ },
+ "hasPart": [
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ {
+ "@id": "input1.txt"
+ },
+ {
+ "@id": "workflow/289/"
+ }
+ ],
+ "mainEntity": {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ "mentions": [
+ {
+ "@id": "#query-37252371-c937-43bd-a0a7-3680b48c0538"
+ },
+ {
+ "@id": "#check-f33fe90c-0c22-4c72-b299-de509028410e"
+ },
+ {
+ "@id": "#validate-1146f640-819e-4c86-b029-b763a0040896"
+ },
+ {
+ "@id": "#download-8b51bf57-6b29-44da-b24b-638c8df91639"
+ },
+ {
+ "@id": "#signoff-3b741265-cfef-49ea-8138-a2fa149bf2f0"
+ },
+ {
+ "@id": "#disclosure-b16c1f0a-ae7f-4582-9b28-7d9df3313e27"
+ },
+ {
+ "@id": "#bagit-ce785c0b-c988-4043-8cbd-1489dcebc14f"
+ }
+ ],
+ "sourceOrganization": {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70"
+ },
+ "publisher": {
+ "@id": "https://tre72.example.com/"
+ },
+ "licence": {
+ "@id": "http://spdx.org/licenses/CC-BY-4.0"
+ }
+ },
+ {
+ "@id": "https://w3id.org/5s-crate/0.4",
+ "@type": "Profile",
+ "name": "Five Safes RO-Crate profile"
+ },
+ {
+ "@id": "https://spdx.org/licenses/CC-BY-4.0",
+ "@type": "CreativeWork",
+ "name": "Creative Commons Attribution 4.0 International",
+ "identifier": "CC-BY-4.0"
+ },
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1",
+ "@type": "Dataset",
+ "name": "CWL Protein MD Setup tutorial with mutations",
+ "conformsTo": {
+ "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0"
+ },
+ "distribution": {
+ "@id": "https://workflowhub.eu/workflows/289/ro_crate?version=1"
+ }
+ },
+ {
+ "@id": "https://workflowhub.eu/workflows/289/ro_crate?version=1",
+ "@type": "DataDownload",
+ "conformsTo": {
+ "@id": "https://w3id.org/ro/crate"
+ },
+ "encodingFormat": "application/zip"
+ },
+ {
+ "@id": "#query-37252371-c937-43bd-a0a7-3680b48c0538",
+ "@type": "CreateAction",
+ "actionStatus": "http://schema.org/CompleteActionStatus",
+ "agent": {
+ "@id": "https://orcid.org/0000-0001-9842-9718"
+ },
+ "instrument": {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ "name": "Execute query 12389 on workflow ",
+ "object": [
+ {
+ "@id": "input1.txt"
+ },
+ {
+ "@id": "#enableFastMode"
+ }
+ ],
+ "result": [
+ {
+ "@id": "outputs/table.csv"
+ },
+ {
+ "@id": "outputs/diagrams/"
+ },
+ {
+ "@id": "urn:uuid:07b81e0f-7ac4-5428-9940-878b241e2397"
+ }
+ ]
+ },
+ {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70",
+ "@type": "Project",
+ "name": "Investigation of cancer (TRE72 project 81)",
+ "identifier": [
+ {
+ "@id": "_:localid:tre72:project81"
+ }
+ ],
+ "funding": {
+ "@id": "https://gtr.ukri.org/projects?ref=10038961"
+ },
+ "member": [
+ {
+ "@id": "https://ror.org/027m9bs27"
+ },
+ {
+ "@id": "https://ror.org/01ee9ar58"
+ }
+ ]
+ },
+ {
+ "@id": "_:localid:tre72:project81",
+ "@type": "PropertyValue",
+ "name": "tre72",
+ "value": "project81"
+ },
+ {
+ "@id": "input1.txt",
+ "@type": "File",
+ "name": "input1",
+ "exampleOfWork": {
+ "@id": "#sequence"
+ }
+ },
+ {
+ "@id": "#enableFastMode",
+ "@type": "PropertyValue",
+ "name": "--fast-mode",
+ "value": "True",
+ "exampleOfWork": {
+ "@id": "#fast"
+ }
+ },
+ {
+ "@id": "#sequence",
+ "@type": "FormalParameter",
+ "name": "input-sequence"
+ },
+ {
+ "@id": "#fast",
+ "@type": "FormalParameter",
+ "name": "fast-mode"
+ },
+ {
+ "@id": "outputs/qa.csv",
+ "@type": "File",
+ "encodingFormat": "text/csv",
+ "name": "Tabular listing of quality assessment"
+ },
+ {
+ "@id": "outputs/diagrams/",
+ "@type": "Dataset",
+ "name": "Diagrams of regions of interest"
+ },
+ {
+ "@id": "workflow/289/",
+ "sameAs": {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ "@type": "Dataset",
+ "name": "CWL Protein MD Setup tutorial with mutations",
+ "conformsTo": {
+ "@id": "https://w3id.org/workflowhub/workflow-ro-crate/1.0"
+ },
+ "distribution": {
+ "@id": "https://workflowhub.eu/workflows/289/ro_crate?version=1"
+ }
+ },
+ {
+ "@id": "#check-f33fe90c-0c22-4c72-b299-de509028410e",
+ "type": "AssessAction",
+ "additionalType": {
+ "@id": "https://w3id.org/shp#CheckValue"
+ },
+ "name": "BagIt checksum of Crate: OK",
+ "endTime": "2023-04-18T12:11:45+01:00",
+ "object": {
+ "@id": "./"
+ },
+ "instrument": {
+ "@id": "https://www.iana.org/assignments/named-information#sha-512"
+ },
+ "agent": {
+ "@id": "#validator-a4a66c63-2fe0-4c57-830d-268a40718313"
+ },
+ "actionStatus": "http://schema.org/CompletedActionStatus"
+ },
+ {
+ "@id": "#validate-1146f640-819e-4c86-b029-b763a0040896",
+ "type": "AssessAction",
+ "additionalType": {
+ "@id": "https://w3id.org/shp#ValidationCheck"
+ },
+ "name": "Validation against Five Safes RO-Crate profile: approved",
+ "startTime": "2023-04-18T12:11:46+01:00",
+ "endTime": "2023-04-18T12:11:49+01:00",
+ "object": {
+ "@id": "./"
+ },
+ "instrument": {
+ "@id": "https://w3id.org/5s-crate/0.4"
+ },
+ "agent": {
+ "@id": "#validator-a4a66c63-2fe0-4c57-830d-268a40718313"
+ },
+ "actionStatus": "http://schema.org/CompletedActionStatus"
+ },
+ {
+ "@id": "#download-8b51bf57-6b29-44da-b24b-638c8df91639",
+ "type": "DownloadAction",
+ "name": "Downloaded workflow RO-Crate via proxy",
+ "startTime": "2023-04-18T12:11:50+01:00",
+ "endTime": "2023-04-18T12:11:52+01:00",
+ "object": {
+ "@id": "https://workflowhub.eu/workflows/289/ro_crate?version=1"
+ },
+ "result": {
+ "@id": "workflow/289/"
+ },
+ "agent": {
+ "@id": "http://proxy.example.com/"
+ },
+ "actionStatus": "http://schema.org/CompletedActionStatus"
+ },
+ {
+ "@id": "#signoff-3b741265-cfef-49ea-8138-a2fa149bf2f0",
+ "type": "AssessAction",
+ "additionalType": {
+ "@id": "https://w3id.org/shp#SignOff"
+ },
+ "name": "Sign-off of execution according to Agreement policy: approved",
+ "endTime": "2023-04-19T17:15:12+01:00",
+ "object": [
+ {
+ "@id": "./"
+ },
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70"
+ }
+ ],
+ "instrument": {
+ "@id": "https://tre72.example.com/agreement-policy/81"
+ },
+ "agent": {
+ "@id": "https://orcid.org/0000-0002-1825-0097"
+ },
+ "actionStatus": "http://schema.org/CompletedActionStatus"
+ },
+ {
+ "@id": "#disclosure-b16c1f0a-ae7f-4582-9b28-7d9df3313e27",
+ "type": "AssessAction",
+ "additionalType": {
+ "@id": "https://w3id.org/shp#DisclosureCheck"
+ },
+ "name": "Disclosure check of workflow results: approved",
+ "endTime": "2023-04-25T16:00:00+01:00",
+ "object": {
+ "@id": "./"
+ },
+ "agent": {
+ "@id": "https://orcid.org/0000-0002-1825-0097"
+ },
+ "actionStatus": "http://schema.org/CompletedActionStatus"
+ },
+ {
+ "@id": "#bagit-ce785c0b-c988-4043-8cbd-1489dcebc14f",
+ "type": "UpdateAction",
+ "startTime": "2023-04-29T12:12:25+01:00",
+ "additionalType": {
+ "@id": "https://w3id.org/shp#GenerateCheckValue"
+ },
+ "name": "BagIt manifests of Crate updated",
+ "object": {
+ "@id": "./"
+ },
+ "instrument": {
+ "@id": "https://www.iana.org/assignments/named-information#sha-512"
+ },
+ "agent": {
+ "@id": "#validator-a4a66c63-2fe0-4c57-830d-268a40718313"
+ },
+ "actionStatus": "http://schema.org/CompletedActionStatus"
+ },
+ {
+ "@id": "urn:uuid:07b81e0f-7ac4-5428-9940-878b241e2397",
+ "@type": "DigitalDocument",
+ "encodingFormat": "text/csv",
+ "name": "Patient measurement 07b81e0f-7ac4-5428-9940-878b241e2397",
+ "hasDigitalDocumentPermission": {
+ "@id": "#permissions-07b81e0f"
+ }
+ },
+ {
+ "@id": "#permissions-07b81e0f",
+ "@type": "DigitalDocumentPermission",
+ "permissionType": "http://schema.org/ReadPermission",
+ "grantee": {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70"
+ }
+ },
+ {
+ "@id": "https://orcid.org/0000-0001-9842-9718",
+ "@type": "Person",
+ "name": "Stian Soiland-Reyes",
+ "affiliation": {
+ "@id": "https://ror.org/027m9bs27"
+ },
+ "memberOf": [
+ {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70"
+ }
+ ]
+ },
+ {
+ "@id": "https://ror.org/027m9bs27",
+ "@type": "Organization",
+ "name": "The University of Manchester"
+ },
+ {
+ "@id": "https://gtr.ukri.org/projects?ref=10038961",
+ "@type": "Grant",
+ "name": "EOSC4Cancer"
+ },
+ {
+ "@id": "https://tre72.example.com/",
+ "@type": "Organization",
+ "name": "TRE 72 trusted research environment at The University of Manchester",
+ "parentOrganization": {
+ "@id": "https://ror.org/027m9bs27"
+ }
+ },
+ {
+ "@id": "https://tre72.example.com/#crate-validator",
+ "@type": "SoftwareApplication",
+ "name": "RO-Crate validator at TRE72",
+ "provider": {
+ "@id": "https://tre72.example.com/"
+ }
+ },
+ {
+ "@id": "https://tre72.example.com/agreement-policy/81",
+ "@type": "CreativeWork",
+ "name": "Agreement policy for TRE72 for project 81"
+ },
+ {
+ "@id": "https://www.iana.org/assignments/named-information#sha-512",
+ "@type": "DefinedTerm",
+ "name": "sha-512 algorithm"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/data/crates/valid/five-safes-profile-crate/ro-crate-metadata.json b/tests/data/crates/valid/five-safes-profile-crate/ro-crate-metadata.json
new file mode 100644
index 00000000..5ca7ea11
--- /dev/null
+++ b/tests/data/crates/valid/five-safes-profile-crate/ro-crate-metadata.json
@@ -0,0 +1,461 @@
+{
+ "@context": "https://w3id.org/ro/crate/1.1/context",
+ "@graph": [
+ {
+ "@type": "CreativeWork",
+ "@id": "ro-crate-metadata.json",
+ "about": {
+ "@id": "https://w3id.org/5s-crate/0.4"
+ },
+ "licence": {
+ "@id": "http://spdx.org/licenses/CC0-1.0"
+ },
+ "conformsTo": {
+ "@id": "https://w3id.org/ro/crate/1.1"
+ }
+ },
+ {
+ "@id": "https://w3id.org/5s-crate/0.4",
+ "@type": [
+ "Dataset",
+ "Profile"
+ ],
+ "name": "Five Safes RO-Crate profile",
+ "cite-as": "https://w3id.org/5s-crate/0.4",
+ "version": "0.4",
+ "datePublished": "2023-05-15T10:32:00Z",
+ "licence": {
+ "@id": "http://spdx.org/licenses/MIT"
+ },
+ "copyrightHolder": {
+ "@id": "https://ror.org/027m9bs27"
+ },
+ "copyrightYear": 2023,
+ "hasPart": [
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/index.html"
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-request.bagit.zip"
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-request/data/"
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-result.bagit.zip"
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-result/data/"
+ },
+ {
+ "@id": "http://schema.org/PotentialActionStatus"
+ },
+ {
+ "@id": "http://schema.org/CompletedActionStatus"
+ },
+ {
+ "@id": "http://schema.org/ActiveActionStatus"
+ },
+ {
+ "@id": "http://schema.org/FailedActionStatus"
+ },
+ {
+ "@id": "http://schema.org/CreateAction"
+ },
+ {
+ "@id": "http://schema.org/AssessAction"
+ },
+ {
+ "@id": "http://schema.org/DownloadAction"
+ },
+ {
+ "@id": "http://schema.org/UpdateAction"
+ },
+ {
+ "@id": "http://schema.org/grantee"
+ },
+ {
+ "@id": "http://schema.org/DigitalDocument"
+ },
+ {
+ "@id": "http://schema.org/DigitalDocumentPermission"
+ },
+ {
+ "@id": "http://schema.org/hasDigitalDocumentPermission"
+ },
+ {
+ "@id": "http://schema.org/ReadPermission"
+ },
+ {
+ "@id": "https://bioschemas.org/FormalParameter"
+ },
+ {
+ "@id": "https://w3id.org/shp#CheckValue"
+ },
+ {
+ "@id": "https://w3id.org/shp#ValidationCheck"
+ },
+ {
+ "@id": "https://w3id.org/shp#SignOff"
+ },
+ {
+ "@id": "https://w3id.org/shp#DisclosureCheck"
+ },
+ {
+ "@id": "https://w3id.org/shp#GenerateCheckValue"
+ }
+ ],
+ "hasResource": [
+ {
+ "@id": "#hasSpecification"
+ },
+ {
+ "@id": "#hasExampleRequest"
+ },
+ {
+ "@id": "#hasExampleResult"
+ },
+ {
+ "@id": "#usesSHP"
+ }
+ ],
+ "publisher": {
+ "@id": "https://trefx.uk/"
+ },
+ "funding": {
+ "@id": "https://gtr.ukri.org/projects?ref=MC_PC_23007"
+ },
+ "author": [
+ {
+ "@id": "https://orcid.org/0000-0001-9842-9718"
+ },
+ {
+ "@id": "https://orcid.org/0009-0003-2419-1964"
+ }
+ ]
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/index.html",
+ "@type": "CreativeWork",
+ "name": "Five Safes RO-Crate profile (specification)"
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-request/data/",
+ "@type": "Dataset",
+ "name": "Example Crate in Request state",
+ "conformsTo": {
+ "@id": "https://w3id.org/5s-crate/0.4"
+ },
+ "subjectOf": [
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-request/data/ro-crate-metadata.json"
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-request/data/ro-crate-preview.html"
+ }
+ ],
+ "distribution": {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-request.bagit.zip"
+ }
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-result/data/",
+ "@type": "Dataset",
+ "name": "Example Crate in Request state",
+ "conformsTo": {
+ "@id": "https://w3id.org/5s-crate/0.4"
+ },
+ "subjectOf": [
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-result/data/ro-crate-metadata.json"
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-result/data/ro-crate-preview.html"
+ }
+ ],
+ "distribution": {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-result.bagit.zip"
+ }
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-result.bagit.zip",
+ "@type": "DataDownload",
+ "name": "example-result.bagit.zip",
+ "description": "Example Result following the 5s-crate profile, archived as BagIt ZIP",
+ "encodingFormat": "application/zip",
+ "conformsTo": {
+ "@id": "https://w3id.org/ro/crate"
+ }
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-request.bagit.zip",
+ "@type": "DataDownload",
+ "name": "example-request.bagit.zip",
+ "description": "Example Request following the 5s-crate profile, archived as BagIt ZIP",
+ "encodingFormat": "application/zip",
+ "conformsTo": {
+ "@id": "https://w3id.org/ro/crate"
+ }
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-request/data/ro-crate-metadata.json",
+ "@type": "CreativeWork",
+ "encodingFormat": "application/ld+json"
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-request/data/ro-crate-preview.html",
+ "@type": "CreativeWork",
+ "encodingFormat": "text/html"
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-result/data/ro-crate-metadata.json",
+ "@type": "CreativeWork",
+ "encodingFormat": "application/ld+json"
+ },
+ {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-result/data/ro-crate-preview.html",
+ "@type": "CreativeWork",
+ "encodingFormat": "text/html"
+ },
+ {
+ "@id": "https://bioschemas.org/FormalParameter",
+ "@type": "DefinedTerm"
+ },
+ {
+ "@id": "https://w3id.org/shp",
+ "@type": "DefinedTermSet",
+ "name": "The Safe Haven Provenance (SHP) Ontology",
+ "version": "0.1"
+ },
+ {
+ "@id": "https://w3id.org/shp#CheckValue",
+ "@type": "DefinedTerm",
+ "inDefinedTermSet": {
+ "@id": "https://w3id.org/shp"
+ }
+ },
+ {
+ "@id": "https://w3id.org/shp#ValidationCheck",
+ "@type": "DefinedTerm",
+ "inDefinedTermSet": {
+ "@id": "https://w3id.org/shp"
+ }
+ },
+ {
+ "@id": "https://w3id.org/shp#SignOff",
+ "@type": "DefinedTerm",
+ "inDefinedTermSet": {
+ "@id": "https://w3id.org/shp"
+ }
+ },
+ {
+ "@id": "https://w3id.org/shp#DisclosureCheck",
+ "@type": "DefinedTerm",
+ "inDefinedTermSet": {
+ "@id": "https://w3id.org/shp"
+ }
+ },
+ {
+ "@id": "https://w3id.org/shp#GenerateCheckValue",
+ "@type": "DefinedTerm",
+ "inDefinedTermSet": {
+ "@id": "https://w3id.org/shp"
+ }
+ },
+ {
+ "@id": "https://w3id.org/shp#CheckValue",
+ "@type": "DefinedTerm",
+ "inDefinedTermSet": {
+ "@id": "https://w3id.org/shp"
+ }
+ },
+ {
+ "@id": "https://w3id.org/shp#ValidationCheck",
+ "@type": "DefinedTerm",
+ "inDefinedTermSet": {
+ "@id": "https://w3id.org/shp"
+ }
+ },
+ {
+ "@id": "https://w3id.org/shp#SignOff",
+ "@type": "DefinedTerm",
+ "inDefinedTermSet": {
+ "@id": "https://w3id.org/shp"
+ }
+ },
+ {
+ "@id": "https://w3id.org/shp#DisclosureCheck",
+ "@type": "DefinedTerm",
+ "inDefinedTermSet": {
+ "@id": "https://w3id.org/shp"
+ }
+ },
+ {
+ "@id": "https://w3id.org/shp#GenerateCheckValue",
+ "@type": "DefinedTerm",
+ "inDefinedTermSet": {
+ "@id": "https://w3id.org/shp"
+ }
+ },
+ {
+ "@id": "https://www.iana.org/assignments/named-information#sha-512",
+ "@type": "DefinedTerm",
+ "name": "sha-512 algorithm"
+ },
+ {
+ "@id": "#usesSHP",
+ "name": "uses vocabulary SHP",
+ "@type": "ResourceDescriptor",
+ "hasRole": {
+ "@id": "http://www.w3.org/ns/dx/prof/role/vocabulary"
+ },
+ "hasArtifact": {
+ "@id": "https://w3id.org/shp"
+ }
+ },
+ {
+ "@id": "#hasSpecification",
+ "@type": "ResourceDescriptor",
+ "name": "has specification",
+ "hasRole": {
+ "@id": "http://www.w3.org/ns/dx/prof/role/specification"
+ },
+ "hasArtifact": {
+ "@id": "https://trefx.uk/5s-crate/0.4/index.html"
+ }
+ },
+ {
+ "@id": "#hasExampleRequest",
+ "@type": "ResourceDescriptor",
+ "name": "has example: Request",
+ "hasRole": {
+ "@id": "http://www.w3.org/ns/dx/prof/role/example"
+ },
+ "hasArtifact": {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-request/data/"
+ }
+ },
+ {
+ "@id": "#hasExampleResult",
+ "@type": "ResourceDescriptor",
+ "name": "has example: Result",
+ "hasRole": {
+ "@id": "http://www.w3.org/ns/dx/prof/role/example"
+ },
+ "hasArtifact": {
+ "@id": "https://trefx.uk/5s-crate/0.4/example-result/data/"
+ }
+ },
+
+ {
+ "@id": "http://www.w3.org/ns/dx/prof/role/example",
+ "@type": [
+ "DefinedTerm",
+ "ResourceRole"
+ ],
+ "name": "Example",
+ "description": "Sample instance data conforming to the profile"
+ },
+ {
+ "@id": "http://www.w3.org/ns/dx/prof/role/specification",
+ "@type": [
+ "DefinedTerm",
+ "ResourceRole"
+ ],
+ "name": "Specification",
+ "description": "Defining the profile in human-readable form"
+ },
+ {
+ "@id": "http://www.w3.org/ns/dx/prof/role/vocabulary",
+ "@type": [
+ "DefinedTerm",
+ "ResourceRole"
+ ],
+ "name": "Vocabulary",
+ "description": "Defines terms used in the profile specification"
+ },
+ {
+ "@id": "http://spdx.org/licenses/CC0-1.0",
+ "@type": "CreativeWork",
+ "name": "Creative Commons Zero v1.0 Universal",
+ "identifier": "CC0-1.0",
+ "url": "https://creativecommons.org/publicdomain/zero/1.0/"
+ },
+ {
+ "@id": "http://spdx.org/licenses/MIT",
+ "@type": "CreativeWork",
+ "name": "MIT Licence",
+ "identifier": "MIT"
+ },
+ {
+ "@id": "https://gtr.ukri.org/projects?ref=MC_PC_23007",
+ "@type": "Grant",
+ "identifier": {
+ "@id": "_:ukri:MC_PC_23007"
+ },
+ "name": "DARE-FX: Delivering a federated network of TREs to enable safe analytics",
+ "description": "",
+ "funder": {
+ "@id": "https://ror.org/001aqnf71"
+ },
+ "sponsor": {
+ "@id": "https://dareuk.org.uk/"
+ }
+ },
+ {
+ "@id": "https://dareuk.org.uk/",
+ "@type": "FundingScheme",
+ "name": "DARE UK",
+ "funder": {
+ "@id": "https://ror.org/001aqnf71"
+ }
+ },
+ {
+ "@id": "_:ukri:MC_PC_23007",
+ "@type": "PropertyValue",
+ "name": "UKRI",
+ "value": "MC_PC_23007"
+ },
+ {
+ "@id": "https://trefx.uk/",
+ "@type": "ResearchProject",
+ "name": "TRE-FX",
+ "description": "Delivering a federated network of TREs to enable safe analytics",
+ "funding": {
+ "@id": "https://gtr.ukri.org/projects?ref=MC_PC_23007"
+ }
+ },
+ {
+ "@id": "https://ror.org/001aqnf71",
+ "@type": "FundingAgency",
+ "name": "UK Research and Innovation",
+ "alternateName": "UKRI",
+ "url": "https://www.ukri.org/"
+ },
+ {
+ "@id": "https://orcid.org/0000-0001-9842-9718",
+ "@type": "Person",
+ "name": "Stian Soiland-Reyes",
+ "affiliation": {
+ "@id": "https://ror.org/027m9bs27"
+ },
+ "memberOf": {
+ "@id": "https://trefx.uk/"
+ }
+ },
+ {
+ "@id": "https://ror.org/027m9bs27",
+ "@type": "CollegeOrUniversity",
+ "name": "The University of Manchester",
+ "url": "https://www.manchester.ac.uk/"
+ },
+ {
+ "@id": "https://orcid.org/0009-0003-2419-1964",
+ "@type": "Person",
+ "name": "Stuart Wheater",
+ "memberOf": {
+ "@id": "https://trefx.uk/"
+ }
+ }
+ ]
+}
\ No newline at end of file
From cf2b8088f41a09ff82a5d036d6f0332ef40173ae Mon Sep 17 00:00:00 2001
From: Douglas Lowe <10961945+douglowe@users.noreply.github.com>
Date: Thu, 18 Sep 2025 13:54:14 +0100
Subject: [PATCH 04/18] tests for 5-safe crate request and result profiles
---
.../five-safes-crate/test_valid_5src.py | 44 +++++++++++++++++++
tests/ro_crates.py | 8 ++++
2 files changed, 52 insertions(+)
create mode 100644 tests/integration/profiles/five-safes-crate/test_valid_5src.py
diff --git a/tests/integration/profiles/five-safes-crate/test_valid_5src.py b/tests/integration/profiles/five-safes-crate/test_valid_5src.py
new file mode 100644
index 00000000..1cc503b0
--- /dev/null
+++ b/tests/integration/profiles/five-safes-crate/test_valid_5src.py
@@ -0,0 +1,44 @@
+# Copyright (c) 2024-2025 CRS4
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+
+from rocrate_validator.models import Severity
+from tests.conftest import SKIP_LOCAL_DATA_ENTITY_EXISTENCE_CHECK_IDENTIFIER
+from tests.ro_crates import ValidROC
+from tests.shared import do_entity_test
+
+logger = logging.getLogger(__name__)
+logger.setLevel(logging.DEBUG)
+
+
+def test_valid_five_safes_crate_request_required():
+ """Test a valid Workflow Run Crate."""
+ do_entity_test(
+ ValidROC().five_safes_crate_request,
+ Severity.REQUIRED,
+ True,
+ profile_identifier="five-safes-crate",
+ skip_checks=[SKIP_LOCAL_DATA_ENTITY_EXISTENCE_CHECK_IDENTIFIER]
+ )
+
+def test_valid_five_safes_crate_result_required():
+ """Test a valid Workflow Run Crate."""
+ do_entity_test(
+ ValidROC().five_safes_crate_result,
+ Severity.REQUIRED,
+ True,
+ profile_identifier="five-safes-crate",
+ skip_checks=[SKIP_LOCAL_DATA_ENTITY_EXISTENCE_CHECK_IDENTIFIER]
+ )
diff --git a/tests/ro_crates.py b/tests/ro_crates.py
index 1c3d03a9..6ecc64ab 100644
--- a/tests/ro_crates.py
+++ b/tests/ro_crates.py
@@ -91,6 +91,14 @@ def provenance_run_crate(self) -> Path:
def multi_profile_crate(self) -> Path:
return VALID_CRATES_DATA_PATH / "multi-profile-crate"
+ @property
+ def five_safes_crate_request(self) -> Path:
+ return VALID_CRATES_DATA_PATH / "five-safes-crate-request"
+
+ @property
+ def five_safes_crate_result(self) -> Path:
+ return VALID_CRATES_DATA_PATH / "five-safes-crate-result"
+
class InvalidFileDescriptor:
From cab85790f4548965d0a8b65699aa7bf76d7e8475 Mon Sep 17 00:00:00 2001
From: Douglas Lowe <10961945+douglowe@users.noreply.github.com>
Date: Sat, 20 Sep 2025 15:12:16 +0100
Subject: [PATCH 05/18] five-safes request and result conform to rocrate-1.1
---
.../ro-crate-metadata.json | 8 +++--
.../ro-crate-metadata.json | 29 ++++++++++++-------
2 files changed, 25 insertions(+), 12 deletions(-)
diff --git a/tests/data/crates/valid/five-safes-crate-request/ro-crate-metadata.json b/tests/data/crates/valid/five-safes-crate-request/ro-crate-metadata.json
index b8a84271..9fb0d7bf 100644
--- a/tests/data/crates/valid/five-safes-crate-request/ro-crate-metadata.json
+++ b/tests/data/crates/valid/five-safes-crate-request/ro-crate-metadata.json
@@ -1,5 +1,5 @@
{
- "@context": "https://w3id.org/ro/crate/1.2-DRAFT/context",
+ "@context": "https://w3id.org/ro/crate/1.1/context",
"@graph": [
{
"@type": "CreativeWork",
@@ -8,12 +8,16 @@
"@id": "./"
},
"conformsTo": {
- "@id": "https://w3id.org/ro/crate/1.2-DRAFT"
+ "@id": "https://w3id.org/ro/crate/1.1"
}
},
{
"@id": "./",
"@type": "Dataset",
+ "name": "5-Safe RO-Crate Request",
+ "description": "example 5-Safe RO-Crate request metadata for testing",
+ "license": "Apache-2.0",
+ "datePublished": "2025-09-20T14:38:00+00:00",
"conformsTo": {
"@id": "https://w3id.org/5s-crate/0.4"
},
diff --git a/tests/data/crates/valid/five-safes-crate-result/ro-crate-metadata.json b/tests/data/crates/valid/five-safes-crate-result/ro-crate-metadata.json
index 3b43f636..a6475f63 100644
--- a/tests/data/crates/valid/five-safes-crate-result/ro-crate-metadata.json
+++ b/tests/data/crates/valid/five-safes-crate-result/ro-crate-metadata.json
@@ -1,5 +1,5 @@
{
- "@context": "https://w3id.org/ro/crate/1.2-DRAFT/context",
+ "@context": "https://w3id.org/ro/crate/1.1/context",
"@graph": [
{
"@type": "CreativeWork",
@@ -8,12 +8,15 @@
"@id": "./"
},
"conformsTo": {
- "@id": "https://w3id.org/ro/crate/1.2-DRAFT"
+ "@id": "https://w3id.org/ro/crate/1.1"
}
},
{
"@id": "./",
"@type": "Dataset",
+ "name": "5-Safe RO-Crate Result",
+ "description": "example 5-Safe RO-Crate result metadata for testing",
+ "datePublished": "2025-09-20T14:45:00+00:00",
"conformsTo": {
"@id": "https://w3id.org/5s-crate/0.4"
},
@@ -24,6 +27,12 @@
{
"@id": "input1.txt"
},
+ {
+ "@id": "outputs/qa.csv"
+ },
+ {
+ "@id": "outputs/diagrams/"
+ },
{
"@id": "workflow/289/"
}
@@ -60,7 +69,7 @@
"publisher": {
"@id": "https://tre72.example.com/"
},
- "licence": {
+ "license": {
"@id": "http://spdx.org/licenses/CC-BY-4.0"
}
},
@@ -115,7 +124,7 @@
],
"result": [
{
- "@id": "outputs/table.csv"
+ "@id": "outputs/qa.csv"
},
{
"@id": "outputs/diagrams/"
@@ -206,7 +215,7 @@
},
{
"@id": "#check-f33fe90c-0c22-4c72-b299-de509028410e",
- "type": "AssessAction",
+ "@type": "AssessAction",
"additionalType": {
"@id": "https://w3id.org/shp#CheckValue"
},
@@ -225,7 +234,7 @@
},
{
"@id": "#validate-1146f640-819e-4c86-b029-b763a0040896",
- "type": "AssessAction",
+ "@type": "AssessAction",
"additionalType": {
"@id": "https://w3id.org/shp#ValidationCheck"
},
@@ -245,7 +254,7 @@
},
{
"@id": "#download-8b51bf57-6b29-44da-b24b-638c8df91639",
- "type": "DownloadAction",
+ "@type": "DownloadAction",
"name": "Downloaded workflow RO-Crate via proxy",
"startTime": "2023-04-18T12:11:50+01:00",
"endTime": "2023-04-18T12:11:52+01:00",
@@ -262,7 +271,7 @@
},
{
"@id": "#signoff-3b741265-cfef-49ea-8138-a2fa149bf2f0",
- "type": "AssessAction",
+ "@type": "AssessAction",
"additionalType": {
"@id": "https://w3id.org/shp#SignOff"
},
@@ -289,7 +298,7 @@
},
{
"@id": "#disclosure-b16c1f0a-ae7f-4582-9b28-7d9df3313e27",
- "type": "AssessAction",
+ "@type": "AssessAction",
"additionalType": {
"@id": "https://w3id.org/shp#DisclosureCheck"
},
@@ -305,7 +314,7 @@
},
{
"@id": "#bagit-ce785c0b-c988-4043-8cbd-1489dcebc14f",
- "type": "UpdateAction",
+ "@type": "UpdateAction",
"startTime": "2023-04-29T12:12:25+01:00",
"additionalType": {
"@id": "https://w3id.org/shp#GenerateCheckValue"
From 599ffd0e8a1f0d7674712e83104819049dc737c1 Mon Sep 17 00:00:00 2001
From: Douglas Lowe <10961945+douglowe@users.noreply.github.com>
Date: Sat, 20 Sep 2025 17:48:18 +0100
Subject: [PATCH 06/18] 5S-crate funder test added
---
.../five-safes-crate/must/0_funder.ttl | 35 +++++++++++++++++++
...ta.ttl => 1_root_data_entity_metadata.ttl} | 16 +++++----
2 files changed, 44 insertions(+), 7 deletions(-)
create mode 100644 rocrate_validator/profiles/five-safes-crate/must/0_funder.ttl
rename rocrate_validator/profiles/five-safes-crate/must/{0_root_data_entity_metadata.ttl => 1_root_data_entity_metadata.ttl} (64%)
diff --git a/rocrate_validator/profiles/five-safes-crate/must/0_funder.ttl b/rocrate_validator/profiles/five-safes-crate/must/0_funder.ttl
new file mode 100644
index 00000000..247faa90
--- /dev/null
+++ b/rocrate_validator/profiles/five-safes-crate/must/0_funder.ttl
@@ -0,0 +1,35 @@
+# Copyright (c) 2024-2025 CRS4
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+@prefix ro: <./> .
+@prefix ro-crate: .
+@prefix five-safes-crate: .
+@prefix schema_org: .
+@prefix sh: .
+@prefix bioschemas: .
+
+five-safes-crate:FundingBody a sh:NodeShape ;
+ sh:name "Funding body Project" ;
+ sh:description "Project which is funding this work" ;
+ sh:targetClass schema_org:Project ;
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "Project Name" ;
+ sh:description """Check if the Project Entity `name` (as specified by schema.org)
+ to clearly identify the dataset and distinguish it from other projects.""" ;
+ sh:minCount 1 ;
+ sh:nodeKind sh:Literal ;
+ sh:path schema_org:name;
+ sh:message "The Project Entity MUST have a `name` property (as specified by schema.org)" ;
+ ] .
diff --git a/rocrate_validator/profiles/five-safes-crate/must/0_root_data_entity_metadata.ttl b/rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl
similarity index 64%
rename from rocrate_validator/profiles/five-safes-crate/must/0_root_data_entity_metadata.ttl
rename to rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl
index 2cac720c..645f5dd0 100644
--- a/rocrate_validator/profiles/five-safes-crate/must/0_root_data_entity_metadata.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl
@@ -14,6 +14,7 @@
@prefix ro: <./> .
@prefix ro-crate: .
+@prefix five-safes-crate: .
@prefix rdf: .
@prefix schema_org: .
@prefix sh: .
@@ -21,17 +22,18 @@
@prefix xsd: .
-ro-crate:RootDataEntityRequiredProperties
+five-safes-crate:RootDataEntityRequiredProperties
a sh:NodeShape ;
sh:name "Five Safes Crate Root Data Entity REQUIRED properties" ;
- sh:description "The Root Data Entity MUST have a `funding`" ;
+ sh:description "The Root Data Entity MUST have a `sourceOrganisation`" ;
sh:targetClass ro-crate:RootDataEntity ;
sh:property [
a sh:PropertyShape ;
- sh:name "Root Data Entity: `funding` property" ;
- sh:description """Check if the Root Data Entity includes a `funding` property (as specified by schema.org).""" ;
+ sh:name "Root Data Entity: `sourceOrganization` property" ;
+ sh:description """Check if the Root Data Entity includes a `sourceOrganization` (as specified by schema.org).""" ;
+ sh:path schema_org:sourceOrganization;
sh:minCount 1 ;
- sh:nodeKind sh:Literal ;
- sh:path schema_org:funding;
- sh:message "The Root Data Entity MUST have a `funding` property (as specified by schema.org)" ;
+ sh:class ro-crate:ContextualEntity ;
+ sh:message """The Root Data Entity MUST have a `sourceOrganization` property (as specified by schema.org).
+ SHOULD link to a Contextual Entity in the RO-Crate Metadata File with a name.""" ;
] .
From 2cc55b9208b57b4969a0cdcf6a4c3aeb7a3fd649 Mon Sep 17 00:00:00 2001
From: Douglas Lowe <10961945+douglowe@users.noreply.github.com>
Date: Mon, 22 Sep 2025 16:44:28 +0100
Subject: [PATCH 07/18] renumber funder test for now
---
.../profiles/five-safes-crate/must/{0_funder.ttl => 1_funder.ttl} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename rocrate_validator/profiles/five-safes-crate/must/{0_funder.ttl => 1_funder.ttl} (100%)
diff --git a/rocrate_validator/profiles/five-safes-crate/must/0_funder.ttl b/rocrate_validator/profiles/five-safes-crate/must/1_funder.ttl
similarity index 100%
rename from rocrate_validator/profiles/five-safes-crate/must/0_funder.ttl
rename to rocrate_validator/profiles/five-safes-crate/must/1_funder.ttl
From 47023b1701f9850e314e4e06b95828acc2cb18a9 Mon Sep 17 00:00:00 2001
From: Ettore Murabito
Date: Thu, 25 Sep 2025 13:25:44 +0100
Subject: [PATCH 08/18] Added chekts for rules about responsible Agent.
---
.../five-safes-crate/must/2_agent_entity.ttl | 107 ++++++++++++++++++
.../should/2_agent_entity.ttl | 26 +++++
2 files changed, 133 insertions(+)
create mode 100644 rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl
create mode 100644 rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
diff --git a/rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl b/rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl
new file mode 100644
index 00000000..30805ceb
--- /dev/null
+++ b/rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl
@@ -0,0 +1,107 @@
+# Copyright (c) 2024-2025 CRS4
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+@prefix ro: <./> .
+@prefix ro-crate: .
+@prefix five-safes-crate: .
+@prefix rdf: .
+@prefix schema: .
+@prefix sh: .
+@prefix validator: .
+@prefix xsd: .
+
+
+# Any CreateAction entity must have one (and only one) agent
+five-safes-crate:CreateActionHasAgent
+ a sh:NodeShape ;
+ sh:description "CreateAction MUST have an agent property." ;
+ sh:targetClass schema:CreateAction ;
+ sh:property [
+ sh:path schema:agent ;
+ sh:minCount 1 ;
+ sh:maxCount 1 ;
+ sh:nodeKind sh:IRI ;
+ sh:message "CreateAction MUST have an agent property." ;
+ ] .
+
+
+# The agent of a CreateAction must be a Person
+five-safes-crate:CreateActionAgentIsPerson
+ a sh:NodeShape ;
+ sh:description "The agent of a CreateAction entity MUST be a Person." ;
+ sh:target [
+ a sh:SPARQLTarget ;
+ sh:prefixes ro-crate:sparqlPrefixes ;
+ sh:select """
+ SELECT DISTINCT ?this WHERE {
+ ?action a schema:CreateAction ;
+ schema:agent ?this .
+ }
+ """
+ ] ;
+ sh:class schema:Person ;
+ sh:severity sh:Violation ;
+ sh:message "The agent of a CreateAction entity MUST be a Person." .
+
+
+# The affiliation (if any) of a CreateAction's agent MUST be an Organization
+five-safes-crate:AgentAffiliationIsOrganization
+ a sh:NodeShape ;
+ sh:description "The affiliation (if any) of a CreateAction's agent MUST be an Organization" ;
+ sh:severity sh:Violation ;
+ sh:target [
+ a sh:SPARQLTarget ;
+ sh:prefixes ro-crate:sparqlPrefixes ;
+ sh:select """
+ SELECT DISTINCT ?this WHERE {
+ ?action a schema:CreateAction ;
+ schema:agent ?this .
+ ?this a schema:Person .
+ ?this schema:affiliation ?aff .
+ }
+ """
+ ] ;
+ sh:property [
+ sh:path schema:affiliation ;
+ sh:class schema:Organization ;
+ sh:message "The affiliation (if any) of a CreateAction's agent MUST be an Organization" ;
+ ] .
+
+
+# All schema:Organization instances: @id MUST be a PID permalink (ROR / ISNI / Wikidata)
+five-safes-crate:OrganizationIdIsPIDPermalink
+ a sh:NodeShape ;
+ sh:name "Organizations value restriction" ;
+ sh:description "An Organization `@id` must be a PID permalink (ROR, ISNI, or Wikidata)." ;
+
+ # Target the CLASS node; values are all subjects with rdf:type schema:Organization
+ sh:targetNode schema:Organization ;
+
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "Organization URI value" ;
+ sh:description "Check that the Organization entity URI (@id) is a PID permalink." ;
+
+ # From the class node, walk inverse rdf:type to all instances
+ sh:path [ sh:inversePath rdf:type ] ;
+
+ # Require at least one instance (prevents empty graphs from 'passing')
+ sh:minCount 1 ;
+
+ # Regex over the string form of the instance IRI
+ sh:pattern "^(?:https://(?:ror\\.org/0[0-9a-hjkmnp-tv-z]{6}[0-9]{2}|isni\\.org/isni/\\d{15}[\\dX]|(?:www\\.)?wikidata\\.org/entity/Q\\d+))$" ;
+ sh:flags "i" ;
+
+ sh:message "Organization @id MUST be a PID permalink (ROR/ISNI/Wikidata)." ;
+ ] .
diff --git a/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl b/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
new file mode 100644
index 00000000..1e9f6658
--- /dev/null
+++ b/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
@@ -0,0 +1,26 @@
+@prefix ro: <./> .
+@prefix ro-crate: .
+@prefix five-safes-crate: .
+@prefix rdf: .
+@prefix schema: .
+@prefix sh: .
+@prefix validator: .
+@prefix xsd: .
+
+
+# Person who is the agent of a CreateAction SHOULD have an affiliation
+five-safes-crate:PersonAgentHasAffiliation
+ a sh:NodeShape ;
+ sh:name "Organizations value restriction" ;
+ sh:description "An Organization `@id` must be a permalink" ;
+ sh:targetClass schema:Organization ;
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "Organization URI value" ;
+ sh:description "Check if the Organization Entity URI is a permalink" ;
+ sh:path [ sh:inversePath rdf:type ] ;
+ sh:minCount 1 ;
+ sh:message """An Organization URI MUST be a permalink""" ;
+ sh:pattern "^(https://(ror\\.org/0[0-9a-hjkmnp-tv-z]{6}[0-9]{2}|isni\\.org/isni/[0-9]{15}[0-9X]|(www\\.)?wikidata\\.org/entity/Q[0-9]+))$" ;
+sh:flags "i" ;
+ ] .
\ No newline at end of file
From c7d608498bfd5ac29e02fbb45dae8e8b1c2ec922 Mon Sep 17 00:00:00 2001
From: Ettore Murabito
Date: Thu, 25 Sep 2025 14:10:54 +0100
Subject: [PATCH 09/18] Ammended test checking that agent SHOULD have an
affiliation.
---
.../five-safes-crate/must/2_agent_entity.ttl | 28 ----------
.../should/2_agent_entity.ttl | 55 +++++++++++++++----
2 files changed, 44 insertions(+), 39 deletions(-)
diff --git a/rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl b/rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl
index 30805ceb..684674f0 100644
--- a/rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl
@@ -77,31 +77,3 @@ five-safes-crate:AgentAffiliationIsOrganization
sh:class schema:Organization ;
sh:message "The affiliation (if any) of a CreateAction's agent MUST be an Organization" ;
] .
-
-
-# All schema:Organization instances: @id MUST be a PID permalink (ROR / ISNI / Wikidata)
-five-safes-crate:OrganizationIdIsPIDPermalink
- a sh:NodeShape ;
- sh:name "Organizations value restriction" ;
- sh:description "An Organization `@id` must be a PID permalink (ROR, ISNI, or Wikidata)." ;
-
- # Target the CLASS node; values are all subjects with rdf:type schema:Organization
- sh:targetNode schema:Organization ;
-
- sh:property [
- a sh:PropertyShape ;
- sh:name "Organization URI value" ;
- sh:description "Check that the Organization entity URI (@id) is a PID permalink." ;
-
- # From the class node, walk inverse rdf:type to all instances
- sh:path [ sh:inversePath rdf:type ] ;
-
- # Require at least one instance (prevents empty graphs from 'passing')
- sh:minCount 1 ;
-
- # Regex over the string form of the instance IRI
- sh:pattern "^(?:https://(?:ror\\.org/0[0-9a-hjkmnp-tv-z]{6}[0-9]{2}|isni\\.org/isni/\\d{15}[\\dX]|(?:www\\.)?wikidata\\.org/entity/Q\\d+))$" ;
- sh:flags "i" ;
-
- sh:message "Organization @id MUST be a PID permalink (ROR/ISNI/Wikidata)." ;
- ] .
diff --git a/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl b/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
index 1e9f6658..86d97f72 100644
--- a/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
@@ -11,16 +11,49 @@
# Person who is the agent of a CreateAction SHOULD have an affiliation
five-safes-crate:PersonAgentHasAffiliation
a sh:NodeShape ;
- sh:name "Organizations value restriction" ;
- sh:description "An Organization `@id` must be a permalink" ;
- sh:targetClass schema:Organization ;
+ sh:mame "Agent's affiliation" ;
+ sh:description "The agent of a CreateAction entity SHOULD have an affiliation" ;
+ sh:target [
+ a sh:SPARQLTarget ;
+ sh:prefixes ro-crate:sparqlPrefixes ;
+ sh:select """
+ SELECT DISTINCT ?this WHERE {
+ ?action a schema:CreateAction ;
+ schema:agent ?this .
+ ?this a schema:Person .
+ }
+ """
+ ] ;
sh:property [
- a sh:PropertyShape ;
- sh:name "Organization URI value" ;
- sh:description "Check if the Organization Entity URI is a permalink" ;
- sh:path [ sh:inversePath rdf:type ] ;
+ sh:path schema:affiliation ;
sh:minCount 1 ;
- sh:message """An Organization URI MUST be a permalink""" ;
- sh:pattern "^(https://(ror\\.org/0[0-9a-hjkmnp-tv-z]{6}[0-9]{2}|isni\\.org/isni/[0-9]{15}[0-9X]|(www\\.)?wikidata\\.org/entity/Q[0-9]+))$" ;
-sh:flags "i" ;
- ] .
\ No newline at end of file
+ sh:message "The agent of a CreateAction entity SHOULD have an affiliation" ;
+ ] .
+
+
+# All schema:Organization instances: @id SHOULD be a PID permalink (ROR / ISNI / Wikidata)
+five-safes-crate:OrganizationIdIsPIDPermalink
+ a sh:NodeShape ;
+ sh:name "Organizations value restriction" ;
+ sh:description "An Organization `@id` should be a PID permalink (ROR, ISNI, or Wikidata)." ;
+
+ # Target the CLASS node; values are all subjects with rdf:type schema:Organization
+ sh:targetNode schema:Organization ;
+
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "Organization URI value" ;
+ sh:description "Check that the Organization entity URI (@id) is a PID permalink." ;
+
+ # From the class node, walk inverse rdf:type to all instances
+ sh:path [ sh:inversePath rdf:type ] ;
+
+ # Require at least one instance (prevents empty graphs from 'passing')
+ sh:minCount 1 ;
+
+ # Regex over the string form of the instance IRI
+ sh:pattern "^(?:https://(?:ror\\.org/0[0-9a-hjkmnp-tv-z]{6}[0-9]{2}|isni\\.org/isni/\\d{15}[\\dX]|(?:www\\.)?wikidata\\.org/entity/Q\\d+))$" ;
+ sh:flags "i" ;
+
+ sh:message "Organization @id SHOULD be a PID permalink (ROR/ISNI/Wikidata)." ;
+ ] .
\ No newline at end of file
From b0f21746892c90198870eea8800c5ec6d5a683e4 Mon Sep 17 00:00:00 2001
From: Ettore Murabito
Date: Thu, 25 Sep 2025 14:25:31 +0100
Subject: [PATCH 10/18] Removed typo.
---
.../profiles/five-safes-crate/should/2_agent_entity.ttl | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl b/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
index 86d97f72..caceab2c 100644
--- a/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
@@ -11,8 +11,9 @@
# Person who is the agent of a CreateAction SHOULD have an affiliation
five-safes-crate:PersonAgentHasAffiliation
a sh:NodeShape ;
- sh:mame "Agent's affiliation" ;
+ sh:name "Agent's affiliation" ;
sh:description "The agent of a CreateAction entity SHOULD have an affiliation" ;
+ sh:message "The agent of a CreateAction entity SHOULD have an affiliation" ;
sh:target [
a sh:SPARQLTarget ;
sh:prefixes ro-crate:sparqlPrefixes ;
From 35fad70f0af7ebdd7f906a059502f7f7a527c968 Mon Sep 17 00:00:00 2001
From: Ettore Murabito
Date: Mon, 29 Sep 2025 12:47:40 +0100
Subject: [PATCH 11/18] 1) Now a CreateAction entity can have more than 1
agent. 2) Also, check on @id being a permalink is now restricted to
Organizations that are affiliations of agents.
---
.../five-safes-crate/must/2_agent_entity.ttl | 3 +-
.../should/2_agent_entity.ttl | 42 ++++++++++---------
2 files changed, 24 insertions(+), 21 deletions(-)
diff --git a/rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl b/rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl
index 684674f0..f86386de 100644
--- a/rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl
@@ -29,8 +29,7 @@ five-safes-crate:CreateActionHasAgent
sh:targetClass schema:CreateAction ;
sh:property [
sh:path schema:agent ;
- sh:minCount 1 ;
- sh:maxCount 1 ;
+ sh:minCount 1 ;
sh:nodeKind sh:IRI ;
sh:message "CreateAction MUST have an agent property." ;
] .
diff --git a/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl b/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
index caceab2c..61aebc2c 100644
--- a/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
@@ -32,29 +32,33 @@ five-safes-crate:PersonAgentHasAffiliation
] .
-# All schema:Organization instances: @id SHOULD be a PID permalink (ROR / ISNI / Wikidata)
-five-safes-crate:OrganizationIdIsPIDPermalink
+five-safes-crate:PersonAgentOfCreateAction_AffiliationPermalinkCheck
a sh:NodeShape ;
- sh:name "Organizations value restriction" ;
- sh:description "An Organization `@id` should be a PID permalink (ROR, ISNI, or Wikidata)." ;
+ sh:name "Person (agent of CreateAction) → affiliation Organization PID check" ;
+ sh:description "For Persons who are agents of a CreateAction, validate that any affiliation Organization has a PID permalink @id." ;
- # Target the CLASS node; values are all subjects with rdf:type schema:Organization
- sh:targetNode schema:Organization ;
+ # Target: Persons that are objects of schema:agent where the subject is a CreateAction
+ sh:target [
+ a sh:SPARQLTarget ;
+ sh:prefixes ro-crate:sparqlPrefixes ;
+ sh:select """
+ SELECT ?this WHERE {
+ ?this a schema:Person .
+ ?action a schema:CreateAction ;
+ schema:agent ?this .
+ }
+ """ ;
+ ] ;
+ # If the Person has an affiliation, validate the affiliation node's IRI
sh:property [
a sh:PropertyShape ;
- sh:name "Organization URI value" ;
- sh:description "Check that the Organization entity URI (@id) is a PID permalink." ;
-
- # From the class node, walk inverse rdf:type to all instances
- sh:path [ sh:inversePath rdf:type ] ;
-
- # Require at least one instance (prevents empty graphs from 'passing')
- sh:minCount 1 ;
-
- # Regex over the string form of the instance IRI
+ sh:name "affiliation Organization PID permalink" ;
+ sh:path schema:affiliation ;
+ # Optional typing requirement (keep or drop as you prefer)
+ sh:class schema:Organization ;
+ sh:nodeKind sh:IRI ;
sh:pattern "^(?:https://(?:ror\\.org/0[0-9a-hjkmnp-tv-z]{6}[0-9]{2}|isni\\.org/isni/\\d{15}[\\dX]|(?:www\\.)?wikidata\\.org/entity/Q\\d+))$" ;
sh:flags "i" ;
-
- sh:message "Organization @id SHOULD be a PID permalink (ROR/ISNI/Wikidata)." ;
- ] .
\ No newline at end of file
+ sh:message "Affiliation Organization @id SHOULD be a PID permalink (ROR/ISNI/Wikidata)." ;
+ ] .
From 5279b6fa2257c3be80fa0174b6b0e4a0d9bdfe14 Mon Sep 17 00:00:00 2001
From: Ettore Murabito
Date: Mon, 29 Sep 2025 16:06:31 +0100
Subject: [PATCH 12/18] Renamed files containing tests for 'requesting agent'.
---
.../must/{2_agent_entity.ttl => 2_requesting_agent.ttl} | 0
.../should/{2_agent_entity.ttl => 2_requesting_agent.ttl} | 4 ++++
2 files changed, 4 insertions(+)
rename rocrate_validator/profiles/five-safes-crate/must/{2_agent_entity.ttl => 2_requesting_agent.ttl} (100%)
rename rocrate_validator/profiles/five-safes-crate/should/{2_agent_entity.ttl => 2_requesting_agent.ttl} (89%)
diff --git a/rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl b/rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl
similarity index 100%
rename from rocrate_validator/profiles/five-safes-crate/must/2_agent_entity.ttl
rename to rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl
diff --git a/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl b/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl
similarity index 89%
rename from rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
rename to rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl
index 61aebc2c..f16803ab 100644
--- a/rocrate_validator/profiles/five-safes-crate/should/2_agent_entity.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl
@@ -58,6 +58,10 @@ five-safes-crate:PersonAgentOfCreateAction_AffiliationPermalinkCheck
# Optional typing requirement (keep or drop as you prefer)
sh:class schema:Organization ;
sh:nodeKind sh:IRI ;
+ # Match the string form of the IRI against approved PID patterns.
+ # - ROR: https://ror.org/0XXXXXXX## (Crockford base32 + 2 digits)
+ # - ISNI: https://isni.org/isni/NNNNNNNNNNNNNNNX (X allowed as checksum)
+ # - Wikidata: https://www.wikidata.org/entity/Q (or without www)
sh:pattern "^(?:https://(?:ror\\.org/0[0-9a-hjkmnp-tv-z]{6}[0-9]{2}|isni\\.org/isni/\\d{15}[\\dX]|(?:www\\.)?wikidata\\.org/entity/Q\\d+))$" ;
sh:flags "i" ;
sh:message "Affiliation Organization @id SHOULD be a PID permalink (ROR/ISNI/Wikidata)." ;
From b27c830503d427a2511b9895fc8d2b73052591ef Mon Sep 17 00:00:00 2001
From: Ettore Murabito
Date: Tue, 30 Sep 2025 09:13:57 +0100
Subject: [PATCH 13/18] Refactored code
---
.../must/2_requesting_agent.ttl | 78 ++++++++-----------
.../should/2_requesting_agent.ttl | 62 ++++++---------
2 files changed, 53 insertions(+), 87 deletions(-)
diff --git a/rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl b/rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl
index f86386de..26ac186f 100644
--- a/rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl
@@ -22,57 +22,41 @@
@prefix xsd: .
-# Any CreateAction entity must have one (and only one) agent
+
five-safes-crate:CreateActionHasAgent
- a sh:NodeShape ;
- sh:description "CreateAction MUST have an agent property." ;
- sh:targetClass schema:CreateAction ;
- sh:property [
- sh:path schema:agent ;
- sh:minCount 1 ;
- sh:nodeKind sh:IRI ;
- sh:message "CreateAction MUST have an agent property." ;
- ] .
+ a sh:NodeShape ;
+ sh:name: "CreateAction" ;
+ sh:targetClass schema:CreateAction ;
+ sh:description "Checks that a CreateAction has an agent and that each agent is a schema:Person." ;
+ # CreateAction entity MUST have an agent (IRI)
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "Has Agent" ;
+ sh:path schema:agent ;
+ sh:minCount 1 ;
+ sh:nodeKind sh:IRI ;
+ sh:severity sh:Violation ;
+ sh:message "CreateAction MUST have at least one schema:agent that is an IRI." ;
+ ] ;
-# The agent of a CreateAction must be a Person
-five-safes-crate:CreateActionAgentIsPerson
- a sh:NodeShape ;
- sh:description "The agent of a CreateAction entity MUST be a Person." ;
- sh:target [
- a sh:SPARQLTarget ;
- sh:prefixes ro-crate:sparqlPrefixes ;
- sh:select """
- SELECT DISTINCT ?this WHERE {
- ?action a schema:CreateAction ;
- schema:agent ?this .
- }
- """
- ] ;
+ # The agent of a CreateAction entity MUST be a Person
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "Agent is a Person" ;
+ sh:path schema:agent ;
sh:class schema:Person ;
sh:severity sh:Violation ;
- sh:message "The agent of a CreateAction entity MUST be a Person." .
-
+ sh:message "Each CreateAction agent MUST be typed as schema:Person and be an IRI." ;
+ ] ;
-# The affiliation (if any) of a CreateAction's agent MUST be an Organization
-five-safes-crate:AgentAffiliationIsOrganization
- a sh:NodeShape ;
- sh:description "The affiliation (if any) of a CreateAction's agent MUST be an Organization" ;
+ # If any agent affiliation exists, it MUST be an Organization (IRI)
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "Affiliation is an Organization" ;
+ sh:path ( schema:agent schema:affiliation ) ;
+ sh:class schema:Organization ;
+ sh:nodeKind sh:IRI ;
sh:severity sh:Violation ;
- sh:target [
- a sh:SPARQLTarget ;
- sh:prefixes ro-crate:sparqlPrefixes ;
- sh:select """
- SELECT DISTINCT ?this WHERE {
- ?action a schema:CreateAction ;
- schema:agent ?this .
- ?this a schema:Person .
- ?this schema:affiliation ?aff .
- }
- """
- ] ;
- sh:property [
- sh:path schema:affiliation ;
- sh:class schema:Organization ;
- sh:message "The affiliation (if any) of a CreateAction's agent MUST be an Organization" ;
- ] .
+ sh:message "The affiliation (if any) of a CreateAction's agent MUST be a schema:Organization and be an IRI." ;
+ ] .
\ No newline at end of file
diff --git a/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl b/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl
index f16803ab..467abc8c 100644
--- a/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl
@@ -11,9 +11,8 @@
# Person who is the agent of a CreateAction SHOULD have an affiliation
five-safes-crate:PersonAgentHasAffiliation
a sh:NodeShape ;
- sh:name "Agent's affiliation" ;
- sh:description "The agent of a CreateAction entity SHOULD have an affiliation" ;
- sh:message "The agent of a CreateAction entity SHOULD have an affiliation" ;
+ sh:name "Agent of CreateAction" ;
+ sh:description "The agent of a CreateAction entity" ;
sh:target [
a sh:SPARQLTarget ;
sh:prefixes ro-crate:sparqlPrefixes ;
@@ -21,48 +20,31 @@ five-safes-crate:PersonAgentHasAffiliation
SELECT DISTINCT ?this WHERE {
?action a schema:CreateAction ;
schema:agent ?this .
- ?this a schema:Person .
}
"""
] ;
+
+ # The agent of a CreateAction entity SHOULD have an affiliation
sh:property [
+ sh:name "Presence of affiliations" ;
sh:path schema:affiliation ;
sh:minCount 1 ;
+ sh:severity sh:Warning ;
sh:message "The agent of a CreateAction entity SHOULD have an affiliation" ;
- ] .
-
-
-five-safes-crate:PersonAgentOfCreateAction_AffiliationPermalinkCheck
- a sh:NodeShape ;
- sh:name "Person (agent of CreateAction) → affiliation Organization PID check" ;
- sh:description "For Persons who are agents of a CreateAction, validate that any affiliation Organization has a PID permalink @id." ;
-
- # Target: Persons that are objects of schema:agent where the subject is a CreateAction
- sh:target [
- a sh:SPARQLTarget ;
- sh:prefixes ro-crate:sparqlPrefixes ;
- sh:select """
- SELECT ?this WHERE {
- ?this a schema:Person .
- ?action a schema:CreateAction ;
- schema:agent ?this .
- }
- """ ;
- ] ;
+ ] ;
- # If the Person has an affiliation, validate the affiliation node's IRI
- sh:property [
- a sh:PropertyShape ;
- sh:name "affiliation Organization PID permalink" ;
- sh:path schema:affiliation ;
- # Optional typing requirement (keep or drop as you prefer)
- sh:class schema:Organization ;
- sh:nodeKind sh:IRI ;
- # Match the string form of the IRI against approved PID patterns.
- # - ROR: https://ror.org/0XXXXXXX## (Crockford base32 + 2 digits)
- # - ISNI: https://isni.org/isni/NNNNNNNNNNNNNNNX (X allowed as checksum)
- # - Wikidata: https://www.wikidata.org/entity/Q (or without www)
- sh:pattern "^(?:https://(?:ror\\.org/0[0-9a-hjkmnp-tv-z]{6}[0-9]{2}|isni\\.org/isni/\\d{15}[\\dX]|(?:www\\.)?wikidata\\.org/entity/Q\\d+))$" ;
- sh:flags "i" ;
- sh:message "Affiliation Organization @id SHOULD be a PID permalink (ROR/ISNI/Wikidata)." ;
- ] .
+ # If the agent has an affiliation, validate the affiliation node's IRI
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "Affiliation IRI" ;
+ sh:path schema:affiliation ;
+ sh:nodeKind sh:IRI ;
+ sh:or (
+ [ sh:pattern "^https://ror\\.org/0[0-9a-hjkmnp-tv-z]{6}[0-9]{2}$" ]
+ [ sh:pattern "^https://isni\\.org/isni/\\d{15}[\\dX]$" ]
+ [ sh:pattern "^https://(?:www\\.)?wikidata\\.org/entity/Q\\d+$" ]
+ ) ;
+ sh:flags "i" ;
+ sh:severity sh:Warning ;
+ sh:message "Affiliation Organization @id SHOULD be a permalink (ROR/ISNI/Wikidata)." ;
+ ] .
\ No newline at end of file
From b3f4740ff778a41491ac69a557b4e12bede8a93e Mon Sep 17 00:00:00 2001
From: Ettore Murabito
Date: Wed, 8 Oct 2025 10:10:40 +0100
Subject: [PATCH 14/18] Addressed most of Alex' review points. Still need to
address copyright (and possibly licence for RooDataEntity...???)
---
.../profiles/five-safes-crate/must/2_requesting_agent.ttl | 3 ++-
.../five-safes-crate/should/2_requesting_agent.ttl | 8 ++++----
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl b/rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl
index 26ac186f..1a722a9c 100644
--- a/rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl
@@ -25,7 +25,7 @@
five-safes-crate:CreateActionHasAgent
a sh:NodeShape ;
- sh:name: "CreateAction" ;
+ sh:name "CreateAction" ;
sh:targetClass schema:CreateAction ;
sh:description "Checks that a CreateAction has an agent and that each agent is a schema:Person." ;
@@ -45,6 +45,7 @@ five-safes-crate:CreateActionHasAgent
a sh:PropertyShape ;
sh:name "Agent is a Person" ;
sh:path schema:agent ;
+ sh:nodeKind sh:IRI ;
sh:class schema:Person ;
sh:severity sh:Violation ;
sh:message "Each CreateAction agent MUST be typed as schema:Person and be an IRI." ;
diff --git a/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl b/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl
index 467abc8c..5431e8ea 100644
--- a/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl
@@ -26,6 +26,7 @@ five-safes-crate:PersonAgentHasAffiliation
# The agent of a CreateAction entity SHOULD have an affiliation
sh:property [
+ a sh:PropertyShape ;
sh:name "Presence of affiliations" ;
sh:path schema:affiliation ;
sh:minCount 1 ;
@@ -40,11 +41,10 @@ five-safes-crate:PersonAgentHasAffiliation
sh:path schema:affiliation ;
sh:nodeKind sh:IRI ;
sh:or (
- [ sh:pattern "^https://ror\\.org/0[0-9a-hjkmnp-tv-z]{6}[0-9]{2}$" ]
- [ sh:pattern "^https://isni\\.org/isni/\\d{15}[\\dX]$" ]
- [ sh:pattern "^https://(?:www\\.)?wikidata\\.org/entity/Q\\d+$" ]
+ [ sh:pattern "^https://ror\\.org/0[0-9a-hjkmnp-tv-z]{6}[0-9]{2}$" ; sh:flags "i"]
+ [ sh:pattern "^https://isni\\.org/isni/\\d{15}[\\dX]$" ; sh:flags "i"]
+ [ sh:pattern "^https://(?:www\\.)?wikidata\\.org/entity/Q\\d+$" ; sh:flags "i"]
) ;
- sh:flags "i" ;
sh:severity sh:Warning ;
sh:message "Affiliation Organization @id SHOULD be a permalink (ROR/ISNI/Wikidata)." ;
] .
\ No newline at end of file
From 6d352126d825c790e4b08c888cf0f19786155c9c Mon Sep 17 00:00:00 2001
From: Ettore Murabito
Date: Wed, 8 Oct 2025 10:21:14 +0100
Subject: [PATCH 15/18] Addressed copyright plus licence for one of the ttl
file (where it was missing).
---
.../five-safes-crate/must/2_requesting_agent.ttl | 2 +-
.../five-safes-crate/should/2_requesting_agent.ttl | 14 ++++++++++++++
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl b/rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl
index 1a722a9c..71b4fe1b 100644
--- a/rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/must/2_requesting_agent.ttl
@@ -1,4 +1,4 @@
-# Copyright (c) 2024-2025 CRS4
+# Copyright (c) 2025 eScience Lab, The University of Manchester
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl b/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl
index 5431e8ea..8aee0a20 100644
--- a/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/should/2_requesting_agent.ttl
@@ -1,3 +1,17 @@
+# Copyright (c) 2025 eScience Lab, The University of Manchester
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
@prefix ro: <./> .
@prefix ro-crate: .
@prefix five-safes-crate: .
From 04a6d8fb1685573d4e048e1133368e32699c5e26 Mon Sep 17 00:00:00 2001
From: Alex Hambley <33315205+alexhambley@users.noreply.github.com>
Date: Thu, 9 Oct 2025 09:24:54 +0100
Subject: [PATCH 16/18] Add SHACL rule for profile conformsTo (#16)
---
.../should/5_profile_conformance.ttl | 39 +++++++++++++++++++
1 file changed, 39 insertions(+)
create mode 100644 rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl
diff --git a/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl b/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl
new file mode 100644
index 00000000..d06c9685
--- /dev/null
+++ b/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl
@@ -0,0 +1,39 @@
+# Copyright (c) 2025 eScience Lab, The University of Manchester
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+@prefix ro: <./> .
+@prefix ro-crate: .
+@prefix five-safes-crate: .
+@prefix rdf: .
+@prefix schema: .
+@prefix sh: .
+@prefix validator: .
+@prefix xsd: .
+
+# Root Dataset SHOULD declare conformsTo Five Safes profile
+five-safes-crate:RootDatasetConformsToFiveSafes
+ a sh:NodeShape ;
+ sh:name "Root Dataset profile conformance" ;
+ sh:description "The Root Data Entity (./) SHOULD declare conformsTo the Five Safes RO-Crate profile." ;
+ # targets the RO-Crate Root Data Entity "./"
+ sh:targetNode ro: ;
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "conformsTo Five Safes profile" ;
+ sh:description "Root Dataset SHOULD include schema:conformsTo https://w3id.org/5s-crate/0.4" ;
+ sh:path schema:conformsTo ;
+ sh:hasValue ;
+ sh:severity sh:Warning ;
+ sh:message "Profile Conformance: Root Dataset SHOULD include schema:conformsTo with @id https://w3id.org/5s-crate/0.4" ;
+ ] .
From e039661dce9cab110672c7bda14be3b8522249d1 Mon Sep 17 00:00:00 2001
From: Alex Hambley <33315205+alexhambley@users.noreply.github.com>
Date: Thu, 9 Oct 2025 10:41:24 +0100
Subject: [PATCH 17/18] Add rules for datePublished + licence on published
crates (#16)
---
.../should/5_profile_conformance.ttl | 40 +++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl b/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl
index d06c9685..6e567177 100644
--- a/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl
@@ -37,3 +37,43 @@ five-safes-crate:RootDatasetConformsToFiveSafes
sh:severity sh:Warning ;
sh:message "Profile Conformance: Root Dataset SHOULD include schema:conformsTo with @id https://w3id.org/5s-crate/0.4" ;
] .
+
+five-safes-crate:RootDatasetDatePublishedWhenPublished
+ a sh:NodeShape ;
+ sh:name "datePublished on published crates" ;
+ sh:description "If the root dataset is published (has schema:publisher), it SHOULD have schema:datePublished." ;
+ sh:targetNode ro: ;
+ sh:or (
+ # datePublished not required if no publisher:
+ [ sh:not [ sh:property [
+ sh:path schema:publisher ;
+ sh:minCount 1 ;
+ ]]]
+ # datePublished required if publisher present:
+ [ sh:property [
+ sh:path schema:datePublished ;
+ sh:minCount 1 ;
+ sh:message "Published crates SHOULD include schema:datePublished." ;
+ sh:severity sh:Warning ;
+ ]]
+ ) .
+
+five-safes-crate:RootDatasetLicenceWhenPublished
+ a sh:NodeShape ;
+ sh:name "licence on published crates" ;
+ sh:description "If the root dataset is published (has schema:publisher), it SHOULD declare a licence." ;
+ sh:targetNode ro: ;
+ sh:severity sh:Warning ;
+ sh:message "Profile Conformance: Published crates SHOULD include a licence (schema:license or schema:licence)." ;
+ sh:or (
+ # license not required if no publisher:
+ [ sh:not [ sh:property [
+ sh:path schema:publisher ;
+ sh:minCount 1 ;
+ ]]]
+ # license/licence required if publisher present:
+ [ sh:property [
+ sh:path [ sh:alternativePath ( schema:license schema:licence ) ] ;
+ sh:minCount 1 ;
+ ]]
+ ) .
\ No newline at end of file
From b13ed73b6e2039af502cdf9a530113bf846d3ae9 Mon Sep 17 00:00:00 2001
From: Alex Hambley <33315205+alexhambley@users.noreply.github.com>
Date: Thu, 30 Oct 2025 15:14:56 +0000
Subject: [PATCH 18/18] Tidied up profile conformance tests
---
.../should/5_profile_conformance.ttl | 104 +++++++++---------
1 file changed, 53 insertions(+), 51 deletions(-)
diff --git a/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl b/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl
index 6e567177..ea2a4fd8 100644
--- a/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/should/5_profile_conformance.ttl
@@ -23,57 +23,59 @@
# Root Dataset SHOULD declare conformsTo Five Safes profile
five-safes-crate:RootDatasetConformsToFiveSafes
- a sh:NodeShape ;
- sh:name "Root Dataset profile conformance" ;
- sh:description "The Root Data Entity (./) SHOULD declare conformsTo the Five Safes RO-Crate profile." ;
- # targets the RO-Crate Root Data Entity "./"
- sh:targetNode ro: ;
- sh:property [
- a sh:PropertyShape ;
- sh:name "conformsTo Five Safes profile" ;
- sh:description "Root Dataset SHOULD include schema:conformsTo https://w3id.org/5s-crate/0.4" ;
- sh:path schema:conformsTo ;
- sh:hasValue ;
- sh:severity sh:Warning ;
- sh:message "Profile Conformance: Root Dataset SHOULD include schema:conformsTo with @id https://w3id.org/5s-crate/0.4" ;
- ] .
+ a sh:NodeShape ;
+ sh:name "Root Dataset Five Safes RO-Crate profile conformance" ;
+ sh:description "The Root Data Entity (./) SHOULD declare conformsTo the Five Safes RO-Crate profile." ;
+ sh:targetNode ro: ;
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "conformsTo Five Safes profile" ;
+ sh:description "Root Dataset SHOULD include schema:conformsTo https://w3id.org/5s-crate/0.4" ;
+ sh:path schema:conformsTo ;
+ sh:qualifiedValueShape [
+ sh:hasValue
+ ] ;
+ sh:qualifiedMinCount 1 ;
+ sh:severity sh:Warning ;
+ sh:message "Profile Conformance: Root Dataset SHOULD include schema:conformsTo with @id https://w3id.org/5s-crate/0.4" ;
+ ] .
five-safes-crate:RootDatasetDatePublishedWhenPublished
- a sh:NodeShape ;
- sh:name "datePublished on published crates" ;
- sh:description "If the root dataset is published (has schema:publisher), it SHOULD have schema:datePublished." ;
- sh:targetNode ro: ;
- sh:or (
- # datePublished not required if no publisher:
- [ sh:not [ sh:property [
- sh:path schema:publisher ;
- sh:minCount 1 ;
- ]]]
- # datePublished required if publisher present:
- [ sh:property [
- sh:path schema:datePublished ;
- sh:minCount 1 ;
- sh:message "Published crates SHOULD include schema:datePublished." ;
- sh:severity sh:Warning ;
- ]]
- ) .
+ a sh:NodeShape ;
+ sh:name "datePublished present on published crates" ;
+ sh:description "If the root dataset is published (has schema:publisher), it SHOULD have schema:datePublished." ;
+ sh:targetNode ro: ;
+ sh:severity sh:Warning ;
+ sh:message "Published crates SHOULD include schema:datePublished." ;
+ sh:or (
+ # datePublished not required if no publisher:
+ [ sh:not [ sh:property [
+ sh:path schema:publisher ;
+ sh:minCount 1 ;
+ ]]]
+ # datePublished required if publisher present:
+ [ sh:property [
+ sh:path schema:datePublished ;
+ sh:minCount 1 ;
+ ]]
+ ) .
-five-safes-crate:RootDatasetLicenceWhenPublished
- a sh:NodeShape ;
- sh:name "licence on published crates" ;
- sh:description "If the root dataset is published (has schema:publisher), it SHOULD declare a licence." ;
- sh:targetNode ro: ;
- sh:severity sh:Warning ;
- sh:message "Profile Conformance: Published crates SHOULD include a licence (schema:license or schema:licence)." ;
- sh:or (
- # license not required if no publisher:
- [ sh:not [ sh:property [
- sh:path schema:publisher ;
- sh:minCount 1 ;
- ]]]
- # license/licence required if publisher present:
- [ sh:property [
- sh:path [ sh:alternativePath ( schema:license schema:licence ) ] ;
- sh:minCount 1 ;
- ]]
- ) .
\ No newline at end of file
+five-safes-crate:RootDatasetLicenseWhenPublished
+ a sh:NodeShape ;
+ sh:name "License present on published crates" ;
+ sh:description "If the root dataset is published (has schema:publisher), it SHOULD declare a license." ;
+ sh:targetNode ro: ;
+ sh:severity sh:Warning ;
+ sh:message "Profile Conformance: Published crates SHOULD include a license." ;
+ sh:or (
+ # license not required if no publisher:
+ [ sh:not [ sh:property [
+ sh:path schema:publisher ;
+ sh:minCount 1 ;
+ ]]]
+ # license required if publisher present:
+ [ sh:property [
+ sh:path schema:license ;
+ sh:minCount 1 ;
+ ]]
+ ) .
\ No newline at end of file