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, + )