
From Local Conductor Loops to CI Governance
In two previous deep dives, I explored running code reviews in two distinct domains of the modern software development lifecycle:
• DIY PR Code Reviews with Antigravity CLI in GitHub Actions: In this earlier post, I walked through building automated, stateless pull request code reviews in the outer loop (CI/CD pipeline) using Google Antigravity CLI (run-antigravity-cli). I demonstrated how to leverage Workload Identity Federation and service account impersonation to let an agent inspect incoming PR diffs via the GitHub REST API and post review feedback without needing local checkouts or stored secrets. A small note: I have since updated the code to direct Workload Identity Federation, eliminating the need for service account impersonation.
• Extending Conductor with CodeMender: AI-Powered Threat Modeling and Remediation: In this follow-up article, I shifted security left into the inner loop (the local developer environment). I showed how embedding CodeMender CLI ( cm ) into Conductor’s review phase enabled deep threat modeling, trust boundary exploration, sandboxed proof-of-concept exploit verification, and automated patching ( cm fix ) directly on the engineer’s workstation before code is committed.
In the same Conductor post, I posed a central architectural thesis: catching security defects locally in the inner loop is essential for developer velocity, but robust enterprise governance still demands an unbypassable gatekeeper in the outer loop (CI). No matter how diligent developers are locally, pull request pipelines must independently verify that incoming code changes introduce zero security regressions.
Naturally, the logical next step was: Why not also run CodeMender CLI directly inside GitHub Actions alongside Antigravity CLI?
What’s New in This Blog Post
This post bridges the inner and outer loops by documenting the exact configurations required to run CodeMender CLI in GitHub Actions. Specifically, I cover:
• Auth Reality Check (Direct WIF vs. ADC File Impersonation): Why the pure 1-hop Direct WIF architecture celebrated in the Antigravity CLI post does not work out-of-the-box for CodeMender CLI, and how to use the 2-hop WIF with service account impersonation and physical ADC credentials generation together.
• The CI Sandboxing Dilemma & Path Constriction: Why the Linux namespace and bubblewrap sandboxing highlighted in our Conductor post fails inside CI runners. We dissect how passing relative paths triggers severe 🚫 SANDBOX VIOLATION errors that blind the agent, how I solved it with workspace root declarations and absolute paths, and when it is safe (or unsafe) to disable sandboxing in CI.
• Hardening Cross-Repository PRs Against Fork Abuse: How to safely allow CodeMender scans on open-source fork PRs using pull_request_target without opening your Google Cloud WIF pool to credential exfiltration.
• Operating in Gated Public Preview: How to manage CodeMender CLI’s gated preview status, Artifact Registry distribution, project allowlisting, and automated preflight dry-run validation.
Cloud Authentication Architecture: Direct WIF vs. ADC File
One of the most consequential differences between running Antigravity CLI alone and orchestrating CodeMender CLI in CI lies in how each tool handles Google Cloud authentication.
Antigravity CLI: Stateless 1-Hop Direct Workload Identity Federation
When running Antigravity CLI in consumer repositories, such as in nedtargaryen243870-code/modern-app, I make use of Direct Workload Identity Federation (Direct WIF). Google Cloud IAM permissions are bound directly to the federated external GitHub identity without needing any intermediate service account.
As detailed in modern-app PR #10 (Remove service account email from GCP auth), eliminating the service account compressed the authentication handshake from a traditional 2-hop flow down to a direct 1-hop flow:
• Legacy 2-Hop Impersonation: GitHub OIDC Token → Security Token Service (STS) → IAM Credentials API (impersonating a service account) → Access Google Cloud Agent Platform.
• Direct 1-Hop WIF: GitHub OIDC Token → Security Token Service (STS) → Direct Access to Google Cloud Agent Platform.
By granting roles/aiplatform.user directly to the federated principal set:
principalSet://iam.googleapis.com/projects/<PROJECT_NUM>/locations/global/workloadIdentityPools/<POOL_ID>/attribute.repository/<REPO_OWNER>/<REPO_NAME>
the workflow in .github/workflows/test.yml and consumer repos no longer specifies a service_account parameter in google-github-actions/auth@v3 (formalized in run-antigravity-cli PR #14).
CodeMender CLI: Standard Application Default Credentials (ADC) Requirements
Unlike lightweight API clients, CodeMender CLI ( cm) is an integrated, packaged command-line binary. Under the hood, it utilizes Google Cloud client libraries that expect standard Application Default Credentials (ADC) materialized as a file on disk.
When running CodeMender CLI in CI, attempting to use pure in-memory Direct WIF environment variables causes CodeMender to fail with missing credentials. As resolved in Fork PR #2 (fix: configure ADC credentials file and export GOOGLE_CLOUD_PROJECT) and upstreamed in .github/workflows/test-cm.yml, the auth step must generate a physical credentials file and export environment variables:
# -------------------------------------------------------------------------
# Authenticate to Google Cloud via Workload Identity Federation (OIDC)
# -------------------------------------------------------------------------
- name: Authenticate to Google Cloud (OIDC)
id: gcp-auth
uses: google-github-actions/auth@v3
continue-on-error: ${{ inputs.dry_run == true }}
with:
project_id: ${{ vars.GCP_PROJECT_ID }}
workload_identity_provider: ${{ vars.GCP_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ vars.GCP_SERVICE_ACCOUNT_EMAIL }}
create_credentials_file: true
export_environment_variables: true
Additionally, CodeMender reads project settings from ~/.codemender/config.yaml. The automated setup script (scripts/setup_cm_config.py) writes the required server.project and server.endpoint fields, ensuring CodeMender CLI has full ADC alignment before scanning starts.
The Sandboxing Dilemma: Container Namespaces vs. Ephemeral CI Runners
Sandboxing is a core architectural pillar of autonomous coding agents. When an AI agent executes autonomously on your workstation, you do not want it reading your private SSH keys ( ~/.ssh ), querying sensitive credentials, or tampering with system binaries. CodeMender enforces this locally using Linux unprivileged user namespaces and bubblewrap isolation.
The Relative-Path Constriction Trap
However, running that same sandbox inside GitHub Actions runners created unexpected failures. When my initial CI workflow attempted to scan changed files in a pull request by passing relative paths (e.g., cm find tests/test_workflow_cm.py ) with an empty default project_paths” [] , CodeMender’s internal agent sandbox constricted allowed roots strictly to:
- /home/runner/work/run-antigravity-cli/run-antigravity-cli/tests/test_workflow_cm.py
- /home/runner/.codemender
- /tmp
As the agent reasoned through the test file, it naturally attempted to inspect project imports, configuration helpers in scripts/, and workflow files in .github/. CodeMender intercepted these calls as sandbox violations. Citing the exact log preserved in Fork PR #2 comment #5346219652:
2026–08–20T21:18:02Z [WARN] 🚫 SANDBOX VIOLATION #1: Agent requested path "/home/runner/work/run-antigravity-cli/run-antigravity-cli" - ⛔ blocked (allowed roots: [/home/runner/work/run-antigravity-cli/run-antigravity-cli/tests/test_workflow_cm.py /home/runner/.codemender /tmp])
2026–08–20T21:18:17Z [WARN] 🚫 SANDBOX VIOLATION #2: Agent requested path ".." - ⛔ blocked
2026–08–20T21:18:38Z [WARN] 🚫 SANDBOX VIOLATION #4: Agent requested path "../scripts/setup_cm_config.py" - ⛔ blocked
2026–08–20T21:18:54Z [WARN] 🚫 SANDBOX VIOLATION #5: Agent requested path "../.github/workflows/test-cm.yml" - ⛔ blocked
Because the sandbox roots were too narrow, the agent was blinded to the broader codebase, unable to follow cross-file references or inspect schemas.
The Fix: Explicit Workspace Roots and CI Sandbox Disabling
In run-antigravity-cli PR #12 (fix: disable namespace sandbox in CI and pass absolute paths), I let my coding agent engineer a threefold fix:
- Declared Workspace Roots: Updated scripts/setup_cm_config.py to default project_paths to [“.”], ensuring the entire repository root is registered inside the agent’s allowed boundaries.
- Absolute Path Normalization: Added the –absolute flag to scripts/resolve_pr_files.py, ensuring target paths are fully qualified and never accidentally restrict directory traversal.
- Disabled Namespace Sandbox in CI: Set sandbox.enabled: false in the headless CI configuration.
With these changes, CodeMender executed flawlessly across 5 target files with zero boundary violations, publishing the clean PR #12 Security Scan Report.
In PR #19 feat(ci): adopt CodeMender native find — diff mode with impact analysis, the workflow further evolved to use CodeMender’s native Git diff mode, i.e. cm find . –diff=… –sandbox=false, scanning from the repository root while retaining –sandbox=false. It also produced a clean PR #19 Security Scan Report.
Security Analysis: Why It Is Safe in CI (And When It Isn’t)
Disabling a security sandbox should never be done lightly. Why is it acceptable here?
• Why It Is Safe on GitHub-Hosted Runners: GitHub-hosted runners ( ubuntu-latest ) are ephemeral, isolated virtual machines provisioned on demand and destroyed immediately after job completion. No persistent secrets, credentials, or state linger after the workflow finishes. Furthermore, cm find is a read-only detection scan. It analyzes ASTs, code paths, and data flows to detect flaws without compiling, executing untrusted binaries, or modifying the host filesystem. Combined with short-lived Workload Identity Federation (OIDC) tokens and isolated CI scripts, there are no static credentials for untrusted code to exfiltrate.
• When It Is NOT Safe (Cautionary Scenarios): If your organization operates self-hosted or persistent CI runners that run multiple jobs sequentially, disabling sandboxing is dangerous. A malicious dependency or prompt injection could inspect neighboring repositories or pivot across the runner host. Similarly, if you execute active remediation ( cm verify and cm fix ) or run build scripts on untrusted fork code, namespace or container isolation is mandatory to prevent arbitrary code execution.
Securing Cross-Repository PRs: Preventing Fork Abuse
A recurring vulnerability in CI pipelines involves handling pull requests submitted from external forks. In public open-source projects, anyone can fork the repository, modify code, and open a PR.
Standard GitHub Actions pull_request triggers run in the context of the fork with read-only repository tokens. Crucially, their OIDC tokens possess external repository claims, preventing them from minting Google Cloud WIF credentials for your cloud project. If you switch blindly to pull_request_target to grant WIF access, a malicious contributor could modify workflow steps to exfiltrate tokens or abuse cloud quota.
To resolve this safely, I approved to have my coding agent implement a defense-in-depth architecture in run-antigravity-cli PR #13 and run-antigravity-cli PR #18:
- Dual-Trigger Architecture & Declarative Association Gating: Workflows listen to both pull_request for internal branches and pull_request_target for external forks. Internal PRs and trusted collaborators ( COLLABORATOR, MEMBER, OWNER ) are evaluated natively in GitHub Actions if: expressions before runners are provisioned, avoiding unnecessary credential minting.
- TOCTOU-Resistant Label Gating ( safe-to-test ): External fork PRs from non-collaborators run when an authorized maintainer explicitly attaches the safe-to-test label after reviewing the diff. To eliminate Time-of-Check to Time-of-Use (TOCTOU) exploits, where an attacker pushes malicious code ( synchronize ) after receiving approval, the scan job only triggers on action == ‘labeled’. In addition, an automated remove-stale-approval job immediately revokes the safe-to-test lable upon any subsequent commit push or PR reopen.
- Trusted Script Isolation ( $RUNNER_TEMP ): Under pull_request_target, the workflow YAML executes from the trusted base branch. However, because CodeMender must inspect the actual PR commit ( head.sha ), untrusted workspace code is checked out on the runner. To prevent the runner from executing attacker-tampered helper scripts, the workflow performs a sparse checkout of scripts/ from the trusted base ref into .trusted-ci, and executes all CI tooling ( setup_cm_config.py, resolve_pr_files.py, report_cm_results.py ) strictly from this isolated directory.
The Operational Reality: Gated Public Preview
For teams eager to adopt CodeMender CLI in their CI pipelines today, there is an important operational prerequisite: CodeMender CLI is currently in a Gated Public Preview.

While the CLI binary is distributed via Google Cloud Artifact Registry, invoking the backend scanning and verification services on Google Cloud Agent Platform requires the calling Google Cloud Project to be allowlisted.
To enable teams to build, test, and wire their GitHub Actions workflows before allowlisting is complete, my workflow and scripts provide a built-in preflight mode:
python3 scripts/setup_cm_config.py - project-id "${{ vars.GCP_PROJECT_ID }}" - project-paths "." - sync-workspace
python3 scripts/resolve_pr_files.py - base-ref "${{ github.base_ref }}" - absolute - dry-run
This allows continuous integration teams to validate WIF token issuance, ADC file materialization, configuration generation, and target file resolution without triggering backend permission rejections.
Key Takeaways & Best Practices Checklist
Deploying autonomous AI security reviewers in GitHub Actions bridges the gap between passive code review and proactive defense. Here is the operational checklist for success:
- Choose the Right Auth Model: Use Direct WIF (1-hop) for stateless API tools like Antigravity CLI to eliminate service accounts and keys; use ADC with service account impersonation (2-hop) with create_credentials_file: true for CodeMender CLI.
- Declare Project Roots & Normalize Paths: Avoid relative path constriction by setting project_path: [“.”] and passing fully qualified absolute paths to cm find.
- Evaluate Sandbox Safety: Disabling namespace sandboxing is safe on ephemeral, single-use GitHub-hosted VMs for read-only scans, but must be strictly preserved or containerized on persistent self-hosted runners.
- Protect Against Untrusted Forks: Always gate external PR execution under pull_request_target with manual review guardrails.
- Plan for Preview Allowlisting: Validate your CI pipeline using dry-run preflights while coordinating Google Cloud Project allowlisting for CodeMender CLI access.
Automating Agentic Security Reviews: Running CodeMender CLI in GitHub Actions was originally published in Google Cloud – Community on Medium, where people are continuing the conversation by highlighting and responding to this story.
Source Credit: https://medium.com/google-cloud/automating-agentic-security-reviews-running-codemender-cli-in-github-actions-03ba291ac0a6?source=rss—-e52cf94d98af—4
