diff --git a/ontology/uco/core/core.ttl b/ontology/uco/core/core.ttl index 8bd191fb..3ecac152 100644 --- a/ontology/uco/core/core.ttl +++ b/ontology/uco/core/core.ttl @@ -317,6 +317,20 @@ core:ModusOperandi sh:targetClass core:ModusOperandi ; . +core:ObjectStatusVocab + a rdfs:Datatype ; + rdfs:label "Object Status Vocabulary"@en-US ; + owl:equivalentClass [ + a rdfs:Datatype ; + owl:onDatatype xsd:string ; + owl:oneOf ( + "Draft"^^core:ObjectStatusVocab + "Final"^^core:ObjectStatusVocab + "Deprecated"^^core:ObjectStatusVocab + ) ; + ] ; + . + core:Relationship a owl:Class , @@ -451,6 +465,17 @@ core:UcoObject sh:datatype xsd:string ; sh:nodeKind sh:Literal ; sh:path core:tag ; + ] , + [ + sh:datatype core:ObjectStatusVocab ; + sh:in ( + "Draft"^^core:ObjectStatusVocab + "Final"^^core:ObjectStatusVocab + "Deprecated"^^core:ObjectStatusVocab + ) ; + sh:maxCount "1"^^xsd:integer ; + sh:nodeKind sh:Literal ; + sh:path core:objectStatus ; ] ; sh:targetClass core:UcoObject ; @@ -697,6 +722,19 @@ core:objectMarking rdfs:range core:MarkingDefinitionAbstraction ; . +core:objectStatus + a owl:AnnotationProperty ; + rdfs:label "objectStatus"@en ; + rdfs:comment "The current state of formality and acceptance for a UCO object."@en-US ; + rdfs:range core:ObjectStatusVocab ; + . + +core:objectStatus-subjects-shape + a sh:NodeShape ; + sh:class core:UcoObject ; + sh:targetSubjectsOf core:objectStatus ; + . + core:referenceURL a owl:DatatypeProperty ; rdfs:label "referenceURL"@en ; diff --git a/tests/examples/Makefile b/tests/examples/Makefile index 66b33e05..552c0b89 100644 --- a/tests/examples/Makefile +++ b/tests/examples/Makefile @@ -41,6 +41,8 @@ all: \ location_XFAIL_validation.ttl \ message_thread_PASS_validation.ttl \ message_thread_XFAIL_validation.ttl \ + object_status_PASS_validation.ttl \ + object_status_XFAIL_validation.ttl \ observable_creation_time_PASS_validation.ttl \ owl_axiom_PASS_validation.ttl \ owl_axiom_XFAIL_validation.ttl \ @@ -116,6 +118,8 @@ check: \ location_XFAIL_validation.ttl \ message_thread_PASS_validation.ttl \ message_thread_XFAIL_validation.ttl \ + object_status_PASS_validation.ttl \ + object_status_XFAIL_validation.ttl \ observable_creation_time_PASS_validation.ttl \ owl_axiom_PASS_validation.ttl \ owl_axiom_XFAIL_validation.ttl \ diff --git a/tests/examples/object_status_PASS.json b/tests/examples/object_status_PASS.json new file mode 100644 index 00000000..2d10dc40 --- /dev/null +++ b/tests/examples/object_status_PASS.json @@ -0,0 +1,16 @@ +{ + "@context": { + "core": "https://ontology.unifiedcyberontology.org/uco/core/", + "kb": "http://example.org/kb/" + }, + "@graph": [ + { + "@id": "kb:UcoObject-f86c567d-374a-4873-b9bc-a746ca2bf360", + "@type": "core:UcoObject", + "core:objectStatus": { + "@type": "core:ObjectStatusVocab", + "@value": "Draft" + } + } + ] +} diff --git a/tests/examples/object_status_PASS_validation.ttl b/tests/examples/object_status_PASS_validation.ttl new file mode 100644 index 00000000..33496ff0 --- /dev/null +++ b/tests/examples/object_status_PASS_validation.ttl @@ -0,0 +1,11 @@ +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix xsd: . + +[] + a sh:ValidationReport ; + sh:conforms "true"^^xsd:boolean ; + . + diff --git a/tests/examples/object_status_XFAIL.json b/tests/examples/object_status_XFAIL.json new file mode 100644 index 00000000..b827c238 --- /dev/null +++ b/tests/examples/object_status_XFAIL.json @@ -0,0 +1,26 @@ +{ + "@context": { + "core": "https://ontology.unifiedcyberontology.org/uco/core/", + "kb": "http://example.org/kb/", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#" + }, + "@graph": [ + { + "@id": "kb:UcoObject-6ae2b245-a8cd-45dc-9f40-5b2738879351", + "@type": "core:UcoObject", + "rdfs:comment": "This will trigger an error from using a value outside of the required vocabulary.", + "core:objectStatus": "Initial draft" + }, + { + "@id": "kb:File-c9c36379-8eca-4a85-887c-b51f7721edfd", + "@type": "observable:File", + "core:hasFacet": { + "@id": "kb:ArchiveFileFacet-5884ca1c-2f5e-4e66-bdc6-7d48606f9fbc", + "@type": "observable:ArchiveFileFacet", + "rdfs:comment": "This will trigger an error from using objectStatus on a non-UcoObject thing.", + "core:objectStatus": "Draft", + "observable:archiveType": "Currently-unknown compressing-and-encrypting type seen multiple places, further research needed" + } + } + ] +} diff --git a/tests/examples/object_status_XFAIL_validation.ttl b/tests/examples/object_status_XFAIL_validation.ttl new file mode 100644 index 00000000..b84dd57b --- /dev/null +++ b/tests/examples/object_status_XFAIL_validation.ttl @@ -0,0 +1,63 @@ +@prefix core: . +@prefix owl: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix xsd: . + +[] + a sh:ValidationReport ; + sh:conforms "false"^^xsd:boolean ; + sh:result + [ + a sh:ValidationResult ; + sh:focusNode ; + sh:resultMessage "Value does not have class core:UcoObject" ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:ClassConstraintComponent ; + sh:sourceShape core:objectStatus-subjects-shape ; + sh:value ; + ] , + [ + a sh:ValidationResult ; + sh:focusNode ; + sh:resultMessage "Value Literal(\"Initial draft\") not in list ['Literal(\"Draft\" = None, datatype=core:ObjectStatusVocab)', 'Literal(\"Final\" = None, datatype=core:ObjectStatusVocab)', 'Literal(\"Deprecated\" = None, datatype=core:ObjectStatusVocab)']" ; + sh:resultPath core:objectStatus ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:InConstraintComponent ; + sh:sourceShape [ + sh:datatype core:ObjectStatusVocab ; + sh:in ( + "Draft"^^core:ObjectStatusVocab + "Final"^^core:ObjectStatusVocab + "Deprecated"^^core:ObjectStatusVocab + ) ; + sh:maxCount "1"^^xsd:integer ; + sh:nodeKind sh:Literal ; + sh:path core:objectStatus ; + ] ; + sh:value "Initial draft" ; + ] , + [ + a sh:ValidationResult ; + sh:focusNode ; + sh:resultMessage "Value is not Literal with datatype core:ObjectStatusVocab" ; + sh:resultPath core:objectStatus ; + sh:resultSeverity sh:Violation ; + sh:sourceConstraintComponent sh:DatatypeConstraintComponent ; + sh:sourceShape [ + sh:datatype core:ObjectStatusVocab ; + sh:in ( + "Draft"^^core:ObjectStatusVocab + "Final"^^core:ObjectStatusVocab + "Deprecated"^^core:ObjectStatusVocab + ) ; + sh:maxCount "1"^^xsd:integer ; + sh:nodeKind sh:Literal ; + sh:path core:objectStatus ; + ] ; + sh:value "Initial draft" ; + ] + ; + . + diff --git a/tests/examples/test_validation.py b/tests/examples/test_validation.py index 6c4fc658..609c1b77 100644 --- a/tests/examples/test_validation.py +++ b/tests/examples/test_validation.py @@ -425,6 +425,28 @@ def test_message_thread_PASS_validation() -> None: def test_message_thread_XFAIL_validation() -> None: confirm_validation_results("message_thread_XFAIL_validation.ttl", False) +def test_object_status_PASS() -> None: + confirm_validation_results( + "object_status_PASS_validation.ttl", + True, + ) + +def test_object_status_XFAIL() -> None: + confirm_validation_results( + "object_status_XFAIL_validation.ttl", + False, + expected_focus_node_severities={ + ( + "http://example.org/kb/UcoObject-6ae2b245-a8cd-45dc-9f40-5b2738879351", + str(NS_SH.Violation) + ), + ( + "http://example.org/kb/ArchiveFileFacet-5884ca1c-2f5e-4e66-bdc6-7d48606f9fbc", + str(NS_SH.Violation) + ), + } + ) + def test_observable_creation_time_PASS() -> None: confirm_validation_results( "observable_creation_time_PASS_validation.ttl",