Skip to content

fix(x2a): Fix/policy lock token leak#2636

Open
elai-shalev wants to merge 2 commits intoredhat-developer:mainfrom
elai-shalev:fix/policy-lock-token-leak
Open

fix(x2a): Fix/policy lock token leak#2636
elai-shalev wants to merge 2 commits intoredhat-developer:mainfrom
elai-shalev:fix/policy-lock-token-leak

Conversation

@elai-shalev
Copy link
Copy Markdown
Contributor

This PR will remove the generic copy command that includes the policy.lock.json in the commited code to the target repo, and will improve the sanitization.

@rhdh-qodo-merge
Copy link
Copy Markdown

Review Summary by Qodo

Fix SCM token leak in Policyfile.lock.json copying

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Prevent Policyfile.lock.json token leak by removing wildcard JSON copy
• Replace generic JSON copy with specific metadata file only
• Improve URL credential sanitization regex pattern
• Remove JSON copying from analyze and convert phases
Diagram
flowchart LR
  A["Wildcard JSON copy<br/>*.json"] -->|Remove| B["Specific file copy<br/>generated-project-metadata.json"]
  C["Generic regex<br/>token@host"] -->|Improve| D["Enhanced regex<br/>credentials sanitization"]
  E["Init/Analyze/Convert<br/>phases"] -->|Update| F["Secure file handling"]
Loading

Grey Divider

File Changes

1. workspaces/x2a/plugins/x2a-backend/templates/x2a-job-script.sh 🐞 Bug fix +5/-7

Prevent token leak and improve credential sanitization

• Improved URL credential sanitization regex by removing unnecessary colon character class
• Updated comment to reflect broader credential stripping capability
• Replaced wildcard *.json copy with specific generated-project-metadata.json in init phase
• Removed *.json wildcard copy from analyze phase to prevent Policyfile.lock.json leak
• Removed *.json wildcard copy from convert phase for consistency

workspaces/x2a/plugins/x2a-backend/templates/x2a-job-script.sh


2. workspaces/x2a/.changeset/fix-policy-lock-token-leak.md 📝 Documentation +5/-0

Changeset for policy lock token leak fix

• Added changeset entry documenting the security fix
• Describes prevention of SCM token leak in Policyfile.lock.json
• Notes improvement to URL credential sanitization

workspaces/x2a/.changeset/fix-policy-lock-token-leak.md


Grey Divider

Qodo Logo

@rhdh-qodo-merge
Copy link
Copy Markdown

rhdh-qodo-merge bot commented Mar 29, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Metadata read can fail 🐞 Bug ⛯ Reliability
Description
In the init phase, the script suppresses errors when copying generated-project-metadata.json but
then unconditionally reads it with cat under set -e, which will terminate the job if the file
wasn’t produced and prevent artifact reporting. This contradicts the backend behavior, which
explicitly supports init success without any project_metadata artifact.
Code

workspaces/x2a/plugins/x2a-backend/templates/x2a-job-script.sh[R238-239]

+    # Copy generated metadata (only specific files — avoid copying Chef artifacts like Policyfile.lock.json)
+    cp -v "${SOURCE_BASE}/generated-project-metadata.json" "${PROJECT_PATH}/" 2>/dev/null || true
Evidence
The init phase copies generated-project-metadata.json with || true (making it optional), but
immediately reads it unguarded; with set -e, a missing file will exit the script. The backend’s
init phase action and tests show project_metadata is optional (phase action returns early if
absent), so the job script should not hard-fail when it’s missing.

workspaces/x2a/plugins/x2a-backend/templates/x2a-job-script.sh[1-2]
workspaces/x2a/plugins/x2a-backend/templates/x2a-job-script.sh[234-256]
workspaces/x2a/plugins/x2a-backend/src/router/phaseActions.ts[43-50]
workspaces/x2a/plugins/x2a-backend/src/router/collectArtifactsActions.test.ts[174-209]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`x2a-job-script.sh` treats `generated-project-metadata.json` as optional (copy errors suppressed) but then unconditionally reads it with `cat` while the script is running with `set -e`. If the file is absent, the init phase exits and the job can’t report artifacts.

### Issue Context
The backend explicitly supports init success without any `project_metadata` artifact (phase action is skipped when the artifact is missing), so the job script should either (a) only add the artifact when the file exists, or (b) make the metadata file required and fail with a clear error message (and remove `|| true`).

### Fix Focus Areas
- workspaces/x2a/plugins/x2a-backend/templates/x2a-job-script.sh[234-256]

### Suggested change (behavior: optional)
- After copying, check `-f "${PROJECT_PATH}/generated-project-metadata.json"`.
- Only then `cat` it and append `ARTIFACTS+=("project_metadata:${METADATA}")`.
- Otherwise, log that metadata wasn’t produced and continue (still report migration_plan).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Sanitizer forces HTTPS scheme 🐞 Bug ✓ Correctness
Description
sanitize_secrets replaces credentialed URLs matched by https?://...@ with a hard-coded https://,
so http://user:token@host/... becomes https://host/.... This changes content semantics beyond
secret removal and can break outputs that intentionally use plain HTTP.
Code

workspaces/x2a/plugins/x2a-backend/templates/x2a-job-script.sh[R62-64]

+    if grep -qE 'https?://[^@/[:space:]]+@' "$file" 2>/dev/null; then
+      # Strip credentials from URLs: https://user:token@host/... → https://host/...
+      sed -i 's|https\?://[^@/[:space:]]*@|https://|g' "$file"
Evidence
The match allows both http and https (https\?://), but the replacement string is always
https://, which rewrites the scheme when credentials are present.

workspaces/x2a/plugins/x2a-backend/templates/x2a-job-script.sh[59-68]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The sed replacement in `sanitize_secrets` strips userinfo but also rewrites `http://` to `https://` because the replacement is hard-coded.

### Issue Context
The goal is to remove credentials (`user:token@`) while leaving the original URL otherwise intact.

### Fix Focus Areas
- workspaces/x2a/plugins/x2a-backend/templates/x2a-job-script.sh[59-65]

### Suggested change
Use a capture group to preserve the original scheme, e.g. (GNU sed / current style):
- `sed -i 's|\(https\?\)://[^@/[:space:]]*@|\1://|g' "$file"`

This keeps `http` vs `https` while still removing credentials.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@rhdh-gh-app
Copy link
Copy Markdown

rhdh-gh-app bot commented Mar 29, 2026

Changed Packages

Package Name Package Path Changeset Bump Current Version
@red-hat-developer-hub/backstage-plugin-x2a-backend workspaces/x2a/plugins/x2a-backend patch v1.1.0

@elai-shalev
Copy link
Copy Markdown
Contributor Author

@mareklibra

@sonarqubecloud
Copy link
Copy Markdown

Comment on lines +238 to +239
# Copy generated metadata (only specific files — avoid copying Chef artifacts like Policyfile.lock.json)
cp -v "${SOURCE_BASE}/generated-project-metadata.json" "${PROJECT_PATH}/" 2>/dev/null || true
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Metadata read can fail 🐞 Bug ⛯ Reliability

In the init phase, the script suppresses errors when copying generated-project-metadata.json but
then unconditionally reads it with cat under set -e, which will terminate the job if the file
wasn’t produced and prevent artifact reporting. This contradicts the backend behavior, which
explicitly supports init success without any project_metadata artifact.
Agent Prompt
### Issue description
`x2a-job-script.sh` treats `generated-project-metadata.json` as optional (copy errors suppressed) but then unconditionally reads it with `cat` while the script is running with `set -e`. If the file is absent, the init phase exits and the job can’t report artifacts.

### Issue Context
The backend explicitly supports init success without any `project_metadata` artifact (phase action is skipped when the artifact is missing), so the job script should either (a) only add the artifact when the file exists, or (b) make the metadata file required and fail with a clear error message (and remove `|| true`).

### Fix Focus Areas
- workspaces/x2a/plugins/x2a-backend/templates/x2a-job-script.sh[234-256]

### Suggested change (behavior: optional)
- After copying, check `-f "${PROJECT_PATH}/generated-project-metadata.json"`.
- Only then `cat` it and append `ARTIFACTS+=("project_metadata:${METADATA}")`.
- Otherwise, log that metadata wasn’t produced and continue (still report migration_plan).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

# Note: x2a tool produces migration-plan-{module_name}.md (spaces replaced with underscores)
echo "Copying output to ${OUTPUT_DIR}/"
cp -v "${SOURCE_BASE}/migration-plan-${MODULE_NAME_SANITIZED}.md" "${OUTPUT_DIR}/"
cp -v "${SOURCE_BASE}"/*.json "${OUTPUT_DIR}/" 2>/dev/null || true
Copy link
Copy Markdown
Contributor

@eloycoto eloycoto Mar 29, 2026

Choose a reason for hiding this comment

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

wait, these files are important, and we don't have here migration-dependencies when we should!

When migration cache, we are referencing all inside the migration-dependencies, inside the migration-plan-module, and we should be able to analyze that files to write the ansible code correctly.

This file is the main lock file for when we donwload all the vendor dependencies when we used, and it's our "DNS" for the dependencies.

Without this folder, and the json files we shouldn't be able to do the right on cache, because cache to_ansible will try to read files that are not in there

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Were still copying the ""${SOURCE_BASE}/generated-project-metadata.json" file, which has the needed metadata
I've just ommitted the Policyfile.lock.json and the solo.json

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.

both files are needed, also the migration_dependencies which are referenced on migration-plan-cache.md

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

ok, I'll revert the changes and add more guards around sanitization all of the committed files.

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.

2 participants