This is an automated email from the ASF dual-hosted git repository.
henry3260 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 8b4e4df8056 Keep the URL scheme out of path masking in airflow info
--anonymize (#73599)
8b4e4df8056 is described below
commit 8b4e4df805665ec69aa99f21a85f94c4a9f131cf
Author: wiasliaw <[email protected]>
AuthorDate: Wed Sep 23 17:24:23 2026 +0800
Keep the URL scheme out of path masking in airflow info --anonymize (#73599)
Since #73179 a netloc-less connection string is masked through the
unanchored username substitution, so an OS username that happens to be
a substring of the scheme (e.g. "lite" or "db") corrupts the scheme
itself: "sqlite:" becomes "sq${USER}:". Splitting on the first colon
puts the scheme out of the substitution's reach; non-URL fallback
values such as "NOT AVAILABLE" stay intact for the same reason.
Suggested as an optional follow-up in the review of #73179.
---
.../src/airflow/cli/commands/info_command.py | 6 ++--
.../tests/unit/cli/commands/test_info_command.py | 37 ++++++++++++++++++++++
2 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/airflow-core/src/airflow/cli/commands/info_command.py
b/airflow-core/src/airflow/cli/commands/info_command.py
index f5d9f22e0c1..3f9f81f56ae 100644
--- a/airflow-core/src/airflow/cli/commands/info_command.py
+++ b/airflow-core/src/airflow/cli/commands/info_command.py
@@ -120,8 +120,10 @@ class PiiAnonymizer(Anonymizer):
netloc = ""
else:
# A netloc-less URL is a local-file backend (SQLite is the
default), where
- # the path itself is the identifying information.
- return self.process_path(value)
+ # the path itself is the identifying information. Split off the
scheme so the
+ # unanchored username substitution cannot touch it ("sqlite:" ->
"sq${USER}:").
+ scheme, sep, rest = value.partition(":")
+ return f"{scheme}{sep}{self.process_path(rest)}"
return urlunsplit((url_parts.scheme, netloc, url_parts.path,
url_parts.query, url_parts.fragment))
diff --git a/airflow-core/tests/unit/cli/commands/test_info_command.py
b/airflow-core/tests/unit/cli/commands/test_info_command.py
index 7f1cba4d834..321a2ae2531 100644
--- a/airflow-core/tests/unit/cli/commands/test_info_command.py
+++ b/airflow-core/tests/unit/cli/commands/test_info_command.py
@@ -21,6 +21,7 @@ import importlib
import logging
import os
from io import StringIO
+from unittest import mock
import pytest
@@ -73,6 +74,42 @@ class TestPiiAnonymizer:
def test_should_remove_pii_from_url(self, before, after):
assert after == self.instance.process_url(before)
+ @pytest.mark.parametrize(
+ ("username", "home", "before", "after"),
+ [
+ (
+ "lite",
+ "/home/lite",
+ "sqlite:////home/lite/airflow.db",
+ "sqlite:///${HOME}/airflow.db",
+ ),
+ (
+ "db",
+ "/home/db",
+ "duckdb:////home/db/wh.duckdb",
+ "duckdb:///${HOME}/wh.duck${USER}",
+ ),
+ (
+ "AVA",
+ "/home/AVA",
+ "NOT AVAILABLE",
+ "NOT AVAILABLE",
+ ),
+ ],
+ )
+ @mock.patch("airflow.cli.commands.info_command.os.path.expanduser",
autospec=True)
+ @mock.patch("airflow.cli.commands.info_command.getuser", autospec=True)
+ def test_should_leave_scheme_out_of_path_masking(
+ self, mock_getuser, mock_expanduser, username, home, before, after
+ ):
+ # The scheme of a netloc-less URL must stay out of reach of the
unanchored
+ # username substitution: a user named "lite" must not turn "sqlite:"
into
+ # "sq${USER}:". Anything before the first colon is exempt from masking,
+ # which also keeps non-URL fallback values like "NOT AVAILABLE" intact.
+ mock_getuser.return_value = username
+ mock_expanduser.return_value = home
+ assert after == info_command.PiiAnonymizer().process_url(before)
+
class TestAirflowInfo:
@classmethod