Skip to content

Redact sensitive env vars in exectools command logging#2694

Merged
openshift-merge-bot[bot] merged 1 commit intoopenshift-eng:mainfrom
ashwindasr:redact-secrets-in-exectools-logging
Apr 1, 2026
Merged

Redact sensitive env vars in exectools command logging#2694
openshift-merge-bot[bot] merged 1 commit intoopenshift-eng:mainfrom
ashwindasr:redact-secrets-in-exectools-logging

Conversation

@ashwindasr
Copy link
Copy Markdown
Contributor

Summary

  • cmd_gather in exectools.py logs the entire set_env dict, which leaks secrets like GIT_PASSWORD (GitHub App installation tokens ghs_*) into Jenkins build logs
  • Add _redact_env_for_logging() helper that replaces values of env vars whose names contain PASSWORD, TOKEN, SECRET, KEY, or CREDENTIAL with ***REDACTED***
  • This was discovered during integration testing of PR ART-14700: Upgrade PyGithub to 2.x and add GitHub App authentication support #2587 (PyGithub 2.x upgrade) -- the gen-assembly build Add e2e tests for scos okd #1092 logs showed the full GIT_PASSWORD value in plaintext

Test plan

  • Unit tests for _redact_env_for_logging covering sensitive keys, non-sensitive keys, case insensitivity, and empty dict
  • Integration test: cmd_gather with a secret env var verifies the secret does not appear in log output
  • All 21 tests in test_exectools.py pass
  • ruff check and ruff format pass

Made with Cursor

cmd_gather logs the full set_env dict, which leaks secrets like
GIT_PASSWORD (GitHub App installation tokens) into Jenkins build logs.
Add _redact_env_for_logging() to replace values of env vars whose names
contain PASSWORD, TOKEN, SECRET, KEY, or CREDENTIAL with ***REDACTED***.

Made-with: Cursor
Entire-Checkpoint: d8832137af58

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 1, 2026

Walkthrough

This change introduces environment variable redaction for logging purposes. A new internal function detects environment variable keys matching sensitive patterns (passwords, tokens, secrets, credentials) and replaces their logged values with ***REDACTED***. The cmd_gather function now logs a sanitized representation of environment variables while preserving the actual environment update behavior.

Changes

Cohort / File(s) Summary
Environment Redaction Implementation
artcommon/artcommonlib/exectools.py
Added _SENSITIVE_ENV_KEY_PATTERNS constant and _redact_env_for_logging() helper function to detect and redact sensitive environment variable keys in logs. Updated cmd_gather to include a redacted representation of set_env in the logged cmd_info string.
Environment Redaction Tests
artcommon/tests/test_exectools.py
Added TestRedactEnvForLogging test suite validating case-insensitive pattern matching for sensitive keys (password, token, secret, key, credential patterns), preservation of non-sensitive values (e.g., GIT_* vars), and empty dict handling. Added integration test verifying cmd_gather logging excludes raw secrets and includes the redaction marker.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
artcommon/artcommonlib/exectools.py (1)

39-48: Consider boundary-based key matching to reduce over-redaction noise

Current substring matching ("KEY" in key) can redact unrelated env vars (e.g., names containing MONKEY), which may reduce debugging value. A boundary-aware regex keeps the security intent while limiting accidental matches.

Optional refinement
+import re
@@
-_SENSITIVE_ENV_KEY_PATTERNS = frozenset({'PASSWORD', 'TOKEN', 'SECRET', 'KEY', 'CREDENTIAL'})
+_SENSITIVE_ENV_KEY_RE = re.compile(
+    r'(^|_)(PASSWORD|TOKEN|SECRET|CREDENTIAL|KEY)(_|$)', re.IGNORECASE
+)
@@
 def _redact_env_for_logging(env_dict: Dict[str, str]) -> Dict[str, str]:
     """Return a copy of env_dict with values redacted for keys that look secret."""
