Describe the bug
When creating a Relationship between two facts, the Relationship class only requires a source Fact as documented here and as seen in the constructor here. However when processed by create_relationships and save_fact, processing will error out and cease for the current ability instance if a Relationship with an undefined target (i.e., a Relationship without a target Fact) exists in the provided list.
To Reproduce
Steps to reproduce the behavior:
- Using a parser, create a relationship with only a source fact and edge:
def parse(self, blob):
relationships = []
source = "domain.computer.hostname"
computer_name = "www02"
edge = "can_delegate_unconstrained"
relationships.append(
Relationship(
source=Fact(source, computer_name),
edge=edge
)
)
return relationships
Expected behavior
A new fact should be created (if not existing), with an updated relationship with an outbound edge of the type specified:
{
"unique": "domain.computer.hostnamewww02",
"trait": "domain.computer.hostname",
"name": "domain.computer.hostname",
"value": "www02",
"created": "2026-01-28T22:56:27Z",
"score": 1,
"source": "0d959eb9-46f3-4160-8d5a-55a12f1e5ef0",
"origin_type": "LEARNED",
"links": [
"43940a78-5fc7-4891-a39a-8c6422784a1a",
"484f9814-b468-436a-8d2b-9abc92a2bacb"
],
"relationships": [
"domain.computer.hostname(www02) : has_address : domain.computer.ipaddress(10.100.32.122)",
"domain.computer.hostname(www02) : has_address : domain.computer.dnshostname(www02.int.example)",
"domain.computer.hostname(www02) : can_delegate_unconstrained"
],
"limit_count": -1,
"collected_by": [
"sontsq",
"evsuvl"
],
"technique_id": "T1018"
},
Additional context
Add any other context about the problem here.
Adding in a try / catch block allowed the operation to proceed with the expected Relationships being generated. This also outlines the underlying issue when trying to access trait on a None type object:
Updated create_relationships method:
async def create_relationships(self, relationships, operation):
for relationship in relationships:
relationship.origin = operation.id if operation else self.id
try:
await self.save_fact(operation, relationship.source, relationship.score, relationship.shorthand)
await self.save_fact(operation, relationship.target, relationship.score, relationship.shorthand)
except Exception as e:
logging.getLogger("link").warning("Trying to process relationship %s failed: %s",
relationship.shorthand,
e)
if all((relationship.source.trait, relationship.edge)):
knowledge_svc_handle = BaseService.get_service('knowledge_svc')
await knowledge_svc_handle.add_relationship(relationship)
self.relationships.append(relationship)
Resulting log output:
Trying to process relationship domain.computer.hostname(www02) : can_delegate_unconstrained failed: 'NoneType' object has no attribute 'trait' c_link.py:269
Describe the bug
When creating a Relationship between two facts, the Relationship class only requires a
sourceFact as documented here and as seen in the constructor here. However when processed bycreate_relationshipsandsave_fact, processing will error out and cease for the current ability instance if a Relationship with an undefinedtarget(i.e., a Relationship without atargetFact) exists in the provided list.To Reproduce
Steps to reproduce the behavior:
Expected behavior
A new fact should be created (if not existing), with an updated relationship with an outbound edge of the type specified:
Additional context
Add any other context about the problem here.
Adding in a try / catch block allowed the operation to proceed with the expected Relationships being generated. This also outlines the underlying issue when trying to access
traiton aNonetype object:Updated
create_relationshipsmethod:Resulting log output: