Skip to content

feat(pr-generator-core): add environment config parser, command executor, GitHub R…#28435

Open
joneba-google wants to merge 1 commit into
google-gemini:mainfrom
JonE01:pr-generator-utils
Open

feat(pr-generator-core): add environment config parser, command executor, GitHub R…#28435
joneba-google wants to merge 1 commit into
google-gemini:mainfrom
JonE01:pr-generator-utils

Conversation

@joneba-google

@joneba-google joneba-google commented Jul 17, 2026

Copy link
Copy Markdown

Overview

This PR introduces the foundational utility modules and package structure for the Gemini CLI SSR Pipeline. It packages configuration parsing, subprocess execution with structured logging, GitHub v3 REST API client integration, and ANSI preflight test output filtering.
──────

Summary of Changes

1. Package Initialization (init.py)

• Establishes the workflow package definition and documents the core module architecture.

2. Environment Configuration (config.py)

• Environment Parser (config.py): Parses and validates required GCP environment variables (REPO_URL, GIT_TOKEN, FIRESTORE_DOC, FIRESTORE_ID, EXECUTION_ID, GOOGLE_CLOUD_PROJECT, MAX_ATTEMPTS).
• Path Resolution: Dynamically configures temporary PR and evaluation workspace paths (/tmp/pr/, /tmp/eval/).
• Schema Validation (config.py): Ensures FIRESTORE_DOC contains valid JSON and raises structured config.py on failure.

3. Subprocess Execution Utility (command_executor.py)

• Safe Command Runner (command_executor.py): Executes system shell commands, logs execution parameters and working directories, and cleanly captures standard streams.
• Error Handling: Raises command_executor.py with exit codes, stdout, and stderr on command failures.

4. GitHub REST API Client (github_client.py)

• Lightweight REST Integration (github_client.py): Uses standard urllib to avoid heavy external HTTP client dependencies in the container.
• Automated PR Submission (github_client.py): Authenticates using Bearer tokens and submits POST requests to GitHub v3 REST API endpoints (/repos/{owner}/{repo}/pulls), returning the created PR URL.

5. Preflight Test & Lint Output Filter (preflight_filter.py)

• ANSI Sanitization (preflight_filter.py): Removes terminal escape sequences using a module-level precompiled regex constant (_ANSI_ESCAPE_RE).
• Failure Analysis (preflight_filter.py): Analyzes test output traces to selectively bypass known sandbox-level root privilege test failures while flagging unapproved regressions.

@joneba-google
joneba-google requested a review from a team as a code owner July 17, 2026 19:04
@github-actions github-actions Bot added the size/l A large sized PR label Jul 17, 2026
@github-actions

Copy link
Copy Markdown

📊 PR Size: size/L

  • Lines changed: 352
  • Additions: +352
  • Deletions: -0
  • Files changed: 5

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request establishes the foundational infrastructure for the Gemini CLI Issue-to-PR Code Generation Pipeline. It introduces modular utilities for managing environment configurations, executing system commands, interacting with the GitHub API, and filtering test outputs. These components are designed to work within a containerized environment, ensuring reliable orchestration of the code generation and evaluation workflow.

Highlights

  • Package Architecture: Initialized the core workflow package structure for the Gemini CLI Issue-to-PR pipeline.
  • Configuration Management: Implemented a robust configuration parser to handle environment variables, path resolution, and schema validation for Firestore documents.
  • Subprocess Execution: Added a safe command execution utility that captures standard streams and provides structured logging for shell operations.
  • GitHub Integration: Developed a lightweight GitHub REST API client using standard libraries to facilitate automated pull request creation.
  • Preflight Filtering: Introduced an ANSI-sanitization and test-failure analysis module to selectively bypass known sandbox-level test regressions.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces the workflow package for the SSR Agent Orchestrator, adding configuration, command execution, GitHub API integration, and preflight test filtering. The review comments correctly identify several critical issues: a potential remote code execution (RCE) vulnerability from globally trusting workspaces, command injection risks from using shell=True, a missing timeout on GitHub API requests, and brittle regex patterns in the preflight filter that fail to handle monorepo paths and standard Jest/Vitest test summaries.

Comment on lines +55 to +56
os.environ["GEMINI_CLI_WORKSPACE_TRUSTED"] = "true"
os.environ["GEMINI_CLI_TRUST_WORKSPACE"] = "true"

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-high high

Globally setting GEMINI_CLI_WORKSPACE_TRUSTED and GEMINI_CLI_TRUST_WORKSPACE to "true" instructs the Gemini CLI to trust any workspace it runs in. Since this orchestrator is designed to process untrusted pull requests and clone external repositories, trusting the workspace globally allows a malicious pull request to include crafted configuration files or hooks that the Gemini CLI will execute automatically, leading to Remote Code Execution (RCE) within the container.

