The configure role's name resolver previously used dict.get(name, name)
fallbacks, so any unresolvable reference in YAML config was silently
passed through to the API as if it were a valid ID. On the server side,
the reference was discarded — producing half-applied policies whose
rules ended up with sources: null (or destinations/auto_groups wiped).
Common failure mode: a typo in a group name ships a broken firewall
rule that reports changed=true but has no source constraint.
This change makes the resolver strict:
- Unknown name that is ALSO not an existing ID -> AnsibleFilterError
with a message naming the resource, field, and unresolved value.
- Known name -> resolves to ID (unchanged).
- Value that matches an existing ID -> passes through (preserves
backward compatibility for YAML configs that use raw IDs).
Applies to groups in policy sources/destinations, setup_key auto_groups,
policy source_posture_checks, peer refs in policy source_resource/
destination_resource, and network router.peer / resource.groups.
Also: the /api/networks/{id}/routers endpoint returns router.peer as
the peer's HOSTNAME rather than its canonical name. The peer_ids map
(configure role) and peer_id_map (export role) now include hostname
aliases so round-trips stay idempotent.
Files:
- plugins/filter/netbird_resolve.py: strict _resolve_names,
_resolve_resource_ref, new _resolve_peer_id helper
- roles/configure/tasks/main.yml: peer_ids merges hostname->id
aliases with name->id
- roles/export/tasks/main.yml: peer_id_map merges hostname->name
aliases with id->name
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR#31 fixed export silently dropping peer-based policy sources, but
collapsed them into sources: [peer_name]. The configure role resolver
only maps sources against group_ids, so peer names fell through
unresolved. The netbird_policy module then sent literal peer names to
the API, which silently accepted them and wiped sourceResource --
turning the exported YAML into a policy with no source at all (reported
as changed: true).
Changes:
- Export template emits source_resource: {name, type: peer} for
peer-type resources (keeps host/domain/subnet as {id, type}).
- _resolve_policy in netbird_resolve accepts peer_ids and converts
{name, type: peer} to {id, type: peer}; non-peer refs pass through.
- configure/tasks/main.yml passes peer_ids to the policy resolve call
(the map is already built on line 214 for networks).
Roundtrip verified on live NetBird: sourceResource preserved; apply
reports ok (idempotent) instead of false changed: true.