-    upper_key_cache = {k: k.upper() for k in env_dict}
     return {
-        k: '***REDACTED***' if any(p in upper_key_cache[k] for p in _SENSITIVE_ENV_KEY_PATTERNS) else v
+        k: '***REDACTED***' if _SENSITIVE_ENV_KEY_RE.search(k) else v
         for k, v in env_dict.items()
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@artcommon/artcommonlib/exectools.py` around lines 39 - 48, The current
_redact_env_for_logging uses simple substring checks against
_SENSITIVE_ENV_KEY_PATTERNS which over-redacts keys like MONKEY; change the
matching to boundary-aware checks by building regexes for each pattern (e.g.,
word or underscore boundaries) and testing the upper-cased key with those
regexes instead of "any(p in upper_key_cache[k])"; update the logic inside
_redact_env_for_logging (which uses upper_key_cache and iterates
env_dict.items()) to compile or reuse these boundary-aware patterns and only
redact when a pattern match is found.
artcommon/tests/test_exectools.py (1)

304-306: Use neutral test token literals to avoid secret-scanner noise

secret_val and a realistic token-like value can trigger false positives in some security scanners. Consider using a neutral placeholder to keep scans cleaner.

Optional test-only tweak
-        secret_val = "ghs_SuperSecretToken123"
-        env = {"GIT_PASSWORD": secret_val, "GIT_ASKPASS": "/tmp/askpass.sh"}
+        test_token = "dummy-token-value"
+        env = {"GIT_PASSWORD": test_token, "GIT_ASKPASS": "/tmp/askpass.sh"}
@@
-                self.assertNotIn(secret_val, log_text)
+                self.assertNotIn(test_token, log_text)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@artcommon/tests/test_exectools.py` around lines 304 - 306, The test uses a
realistic token string in the secret_val variable which can trigger secret
scanners; replace secret_val (and any direct realistic token literals) with a
neutral placeholder like "TEST_GIT_TOKEN" or "neutral-token" and keep the env
mapping to "GIT_PASSWORD": secret_val (the code around secret_val and env and
the test that patches subprocess.Popen should be updated). Ensure you update any
similar test literals in this file (e.g., other uses of secret_val or realistic
token-like strings) to the neutral placeholder to avoid scanner false positives.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@artcommon/artcommonlib/exectools.py`:
- Around line 39-48: The current _redact_env_for_logging uses simple substring
checks against _SENSITIVE_ENV_KEY_PATTERNS which over-redacts keys like MONKEY;
change the matching to boundary-aware checks by building regexes for each
pattern (e.g., word or underscore boundaries) and testing the upper-cased key
with those regexes instead of "any(p in upper_key_cache[k])"; update the logic
inside _redact_env_for_logging (which uses upper_key_cache and iterates
env_dict.items()) to compile or reuse these boundary-aware patterns and only
redact when a pattern match is found.

In `@artcommon/tests/test_exectools.py`:
- Around line 304-306: The test uses a realistic token string in the secret_val
variable which can trigger secret scanners; replace secret_val (and any direct
realistic token literals) with a neutral placeholder like "TEST_GIT_TOKEN" or
"neutral-token" and keep the env mapping to "GIT_PASSWORD": secret_val (the code
around secret_val and env and the test that patches subprocess.Popen should be
updated). Ensure you update any similar test literals in this file (e.g., other
uses of secret_val or realistic token-like strings) to the neutral placeholder
to avoid scanner false positives.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5f009f8c-fe2b-4b34-abd3-757dd307e33a

📥 Commits

Reviewing files that changed from the base of the PR and between 69878f0 and 1d3cb9a.

📒 Files selected for processing (2)
  • artcommon/artcommonlib/exectools.py
  • artcommon/tests/test_exectools.py

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Apr 1, 2026

@ashwindasr: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/security 1d3cb9a link false /test security

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@pruan-rht
Copy link
Copy Markdown
Contributor

/lgtm
/approve

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Apr 1, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Apr 1, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: pruan-rht

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Apr 1, 2026
@openshift-merge-bot openshift-merge-bot bot merged commit 4a87e96 into openshift-eng:main Apr 1, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants