DEV Community

Cover image for Injecting AI Agents into CI/CD: Using GitHub Copilot CLI in GitHub Actions for Smart Failures
Ve Sharma
Ve Sharma

Posted on

Injecting AI Agents into CI/CD: Using GitHub Copilot CLI in GitHub Actions for Smart Failures

TL;DR for the Busy Dev

We are used to CI/CD pipelines that fail on syntax errors or failed unit tests. But what about "qualitative" failures? By embedding the GitHub Copilot CLI directly into a GitHub Action, you can build AI Agents that review your code for security, logic, or product specs. If the Agent detects a critical issue, it triggers a programmatic failure, stopping the merge before a human even reviews it.


The holy grail of DevOps is "Shift Left"—catching problems as early as possible. We have mastered this for deterministic issues:

  • Linter: "You missed a semicolon." -> ❌ Fail.
  • Jest: "Expected 200, got 500." -> ❌ Fail.

But we still rely heavily on humans for non-deterministic reviews:

  • "Is this SQL query actually secure?"
  • "Did we update the documentation for this new feature?"
  • "Does this code actually meet the acceptance criteria?"

This article demonstrates how to bridge that gap. We will build a Security Agent that lives in your CI pipeline, scans your code using the Copilot CLI, and fails the build if it finds a critical vulnerability.

The Architecture: How It Works

This isn't just asking ChatGPT to summarize a PR. We are building a closed-loop system:

  1. The Brain: The GitHub Copilot CLI (npm i -g @github/copilot), which creates the intelligence layer.
  2. The Persona: A markdown file (.github/agents/security-reporter.agent.md) that acts as the System Prompt.
  3. The Trigger: A bash script that parses the AI's natural language output for specific "Kill Switch" phrases to determine pass/fail.

Step 1: Defining the Agent (Prompt Engineering)

The most critical part of this workflow isn't the YAML; it's the Prompt Engineering. We need the AI to be a harsh auditor, not a helpful assistant.

We store this prompt in .github/agents/security-reporter.agent.md.
Link to full prompt file here.

---
name: SecurityReportAgent
description: Security Report Agent - Analyzes TypeScript and React code for security vulnerabilities and creates security reports
model: GPT-5.1 (Preview)
---

## Purpose

This agent performs comprehensive security analysis of the Astro, TypeScript code. It identifies security vulnerabilities, assesses risks, and produces detailed security reports without modifying the codebase directly.

## Security Scanning Capabilities

This agent can perform comprehensive security analysis across the full stack:

### Code Analysis

- **SAST (Static Code Analysis)** - Scans TypeScript/React source code for security vulnerabilities
- Identify security vulnerabilities including:
  - SQL Injection risks
  - Cross-Site Scripting (XSS) vulnerabilities
  - Cross-Site Request Forgery (CSRF) issues
  - Authentication and authorization flaws
  - Insecure cryptographic implementations
  - Hardcoded secrets or credentials
  - Path traversal vulnerabilities
  - Insecure deserialization
  - Insufficient input validation
  - Information disclosure risks
  - Missing security headers
  - Dependency vulnerabilities
  - Input validation analysis - review all user input handling
  - Data Encryption - check encryption at rest and in transit
  - Error Handling - ensure errors don't leak sensitive information

### Dependency & Component Analysis

- **SCA (Software Composition Analysis)** - Monitors npm dependencies for known vulnerabilities & CVEs
- **License Scanning** - Identifies licensing risks in open source components
- **Outdated Software Detection** - Flags unmaintained frameworks and end-of-life runtimes
- **Malware Detection** - Checks for malicious packages in supply chain

### Infrastructure & Configuration

- **Secrets Detection** - Finds hardcoded API keys, passwords, certificates
- **Cloud Configuration Review** - Azure Functions and services security posture
- **IaC Scanning** - Analyzes Terraform/CloudFormation/Kubernetes configurations
- **Container Image Scanning** - Scans Azure container images for vulnerabilities

### API & Runtime Security

- **API Security** - Reviews endpoint security and access controls
- **Database Security** - Checks for secure queries and connection practices
- **WebSocket Security** - Validates secure WebSocket implementations
- **File Upload Security** - Reviews secure file handling practices

### Compliance & Best Practices

- OWASP Top 10: Check against latest OWASP security risks
- TypeScript/React Security Guidelines: Verify adherence to Node.js and React security best practices
- Secure coding standards: Validate code follows industry standards
- Dependency scanning: Check for known vulnerabilities in npm dependencies
- Security headers: Verify proper HTTP security headers
- Data privacy: Review GDPR/privacy compliance considerations