Suggested change
os.environ["GEMINI_CLI_WORKSPACE_TRUSTED"] = "true"
os.environ["GEMINI_CLI_TRUST_WORKSPACE"] = "true"
# Avoid globally trusting untrusted workspaces to prevent RCE from malicious PRs.

Comment on lines +49 to +57
result = subprocess.run(
cmd,
shell=True,
cwd=cwd,
env=env,
capture_output=True,
text=True,
check=False
)

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-high high

CommandExecutor.run executes shell commands using subprocess.run with shell=True. While this supports shell features, executing commands with untrusted inputs (such as branch names, PR titles, or repository URLs) poses a security risk. Note that untrusted inputs must be sanitized, escaped, and wrapped at the ingestion service layer before being passed to downstream components like this orchestrator, rather than performing sanitization in this downstream orchestration logic. Additionally, consider avoiding shell=True to prevent command injection.

References
  1. Sanitize, escape, and wrap untrusted inputs at the ingestion service layer before publishing to Pub/Sub or passing to downstream components, rather than performing sanitization in the downstream orchestration or prompt construction logic.

"Sending Pull Request creation request for branch: %s", branch_name
)
try:
with urllib.request.urlopen(req) as response:

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.

high

The urllib.request.urlopen call is made without a specified timeout. In a production environment like Cloud Run, network requests without a timeout can block indefinitely if the remote server hangs or experiences high latency. This can lead to resource exhaustion and container hangs.

Please specify a reasonable timeout (e.g., timeout=30) to ensure the request fails fast if the GitHub API is unresponsive.

Suggested change
with urllib.request.urlopen(req) as response:
with urllib.request.urlopen(req, timeout=30) as response:

Comment on lines +48 to +67
# Regex search for failing files of format "FAIL src/..."
failing_files = set(re.findall(r"FAIL\s+(src/[^\s>]+)", clean_output))
logging.info("Analyzing failing test files: %s", failing_files)

allowed_failures = {
"src/utils/sessionCleanup.test.ts",
"src/config/extension-manager-permissions.test.ts",
}

if not failing_files:
logging.info("No failing test files matched.")
return False

# If failures exist that are not inside our allowed list, we cannot ignore
if not failing_files.issubset(allowed_failures):
logging.warning(
"Unapproved test failures detected: %s",
failing_files - allowed_failures,
)
return False

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.

high

In a monorepo structure, test files are typically located within sub-packages (e.g., packages/core/src/... or packages/cli/src/...). The current regex FAIL\s+(src/[^\s>]+) strictly expects the path to start with src/, which will fail to match any test failures when run from the monorepo root. This means allowed failures will not be detected, and the preflight bypass logic will fail.

Additionally, simply filtering out unapproved failures from the matched list can be dangerous if we only match a subset of failures. Instead, we should capture all failing paths and verify that every single one of them ends with one of the allowed failure paths.

        # Regex search for failing files of format "FAIL [path]"
        failing_files = set(re.findall(r"FAIL\s+(\S+)", clean_output))
        logging.info("Analyzing failing test files: %s", failing_files)

        allowed_failures = {
            "src/utils/sessionCleanup.test.ts",
            "src/config/extension-manager-permissions.test.ts",
        }

        if not failing_files:
            logging.info("No failing test files matched.")
            return False

        # If failures exist that are not inside our allowed list, we cannot ignore
        unapproved_failures = {
            f for f in failing_files
            if not any(f.endswith(allowed) for allowed in allowed_failures)
        }
        if unapproved_failures:
            logging.warning(
                "Unapproved test failures detected: %s",
                unapproved_failures,
            )
            return False

return False

# Find total test failure count summary in JEST style output: e.g. "Tests: 3 failed, 4 passed"
match = re.search(r"Tests\s+(\d+)\s+failed", clean_output)

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.

high

The regex Tests\s+(\d+)\s+failed expects whitespace immediately after Tests. However, standard Jest and Vitest test summaries format this as Tests: 3 failed, 4 passed (with a colon :). Because \s does not match a colon, this regex will fail to match standard test summaries, causing the bypass logic to always return False.

Updating the regex to Tests:?\s*(\d+)\s+failed makes the colon optional and robustly handles any whitespace variations.

Suggested change
match = re.search(r"Tests\s+(\d+)\s+failed", clean_output)
match = re.search(r"Tests:?\s*(\d+)\s+failed", clean_output)

@gemini-cli gemini-cli Bot added the status/need-issue Pull requests that need to have an associated issue. label Jul 17, 2026
@joneba-google joneba-google changed the title feat(core): add environment config parser, command executor, GitHub R… feat(pr-generator-core): add environment config parser, command executor, GitHub R… Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/l A large sized PR status/need-issue Pull requests that need to have an associated issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant