Skip to content

Conversation

@galz10
Copy link
Collaborator

@galz10 galz10 commented Aug 18, 2025

TLDR

This PR enhances CI/CD security by splitting the pipeline into two distinct workflows:

  1. Untrusted (ci.yml): Runs on all PRs. It lints, runs unit tests, and builds the code. It has no access to secrets.
  2. Trusted (trusted-ci.yml): Runs only after the untrusted workflow succeeds. It downloads the artifacts built in the first stage and runs integration tests using the necessary secrets.

This separation prevents untrusted code from pull requests from having access to sensitive secrets, mitigating the risk of secret exfiltration.

Dive Deeper

The core of this change is the introduction of a two-stage CI process using workflow_run as a trigger.

  • The existing ci.yml is now the "untrusted" stage. It handles all checks that don't require secrets, such as linting, formatting, type checking, and unit tests. Its final step is to build the project and upload the compiled dist directories as a single artifact.
  • The new trusted-ci.yml workflow acts as the "trusted" stage. It is triggered only upon the successful completion of a ci.yml run associated with a pull request. Instead of checking out the potentially malicious PR code, it checks out the base branch and then downloads the build artifacts from the untrusted stage. These pre-built artifacts are then used to run the integration tests, which require access to GEMINI_API_KEY.

This approach ensures that the environment with access to secrets never directly executes code from the pull request, only the artifacts generated in the sandboxed, secret-less environment.

To enforce that integration tests are never skipped, a step was added to trusted-ci.yml that explicitly fails the workflow if the GEMINI_API_KEY secret is not available. This guarantees that all PRs are fully tested.

Finally, the test job in the trusted workflow is associated with a GitHub Environment named trusted-ci-env. This allows for additional protections, such as requiring manual approval before the job can run, providing an extra layer of security for sensitive operations.

Reviewer Test Plan

  1. Review the workflow files .github/workflows/ci.yml and .github/workflows/trusted-ci.yml.
  2. Confirm that ci.yml does not contain any steps that access secrets.
  3. Confirm that trusted-ci.yml is triggered by workflow_run and not directly by pull_request.
  4. Verify that trusted-ci.yml checks out the base branch and downloads artifacts rather than checking out the PR head.
  5. Create a test pull request and observe the GitHub Actions tab:
    • Ensure the "Gemini CLI CI" workflow runs first.
    • After it succeeds, ensure the "Gemini CLI Trusted CI" workflow is triggered and runs the integration tests.

Testing Matrix

The changes are to the CI/CD pipeline. The existing test suite should pass as before. The primary validation is observing that the GitHub Actions workflows execute correctly.

🍏 🪟 🐧
npm run
npx
Docker
Podman - -
Seatbelt - -

Linked issues / bugs

@galz10 galz10 requested a review from a team as a code owner August 18, 2025 23:14
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Summary of Changes

Hello @galz10, 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 significantly enhances the security of the CI/CD pipeline by implementing a robust two-stage workflow. It separates the build and test processes into an 'untrusted' stage that handles initial code validation without secret access, and a 'trusted' stage that executes sensitive integration tests only after the untrusted stage successfully completes and using pre-built artifacts. This architecture prevents potentially malicious code from directly accessing secrets, thereby mitigating the risk of secret exfiltration and ensuring a more secure development lifecycle.