### Security Metrics & Reporting

- **Vulnerability Count by Severity** - Critical, High, Medium, Low categorization
- **Code Coverage Analysis** - Security-critical code coverage metrics
- **OWASP Top 10 Mapping** - Maps findings to current OWASP risks
- **CWE Classification** - Uses Common Weakness Enumeration for standardization
- **Risk Score** - Overall security posture assessment
- **Remediation Timeline** - Priority-based fix recommendations

## Report Structure

### Security Assessment Report

1. **Executive Summary**
   - **Security Posture**: [Risk Level] (e.g., HIGH RISK, MEDIUM RISK)
   - **Score**: [0-10]/10
   - **Findings Summary**:
     | Severity | Count |
     | :--- | :--- |
     | Critical | [Count] |
     | High | [Count] |
     | Medium | [Count] |
     | Low | [Count] |
   - Brief overview of the security state.

2. Vulnerability Findings
   For each vulnerability:

- Severity: Critical/High/Medium/Low
- Category: (e.g., Injection, Authentication, etc.)
- Location: File and line number
- Description: What the issue is
- Impact: Potential consequences
- Recommendation: How to fix it
- References: OWASP/CWE/Microsoft docs

3. Security Best Practices Review

- Areas following best practices
- Areas needing improvement
- Configuration recommendations

4. Dependency Analysis

- Vulnerable packages identified
- Recommended updates

5. Action Items

- Prioritized list of fixes needed
- Quick wins vs. complex remediation

6. Intentional Vulnerabilities

- List any critical or high severity findings found in:
  - Any file within the `infra/` directory.
  - Any file path containing the string `legacy-vibe`.
- Mark them as "Intentional - No Action Required".

7. Critical Vulnerability Warning

- Review all CRITICAL severity findings.
- Filter out any findings that are located in the "Intentional Vulnerabilities" paths defined above (files in `infra/` or containing `legacy-vibe/`).
- If there are any REMAINING Critical vulnerabilities after filtering:
  1. List them briefly under a header "### Blocking Critical Vulnerabilities".
  2. Include exactly this message at the end of the report:

THIS ASSESSMENT CONTAINS A CRITICAL VULNERABILITY


- Do not adapt or change this message in any way.
- If all critical vulnerabilities were filtered out as intentional, DO NOT include the warning message.

Enter fullscreen mode Exit fullscreen mode

The "Kill Switch" Logic

LLMs are chatty. To make an LLM compatible with a binary CI/CD environment (Pass/Fail), we need to force it to output a specific "signal" string when things go wrong.

In our prompt, we give it this explicit instruction:

...
7. Critical Vulnerability Warning
- Review all CRITICAL severity findings.
- Filter out any findings that are located in "Intentional Vulnerabilities" paths (e.g., /legacy-vibe).
- If there are any REMAINING Critical vulnerabilities:
  1. List them briefly.
  2. Include exactly this message at the end of the report:

THIS ASSESSMENT CONTAINS A CRITICAL VULNERABILITY

- Do not adapt or change this message in any way.
...
Enter fullscreen mode Exit fullscreen mode

If that string appears in the output, our pipeline dies. If it doesn't, we proceed. This turns natural language into a boolean check.

Step 2: The GitHub Action Workflow

Here is the full implementation. We use actions/setup-node to install the Copilot CLI, pass it the repository context, and capture the output.

Prerequisite: You must create a fine-grained Personal Access Token (PAT) with Copilot Requests: Read permissions and add it to your repo secrets as COPILOT_GITHUB_TOKEN.

name: Security Agent Workflow

on:
  push:
    branches: ["main"]
  pull_request:

