Skip to content

fix: scrub secret values from CI log artifacts before upload - #488

Merged
mergify[bot] merged 3 commits into
opendatahub-io:mainfrom
nathan-weinberg:RHAIENG-5624
Jul 13, 2026
Merged

fix: scrub secret values from CI log artifacts before upload#488
mergify[bot] merged 3 commits into
opendatahub-io:mainfrom
nathan-weinberg:RHAIENG-5624

Conversation

@nathan-weinberg

@nathan-weinberg nathan-weinberg commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add a defense-in-depth scrub step to the CI workflow that replaces actual secret env-var values with ***REDACTED*** in all log files before the upload-artifact step
  • Add a check-secret-scrub pre-commit hook that ensures the scrub list stays in sync with smoke.sh — greps for secret-looking env vars (KEY, TOKEN, PASSWORD, SECRET, CREDENTIAL) passed to the container and fails if any are missing from the workflow's scrub list

Test plan

  • pre-commit run check-secret-scrub --all-files passes
  • Temporarily removing a var from the scrub list causes the hook to fail with a clear error message
  • CI run uploads log artifacts with redacted values

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added automatic redaction of sensitive values from generated log and test-result artifacts before they’re uploaded.
    • Introduced CI secret-scrubbing steps across multiple response-test workflows.
    • Added a pre-commit hook to validate consistency between local smoke-test secret inputs and CI scrubbing configuration.
  • Bug Fixes

    • Reduced the risk of accidentally exposing tokens, passwords, credentials, and related secret values in uploaded artifacts.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@nathan-weinberg, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 6 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 075c3cd7-7e56-4ad1-8a92-c0fe9395da70

📥 Commits

Reviewing files that changed from the base of the PR and between c66076f and dfd9265.

📒 Files selected for processing (7)
  • .github/workflows/redhat-distro-container.yml
  • .github/workflows/responses-openai.yml
  • .github/workflows/responses-vertexai.yml
  • .github/workflows/responses-vllm-maas.yml
  • .pre-commit-config.yaml
  • tests/check_secret_scrub_list.sh
  • tests/scrub_secrets.sh
📝 Walkthrough

Walkthrough

