Demo 4 · CI/CD non-interactive automation
Theme: automation. Time: ~30 min.
Features: programmatic mode (copilot -p), PAT auth, scoped tool permissions, GitHub Actions.
Story so far: You can build and review changes by hand. This demo: automate that review in CI so every pull request to template-typescript-react gets a Copilot pass — right next to the repo's existing
test.yamlande2e-test.yamlworkflows.
The CLI's programmatic mode (-p/--prompt) runs one prompt and exits, which makes it practical for scripts and CI/CD pipelines (About Copilot CLI).
Least privilege in automation
Automatic approval gives Copilot the same access you have. In CI, never reach for --allow-all-tools blindly. Scope tools with --allow-tool/--deny-tool, run read-mostly tasks, and prefer a sandbox (Security considerations).
Prerequisites
- A fine-grained PAT with the Copilot Requests permission (see Getting Started → Authenticate). Store it as
COPILOT_CLI_TOKENand expose it to the CLI asCOPILOT_GITHUB_TOKEN. - Your fork of template-typescript-react, where you can add a GitHub Actions workflow.
Part A — local scripted run
Start with your laptop. A single command, no interaction (About Copilot CLI):
copilot -p "Show me this week's commits on this repo and summarize them by area (src, telemetry, tests, ci)" --allow-tool='shell(git)'
You can also feed options/prompt from another program by piping into copilot (About Copilot CLI):
./generate-prompt.sh | copilot
A read-mostly triage example that writes a report file but nothing else:
copilot -p "Review the diff of HEAD against origin/main for bugs and security issues. \
Write findings to review.md as a checklist. Do not modify source files." \
--allow-tool='shell(git:*)' \
--allow-tool='write' \
--deny-tool='shell(git push)' \
--deny-tool='shell(rm)'
Part B — GitHub Actions workflow
Wire the same idea into CI. This example runs an automated review on every pull request and posts the result as a comment. It is read-mostly: Copilot may run git and write a report file, but is denied push/destructive commands. It sits alongside the app's existing test.yaml (which runs make ci-test) and e2e-test.yaml workflows.
# .github/workflows/copilot-review.yml
name: Copilot CLI review
on:
pull_request:
types: [opened, synchronize]
permissions:
contents: read
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # need history to diff against the base
- uses: actions/setup-node@v4
with:
node-version: 24 # matches the app's CI (see test.yaml)
- name: Install Copilot CLI
run: npm install -g @github/copilot
- name: Run Copilot review
env:
# PAT with "Copilot Requests" permission
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_CLI_TOKEN }}
run: |
copilot -p "Review the changes in this PR (diff ${{ github.event.pull_request.base.sha }}..${{ github.sha }}). \
Focus on bugs, security, and missing tests in this React + TypeScript app. Write a concise markdown summary to copilot-review.md." \
--allow-tool='shell(git:*)' \
--allow-tool='write' \
--deny-tool='shell(git push)' \
--deny-tool='shell(rm)'
- name: Post review as a comment
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr comment "${{ github.event.pull_request.number }}" --body-file copilot-review.md
Key points:
- Install uses the official npm package
@github/copilot(README). - Auth uses a PAT exposed as
COPILOT_GITHUB_TOKEN, which avoids ambiguity withGH_TOKENandGITHUB_TOKENused byghand Actions. If you use older examples withGH_TOKEN, confirm current precedence withcopilot help environmentand the changelog (copilot-cli changelog 0.0.354). - Permissions are explicitly scoped — Copilot can read history and write one file, nothing else (Security considerations).
- Store the PAT as the
COPILOT_CLI_TOKENrepository secret. Each prompt consumes a premium request (README).
If your workflow opens a pull request
This example posts a comment, so the built-in GITHUB_TOKEN is enough. If you instead let a workflow open a pull request with GITHUB_TOKEN (for example gh pr create), first enable Settings → Actions → General → Workflow permissions → Allow GitHub Actions to create and approve pull requests for the repository (or its organization). New personal-account repositories have this off by default, so the job fails with GitHub Actions is not permitted to create or approve pull requests (createPullRequest). A user PAT used in place of GITHUB_TOKEN is not subject to this guard (Preventing GitHub Actions from creating or approving pull requests).
Make prompt-mode jobs idempotent
CI reruns happen. Write prompts so a second run can safely detect existing output: "update or create copilot-review.md" is safer than "append findings." Keep git push, deployment commands, and destructive file operations denied unless the workflow is explicitly designed to publish changes. The CLI changelog also notes that prompt mode has changed over time for repo hooks and workspace MCP loading, so keep CI jobs explicit about required tools and config (copilot-cli changelog).
graph LR
PR[Pull request event] --> A[Actions runner]
A --> I[npm i -g @github/copilot]
I --> R["copilot -p ... scoped tools"]
R --> F[copilot-review.md]
F --> C[gh pr comment]
Part C — scheduled local automation
Inside an interactive session you can also schedule recurring prompts with /every and one-shot delayed prompts with /after (Using Copilot CLI):
> /every 1h Run `pnpm test:e2e` and report any failures
What you learned
copilot -pruns one prompt and exits, which fits report generation, checks, and release jobs.- PAT +
COPILOT_GITHUB_TOKENenables headless auth in CI. - Scoped
--allow-tool/--deny-toolflags enforce least privilege in pipelines.
Take it further
- Make the workflow fail the check when Copilot finds a high-severity issue (parse
copilot-review.md). - Combine with Demo 8 to auto-draft release notes on tag pushes.
- Read the team guidance in GitHub's Best practices → Team guidelines.