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/16] 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 000000000..75946bfe9
--- /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/16] 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 000000000..2cac720c7
--- /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/16] 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 000000000..b8a84271f
--- /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 000000000..3b43f6365
--- /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 000000000..5ca7ea110
--- /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/16] 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 000000000..1cc503b0a
--- /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 1c3d03a99..6ecc64ab6 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/16] 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 b8a84271f..9fb0d7bf5 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 3b43f6365..a6475f63c 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/16] 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 000000000..247faa906
--- /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 2cac720c7..645f5dd03 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/16] 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 b24d854424cfc1f221543d86968af147c1bd78ce Mon Sep 17 00:00:00 2001
From: Eli Chadwick
Date: Thu, 9 Oct 2025 14:26:14 +0100
Subject: [PATCH 08/16] fix linting
---
tests/integration/profiles/five-safes-crate/test_valid_5src.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/integration/profiles/five-safes-crate/test_valid_5src.py b/tests/integration/profiles/five-safes-crate/test_valid_5src.py
index 1cc503b0a..74565ae03 100644
--- a/tests/integration/profiles/five-safes-crate/test_valid_5src.py
+++ b/tests/integration/profiles/five-safes-crate/test_valid_5src.py
@@ -33,6 +33,7 @@ def test_valid_five_safes_crate_request_required():
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(
From e09dec5936d8abbafdf4a2049fd401d2e8581928 Mon Sep 17 00:00:00 2001
From: Eli Chadwick
Date: Thu, 9 Oct 2025 16:15:15 +0100
Subject: [PATCH 09/16] introduce invalid crate tests
---
.../ro-crate-metadata.json | 400 ++++++++++++++++++
.../ro-crate-metadata.json | 398 +++++++++++++++++
.../ro-crate-metadata.json | 399 +++++++++++++++++
.../five-safes-crate/test_5src_funding.py | 38 ++
.../test_5src_root_data_entity_metadata.py | 55 +++
tests/ro_crates.py | 16 +
6 files changed, 1306 insertions(+)
create mode 100644 tests/data/crates/invalid/6_five_safes_crate/funding_project_no_name/ro-crate-metadata.json
create mode 100644 tests/data/crates/invalid/6_five_safes_crate/root_data_entity_no_source_organization/ro-crate-metadata.json
create mode 100644 tests/data/crates/invalid/6_five_safes_crate/root_data_entity_source_organization_not_entity/ro-crate-metadata.json
create mode 100644 tests/integration/profiles/five-safes-crate/test_5src_funding.py
create mode 100644 tests/integration/profiles/five-safes-crate/test_5src_root_data_entity_metadata.py
diff --git a/tests/data/crates/invalid/6_five_safes_crate/funding_project_no_name/ro-crate-metadata.json b/tests/data/crates/invalid/6_five_safes_crate/funding_project_no_name/ro-crate-metadata.json
new file mode 100644
index 000000000..72a411b87
--- /dev/null
+++ b/tests/data/crates/invalid/6_five_safes_crate/funding_project_no_name/ro-crate-metadata.json
@@ -0,0 +1,400 @@
+{
+ "@context": "https://w3id.org/ro/crate/1.1/context",
+ "@graph": [
+ {
+ "@type": "CreativeWork",
+ "@id": "ro-crate-metadata.json",
+ "about": {
+ "@id": "./"
+ },
+ "conformsTo": {
+ "@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"
+ },
+ "hasPart": [
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ {
+ "@id": "input1.txt"
+ },
+ {
+ "@id": "outputs/qa.csv"
+ },
+ {
+ "@id": "outputs/diagrams/"
+ },
+ {
+ "@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/"
+ },
+ "license": {
+ "@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/qa.csv"
+ },
+ {
+ "@id": "outputs/diagrams/"
+ },
+ {
+ "@id": "urn:uuid:07b81e0f-7ac4-5428-9940-878b241e2397"
+ }
+ ]
+ },
+ {
+ "@id": "#project-be6ffb55-4f5a-4c14-b60e-47e0951090c70",
+ "@type": "Project",
+ "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"
+ }
+ ]
+}
diff --git a/tests/data/crates/invalid/6_five_safes_crate/root_data_entity_no_source_organization/ro-crate-metadata.json b/tests/data/crates/invalid/6_five_safes_crate/root_data_entity_no_source_organization/ro-crate-metadata.json
new file mode 100644
index 000000000..10c51d19c
--- /dev/null
+++ b/tests/data/crates/invalid/6_five_safes_crate/root_data_entity_no_source_organization/ro-crate-metadata.json
@@ -0,0 +1,398 @@
+{
+ "@context": "https://w3id.org/ro/crate/1.1/context",
+ "@graph": [
+ {
+ "@type": "CreativeWork",
+ "@id": "ro-crate-metadata.json",
+ "about": {
+ "@id": "./"
+ },
+ "conformsTo": {
+ "@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"
+ },
+ "hasPart": [
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ {
+ "@id": "input1.txt"
+ },
+ {
+ "@id": "outputs/qa.csv"
+ },
+ {
+ "@id": "outputs/diagrams/"
+ },
+ {
+ "@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"
+ }
+ ],
+ "publisher": {
+ "@id": "https://tre72.example.com/"
+ },
+ "license": {
+ "@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/qa.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"
+ }
+ ]
+}
diff --git a/tests/data/crates/invalid/6_five_safes_crate/root_data_entity_source_organization_not_entity/ro-crate-metadata.json b/tests/data/crates/invalid/6_five_safes_crate/root_data_entity_source_organization_not_entity/ro-crate-metadata.json
new file mode 100644
index 000000000..e181d9034
--- /dev/null
+++ b/tests/data/crates/invalid/6_five_safes_crate/root_data_entity_source_organization_not_entity/ro-crate-metadata.json
@@ -0,0 +1,399 @@
+{
+ "@context": "https://w3id.org/ro/crate/1.1/context",
+ "@graph": [
+ {
+ "@type": "CreativeWork",
+ "@id": "ro-crate-metadata.json",
+ "about": {
+ "@id": "./"
+ },
+ "conformsTo": {
+ "@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"
+ },
+ "hasPart": [
+ {
+ "@id": "https://workflowhub.eu/workflows/289?version=1"
+ },
+ {
+ "@id": "input1.txt"
+ },
+ {
+ "@id": "outputs/qa.csv"
+ },
+ {
+ "@id": "outputs/diagrams/"
+ },
+ {
+ "@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": "Investigation of cancer (TRE72 project 81)",
+ "publisher": {
+ "@id": "https://tre72.example.com/"
+ },
+ "license": {
+ "@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/qa.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"
+ }
+ ]
+}
diff --git a/tests/integration/profiles/five-safes-crate/test_5src_funding.py b/tests/integration/profiles/five-safes-crate/test_5src_funding.py
new file mode 100644
index 000000000..1ec13e209
--- /dev/null
+++ b/tests/integration/profiles/five-safes-crate/test_5src_funding.py
@@ -0,0 +1,38 @@
+# 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.ro_crates import Invalid5sROC
+from tests.shared import do_entity_test
+
+# set up logging
+logger = logging.getLogger(__name__)
+
+
+def test_5src_funding_project_no_name():
+ """\
+ Test a Five Safes Crate where the funding Project does not have a name.
+ """
+ do_entity_test(
+ rocrate_path=Invalid5sROC().funding_project_no_name,
+ requirement_severity=Severity.REQUIRED,
+ expected_validation_result=False,
+ expected_triggered_requirements=["Funding body Project"],
+ expected_triggered_issues=[
+ "The Project Entity MUST have a `name` property (as specified by schema.org)"
+ ],
+ profile_identifier="five-safes-crate",
+ )
diff --git a/tests/integration/profiles/five-safes-crate/test_5src_root_data_entity_metadata.py b/tests/integration/profiles/five-safes-crate/test_5src_root_data_entity_metadata.py
new file mode 100644
index 000000000..60a419b40
--- /dev/null
+++ b/tests/integration/profiles/five-safes-crate/test_5src_root_data_entity_metadata.py
@@ -0,0 +1,55 @@
+# 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.ro_crates import Invalid5sROC
+from tests.shared import do_entity_test
+
+# set up logging
+logger = logging.getLogger(__name__)
+
+
+def test_5src_root_data_entity_no_source_organization():
+ """\
+ Test a Five Safes Crate where the Root Data Entity it does not reference a sourceOrganization.
+ """
+ do_entity_test(
+ rocrate_path=Invalid5sROC().root_data_entity_no_source_organization,
+ requirement_severity=Severity.REQUIRED,
+ expected_validation_result=False,
+ expected_triggered_requirements=["Five Safes Crate Root Data Entity REQUIRED properties"],
+ expected_triggered_issues=[
+ """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."""
+ ],
+ profile_identifier="five-safes-crate",
+ )
+
+def test_5src_root_data_entity_source_organization_not_entity():
+ """\
+ Test a Five Safes Crate where the Root Data Entity it does not reference a sourceOrganization.
+ """
+ do_entity_test(
+ rocrate_path=Invalid5sROC().root_data_entity_source_organization_not_entity,
+ requirement_severity=Severity.REQUIRED,
+ expected_validation_result=False,
+ expected_triggered_requirements=["Five Safes Crate Root Data Entity REQUIRED properties"],
+ expected_triggered_issues=[
+ """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."""
+ ],
+ profile_identifier="five-safes-crate",
+ )
diff --git a/tests/ro_crates.py b/tests/ro_crates.py
index 6ecc64ab6..4f72dee9e 100644
--- a/tests/ro_crates.py
+++ b/tests/ro_crates.py
@@ -978,6 +978,22 @@ def propertyvalue_no_unitcode(self) -> Path:
return self.base_path / "propertyvalue_no_unitcode"
+class Invalid5sROC:
+
+ base_path = INVALID_CRATES_DATA_PATH / "6_five_safes_crate/"
+
+ @property
+ def funding_project_no_name(self) -> Path:
+ return self.base_path / "funding_project_no_name"
+
+ @property
+ def root_data_entity_no_source_organization(self) -> Path:
+ return self.base_path / "root_data_entity_no_source_organization"
+
+ @property
+ def root_data_entity_source_organization_not_entity(self) -> Path:
+ return self.base_path / "root_data_entity_source_organization_not_entity"
+
class InvalidMultiProfileROC:
@property
From fa52a026baa45b457fbd478e7251bccaa7fdfd8d Mon Sep 17 00:00:00 2001
From: Eli Chadwick
Date: Thu, 9 Oct 2025 16:15:46 +0100
Subject: [PATCH 10/16] resolve test failures
---
.../profiles/five-safes-crate/must/1_funder.ttl | 1 +
.../must/1_root_data_entity_metadata.ttl | 6 +++---
.../profiles/five-safes-crate/profile.ttl | 10 ++++++----
.../profiles/five-safes-crate/test_valid_5src.py | 4 ++--
4 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/rocrate_validator/profiles/five-safes-crate/must/1_funder.ttl b/rocrate_validator/profiles/five-safes-crate/must/1_funder.ttl
index 247faa906..474fda436 100644
--- a/rocrate_validator/profiles/five-safes-crate/must/1_funder.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/must/1_funder.ttl
@@ -19,6 +19,7 @@
@prefix sh: .
@prefix bioschemas: .
+# TODO: note that this applies to all Projects, not just those targeted by `funding` relationships
five-safes-crate:FundingBody a sh:NodeShape ;
sh:name "Funding body Project" ;
sh:description "Project which is funding this work" ;
diff --git a/rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl b/rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl
index 645f5dd03..92b5807ea 100644
--- a/rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl
@@ -21,11 +21,11 @@
@prefix validator: .
@prefix xsd: .
-
+# TODO: split into multiple checks
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 `sourceOrganisation`" ;
+ sh:description "The Root Data Entity MUST have a `sourceOrganization`" ;
sh:targetClass ro-crate:RootDataEntity ;
sh:property [
a sh:PropertyShape ;
@@ -33,7 +33,7 @@ five-safes-crate:RootDataEntityRequiredProperties
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:class ro-crate:ContextualEntity ;
+ sh:nodeKind sh:IRI;
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.""" ;
] .
diff --git a/rocrate_validator/profiles/five-safes-crate/profile.ttl b/rocrate_validator/profiles/five-safes-crate/profile.ttl
index 75946bfe9..b6a7c1f47 100644
--- a/rocrate_validator/profiles/five-safes-crate/profile.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/profile.ttl
@@ -29,13 +29,15 @@
# URI of the publisher of the Metadata Specification
dct:publisher ;
+ # TODO: resolve failures when these profiles are applied
# This profile is an extension of Workflow Run Crate for use in Trusted Research Environments (TRE)
- prof:isProfileOf ;
+ # prof:isProfileOf ;
# This profile is a transitive profile of the RO-Crate Metadata Specification
- prof:isTransitiveProfileOf ,
- ,
- ;
+ prof:isTransitiveProfileOf ;
+ # TODO: resolve failures when these profiles are applied
+ # ,
+ # ;
# this profile has a JSON-LD context resource
prof:hasResource [
diff --git a/tests/integration/profiles/five-safes-crate/test_valid_5src.py b/tests/integration/profiles/five-safes-crate/test_valid_5src.py
index 74565ae03..8c0461cfa 100644
--- a/tests/integration/profiles/five-safes-crate/test_valid_5src.py
+++ b/tests/integration/profiles/five-safes-crate/test_valid_5src.py
@@ -24,7 +24,7 @@
def test_valid_five_safes_crate_request_required():
- """Test a valid Workflow Run Crate."""
+ """Test a valid Five Safes Crate representing a request."""
do_entity_test(
ValidROC().five_safes_crate_request,
Severity.REQUIRED,
@@ -35,7 +35,7 @@ def test_valid_five_safes_crate_request_required():
def test_valid_five_safes_crate_result_required():
- """Test a valid Workflow Run Crate."""
+ """Test a valid Five Safes Crate representing a result."""
do_entity_test(
ValidROC().five_safes_crate_result,
Severity.REQUIRED,
From b54c409a63a5a3957513cb0f4530da187939e197 Mon Sep 17 00:00:00 2001
From: Eli Chadwick
Date: Thu, 9 Oct 2025 16:39:12 +0100
Subject: [PATCH 11/16] revert changes which will be superseded
---
.../five-safes-crate/must/1_root_data_entity_metadata.ttl | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl b/rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl
index 92b5807ea..1145bb5a3 100644
--- a/rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl
@@ -21,11 +21,10 @@
@prefix validator: .
@prefix xsd: .
-# TODO: split into multiple checks
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 `sourceOrganization`" ;
+ sh:description "The Root Data Entity MUST have a `sourceOrganisation`" ;
sh:targetClass ro-crate:RootDataEntity ;
sh:property [
a sh:PropertyShape ;
From b1b235c5351efa0d0d13f8eb9f30f3fd0c5ef7c0 Mon Sep 17 00:00:00 2001
From: Eli Chadwick
Date: Thu, 9 Oct 2025 16:39:16 +0100
Subject: [PATCH 12/16] linting
---
.../five-safes-crate/test_5src_root_data_entity_metadata.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/integration/profiles/five-safes-crate/test_5src_root_data_entity_metadata.py b/tests/integration/profiles/five-safes-crate/test_5src_root_data_entity_metadata.py
index 60a419b40..5a45a42a4 100644
--- a/tests/integration/profiles/five-safes-crate/test_5src_root_data_entity_metadata.py
+++ b/tests/integration/profiles/five-safes-crate/test_5src_root_data_entity_metadata.py
@@ -38,6 +38,7 @@ def test_5src_root_data_entity_no_source_organization():
profile_identifier="five-safes-crate",
)
+
def test_5src_root_data_entity_source_organization_not_entity():
"""\
Test a Five Safes Crate where the Root Data Entity it does not reference a sourceOrganization.
From 8bdb692f05ba9bf79cfd401ded764efc86ea6c8d Mon Sep 17 00:00:00 2001
From: Eli Chadwick
Date: Thu, 9 Oct 2025 17:05:53 +0100
Subject: [PATCH 13/16] more linting
---
tests/ro_crates.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/ro_crates.py b/tests/ro_crates.py
index 4f72dee9e..53f772595 100644
--- a/tests/ro_crates.py
+++ b/tests/ro_crates.py
@@ -994,6 +994,7 @@ def root_data_entity_no_source_organization(self) -> Path:
def root_data_entity_source_organization_not_entity(self) -> Path:
return self.base_path / "root_data_entity_source_organization_not_entity"
+
class InvalidMultiProfileROC:
@property
From 21d02d74f58b56ab7d33544e92fb55abf4f68fbf Mon Sep 17 00:00:00 2001
From: Ettore Murabito
Date: Thu, 23 Oct 2025 19:01:52 +0100
Subject: [PATCH 14/16] Implemented SHACL rules for rule set 6 (referencing a
workflow crate)
---
.../five-safes-crate/must/1_funder.ttl | 36 ----------
.../must/1_root_data_entity_metadata.ttl | 38 ----------
.../must/6_workflow_reference.ttl | 71 +++++++++++++++++++
.../should/6_workflow_reference.ttl | 49 +++++++++++++
4 files changed, 120 insertions(+), 74 deletions(-)
delete mode 100644 rocrate_validator/profiles/five-safes-crate/must/1_funder.ttl
delete mode 100644 rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl
create mode 100644 rocrate_validator/profiles/five-safes-crate/must/6_workflow_reference.ttl
create mode 100644 rocrate_validator/profiles/five-safes-crate/should/6_workflow_reference.ttl
diff --git a/rocrate_validator/profiles/five-safes-crate/must/1_funder.ttl b/rocrate_validator/profiles/five-safes-crate/must/1_funder.ttl
deleted file mode 100644
index 474fda436..000000000
--- a/rocrate_validator/profiles/five-safes-crate/must/1_funder.ttl
+++ /dev/null
@@ -1,36 +0,0 @@
-# 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: .
-
-# TODO: note that this applies to all Projects, not just those targeted by `funding` relationships
-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/1_root_data_entity_metadata.ttl b/rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl
deleted file mode 100644
index 1145bb5a3..000000000
--- a/rocrate_validator/profiles/five-safes-crate/must/1_root_data_entity_metadata.ttl
+++ /dev/null
@@ -1,38 +0,0 @@
-# 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_org: .
-@prefix sh: .
-@prefix validator: .
-@prefix xsd: .
-
-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 `sourceOrganisation`" ;
- sh:targetClass ro-crate:RootDataEntity ;
- sh:property [
- a sh:PropertyShape ;
- 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:IRI;
- 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.""" ;
- ] .
diff --git a/rocrate_validator/profiles/five-safes-crate/must/6_workflow_reference.ttl b/rocrate_validator/profiles/five-safes-crate/must/6_workflow_reference.ttl
new file mode 100644
index 000000000..ded22942e
--- /dev/null
+++ b/rocrate_validator/profiles/five-safes-crate/must/6_workflow_reference.ttl
@@ -0,0 +1,71 @@
+# 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 purl: .
+@prefix sh: .
+@prefix validator: .
+@prefix xsd: .
+
+
+
+five-safes-crate:ReferenceToWorkflowCrate
+ a sh:NodeShape ;
+ sh:name "RootDataEntity" ;
+ sh:targetClass ro-crate:RootDataEntity ;
+
+ # RootDataEntity MUST have an mainEntity property
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "mainEntity" ;
+ sh:path schema:mainEntity ;
+ sh:minCount 1 ;
+ sh:maxCount 1 ;
+ sh:nodeKind sh:IRI ;
+ sh:severity sh:Violation ;
+ sh:message "The RootDataEntity MUST have exactly one schema:mainEntity property that is an IRI." ;
+ ] ;
+
+ # The mainEntity of a RootDataEntity MUST be a Dataset
+ sh:property [
+ a sh:PropertyShape ;
+ sh:name "mainEntity" ;
+ sh:path schema:mainEntity ;
+ sh:class schema:Dataset ;
+ sh:severity sh:Violation ;
+ sh:message "The mainEntity pointed to by the RootDataEntity MUST be of type schema:Dataset" ;
+ ] .
+
+five-safes-crate:mainEntityHasProperConformsTo
+ a sh:NodeShape ;
+ sh:name "mainEntity" ;
+ sh:description "The mainEntity of the RootDataEntity MUST have a conformsTo property with an IRI starting with https://w3id.org/workflowhub/workflow-ro-crate" ;
+ sh:targetObjectsOf schema:mainEntity ;
+ sh:sparql [
+ a sh:SPARQLConstraint ;
+ sh:name "conformsTo" ;
+ sh:message "conformsTo IRI must start with https://w3id.org/workflowhub/workflow-ro-crate" ;
+ sh:select """
+ PREFIX schema:
+ PREFIX purl:
+ SELECT $this WHERE {
+ $this purl:conformsTo ?iri .
+ FILTER(!STRSTARTS(STR(?iri), "https://w3id.org/workflowhub/workflow-ro-crate"))
+ }
+ """ ;
+ ] .
diff --git a/rocrate_validator/profiles/five-safes-crate/should/6_workflow_reference.ttl b/rocrate_validator/profiles/five-safes-crate/should/6_workflow_reference.ttl
new file mode 100644
index 000000000..c43107f1c
--- /dev/null
+++ b/rocrate_validator/profiles/five-safes-crate/should/6_workflow_reference.ttl
@@ -0,0 +1,49 @@
+# 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 purl: .
+@prefix sh: .
+@prefix validator: .
+@prefix xsd: .
+
+
+five-safes-crate::DatasetMustHaveDistributionIfURI
+ a sh:NodeShape ;
+ sh:name "mainEntity" ;
+ sh:targetObjectsOf schema:mainEntity ;
+ sh:description "If mainEntity has an HTTP(S) @id, it must have a distribution that is an HTTP(S) URL." ;
+
+ sh:sparql [
+ a sh:SPARQLConstraint ;
+ sh:name "distribution" ;
+ sh:description "If mainEntity has an HTTP(S) @id, it must have a distribution that is an HTTP(S) URL." ;
+ sh:prefixes ro-crate:sparqlPrefixes ;
+ sh:select """
+ SELECT $this
+ WHERE {
+ FILTER (STRSTARTS(STR($this), "http://") || STRSTARTS(STR($this), "https://")) .
+ FILTER NOT EXISTS {
+ $this schema:distribution ?dist .
+ FILTER (STRSTARTS(STR(?dist), "http://") || STRSTARTS(STR(?dist), "https://")) .
+ }
+ }
+ """ ;
+ sh:severity sh:Warning ;
+ sh:message "If mainEntity has an HTTP(S) @id must have at least one distribution with an HTTP(S) URL." ;
+ ] .
\ No newline at end of file
From f15804f83e5ff035f3b9abd8092eb7a818cb5bca Mon Sep 17 00:00:00 2001
From: Ettore Murabito
Date: Mon, 27 Oct 2025 11:57:12 +0000
Subject: [PATCH 15/16] Changed description of SHOULD rule
---
.../five-safes-crate/should/6_workflow_reference.ttl | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/rocrate_validator/profiles/five-safes-crate/should/6_workflow_reference.ttl b/rocrate_validator/profiles/five-safes-crate/should/6_workflow_reference.ttl
index c43107f1c..c7690ae04 100644
--- a/rocrate_validator/profiles/five-safes-crate/should/6_workflow_reference.ttl
+++ b/rocrate_validator/profiles/five-safes-crate/should/6_workflow_reference.ttl
@@ -27,12 +27,12 @@ five-safes-crate::DatasetMustHaveDistributionIfURI
a sh:NodeShape ;
sh:name "mainEntity" ;
sh:targetObjectsOf schema:mainEntity ;
- sh:description "If mainEntity has an HTTP(S) @id, it must have a distribution that is an HTTP(S) URL." ;
+ sh:description "If mainEntity has an HTTP(S) @id, it SHOULD have a distribution that is an HTTP(S) URL." ;
sh:sparql [
a sh:SPARQLConstraint ;
sh:name "distribution" ;
- sh:description "If mainEntity has an HTTP(S) @id, it must have a distribution that is an HTTP(S) URL." ;
+ sh:description "If mainEntity has an HTTP(S) @id, it SHOULD have a distribution that is an HTTP(S) URL." ;
sh:prefixes ro-crate:sparqlPrefixes ;
sh:select """
SELECT $this
@@ -45,5 +45,5 @@ five-safes-crate::DatasetMustHaveDistributionIfURI
}
""" ;
sh:severity sh:Warning ;
- sh:message "If mainEntity has an HTTP(S) @id must have at least one distribution with an HTTP(S) URL." ;
+ sh:message "If mainEntity has an HTTP(S) @id SHOULD have at least one distribution with an HTTP(S) URL." ;
] .
\ No newline at end of file
From d77c9304718dedde8b089f67a409bc7ea7888885 Mon Sep 17 00:00:00 2001
From: Ettore Murabito
Date: Tue, 28 Oct 2025 11:08:10 +0000
Subject: [PATCH 16/16] Added tests for rule-set 6 implemented in SHACL
---
.../test_5src_6_workflow_reference.py | 161 ++++++++++++++++++
1 file changed, 161 insertions(+)
create mode 100644 tests/integration/profiles/five-safes-crate/test_5src_6_workflow_reference.py
diff --git a/tests/integration/profiles/five-safes-crate/test_5src_6_workflow_reference.py b/tests/integration/profiles/five-safes-crate/test_5src_6_workflow_reference.py
new file mode 100644
index 000000000..d61803c70
--- /dev/null
+++ b/tests/integration/profiles/five-safes-crate/test_5src_6_workflow_reference.py
@@ -0,0 +1,161 @@
+# 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.ro_crates import ValidROC
+from tests.shared import do_entity_test, SPARQL_PREFIXES
+
+# set up logging
+logger = logging.getLogger(__name__)
+
+
+# ----- MUST fails tests
+
+
+def test_5src_root_data_entity_no_main_entity():
+ """
+ Remove the RootDataEntity's mainEntity so minCount=1 is violated.
+ """
+ sparql = (
+ SPARQL_PREFIXES
+ + """
+ DELETE {
+ <./> schema:mainEntity ?m .
+ }
+ WHERE {
+ <./> schema:mainEntity ?m .
+ }
+ """
+ )
+
+ do_entity_test(
+ rocrate_path=ValidROC().five_safes_crate_request,
+ requirement_severity=Severity.REQUIRED,
+ expected_validation_result=False,
+ expected_triggered_requirements=["RootDataEntity"],
+ expected_triggered_issues=[
+ "The RootDataEntity MUST have exactly one schema:mainEntity property that is an IRI."
+ ],
+ profile_identifier="five-safes-crate",
+ rocrate_entity_mod_sparql=sparql,
+ )
+
+
+def test_5src_root_data_entity_main_entity_not_dataset_iri():
+ """
+ Test a Five Safes Crate where the RootDataEntity's mainEntity is an IRI but not typed as schema:Dataset.
+ (We point mainEntity to a new crate-local entity typed as something else.)
+ """
+ sparql = (
+ SPARQL_PREFIXES
+ + """
+ DELETE {
+ <./> schema:mainEntity ?m .
+ }
+ INSERT {
+ # add an IRI that is NOT typed as schema:Dataset (e.g. a schema:SoftwareSourceCode)
+ <./> schema:mainEntity <./not-a-dataset> .
+ <./not-a-dataset> a schema:SoftwareSourceCode .
+ }
+ WHERE {
+ <./> schema:mainEntity ?m .
+ }
+ """
+ )
+
+ do_entity_test(
+ rocrate_path=ValidROC().five_safes_crate_request,
+ requirement_severity=Severity.REQUIRED,
+ expected_validation_result=False,
+ expected_triggered_requirements=["RootDataEntity"],
+ expected_triggered_issues=[
+ "The mainEntity pointed to by the RootDataEntity MUST be of type schema:Dataset"
+ ],
+ profile_identifier="five-safes-crate",
+ rocrate_entity_mod_sparql=sparql,
+ )
+
+
+def test_5src_main_entity_conformsTo_invalid():
+ """
+ Test a Five Safes Crate where the mainEntity's purl:conformsTo IRI does NOT start with
+ "https://w3id.org/workflowhub/workflow-ro-crate" (violates the SHACL SPARQL constraint).
+ """
+ sparql = (
+ SPARQL_PREFIXES
+ + """
+ PREFIX purl:
+ DELETE {
+ ?dataset purl:conformsTo ?iri .
+ }
+ INSERT {
+ ?dataset purl:conformsTo .
+ }
+ WHERE {
+ <./> schema:mainEntity ?dataset .
+ ?dataset purl:conformsTo ?iri .
+ FILTER(STRSTARTS(STR(?iri), "https://w3id.org/workflowhub/workflow-ro-crate"))
+ }
+ """
+ )
+
+ do_entity_test(
+ rocrate_path=ValidROC().five_safes_crate_request,
+ requirement_severity=Severity.REQUIRED,
+ expected_validation_result=False,
+ expected_triggered_requirements=["mainEntity"],
+ expected_triggered_issues=[
+ "conformsTo IRI must start with https://w3id.org/workflowhub/workflow-ro-crate"
+ ],
+ profile_identifier="five-safes-crate",
+ rocrate_entity_mod_sparql=sparql,
+ )
+
+
+# ----- SHOULD fails tests
+
+
+def test_5src_main_entity_missing_distribution_warning():
+ """
+ Test a Five Safes Crate where a mainEntity has an HTTP(S) IRI but no distribution with an HTTP(S) URL.
+ This should trigger the SHACL warning about missing or non-HTTP(S) distributions.
+ """
+ sparql = (
+ SPARQL_PREFIXES
+ + """
+ DELETE {
+ ?dataset schema:distribution ?dist .
+ }
+ WHERE {
+ <./> schema:mainEntity ?dataset .
+ ?dataset schema:distribution ?dist .
+ FILTER (STRSTARTS(STR(?dataset), "http://") || STRSTARTS(STR(?dataset), "https://")) .
+ FILTER (STRSTARTS(STR(?dist), "http://") || STRSTARTS(STR(?dist), "https://")) .
+ }
+ """
+ )
+
+ do_entity_test(
+ rocrate_path=ValidROC().five_safes_crate_request,
+ requirement_severity=Severity.RECOMMENDED,
+ expected_validation_result=False,
+ expected_triggered_requirements=["mainEntity"],
+ expected_triggered_issues=[
+ "If mainEntity has an HTTP(S) @id SHOULD have at least one distribution with an HTTP(S) URL."
+ ],
+ profile_identifier="five-safes-crate",
+ rocrate_entity_mod_sparql=sparql,
+ )