From b77a9d24925249e8a1ae969a5ca3e9fb7d6f1143 Mon Sep 17 00:00:00 2001 From: Dan Chaffelson Date: Sat, 24 Oct 2026 09:11:43 +0100 Subject: [PATCH 1/2] fix: accept STATELESS_GROUP affected components and normalise port failures * Add a spec augmentation that mirrors AffectedComponentDTO.referenceType's enum into AffectedComponentEntity, and regenerate. NiFi returns STATELESS_GROUP for components in stateless process groups, but the 2.12.0 OpenAPI spec omits it from the entity (NIFI-16464, fixed upstream in apache/nifi#11811), so parameter provider fetch/apply raised ValueError on flows with stateless groups. Only affected_component_entity.py changes. Remove the augmentation when generating from a NiFi release with the fix. * verify_config: return port failures as {"step", "explanation"} dicts, like controller and processor failures, instead of plain strings. Fixes #419 Fixes #418 --- docs/history.rst | 10 +++ nipyapi/ci/verify_config.py | 3 +- .../nifi/models/affected_component_entity.py | 2 +- .../nifi_affected_component_reference_type.py | 62 +++++++++++++++++++ tests/test_ci.py | 4 ++ tests/test_generated_models.py | 7 +++ 6 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 resources/client_gen/augmentations/nifi_affected_component_reference_type.py diff --git a/docs/history.rst b/docs/history.rst index fa2b1cb1..0a972618 100644 --- a/docs/history.rst +++ b/docs/history.rst @@ -2,6 +2,16 @@ History ======= +Unreleased +---------- + +| Bug fixes for stateless process groups in parameter provider fetch/apply and for ``verify_config`` port results + +**Bug Fixes** + +- **AffectedComponentEntity**: Added ``STATELESS_GROUP`` to the ``reference_type`` allowed values (`#419 `_). NiFi returns it for components in stateless process groups, but the NiFi 2.12.0 OpenAPI spec omits it from the entity (`NIFI-16464 `_), so fetching or applying a parameter provider on a flow with stateless groups raised ``ValueError`` during deserialization. A spec augmentation mirrors the ``AffectedComponentDTO`` enum into the entity until the client is regenerated from a NiFi release that includes the upstream fix. +- **verify_config()**: Port failures in ``port_results`` now use the same ``{"step", "explanation"}`` shape as controller and processor failures (`#418 `_). Previously each port failure was a plain string. Callers that read the port strings directly should read ``explanation`` instead. + 1.8.0 (2026-10-22) ------------------- diff --git a/nipyapi/ci/verify_config.py b/nipyapi/ci/verify_config.py index 47157260..0fe7903f 100644 --- a/nipyapi/ci/verify_config.py +++ b/nipyapi/ci/verify_config.py @@ -115,7 +115,8 @@ def _verify_ports(process_group_id: str) -> List[Dict[str, Any]]: } errors = port.component.validation_errors if errors: - results.append({**base_result, "success": False, "failures": errors}) + failures = [{"step": "Port validation", "explanation": e} for e in errors] + results.append({**base_result, "success": False, "failures": failures}) else: results.append({**base_result, "success": True, "failures": []}) return results diff --git a/nipyapi/nifi/models/affected_component_entity.py b/nipyapi/nifi/models/affected_component_entity.py index 9ab08a44..762d606a 100644 --- a/nipyapi/nifi/models/affected_component_entity.py +++ b/nipyapi/nifi/models/affected_component_entity.py @@ -263,7 +263,7 @@ def reference_type(self, reference_type): :type: str """ if Configuration().client_side_validation: - allowed_values = ["PROCESSOR", "CONTROLLER_SERVICE", "INPUT_PORT", "OUTPUT_PORT", "REMOTE_INPUT_PORT", "REMOTE_OUTPUT_PORT", ] + allowed_values = ["PROCESSOR", "CONTROLLER_SERVICE", "INPUT_PORT", "OUTPUT_PORT", "REMOTE_INPUT_PORT", "REMOTE_OUTPUT_PORT", "STATELESS_GROUP", ] if reference_type not in allowed_values: raise ValueError( "Invalid value for `reference_type` ({0}), must be one of {1}" diff --git a/resources/client_gen/augmentations/nifi_affected_component_reference_type.py b/resources/client_gen/augmentations/nifi_affected_component_reference_type.py new file mode 100644 index 00000000..44602357 --- /dev/null +++ b/resources/client_gen/augmentations/nifi_affected_component_reference_type.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +""" +Augmentation to fix AffectedComponentEntity.referenceType enum. + +Upstream NiFi inconsistency: AffectedComponentDTO.referenceType allows +"STATELESS_GROUP", but AffectedComponentEntity.referenceType omits it, even +though NiFi returns it in the referencingComponents of parameter context +update requests and parameter provider apply requests. + +This augmentation updates the entity enum to match the DTO enum. + +Fixed upstream in NIFI-16464 (apache/nifi#11811). Remove this augmentation when +generating from a NiFi release that includes that fix; it is a no-op there. +""" +import json +import sys + + +def fix_affected_component_entity_reference_type(spec): + """Update AffectedComponentEntity.referenceType enum to match the DTO.""" + schemas = spec.get("components", {}).get("schemas", {}) + dto_props = schemas.get("AffectedComponentDTO", {}).get("properties", {}) + complete_enum = dto_props.get("referenceType", {}).get("enum", []) + + if not complete_enum: + # Fallback if the DTO enum is missing + complete_enum = [ + "PROCESSOR", + "CONTROLLER_SERVICE", + "INPUT_PORT", + "OUTPUT_PORT", + "REMOTE_INPUT_PORT", + "REMOTE_OUTPUT_PORT", + "STATELESS_GROUP", + ] + + entity_props = schemas.get("AffectedComponentEntity", {}).get("properties", {}) + ref_type = entity_props.get("referenceType", {}) + if ref_type and "enum" in ref_type: + old_enum = ref_type["enum"] + ref_type["enum"] = old_enum + [v for v in complete_enum if v not in old_enum] + print(f" AffectedComponentEntity.referenceType enum: {old_enum} -> {ref_type['enum']}") + + return spec + + +def main(): + if len(sys.argv) != 3: + print("Usage: nifi_affected_component_reference_type.py ") + sys.exit(1) + + with open(sys.argv[1], "r") as f: + spec = json.load(f) + + spec = fix_affected_component_entity_reference_type(spec) + + with open(sys.argv[2], "w") as f: + json.dump(spec, f, indent=2) + + +if __name__ == "__main__": + main() diff --git a/tests/test_ci.py b/tests/test_ci.py index b9908372..ca3bb83b 100644 --- a/tests/test_ci.py +++ b/tests/test_ci.py @@ -1998,6 +1998,10 @@ def test_verify_config_with_invalid_port(fix_pg, fix_port): assert len(failed_ports) == 1 assert failed_ports[0]["id"] == f_port.id assert len(failed_ports[0]["failures"]) > 0 + # Same failure shape as controller and processor results + for failure in failed_ports[0]["failures"]: + assert set(failure) == {"step", "explanation"} + assert failure["explanation"] def test_get_status_port_counts(fix_pg, fix_port): diff --git a/tests/test_generated_models.py b/tests/test_generated_models.py index 3fffcb4a..e87c54cd 100644 --- a/tests/test_generated_models.py +++ b/tests/test_generated_models.py @@ -98,6 +98,13 @@ def test_deserialize_parameter_provider_fetch_response(payload): assert set(groups[0].parameter_sensitivities) >= {"API_KEY"} +def test_affected_component_accepts_stateless_group(): + # NiFi returns STATELESS_GROUP for components in stateless process groups; + # the 2.12.0 entity enum omits it (NIFI-16464), restored by augmentation + entity = AffectedComponentEntity(reference_type="STATELESS_GROUP") + assert entity.reference_type == "STATELESS_GROUP" + + def test_client_side_validation_can_be_disabled(monkeypatch): monkeypatch.setattr( nipyapi.config.nifi_config, "client_side_validation", False From 63d8cf323b9fbf483550d1c66da7aacc2ba7ec8a Mon Sep 17 00:00:00 2001 From: Dan Chaffelson Date: Sat, 24 Oct 2026 09:15:34 +0100 Subject: [PATCH 2/2] docs: date 1.8.1 release notes --- docs/history.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/history.rst b/docs/history.rst index 0a972618..a79ff134 100644 --- a/docs/history.rst +++ b/docs/history.rst @@ -2,8 +2,8 @@ History ======= -Unreleased ----------- +1.8.1 (2026-10-24) +------------------- | Bug fixes for stateless process groups in parameter provider fetch/apply and for ``verify_config`` port results