Skip to content

adapter: update_node omits source/owner on relationship updates #142

Description

@PhillSimonds

What happened

When the Infrahub adapter updates an existing node, attribution metadata
(source / owner) is written to changed attributes but never to changed
relationships. A relationship modified by a sync ends up with no
source/owner, while attributes changed in the same sync are attributed
correctly.

This is asymmetric with the create path, which does attribute
relationships: InfrahubModel.create builds its payload with
generate_payload_create(..., source=source_id, owner=owner_id, is_protected=True),
and that SDK function stamps the metadata onto attributes and onto both
cardinality-one and cardinality-many relationships.

Expected behavior

A relationship changed during an update carries the same source / owner
attribution as attributes changed in the same update (matching the create path).

Actual behavior

The changed relationship has its new peer wired up but no source / owner
attribution. Concretely, in an update that changes both a position attribute
and a location relationship, position is attributed and location is not.

Steps to reproduce

  1. Configure a sync with source (and/or owner) set (e.g. a CoreAccount /
    CoreAccountGroup).
  2. Match an existing destination node and, in an update (not a create),
    change both an attribute and a cardinality-one relationship — e.g. a device
    whose position (attribute) and location (relationship to a rack) both
    change.
  3. Inspect the updated node's relationship metadata (UI metadata view or the
    GraphQL relationship properties).

Result: the attribute has source/owner; the relationship does not.

Environment

  • infrahub-sync: present in 1.5.6, 2.0.0, and 2.0.1 (update_node is
    byte-identical across 2.0.0/2.0.1 in this region)
  • Infrahub server version: N/A — logic bug in the sync adapter, independent
    of server version
  • OS / Python: N/A — platform- and runtime-independent

Additional context

Location: infrahub_sync/adapters/infrahub.py, update_node() (v2.0.1 lines):

for attr_name, attr_value in attrs.items():
    if attr_name in node._schema.attribute_names:
        attr = getattr(node, attr_name)
        attr.value = attr_value
        if source:
            attr.source = NodeProperty(data=source)   # L121  ← attributed
        if owner:
            attr.owner = NodeProperty(data=owner)      # L123  ← attributed

    if attr_name in node._schema.relationship_names:
        for rel_schema in node._schema.relationships:
            ...
            if rel_schema.cardinality == "one":
                if attr_value:
                    peer_node = resolve_peer_node(...)
                    setattr(node, attr_name, peer_node)   # L144  ← NO source/owner
            elif rel_schema.cardinality == "many":
                ... attr_manager.add(new_id) / .remove(existing_id) ...  # NO source/owner

The docstring itself scopes it to attributes: "source: Optional source ID to
set on updated attributes."

Impact: relationships changed by a sync have no lineage back to the sync
source/owner. This is most visible for update-only flows (object matched
and only its relationships/attributes updated, never created), since such
relationships never traverse the attributing create path.

Suggested fix: mirror the attribute logic onto relationships in
update_node, assigning peers with metadata rather than the bare peer. The SDK's
RelatedNode accepts source / owner / is_protected in its data dict:

# cardinality == "one"
rel_data = {"id": peer_node.id}
if source:
    rel_data["source"] = source
if owner:
    rel_data["owner"] = owner
setattr(node, attr_name, rel_data)

# cardinality == "many": pass the same dict shape per added peer id

Happy to open a PR if this direction looks right.

Metadata

Metadata

Assignees

No one assigned

    Labels

    type/bugSomething isn't working as expected

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions