diff --git a/python/understack-workflows/understack_workflows/ironic_node.py b/python/understack-workflows/understack_workflows/ironic_node.py index 4eb836b67..92632e298 100644 --- a/python/understack-workflows/understack_workflows/ironic_node.py +++ b/python/understack-workflows/understack_workflows/ironic_node.py @@ -37,6 +37,38 @@ class NodeInterface: logger = logging.getLogger(__name__) +# Substrings of patch/update paths whose values must never be logged. +_SENSITIVE_PATH_FRAGMENTS = ("password", "secret", "token") +_REDACTED = "***REDACTED***" + + +def _is_sensitive(path: str) -> bool: + path = path.lower() + return any(fragment in path for fragment in _SENSITIVE_PATH_FRAGMENTS) + + +def _redact_patches(patches: Sequence[dict]) -> list[dict]: + """Return a copy of JSON-patch operations with sensitive values redacted.""" + redacted = [] + for patch_op in patches: + if isinstance(patch_op, dict) and _is_sensitive(str(patch_op.get("path", ""))): + redacted.append({**patch_op, "value": _REDACTED}) + else: + redacted.append(patch_op) + return redacted + + +def _redact_updates(updates: Sequence[str]) -> list[str]: + """Return a copy of "path=value" update strings with sensitive values redacted.""" + redacted = [] + for update in updates: + path, sep, _ = str(update).partition("=") + if sep and _is_sensitive(path): + redacted.append(f"{path}={_REDACTED}") + else: + redacted.append(update) + return redacted + def create_or_update( bmc: Bmc, @@ -127,7 +159,11 @@ def update_ironic_node( updates.append(f"extra/external_cmdb_id={external_cmdb_id}") patches = args_array_to_patch("add", updates) - logger.info("Updating Ironic node %s patches=%s", ironic_node.uuid, patches) + logger.info( + "Updating Ironic node %s patches=%s", + ironic_node.uuid, + _redact_patches(patches), + ) client.update_node(ironic_node.uuid, patches) logger.debug("Ironic node %s Updated.", ironic_node.uuid) @@ -213,7 +249,7 @@ def transition( def patch(node: Node, updates: Sequence[str]) -> None: if not updates: return - logger.info("%s updating node %s", node.uuid, list(updates)) + logger.info("%s updating node %s", node.uuid, _redact_updates(updates)) IronicClient().update_node(node.uuid, args_array_to_patch("add", list(updates)))