jobs:
  security-assessment:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22

      # 1. Install the Intelligence
      - name: Install GitHub Copilot CLI
        run: npm i -g @github/copilot

      # 2. Run the Agent
      - name: Run Security Agent via Copilot CLI
        env:
          COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
          GITHUB_REPOSITORY: ${{ github.repository }}
        run: |
          set -euo pipefail

          # Construct the Prompt
          # We combine the System Prompt (Agent definition) with Dynamic Context
          AGENT_PROMPT=$(cat .github/agents/security-reporter.agent.md)
          PROMPT="$AGENT_PROMPT"
          PROMPT+=$'\n\nContext:\n'
          PROMPT+="- Repository: $GITHUB_REPOSITORY"
          PROMPT+=$'\n\nTask:\n'
          PROMPT+=$"\n- Execute the instructions on the full codebase"
          PROMPT+=$'\n- Generate the security report at /security-reports/security-assessment-report.md'

          # Execute Copilot
          # We use < /dev/null to prevent the CLI from waiting for interactive input
          copilot --prompt "$PROMPT" --allow-all-tools --allow-all-paths < /dev/null

      # 3. Save the Report (Artifacts are forever!)
      - name: Upload security report artifact
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: security-assessment-report-${{ github.run_id }}
          path: security-reports/security-assessment-report.md
          retention-days: 30

      # 4. The Logic Check (The "Smart Fail")
      - name: Check for critical vulnerabilities
        if: always()
        run: |
          set -euo pipefail
          REPORT_PATH="security-reports/security-assessment-report.md"

          if [ ! -f "$REPORT_PATH" ]; then
            echo "No report found. Something went wrong."
            exit 1
          fi

          # The Grep Trap: Looking for the Kill Switch
          if grep -q "THIS ASSESSMENT CONTAINS A CRITICAL VULNERABILITY" "$REPORT_PATH"; then
            echo "❌ CRITICAL VULNERABILITY DETECTED - Workflow failed"
            echo "The security assessment found critical vulnerabilities that must be addressed."
            exit 1 # This breaks the build!
          else
            echo "✅ No critical vulnerabilities detected"
          fi
Enter fullscreen mode Exit fullscreen mode

The "Aha!" Moment: Watching it Fail

In my demo repo (which you can find here), I have an intentionally vulnerable file apps/contoso-web-app/app/api/legacy-vibe/route.ts containing a raw SQL query (SQL Injection).

When the action runs, the Agent:

  1. Scans the file.
  2. Identifies db.query("SELECT * FROM users WHERE id = " + id) as a Critical Risk.
  3. Writes the report.
  4. Appends THIS ASSESSMENT CONTAINS A CRITICAL VULNERABILITY.

The final step of the GitHub Action sees that string and exits with code 1. The PR is blocked.

Security-reporter-agent-failing

Here's the summarized report from the Security Reporter Agent right in the Github Action.
detailed-report

Expanding the Horizon: Other Use Cases

Once you have this "Agent Runner" pattern established, you can apply it to almost any qualitative check.

1. The "Acceptance Criteria" Guard

Imagine a workflow that reads your PR description and the linked Jira ticket/Issue.

  • Prompt: "Compare the code changes against the acceptance criteria in the Issue. If the code misses a criterion, output MISSING_REQUIREMENTS."
  • Benefit: Prevents developers from merging code that works technically but misses the product goal.

2. The Documentation Enforcer

  • Prompt: "Analyze the changes in src/. Check if README.md or docs/ have been updated to reflect these changes. If new features are added without docs, output MISSING_DOCS."
  • Benefit: Keeps your documentation from drifting away from reality.

dev-wow-meme

The Reality Check: Pros vs. Cons

This is bleeding-edge territory ("Agentic DevOps"). It is powerful, but you must know the trade-offs.

✅ The Pros

  • Contextual Understanding: Unlike a regex search for password =, an Agent understands that const apiKey = process.env.KEY is safe, but const apiKey = "12345" is not.
  • Reduced Review Fatigue: It handles the tedious "first pass" of a code review, letting humans focus on architecture and complexity.
  • Educational: The generated reports explain why something is wrong, teaching junior devs as they commit.

❌ The Cons

  • Non-Determinism: LLMs are probabilistic. Occasionally, the Agent might miss something it caught yesterday, or flag a false positive. You need mechanisms (like the "Intentional Vulnerabilities" filter in my prompt) to handle this.
  • Latency & Cost: A full repo scan via LLM takes significantly longer than a linter (minutes vs seconds). This is best used on PRs, not on every local commit.
  • Hallucinations: The Agent might claim a library is deprecated when it isn't. Human oversight is still required to verify the failure.

Final Thoughts

cover-image

We are entering an era where CI/CD pipelines don't just compile code - they understand it.

By using the GitHub Copilot CLI in your Actions, you can create a layer of defense that thinks like a senior engineer but runs automatically like a unit test. Start with a Security Agent, refine your prompts, and see what else you can automate.


I’m Ve Sharma, a Solution Engineer at Microsoft focusing on Cloud & AI working on GitHub Copilot. I help developers become AI-native developers and optimize the SDLC for teams. I also make great memes. Find me on LinkedIn or GitHub.

Top comments (1)

Collapse
 
jacob_keys profile image
Jacob Keys

+1! Just tried this and did not know this was possible!!!