Highlights

  • Two-Stage CI/CD Pipeline: The core change introduces a two-stage CI/CD pipeline: an 'untrusted' stage (ci.yml) for initial checks without secrets, and a 'trusted' stage (trusted-ci.yml) for integration tests requiring secrets.
  • Untrusted CI Workflow (ci.yml): The untrusted ci.yml workflow now handles linting, formatting, type checking, and unit tests, then builds the project and uploads compiled artifacts. It operates without access to any sensitive secrets.
  • Trusted CI Workflow (trusted-ci.yml): The new trusted trusted-ci.yml workflow is triggered only upon successful completion of ci.yml. It checks out the base branch, downloads artifacts from the untrusted stage, and then runs integration tests using necessary secrets like GEMINI_API_KEY.
  • Integration Test Enforcement: To ensure comprehensive testing, trusted-ci.yml includes a step that explicitly fails the workflow if the GEMINI_API_KEY secret is not available, guaranteeing that integration tests are never inadvertently skipped.
  • GitHub Environment for Trusted Workflow: The test job within the trusted workflow is associated with a GitHub Environment named trusted-ci-env, enabling additional security measures such as requiring manual approval for sensitive operations.
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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

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 issue comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize 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 counter productive. 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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

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.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

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 a two-stage CI/CD pipeline to improve security by isolating integration tests that require secrets. The change in package.json adds a new test:unit script intended for the initial, untrusted workflow. My review has identified a critical issue in the implementation of this new script. The current command will incorrectly trigger the setup for integration tests, which will likely cause the untrusted CI workflow to fail. I have provided a detailed comment with a suggested fix to ensure the pipeline functions as intended.

"build:sandbox": "node scripts/build_sandbox.js --skip-npm-install-build",
"bundle": "npm run generate && node esbuild.config.js && node scripts/copy_bundle_assets.js",
"test": "npm run test --workspaces --if-present",
"test:unit": "vitest run --exclude 'integration-tests/**'",
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The current test:unit command, vitest run --exclude 'integration-tests/**', has a critical flaw. When vitest is run from the project root, it discovers all vitest.config.ts files, including integration-tests/vitest.config.ts.

While --exclude prevents integration tests from running, vitest will still execute the globalSetup script from the integration test configuration (integration-tests/globalSetup.ts). This setup script likely requires secrets that are unavailable in the untrusted CI workflow, which would cause the entire 'untrusted' workflow to fail and block all pull requests.

To fix this, the test:unit script should explicitly run tests for workspaces and scripts without relying on vitest's broad discovery, which incorrectly includes the integration test setup. The suggested change ensures only unit tests are run.

Suggested change
"test:unit": "vitest run --exclude 'integration-tests/**'",
"test:unit": "npm test && npm run test:scripts",

@galz10 galz10 force-pushed the galzahavi/add/secure_cicd branch from 034fec4 to 7388f8a Compare August 18, 2025 23:24
   This commit introduces a more secure and robust CI/CD pipeline by separating
   untrusted and trusted workflow execution.

   Key changes include:

   - Introduced a new `.github/workflows/trusted-ci.yml` workflow for
     secret-dependent integration tests, triggered by `workflow_run` after
     untrusted checks pass in `.github/workflows/ci.yml`.
   - `ci.yml` now focuses on linting, unit tests, and building/uploading
     combined artifacts, without access to sensitive secrets.
   - `trusted-ci.yml` downloads pre-built artifacts, ensuring no direct
     execution of untrusted PR source code in the privileged environment.
   - Added a "Fail if no access to secrets" step in `trusted-ci.yml` to
     enforce integration test execution for all pull requests.
   - Refined job permissions in `trusted-ci.yml` to adhere to the principle
     of least privilege.
   - Added `environment: trusted-ci-env` to the `test` job in `trusted-ci.yml`
     to enable manual approval for sensitive operations (to be configured
     via GitHub Environments).
@galz10 galz10 force-pushed the galzahavi/add/secure_cicd branch from 7388f8a to e95af5b Compare August 18, 2025 23:29
@cornmander
Copy link
Collaborator

Hey, thanks for implementing this. I was actually thinking of doing this in a different way. I was thinking of using an RPC replay library like pollyjs to record RPCs locally and then replay them in CI/CD. This would have a few benefits:

  • forks can run integration tests without making their own secrets
  • tests would be much faster
  • tests would be less flaky

What do you think?

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

Labels

maintainer For Roadmap Items

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Configure CI to reliably run integration tests on PRs from forks

3 participants