From 00a0f8ba17cb342329782f17dfd8ae222d95aa71 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Mon, 5 Jan 2026 11:52:33 +0000 Subject: [PATCH 1/7] add generic timestamp format check --- .../must/3_timestamp_format.ttl | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 rocrate_validator/profiles/five-safes-crate/must/3_timestamp_format.ttl diff --git a/rocrate_validator/profiles/five-safes-crate/must/3_timestamp_format.ttl b/rocrate_validator/profiles/five-safes-crate/must/3_timestamp_format.ttl new file mode 100644 index 00000000..ce984b32 --- /dev/null +++ b/rocrate_validator/profiles/five-safes-crate/must/3_timestamp_format.ttl @@ -0,0 +1,32 @@ +# 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:TimeStampFormat + a sh:NodeShape ; + sh:name "Timestamp Format" ; + sh:description "Timestamps MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; + sh:targetObjectsOf schema:startTime, schema:endTime; + sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; + sh:severity sh:Violation ; + sh:message "All `startTime` and `endTime` values MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." . From 7588d5961baacff58cb2dfc4a3b4234ccb71b616 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Mon, 5 Jan 2026 11:55:08 +0000 Subject: [PATCH 2/7] remove timestamp checks from other files --- .../must/11_workflow_execution_phase.ttl | 32 ------------------- .../five-safes-crate/must/12_check_phase.ttl | 19 +---------- .../must/13_validation_phase.ttl | 23 ++----------- .../must/14_workflow_retrieval_phase.ttl | 32 ------------------- .../must/8_disclosure_phase.ttl | 21 +----------- .../should/12_check_phase.ttl | 1 - .../five-safes-crate/should/4_sign_off.ttl | 1 - 7 files changed, 4 insertions(+), 125 deletions(-) diff --git a/rocrate_validator/profiles/five-safes-crate/must/11_workflow_execution_phase.ttl b/rocrate_validator/profiles/five-safes-crate/must/11_workflow_execution_phase.ttl index 4551da6c..2f723c93 100644 --- a/rocrate_validator/profiles/five-safes-crate/must/11_workflow_execution_phase.ttl +++ b/rocrate_validator/profiles/five-safes-crate/must/11_workflow_execution_phase.ttl @@ -41,38 +41,6 @@ five-safes-crate:WorkflowMustHaveDescriptiveName ] . -five-safes-crate:WorkflowexecutionObjectHasCompliantStartTimeFormat - a sh:NodeShape ; - sh:name "WorkflowExecution" ; - sh:description "The startTime of the workflow execution object MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; - sh:targetClass schema:CreateAction ; - - sh:property [ - a sh:PropertyShape ; - sh:name "StartTime" ; - sh:path schema:startTime ; - sh:minCount 0 ; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; - sh:severity sh:Violation ; - sh:message "The startTime of the workflow execution object MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; - ] . - - -five-safes-crate:WorkflowexecutionObjectHasCompliantEndTimeFormat - a sh:NodeShape ; - sh:name "WorkflowExecution" ; - sh:description "The endTime of the workflow execution object MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; - sh:targetClass schema:CreateAction ; - - sh:property [ - a sh:PropertyShape ; - sh:name "EndTime" ; - sh:path schema:endTime ; - sh:minCount 0 ; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; - sh:severity sh:Violation ; - sh:message "The endTime of the workflow execution object MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; - ] . five-safes-crate:WorkflowMustHaveActionStatusWithAllowedValues diff --git a/rocrate_validator/profiles/five-safes-crate/must/12_check_phase.ttl b/rocrate_validator/profiles/five-safes-crate/must/12_check_phase.ttl index b64c29c6..149b15b3 100644 --- a/rocrate_validator/profiles/five-safes-crate/must/12_check_phase.ttl +++ b/rocrate_validator/profiles/five-safes-crate/must/12_check_phase.ttl @@ -75,18 +75,10 @@ five-safes-crate:CheckValueStartTimeMustFollowISOStandard } """ ; - ] ; - - sh:property [ - a sh:PropertyShape ; - sh:name "StartTime" ; - sh:path schema:startTime ; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; - sh:severity sh:Violation ; - sh:message "`CheckValue` --> `startTime` MUST follows the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; ] . + five-safes-crate:CheckValueEndTimeMustFollowISOStandard a sh:NodeShape ; sh:name "CheckValue" ; @@ -103,15 +95,6 @@ five-safes-crate:CheckValueEndTimeMustFollowISOStandard } """ ; - ] ; - - sh:property [ - a sh:PropertyShape ; - sh:name "EndTime" ; - sh:path schema:endTime ; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; - sh:severity sh:Violation ; - sh:message "`CheckValue` --> `endTime` MUST follows the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; ] . diff --git a/rocrate_validator/profiles/five-safes-crate/must/13_validation_phase.ttl b/rocrate_validator/profiles/five-safes-crate/must/13_validation_phase.ttl index 610d0b45..22017bf0 100644 --- a/rocrate_validator/profiles/five-safes-crate/must/13_validation_phase.ttl +++ b/rocrate_validator/profiles/five-safes-crate/must/13_validation_phase.ttl @@ -141,19 +141,10 @@ five-safes-crate:ValidationCheckStartTimeMUSTFollowISOStandard ?this schema:additionalType shp:ValidationCheck . } """ ; - ] ; - - sh:property [ - a sh:PropertyShape ; - sh:name "StartTime" ; - sh:minCount 0; - sh:path schema:startTime ; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; - sh:severity sh:Violation ; - sh:message "ValidationCheck --> `startTime` MUST follows the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; ] . + five-safes-crate:ValidationCheckEndTimeMUSTFollowISOStandard a sh:NodeShape ; sh:name "ValidationCheck" ; @@ -169,14 +160,4 @@ five-safes-crate:ValidationCheckEndTimeMUSTFollowISOStandard ?this schema:additionalType shp:ValidationCheck . } """ ; - ] ; - - sh:property [ - a sh:PropertyShape ; - sh:name "EndTime" ; - sh:minCount 0; - sh:path schema:endTime ; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; - sh:severity sh:Violation ; - sh:message "ValidationCheck --> `endTime` MUST follows the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; - ] . \ No newline at end of file + ] . diff --git a/rocrate_validator/profiles/five-safes-crate/must/14_workflow_retrieval_phase.ttl b/rocrate_validator/profiles/five-safes-crate/must/14_workflow_retrieval_phase.ttl index b9cc96b0..a1108add 100644 --- a/rocrate_validator/profiles/five-safes-crate/must/14_workflow_retrieval_phase.ttl +++ b/rocrate_validator/profiles/five-safes-crate/must/14_workflow_retrieval_phase.ttl @@ -41,38 +41,6 @@ five-safes-crate:DownloadActionObjectMUSTHavesDescriptiveName sh:message "DownloadAction MUST have a human readable name string." ; ] . -five-safes-crate:DownloadActionStartTimeMUSTFollowISOStandard - a sh:NodeShape ; - sh:name "DownloadAction" ; - sh:description "" ; - sh:targetClass schema:DownloadAction ; - - sh:property [ - a sh:PropertyShape ; - sh:name "StartTime" ; - sh:minCount 0; - sh:path schema:startTime ; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; - sh:severity sh:Violation ; - sh:message "`DownloadAction` --> `startTime` MUST follows the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; - ] . - - -five-safes-crate:DownloadActionEndTimeMUSTFollowISOStandard - a sh:NodeShape ; - sh:name "DownloadAction" ; - sh:description "" ; - sh:targetClass schema:DownloadAction ; - - sh:property [ - a sh:PropertyShape ; - sh:name "EndTime" ; - sh:minCount 0; - sh:path schema:endTime ; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; - sh:severity sh:Violation ; - sh:message "`DownloadAction` --> `endTime` MUST follows the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; - ] . five-safes-crate:WorkflowSameAsAndRootDataEntityMainEntityMUSTBeTheSame diff --git a/rocrate_validator/profiles/five-safes-crate/must/8_disclosure_phase.ttl b/rocrate_validator/profiles/five-safes-crate/must/8_disclosure_phase.ttl index d46e38ca..6f5898a5 100644 --- a/rocrate_validator/profiles/five-safes-crate/must/8_disclosure_phase.ttl +++ b/rocrate_validator/profiles/five-safes-crate/must/8_disclosure_phase.ttl @@ -116,18 +116,9 @@ five-safes-crate:DisclosureObjectHasCompliantStartTimeFormat schema:startTime ?o } """ ; - ] ; - - sh:property [ - a sh:PropertyShape ; - sh:name "StartTime" ; - sh:path schema:startTime ; - sh:minCount 0 ; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; - sh:severity sh:Violation ; - sh:message "`DisclosureCheck` --> `startTime` MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; ] . + five-safes-crate:DisclosureObjectHasCompliantEndTimeFormat a sh:NodeShape ; @@ -145,14 +136,4 @@ five-safes-crate:DisclosureObjectHasCompliantEndTimeFormat schema:endTime ?o } """ ; - ] ; - - sh:property [ - a sh:PropertyShape ; - sh:name "EndTime" ; - sh:path schema:endTime ; - sh:minCount 0 ; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; - sh:severity sh:Violation ; - sh:message "`DisclosureCheck` --> `endTime` MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; ] . diff --git a/rocrate_validator/profiles/five-safes-crate/should/12_check_phase.ttl b/rocrate_validator/profiles/five-safes-crate/should/12_check_phase.ttl index 4cd77608..3a8deea4 100644 --- a/rocrate_validator/profiles/five-safes-crate/should/12_check_phase.ttl +++ b/rocrate_validator/profiles/five-safes-crate/should/12_check_phase.ttl @@ -188,4 +188,3 @@ five-safes-crate:CheckValueShouldHaveActionStatus sh:severity sh:Warning ; sh:message "CheckValue SHOULD have actionStatus property." ; ] . - diff --git a/rocrate_validator/profiles/five-safes-crate/should/4_sign_off.ttl b/rocrate_validator/profiles/five-safes-crate/should/4_sign_off.ttl index d671a0d9..7f042aab 100644 --- a/rocrate_validator/profiles/five-safes-crate/should/4_sign_off.ttl +++ b/rocrate_validator/profiles/five-safes-crate/should/4_sign_off.ttl @@ -171,7 +171,6 @@ five-safes-crate:SignOffPhaseEndTime sh:path schema:endTime ; sh:minCount 1 ; sh:maxCount 1 ; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; sh:severity sh:Warning ; sh:description "Sign Off object SHOULD have endTime property if action completed or failed. This must follow ISO-8601 syntax" ; sh:message "Sign Off object SHOULD have endTime property if action completed or failed. This must follow ISO-8601 syntax" ; From 3dea19c0db398ad0f2e0f6b44ff89ce2245d9515 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Mon, 5 Jan 2026 11:55:16 +0000 Subject: [PATCH 3/7] update tests --- .../test_5src_11_workflow_execution.py | 8 +++--- .../test_5src_12_check_phase.py | 8 +++--- .../test_5src_13_validation_phase.py | 8 +++--- .../test_5src_14_workflow_retrieval_phase.py | 9 +++--- .../test_5src_4_signoff_phase.py | 28 +++++++++---------- .../test_5src_8_disclosure_phase.py | 8 +++--- 6 files changed, 34 insertions(+), 35 deletions(-) diff --git a/tests/integration/profiles/five-safes-crate/test_5src_11_workflow_execution.py b/tests/integration/profiles/five-safes-crate/test_5src_11_workflow_execution.py index 6e84c643..68b66b52 100644 --- a/tests/integration/profiles/five-safes-crate/test_5src_11_workflow_execution.py +++ b/tests/integration/profiles/five-safes-crate/test_5src_11_workflow_execution.py @@ -136,10 +136,10 @@ def test_5src_workflow_object_has_no_properly_formatted_start_time(): rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=["WorkflowExecution"], + expected_triggered_requirements=["Timestamp Format"], expected_triggered_issues=[ ( - "The startTime of the workflow execution object MUST follow the RFC 3339 standard " + "All `startTime` and `endTime` values MUST follow the RFC 3339 standard " "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ) ], @@ -169,10 +169,10 @@ def test_5src_workflow_object_has_no_properly_formatted_end_time(): rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=["WorkflowExecution"], + expected_triggered_requirements=["Timestamp Format"], expected_triggered_issues=[ ( - "The endTime of the workflow execution object MUST follow the RFC 3339 standard " + "All `startTime` and `endTime` values MUST follow the RFC 3339 standard " "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ) ], diff --git a/tests/integration/profiles/five-safes-crate/test_5src_12_check_phase.py b/tests/integration/profiles/five-safes-crate/test_5src_12_check_phase.py index 08dceba5..b7e57cbd 100644 --- a/tests/integration/profiles/five-safes-crate/test_5src_12_check_phase.py +++ b/tests/integration/profiles/five-safes-crate/test_5src_12_check_phase.py @@ -108,10 +108,10 @@ def test_5src_check_value_start_time_not_iso_standard(): rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=["CheckValue"], + expected_triggered_requirements=["Timestamp Format"], expected_triggered_issues=[ ( - "`CheckValue` --> `startTime` MUST follows the RFC 3339 standard " + "All `startTime` and `endTime` values MUST follow the RFC 3339 standard " "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ) ], @@ -142,10 +142,10 @@ def test_5src_check_value_end_time_not_iso_standard(): rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=["CheckValue"], + expected_triggered_requirements=["Timestamp Format"], expected_triggered_issues=[ ( - "`CheckValue` --> `endTime` MUST follows the RFC 3339 standard " + "All `startTime` and `endTime` values MUST follow the RFC 3339 standard " "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ) ], diff --git a/tests/integration/profiles/five-safes-crate/test_5src_13_validation_phase.py b/tests/integration/profiles/five-safes-crate/test_5src_13_validation_phase.py index 60ff3afb..36e59646 100644 --- a/tests/integration/profiles/five-safes-crate/test_5src_13_validation_phase.py +++ b/tests/integration/profiles/five-safes-crate/test_5src_13_validation_phase.py @@ -133,10 +133,10 @@ def test_5src_validation_check_start_time_not_iso_standard(): rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=["ValidationCheck"], + expected_triggered_requirements=["Timestamp Format"], expected_triggered_issues=[ ( - "ValidationCheck --> `startTime` MUST follows the RFC 3339 standard " + "All `startTime` and `endTime` values MUST follow the RFC 3339 standard " "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ) ], @@ -166,10 +166,10 @@ def test_5src_validation_check_end_time_not_iso_standard(): rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=["ValidationCheck"], + expected_triggered_requirements=["Timestamp Format"], expected_triggered_issues=[ ( - "ValidationCheck --> `endTime` MUST follows the RFC 3339 standard " + "All `startTime` and `endTime` values MUST follow the RFC 3339 standard " "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ) ], diff --git a/tests/integration/profiles/five-safes-crate/test_5src_14_workflow_retrieval_phase.py b/tests/integration/profiles/five-safes-crate/test_5src_14_workflow_retrieval_phase.py index 3d66d3a8..24bf3335 100644 --- a/tests/integration/profiles/five-safes-crate/test_5src_14_workflow_retrieval_phase.py +++ b/tests/integration/profiles/five-safes-crate/test_5src_14_workflow_retrieval_phase.py @@ -102,10 +102,10 @@ def test_5src_download_action_start_time_not_iso_standard(): rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=["DownloadAction"], + expected_triggered_requirements=["Timestamp Format"], expected_triggered_issues=[ ( - "`DownloadAction` --> `startTime` MUST follows the RFC 3339 standard " + "All `startTime` and `endTime` values MUST follow the RFC 3339 standard " "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ) ], @@ -135,10 +135,10 @@ def test_5src_check_value_end_time_not_iso_standard(): rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=["DownloadAction"], + expected_triggered_requirements=["Timestamp Format"], expected_triggered_issues=[ ( - "`DownloadAction` --> `endTime` MUST follows the RFC 3339 standard " + "All `startTime` and `endTime` values MUST follow the RFC 3339 standard " "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ) ], @@ -361,6 +361,7 @@ def test_5src_download_action_does_not_have_action_status_property(): # ----- MAY fails tests + def test_5src_downloaded_workflow_is_not_represented_by_its_own_entity(): sparql = ( SPARQL_PREFIXES diff --git a/tests/integration/profiles/five-safes-crate/test_5src_4_signoff_phase.py b/tests/integration/profiles/five-safes-crate/test_5src_4_signoff_phase.py index 7f9cd8f3..27780aaa 100644 --- a/tests/integration/profiles/five-safes-crate/test_5src_4_signoff_phase.py +++ b/tests/integration/profiles/five-safes-crate/test_5src_4_signoff_phase.py @@ -112,9 +112,7 @@ def test_5src_signoff_phase_wrong_type(): requirement_severity=Severity.REQUIRED, expected_validation_result=False, expected_triggered_requirements=["SignOff"], - expected_triggered_issues=[ - "Sign Off phase MUST be a `schema:AssessAction`." - ], + expected_triggered_issues=["Sign Off phase MUST be a `schema:AssessAction`."], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, ) @@ -242,10 +240,12 @@ def test_5src_signoff_phase_malformed_endtime(): rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.RECOMMENDED, expected_validation_result=False, - expected_triggered_requirements=["SignOffPhaseEndTime"], + expected_triggered_requirements=["Timestamp Format"], expected_triggered_issues=[ - "Sign Off object SHOULD have endTime property if action completed or failed." - + " This must follow ISO-8601 syntax" + ( + "All `startTime` and `endTime` values MUST follow the RFC 3339 standard " + "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." + ) ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, @@ -310,10 +310,12 @@ def test_5src_signoff_phase_malformed_starttime(): rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.OPTIONAL, expected_validation_result=False, - expected_triggered_requirements=["SignOffPhaseStartTime"], + expected_triggered_requirements=["Timestamp Format"], expected_triggered_issues=[ - "Sign Off object MAY have a startTime property if action is active, completed or failed." - + " This must follow ISO-8601 syntax" + ( + "All `startTime` and `endTime` values MUST follow the RFC 3339 standard " + "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." + ) ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, @@ -343,9 +345,7 @@ def test_5src_signoff_phase_no_actionstatus(): requirement_severity=Severity.RECOMMENDED, expected_validation_result=False, expected_triggered_requirements=["SignOffPhaseProperties"], - expected_triggered_issues=[ - "The Sign-Off Phase SHOULD have an actionStatus" - ], + expected_triggered_issues=["The Sign-Off Phase SHOULD have an actionStatus"], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, ) @@ -374,9 +374,7 @@ def test_5src_signoff_phase_no_agent(): requirement_severity=Severity.RECOMMENDED, expected_validation_result=False, expected_triggered_requirements=["SignOffPhaseProperties"], - expected_triggered_issues=[ - "The Sign-Off Phase SHOULD have an agent" - ], + expected_triggered_issues=["The Sign-Off Phase SHOULD have an agent"], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, ) diff --git a/tests/integration/profiles/five-safes-crate/test_5src_8_disclosure_phase.py b/tests/integration/profiles/five-safes-crate/test_5src_8_disclosure_phase.py index 1d3310c8..cb6ae960 100644 --- a/tests/integration/profiles/five-safes-crate/test_5src_8_disclosure_phase.py +++ b/tests/integration/profiles/five-safes-crate/test_5src_8_disclosure_phase.py @@ -199,10 +199,10 @@ def test_5src_disclosure_object_has_no_properly_formatted_start_time(): rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=["DisclosureCheck"], + expected_triggered_requirements=["Timestamp Format"], expected_triggered_issues=[ ( - "`DisclosureCheck` --> `startTime` MUST follow the RFC 3339 standard " + "All `startTime` and `endTime` values MUST follow the RFC 3339 standard " "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ) ], @@ -232,10 +232,10 @@ def test_5src_disclosure_object_has_no_properly_formatted_end_time(): rocrate_path=ValidROC().five_safes_crate_result, requirement_severity=Severity.REQUIRED, expected_validation_result=False, - expected_triggered_requirements=["DisclosureCheck"], + expected_triggered_requirements=["Timestamp Format"], expected_triggered_issues=[ ( - "`DisclosureCheck` --> `endTime` MUST follow the RFC 3339 standard " + "All `startTime` and `endTime` values MUST follow the RFC 3339 standard " "(YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ) ], From 29c0676fafa7355a78a9b7125669591acae0112d Mon Sep 17 00:00:00 2001 From: Douglas Lowe <10961945+douglowe@users.noreply.github.com> Date: Mon, 5 Jan 2026 16:08:17 +0000 Subject: [PATCH 4/7] switch to target subjects for timestamps so parent id captured --- .../must/3_timestamp_format.ttl | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/rocrate_validator/profiles/five-safes-crate/must/3_timestamp_format.ttl b/rocrate_validator/profiles/five-safes-crate/must/3_timestamp_format.ttl index ce984b32..8ed340da 100644 --- a/rocrate_validator/profiles/five-safes-crate/must/3_timestamp_format.ttl +++ b/rocrate_validator/profiles/five-safes-crate/must/3_timestamp_format.ttl @@ -26,7 +26,22 @@ five-safes-crate:TimeStampFormat a sh:NodeShape ; sh:name "Timestamp Format" ; sh:description "Timestamps MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; - sh:targetObjectsOf schema:startTime, schema:endTime; - sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; - sh:severity sh:Violation ; - sh:message "All `startTime` and `endTime` values MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." . + sh:targetSubjectsOf schema:startTime, schema:endTime; + sh:property [ + a sh:PropertyShape ; + sh:name "End TimeStamp" ; + sh:path schema:endTime ; + sh:minCount 0 ; + sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; + sh:severity sh:Violation ; + sh:message "All `startTime` and `endTime` values MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; + ] ; + sh:property [ + a sh:PropertyShape ; + sh:name "Start TimeStamp" ; + sh:path schema:startTime ; + sh:minCount 0 ; + sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; + sh:severity sh:Violation ; + sh:message "All `startTime` and `endTime` values MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; + ] . \ No newline at end of file From 8ce9491f14c8b3d75b71a0008f1d81f70c985c2a Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Mon, 5 Jan 2026 16:32:03 +0000 Subject: [PATCH 5/7] add property descriptions & useful comments --- .../five-safes-crate/must/3_timestamp_format.ttl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rocrate_validator/profiles/five-safes-crate/must/3_timestamp_format.ttl b/rocrate_validator/profiles/five-safes-crate/must/3_timestamp_format.ttl index 8ed340da..c4f2ddb5 100644 --- a/rocrate_validator/profiles/five-safes-crate/must/3_timestamp_format.ttl +++ b/rocrate_validator/profiles/five-safes-crate/must/3_timestamp_format.ttl @@ -22,6 +22,11 @@ @prefix validator: . @prefix xsd: . + +# to ensure the entity id will be included in any error message, +# target all entities which have startTime and/or endTime properties using sh:targetSubjectsOf, +# then we use sh:property to validate the values of those properties. +# the properties are listed individually so that the property id appears in any error message too five-safes-crate:TimeStampFormat a sh:NodeShape ; sh:name "Timestamp Format" ; @@ -35,6 +40,7 @@ five-safes-crate:TimeStampFormat sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; sh:severity sh:Violation ; sh:message "All `startTime` and `endTime` values MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; + sh:description "End timestamps MUST follow the RFC 3339 standard." ; ] ; sh:property [ a sh:PropertyShape ; @@ -44,4 +50,5 @@ five-safes-crate:TimeStampFormat sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; sh:severity sh:Violation ; sh:message "All `startTime` and `endTime` values MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; - ] . \ No newline at end of file + sh:description "Start timestamps MUST follow the RFC 3339 standard." ; + ] . From 1336fbf79c68521d1b0225a2b695837c933220b1 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Mon, 5 Jan 2026 16:39:19 +0000 Subject: [PATCH 6/7] clean up empty shapes --- .../five-safes-crate/must/12_check_phase.ttl | 39 ------------------- .../must/13_validation_phase.ttl | 37 ------------------ .../must/8_disclosure_phase.ttl | 39 ------------------- .../five-safes-crate/should/4_sign_off.ttl | 4 +- 4 files changed, 2 insertions(+), 117 deletions(-) diff --git a/rocrate_validator/profiles/five-safes-crate/must/12_check_phase.ttl b/rocrate_validator/profiles/five-safes-crate/must/12_check_phase.ttl index 149b15b3..35b5dd15 100644 --- a/rocrate_validator/profiles/five-safes-crate/must/12_check_phase.ttl +++ b/rocrate_validator/profiles/five-safes-crate/must/12_check_phase.ttl @@ -59,45 +59,6 @@ five-safes-crate:CheckValueObjectHasDescriptiveNameAndIsAssessAction sh:message "CheckValue MUST have a human readable name string." ; ] . -five-safes-crate:CheckValueStartTimeMustFollowISOStandard - a sh:NodeShape ; - sh:name "CheckValue" ; - sh:description "" ; - sh:target [ - a sh:SPARQLTarget ; - sh:select """ - PREFIX schema: - PREFIX shp: - SELECT ?this - WHERE { - ?this schema:additionalType shp:CheckValue ; - schema:startTime ?o - - } - """ ; - ] . - - - -five-safes-crate:CheckValueEndTimeMustFollowISOStandard - a sh:NodeShape ; - sh:name "CheckValue" ; - sh:description "" ; - sh:target [ - a sh:SPARQLTarget ; - sh:select """ - PREFIX schema: - PREFIX shp: - SELECT ?this - WHERE { - ?this schema:additionalType shp:CheckValue ; - schema:endTime ?o - - } - """ ; - ] . - - five-safes-crate:CheckValueActionStatusMustHaveAllowedValues a sh:NodeShape ; sh:name "CheckValue" ; diff --git a/rocrate_validator/profiles/five-safes-crate/must/13_validation_phase.ttl b/rocrate_validator/profiles/five-safes-crate/must/13_validation_phase.ttl index 22017bf0..8ce6be48 100644 --- a/rocrate_validator/profiles/five-safes-crate/must/13_validation_phase.ttl +++ b/rocrate_validator/profiles/five-safes-crate/must/13_validation_phase.ttl @@ -124,40 +124,3 @@ five-safes-crate:ValidationCheckActionStatusMustHaveAllowedValue sh:severity sh:Violation ; sh:message "actionStatus MUST be either PotentialActionStatus, ActiveActionStatus, CompletedActionStatus, or FailedActionStatus." ; ] . - - -five-safes-crate:ValidationCheckStartTimeMUSTFollowISOStandard - a sh:NodeShape ; - sh:name "ValidationCheck" ; - sh:description "" ; - sh:target [ - a sh:SPARQLTarget ; - sh:select """ - PREFIX schema: - PREFIX shp: - - SELECT ?this - WHERE { - ?this schema:additionalType shp:ValidationCheck . - } - """ ; - ] . - - - -five-safes-crate:ValidationCheckEndTimeMUSTFollowISOStandard - a sh:NodeShape ; - sh:name "ValidationCheck" ; - sh:description "" ; - sh:target [ - a sh:SPARQLTarget ; - sh:select """ - PREFIX schema: - PREFIX shp: - - SELECT ?this - WHERE { - ?this schema:additionalType shp:ValidationCheck . - } - """ ; - ] . diff --git a/rocrate_validator/profiles/five-safes-crate/must/8_disclosure_phase.ttl b/rocrate_validator/profiles/five-safes-crate/must/8_disclosure_phase.ttl index 6f5898a5..3c8ceca8 100644 --- a/rocrate_validator/profiles/five-safes-crate/must/8_disclosure_phase.ttl +++ b/rocrate_validator/profiles/five-safes-crate/must/8_disclosure_phase.ttl @@ -98,42 +98,3 @@ five-safes-crate:DisclosureObjectHasActionStatusWithAcceptedValue sh:severity sh:Violation ; sh:message "`DisclosureCheck` MUST have an actionStatus with an allowed value (see https://schema.org/ActionStatusType)." ; ] . - - -five-safes-crate:DisclosureObjectHasCompliantStartTimeFormat - a sh:NodeShape ; - sh:name "DisclosureCheck" ; - sh:description "`DisclosureCheck` --> `startTime` MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; - sh:target [ - a sh:SPARQLTarget ; - sh:select """ - PREFIX schema: - PREFIX shp: - - SELECT ?this - WHERE { - ?this schema:additionalType shp:DisclosureCheck ; - schema:startTime ?o - } - """ ; - ] . - - - -five-safes-crate:DisclosureObjectHasCompliantEndTimeFormat - a sh:NodeShape ; - sh:name "DisclosureCheck" ; - sh:description "`DisclosureCheck` --> `endTime` MUST follow the RFC 3339 standard (YYYY-MM-DD'T'hh:mm:ss[.fraction](Z | ±hh:mm))." ; - sh:target [ - a sh:SPARQLTarget ; - sh:select """ - PREFIX schema: - PREFIX shp: - - SELECT ?this - WHERE { - ?this schema:additionalType shp:DisclosureCheck ; - schema:endTime ?o - } - """ ; - ] . diff --git a/rocrate_validator/profiles/five-safes-crate/should/4_sign_off.ttl b/rocrate_validator/profiles/five-safes-crate/should/4_sign_off.ttl index 7f042aab..abbfc615 100644 --- a/rocrate_validator/profiles/five-safes-crate/should/4_sign_off.ttl +++ b/rocrate_validator/profiles/five-safes-crate/should/4_sign_off.ttl @@ -172,6 +172,6 @@ five-safes-crate:SignOffPhaseEndTime sh:minCount 1 ; sh:maxCount 1 ; sh:severity sh:Warning ; - sh:description "Sign Off object SHOULD have endTime property if action completed or failed. This must follow ISO-8601 syntax" ; - sh:message "Sign Off object SHOULD have endTime property if action completed or failed. This must follow ISO-8601 syntax" ; + sh:description "Sign Off object SHOULD have endTime property if action completed or failed." ; + sh:message "Sign Off object SHOULD have endTime property if action completed or failed." ; ] . From a53c83224d48c736f7d26de88596f7fb79a79262 Mon Sep 17 00:00:00 2001 From: Eli Chadwick Date: Mon, 5 Jan 2026 16:55:27 +0000 Subject: [PATCH 7/7] clean up more iso-8601 references --- .../profiles/five-safes-crate/may/4_sign_off.ttl | 4 ++-- .../profiles/five-safes-crate/test_5src_4_signoff_phase.py | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/rocrate_validator/profiles/five-safes-crate/may/4_sign_off.ttl b/rocrate_validator/profiles/five-safes-crate/may/4_sign_off.ttl index b30dedc2..3890e2b3 100644 --- a/rocrate_validator/profiles/five-safes-crate/may/4_sign_off.ttl +++ b/rocrate_validator/profiles/five-safes-crate/may/4_sign_off.ttl @@ -53,6 +53,6 @@ five-safes-crate:SignOffPhaseStartTime sh:maxCount 1 ; sh:pattern "^[0-9]{4}-[0-9]{2}-[0-9]{2}[Tt][0-9]{2}:[0-9]{2}:[0-9]{2}([.|,][0-9]+)?(Z|z|[+-][0-9]{2}:[0-9]{2})$" ; sh:severity sh:Info ; - sh:description "Sign Off object MAY have a startTime property if action is active, completed or failed. This must follow ISO-8601 syntax" ; - sh:message "Sign Off object MAY have a startTime property if action is active, completed or failed. This must follow ISO-8601 syntax" ; + sh:description "Sign Off object MAY have a startTime property if action is active, completed or failed." ; + sh:message "Sign Off object MAY have a startTime property if action is active, completed or failed." ; ] . diff --git a/tests/integration/profiles/five-safes-crate/test_5src_4_signoff_phase.py b/tests/integration/profiles/five-safes-crate/test_5src_4_signoff_phase.py index 27780aaa..f9918348 100644 --- a/tests/integration/profiles/five-safes-crate/test_5src_4_signoff_phase.py +++ b/tests/integration/profiles/five-safes-crate/test_5src_4_signoff_phase.py @@ -207,7 +207,6 @@ def test_5src_signoff_phase_no_endtime(): expected_triggered_requirements=["SignOffPhaseEndTime"], expected_triggered_issues=[ "Sign Off object SHOULD have endTime property if action completed or failed." - + " This must follow ISO-8601 syntax" ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql, @@ -277,7 +276,6 @@ def test_5src_signoff_phase_no_starttime(): expected_triggered_requirements=["SignOffPhaseStartTime"], expected_triggered_issues=[ "Sign Off object MAY have a startTime property if action is active, completed or failed." - + " This must follow ISO-8601 syntax" ], profile_identifier="five-safes-crate", rocrate_entity_mod_sparql=sparql,