Adds tests/scrub_secrets.sh for file-based secret redaction, then invokes it from four GitHub Actions workflows before artifact upload. Adds tests/check_secret_scrub_list.sh and a check-secret-scrub pre-commit hook to compare secret-like variables in tests/smoke.sh with the redaction list used by .github/workflows/redhat-distro-container.yml. Also refreshes pinned distribution dependencies and hashes. These changes address secret exposure in logs and artifacts (CWE-532).

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 8 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Contribution Quality And Spam Detection ⚠️ Warning FAIL: rigid AI/template PR body and a broken scrubber (CWE-20) uses sys.argv[0], so it globs "-c" and redacts nothing. Rewrite the PR description to be repository-specific, fix tests/scrub_secrets.sh to read the glob from sys.argv[1], and add a test proving redaction works.
No Sensitive Data In Logs ⚠️ Warning CWE-532: scrub_secrets.sh uses sys.argv[0] under python3 -c, so the glob is -c and no log files are redacted before artifact upload. Change the helper to read the glob from sys.argv[1] (or pass args via python3 - "$glob" ...) and add a test proving uploaded logs are scrubbed.
✅ Passed checks (8 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title matches the main change: adding secret-scrubbing before CI artifact upload.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No Hardcoded Secrets ✅ Passed No hardcoded secrets found in added lines; only GitHub secret references/env names and non-secret hashes/SHAs. CWE-798 not triggered.
No Weak Cryptography ✅ Passed PASS: Touched files contain no banned primitives, roll-your-own crypto, or secret-value compares; only exact-string redaction and name checks (CWE-327/CWE-208).
No Injection Vectors ✅ Passed PASS: no CWE-89/78/94/502/79 patterns found; new shell/Python/YAML paths use hardcoded globs and trusted env names only.
No Privileged Containers ✅ Passed No changed manifests/Dockerfiles; the new workflow step only scrubs logs, and no privileged/root settings (CWE-250/CWE-732) appear in touched files.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@mergify

mergify Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

⚠️ The sha of the head commit of this PR conflicts with #487. Mergify cannot evaluate rules on this PR. Once #487 is merged or closed, Mergify will resume processing this PR. ⚠️

@nathan-weinberg
nathan-weinberg requested a review from a team July 7, 2026 13:34
Comment thread tests/check_secret_scrub_list.sh
@nathan-weinberg
nathan-weinberg requested review from a team and derekhiggins July 7, 2026 17:29

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
.github/workflows/responses-vllm-maas.yml (1)

139-158: 🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Same ordering issue: scrub runs after test-report publish.

dorny/test-reporter (139-147) publishes the raw XML to the Checks UI before the scrub step (149-158) redacts VLLM_API_TOKEN/VLLM_EMBEDDING_API_TOKEN/TAVILY_SEARCH_API_KEY. Secrets embedded in captured pytest output are already exposed by the time redaction runs.

Reorder so scrubbing precedes "Publish test report" for consistency with the other two responses workflows.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/responses-vllm-maas.yml around lines 139 - 158, The
workflow order in the test results section is wrong: `dorny/test-reporter`
publishes raw XML before `scrub_secrets.sh` redacts sensitive values. Move the
“Scrub secrets from test results” step to run before “Publish test report” in
the responses-vllm-maas workflow, keeping the same secret env vars and
test-results path so the redacted XML is what `test-reporter` consumes.
.github/workflows/responses-vertexai.yml (1)

151-169: 🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Same ordering issue: scrub runs after test-report publish.

dorny/test-reporter (151-159) consumes the raw XML before the scrub step (161-169) redacts VERTEX_AI_PROJECT/TAVILY_SEARCH_API_KEY. Any secret leaked into captured pytest output is already exposed in the Checks UI before redaction occurs.

Reorder so the scrub step precedes "Publish test report".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/responses-vertexai.yml around lines 151 - 169, The
workflow order in the test-results publishing section is wrong: the raw XML is
sent to dorny/test-reporter in Publish test report before Scrub secrets from
test results runs. Move the Scrub secrets from test results step so it executes
first, then publish the report afterward, keeping the existing step names and
the same secret-redaction inputs for VERTEX_AI_PROJECT and
TAVILY_SEARCH_API_KEY.
.github/workflows/responses-openai.yml (1)

135-153: 🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Scrub step runs after the test report is already published — too late to prevent UI exposure.

dorny/test-reporter (135-143) reads /tmp/test-results/*.xml and renders it in the Checks UI before the new scrub step (145-153) redacts secrets from those same files. If OPENAI_API_KEY/TAVILY_SEARCH_API_KEY end up in captured stdout/tracebacks (verbose pytest -s -v), they're exposed in the PR checks tab regardless of the later file-level scrub (CWE-532).

Move the scrub step before "Publish test report" so redaction happens prior to any consumption of the file content.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/responses-openai.yml around lines 135 - 153, The test
results are being published before secrets are scrubbed, so sensitive values can
still appear in the Checks UI. Move the Scrub secrets from test results step to
run before the Publish test report step in the workflow, ensuring the
/tmp/test-results files are redacted before dorny/test-reporter reads them; keep
the existing scrub script and secret env names, and preserve the report step’s
current behavior afterward.
🧹 Nitpick comments (1)
tests/check_secret_scrub_list.sh (1)

24-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

grep -A10 window is brittle.

If the scrub_secrets.sh invocation's argument list in the workflow grows beyond 10 lines, later var names will silently drop out of scrub_vars, weakening the drift check without any visible failure.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/check_secret_scrub_list.sh` around lines 24 - 27, The secret variable
extraction in check_secret_scrub_list.sh is using a fixed grep -A10 window
around the scrub_secrets.sh invocation, which can miss variables if the workflow
arguments expand. Update the logic in the scrub_vars pipeline to avoid relying
on a hardcoded line window and instead parse the full relevant scrub_secrets.sh
block so all referenced uppercase secret vars are captured consistently, even as
the workflow changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/scrub_secrets.sh`:
- Around line 29-38: The scrub step in scrub_secrets.sh currently only skips
IsADirectoryError, so any other read/write failure can stop redaction partway
through while later upload-artifact steps still proceed. Update the scrub
workflow to fail fast on any per-file scrub error, and make the artifact upload
condition depend on scrub success instead of only using always()/!cancelled(),
referencing the scrub logic in scrub_secrets.sh and the upload-artifact steps in
the workflow.

---

Outside diff comments:
In @.github/workflows/responses-openai.yml:
- Around line 135-153: The test results are being published before secrets are
scrubbed, so sensitive values can still appear in the Checks UI. Move the Scrub
secrets from test results step to run before the Publish test report step in the
workflow, ensuring the /tmp/test-results files are redacted before
dorny/test-reporter reads them; keep the existing scrub script and secret env
names, and preserve the report step’s current behavior afterward.

In @.github/workflows/responses-vertexai.yml:
- Around line 151-169: The workflow order in the test-results publishing section
is wrong: the raw XML is sent to dorny/test-reporter in Publish test report
before Scrub secrets from test results runs. Move the Scrub secrets from test
results step so it executes first, then publish the report afterward, keeping
the existing step names and the same secret-redaction inputs for
VERTEX_AI_PROJECT and TAVILY_SEARCH_API_KEY.

In @.github/workflows/responses-vllm-maas.yml:
- Around line 139-158: The workflow order in the test results section is wrong:
`dorny/test-reporter` publishes raw XML before `scrub_secrets.sh` redacts
sensitive values. Move the “Scrub secrets from test results” step to run before
“Publish test report” in the responses-vllm-maas workflow, keeping the same
secret env vars and test-results path so the redacted XML is what
`test-reporter` consumes.

---

Nitpick comments:
In `@tests/check_secret_scrub_list.sh`:
- Around line 24-27: The secret variable extraction in
check_secret_scrub_list.sh is using a fixed grep -A10 window around the
scrub_secrets.sh invocation, which can miss variables if the workflow arguments
expand. Update the logic in the scrub_vars pipeline to avoid relying on a
hardcoded line window and instead parse the full relevant scrub_secrets.sh block
so all referenced uppercase secret vars are captured consistently, even as the
workflow changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 8c2e625a-1da9-4ade-8482-dc310431dc26

📥 Commits

Reviewing files that changed from the base of the PR and between dcb4901 and 0499783.

📒 Files selected for processing (7)
  • .github/workflows/redhat-distro-container.yml
  • .github/workflows/responses-openai.yml
  • .github/workflows/responses-vertexai.yml
  • .github/workflows/responses-vllm-maas.yml
  • .pre-commit-config.yaml
  • tests/check_secret_scrub_list.sh
  • tests/scrub_secrets.sh

Comment thread tests/scrub_secrets.sh
Comment on lines +29 to +38
for f in glob.glob(sys.argv[0]):
try:
with open(f, 'r', errors='replace') as fh:
content = fh.read()
for s in secrets:
content = content.replace(s, '***REDACTED***')
with open(f, 'w') as fh:
fh.write(content)
except IsADirectoryError:
pass

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

git ls-files | rg -n 'scrub_secrets\.sh|artifact|upload|workflow|\.yml$|\.yaml$'

Repository: opendatahub-io/ogx-distribution

Length of output: 1318


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the scrub script and workflow callers, then inspect relevant snippets.
git ls-files | rg '(^|/)tests/scrub_secrets\.sh$|(^|/)\.github/workflows/.*\.(yml|yaml)$'

printf '\n--- scrub_secrets.sh ---\n'
wc -l tests/scrub_secrets.sh
cat -n tests/scrub_secrets.sh

printf '\n--- workflow references ---\n'
rg -n 'scrub_secrets\.sh|upload-artifact|if:\s*(always\(\)|!\s*cancelled\(\))' .github/workflows tests -g '*.yml' -g '*.yaml' -g '*.sh'

Repository: opendatahub-io/ogx-distribution

Length of output: 4831


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the exact workflow steps around the scrub and upload actions.
rg -n -A4 -B6 'scrub_secrets\.sh|upload-artifact|if:\s*(always\(\)|!\s*cancelled\(\))' .github/workflows -g '*.yml' -g '*.yaml'

Repository: opendatahub-io/ogx-distribution

Length of output: 18461


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- tests/scrub_secrets.sh ---'
cat -n tests/scrub_secrets.sh

printf '\n%s\n' '--- workflow upload gates ---'
rg -n -A3 -B6 'scrub_secrets\.sh|upload-artifact|if:\s*(always\(\)|!\s*cancelled\(\))' .github/workflows -g '*.yml' -g '*.yaml'

Repository: opendatahub-io/ogx-distribution

Length of output: 18310


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- tests/scrub_secrets.sh ---'
nl -ba tests/scrub_secrets.sh | sed -n '1,220p'

echo
echo '--- workflow references ---'
rg -n -A5 -B8 'scrub_secrets\.sh|upload-artifact|if:\s*(always\(\)|!\s*cancelled\(\))' .github/workflows -g '*.yml' -g '*.yaml'

Repository: opendatahub-io/ogx-distribution

Length of output: 240


Failing scrub can still leak secrets in uploaded artifacts (CWE-532/CWE-703).
tests/scrub_secrets.sh only ignores IsADirectoryError; any other per-file I/O failure aborts redaction mid-stream, and the downstream upload-artifact steps still run under if: !cancelled()/always(). Fail the workflow on scrub errors and gate artifact upload on scrub success.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/scrub_secrets.sh` around lines 29 - 38, The scrub step in
scrub_secrets.sh currently only skips IsADirectoryError, so any other read/write
failure can stop redaction partway through while later upload-artifact steps
still proceed. Update the scrub workflow to fail fast on any per-file scrub
error, and make the artifact upload condition depend on scrub success instead of
only using always()/!cancelled(), referencing the scrub logic in
scrub_secrets.sh and the upload-artifact steps in the workflow.

@mergify

mergify Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/check_secret_scrub_list.sh (1)

24-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

grep -A10 may truncate long scrub invocations.

If the scrub_secrets.sh invocation in the workflow lists variables across more than 10 lines, variables beyond that window won't be extracted into scrub_vars, producing false "missing" reports. Consider using grep -A with a larger count or a different delimiter-based approach (e.g., sed between invocation markers).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/check_secret_scrub_list.sh` around lines 24 - 27, Update the scrub_vars
extraction around the scrub_secrets.sh invocation so it captures every
referenced variable, even when the invocation spans more than 10 lines. Replace
the fixed grep -A10 window with a delimiter-based extraction between the
invocation and its end, or use a sufficiently robust range that cannot truncate
valid entries; preserve the existing filtering and sorting behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/check_secret_scrub_list.sh`:
- Around line 24-27: Update the scrub_vars extraction around the
scrub_secrets.sh invocation so it captures every referenced variable, even when
the invocation spans more than 10 lines. Replace the fixed grep -A10 window with
a delimiter-based extraction between the invocation and its end, or use a
sufficiently robust range that cannot truncate valid entries; preserve the
existing filtering and sorting behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 6afaf03e-7c62-48ba-8e2a-e46e48838a61

📥 Commits

Reviewing files that changed from the base of the PR and between b110124 and c66076f.

📒 Files selected for processing (8)
  • .github/workflows/redhat-distro-container.yml
  • .github/workflows/responses-openai.yml
  • .github/workflows/responses-vertexai.yml
  • .github/workflows/responses-vllm-maas.yml
  • .pre-commit-config.yaml
  • distribution/requirements-lock.txt
  • tests/check_secret_scrub_list.sh
  • tests/scrub_secrets.sh
🚧 Files skipped from review as they are similar to previous changes (6)
  • .pre-commit-config.yaml
  • .github/workflows/redhat-distro-container.yml
  • .github/workflows/responses-openai.yml
  • .github/workflows/responses-vllm-maas.yml
  • .github/workflows/responses-vertexai.yml
  • tests/scrub_secrets.sh

nathan-weinberg and others added 3 commits July 13, 2026 16:19
Upstream OGX redacts known field names (api_key, api_token, password)
but any provider whose secret uses a different field name would appear
in plaintext in the uploaded log artifacts. Add a defense-in-depth
scrub step that replaces actual secret env-var values with
***REDACTED*** in all log files before the upload-artifact step.

Also add a pre-commit hook (check-secret-scrub) that ensures the
scrub list stays in sync with smoke.sh — it greps for secret-looking
env vars (KEY, TOKEN, PASSWORD, SECRET, CREDENTIAL) passed to the
container and fails if any are missing from the workflow's scrub list.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Nathan Weinberg <nweinber@redhat.com>
Add scrub steps before upload-artifact in the three responses
workflows (OpenAI, Vertex AI, vLLM MaaS) to match the pattern
in redhat-distro-container.yml.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the inline Python scrubber into tests/scrub_secrets.sh and call it
from all workflows that upload artifacts.  Each workflow passes its own
glob pattern and secret env var names as arguments, eliminating the
duplicated Python snippet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@mergify
mergify Bot merged commit f166d44 into opendatahub-io:main Jul 13, 2026
9 checks passed
@nathan-weinberg
nathan-weinberg deleted the RHAIENG-5624 branch July 13, 2026 20:35
@rhods-ci-bot

Copy link
Copy Markdown

@nathan-weinberg: The following test has Succeeded:

OCI Artifact Browser URL

View in Artifact Browser

Inspecting Test Artifacts Manually

To inspect your test artifacts manually, follow these steps:

  1. Install ORAS (see the ORAS installation guide).
  2. Download artifacts with the following commands:
mkdir -p oras-artifacts
cd oras-artifacts
oras pull quay.io/opendatahub/odh-ci-artifacts:ogx-core-functional-its-krg7q

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants