diff --git a/ontology/uco/configuration/configuration.ttl b/ontology/uco/configuration/configuration.ttl
index 625c4f06..0649cb4c 100644
--- a/ontology/uco/configuration/configuration.ttl
+++ b/ontology/uco/configuration/configuration.ttl
@@ -163,6 +163,16 @@ configuration:dependencyType
rdfs:range xsd:string ;
.
+configuration:isConfigurationOf
+ a
+ owl:ObjectProperty ,
+ owl:IrreflexiveProperty
+ ;
+ rdfs:label "isConfigurationOf"@en ;
+ rdfs:comment "The object which has been configured to run in a more specified manner than another object. This property is expected to have a more specific range when associated with a class, such as a configured Tool having this property have a range of a Tool."@en ;
+ rdfs:range core:UcoObject ;
+ .
+
configuration:itemDescription
a owl:DatatypeProperty ;
rdfs:label "itemDescription"@en ;
@@ -205,3 +215,10 @@ configuration:usageContextAssumptions
rdfs:range xsd:string ;
.
+configuration:usesConfiguration
+ a owl:ObjectProperty ;
+ rdfs:label "usesConfiguration"@en ;
+ rdfs:comment "A configuration used by an object."@en ;
+ rdfs:range configuration:Configuration ;
+ .
+
diff --git a/ontology/uco/observable/observable.ttl b/ontology/uco/observable/observable.ttl
index df82e70f..a717d51a 100644
--- a/ontology/uco/observable/observable.ttl
+++ b/ontology/uco/observable/observable.ttl
@@ -1,4 +1,5 @@
# imports: https://ontology.unifiedcyberontology.org/uco/action
+# imports: https://ontology.unifiedcyberontology.org/uco/configuration
# imports: https://ontology.unifiedcyberontology.org/uco/core
# imports: https://ontology.unifiedcyberontology.org/uco/identity
# imports: https://ontology.unifiedcyberontology.org/uco/location
@@ -7,6 +8,7 @@
@prefix action: .
@prefix co: .
+@prefix configuration: .
@prefix core: .
@prefix identity: .
@prefix location: .
@@ -24,6 +26,7 @@
rdfs:label "uco-observable"@en ;
owl:imports
,
+ ,
,
,
,
@@ -1284,6 +1287,31 @@ observable:ComputerSpecificationFacet
sh:targetClass observable:ComputerSpecificationFacet ;
.
+observable:ConfiguredSoftware
+ a
+ owl:Class ,
+ sh:NodeShape
+ ;
+ rdfs:subClassOf observable:Software ;
+ rdfs:label "ConfiguredSoftware"@en ;
+ rdfs:comment "A ConfiguredSoftware is a Software that is known to be configured to run in a more specified manner than some unconfigured or less-configured Software."@en ;
+ sh:property
+ [
+ sh:class configuration:Configuration ;
+ sh:maxCount "1"^^xsd:integer ;
+ sh:nodeKind sh:BlankNodeOrIRI ;
+ sh:path configuration:usesConfiguration ;
+ ] ,
+ [
+ sh:class observable:Software ;
+ sh:maxCount "1"^^xsd:integer ;
+ sh:nodeKind sh:BlankNodeOrIRI ;
+ sh:path configuration:isConfigurationOf ;
+ ]
+ ;
+ sh:targetClass observable:ConfiguredSoftware ;
+ .
+
observable:Contact
a
owl:Class ,
diff --git a/ontology/uco/tool/tool.ttl b/ontology/uco/tool/tool.ttl
index 36013a05..4e41d6a7 100644
--- a/ontology/uco/tool/tool.ttl
+++ b/ontology/uco/tool/tool.ttl
@@ -184,6 +184,31 @@ tool:CompilerType
sh:targetClass tool:CompilerType ;
.
+tool:ConfiguredTool
+ a
+ owl:Class ,
+ sh:NodeShape
+ ;
+ rdfs:subClassOf tool:Tool ;
+ rdfs:label "ConfiguredTool"@en ;
+ rdfs:comment "A ConfiguredTool is a Tool that is known to be configured to run in a more specified manner than some unconfigured or less-configured Tool."@en ;
+ sh:property
+ [
+ sh:class configuration:Configuration ;
+ sh:maxCount "1"^^xsd:integer ;
+ sh:nodeKind sh:BlankNodeOrIRI ;
+ sh:path configuration:usesConfiguration ;
+ ] ,
+ [
+ sh:class tool:Tool ;
+ sh:maxCount "1"^^xsd:integer ;
+ sh:nodeKind sh:BlankNodeOrIRI ;
+ sh:path configuration:isConfigurationOf ;
+ ]
+ ;
+ sh:targetClass tool:ConfiguredTool ;
+ .
+
tool:DefensiveTool
a
owl:Class ,
diff --git a/tests/examples/configuration_setting_PASS.json b/tests/examples/configuration_setting_PASS.json
index 2c61ea06..5d34271b 100644
--- a/tests/examples/configuration_setting_PASS.json
+++ b/tests/examples/configuration_setting_PASS.json
@@ -9,6 +9,21 @@
{
"rdfs:comment": "Settings are numbered with a binary tracking system. 2^0 = itemObject set. 2^1 = itemValue set. With the mutually-exclusive property shapes on ConfigurationSettingType, setting 3 would be invalid."
},
+ {
+ "@id": "kb:tool-1",
+ "@type": "tool:Tool"
+ },
+ {
+ "@id": "kb:configured-object-1",
+ "@type": "tool:ConfiguredTool",
+ "configuration:isConfigurationOf": {
+ "@id": "kb:tool-1"
+ },
+ "configuration:usesConfiguration": {
+ "@id": "kb:configuration-1"
+ }
+ },
+
{
"@id": "kb:thing-1",
"@type": "core:UcoObject"
diff --git a/tests/examples/configuration_setting_XFAIL.json b/tests/examples/configuration_setting_XFAIL.json
index f740f66e..cb5a375a 100644
--- a/tests/examples/configuration_setting_XFAIL.json
+++ b/tests/examples/configuration_setting_XFAIL.json
@@ -3,6 +3,7 @@
"configuration": "https://ontology.unifiedcyberontology.org/uco/configuration/",
"core": "https://ontology.unifiedcyberontology.org/uco/core/",
"kb": "http://example.org/kb/",
+ "observable": "https://ontology.unifiedcyberontology.org/uco/observable/",
"tool": "https://ontology.unifiedcyberontology.org/uco/tool/"
},
"@graph": [
@@ -13,6 +14,21 @@
"@id": "kb:thing-2",
"@type": "core:UcoObject"
},
+ {
+ "@id": "kb:software-1",
+ "@type": "observable:Software"
+ },
+ {
+ "@id": "kb:configured-object-2",
+ "@type": "tool:ConfiguredTool",
+ "rdfs:comment": "This will trigger an error, as kb:software-1 is not declared here to be a tool:Tool. It can be, but it has not been declared here.",
+ "configuration:isConfigurationOf": {
+ "@id": "kb:software-1"
+ },
+ "configuration:usesConfiguration": {
+ "@id": "kb:configuration-2"
+ }
+ },
{
"@id": "kb:configuration-2",
"@type": "configuration:Configuration",
diff --git a/tests/examples/test_validation.py b/tests/examples/test_validation.py
index 9094b533..fd1807f6 100644
--- a/tests/examples/test_validation.py
+++ b/tests/examples/test_validation.py
@@ -182,8 +182,14 @@ def test_configuration_setting_PASS_validation() -> None:
assert isinstance(g, rdflib.Graph)
def test_configuration_setting_XFAIL_validation() -> None:
- g = load_validation_graph("configuration_setting_XFAIL_validation.ttl", False)
- assert isinstance(g, rdflib.Graph)
+ confirm_validation_results(
+ "configuration_setting_XFAIL_validation.ttl",
+ False,
+ expected_focus_node_severities={
+ ("http://example.org/kb/configuration-entry-3", str(NS_SH.Violation)),
+ ("http://example.org/kb/configured-object-2", str(NS_SH.Violation)),
+ }
+)
def test_hash_PASS() -> None:
g = load_validation_graph("hash_PASS_validation.ttl", True)