Skip to content

IKRC Insights

Before an AI Coding Agent Opens Pull Requests, Check What Your Workflows Can Reach

Copilot cloud agent cannot read a repository's Actions secrets, yet the workflows that run on its pull requests can, and one repository setting decides whether a person with write access must start those runs.

Take a hypothetical property-management company with an in-house tenant portal built on .NET. Its deployment workflow reads the production database connection string from a repository secret, and a test workflow runs on every pull request. A developer assigns the issue "charge a late fee on overdue rent" to Copilot cloud agent by selecting Copilot as the assignee, and the agent, working in its own environment powered by GitHub Actions, pushes to a new copilot/ branch and opens a draft pull request. The question that matters is whether code on that branch can run with the production connection string before anyone has reviewed it, and the repository's settings and workflow files decide the answer.

What runs on the agent's branch before anyone approves it

The answer starts with a setting called Require approval for workflow runs, in the Actions workflow approval section of the agent's settings. It is on by default: workflows on the agent's pull request wait until someone with write access has reviewed the code and clicked Approve and run workflows. Only a repository administrator can turn it off, and GitHub's page on the agent's built-in protections gives that exception one line: "Optionally, you can configure Copilot to allow workflows to run automatically."

GitHub does not pass the portal's Actions secrets to the agent itself. It gives the agent a separate Agents type of secret and says the agent "does not have access to GitHub Actions, Codespaces, or Dependabot secrets and variables." The workflows its pushes trigger are another matter. On the settings page where the option lives, GitHub warns that turning approval off "may allow unreviewed code written by Copilot to gain write access to your repository or access your GitHub Actions secrets."

In the portal repository, the test workflow runs on the pull_request event, builds the solution and runs the tests, including the ones the agent just wrote for the late fee. Those tests are the agent's code, and they run as steps of the test job. That job has the GITHUB_TOKEN GitHub creates for every job, with whatever permissions the workflow grants it. A secret reaches a step only where the workflow file sets it as an input or environment variable for that step, its job or the whole workflow, because GitHub Actions "can only read a secret if you explicitly include the secret in a workflow." A test job given no secret still has its token, and nothing from the repository's configured secrets. The pull request can also change the workflow files themselves, which is why the same settings page asks reviewers to be "especially alert to any proposed changes in the .github/workflows/ directory that affect workflow files."

For the portal we would leave approval on. Reading today's workflow files can confirm that the test job gets no secret and that the default GITHUB_TOKEN permission is read access to repository contents, as GitHub's Actions secure use reference recommends. The same reference says the permissions "can then be increased, as required, for individual jobs within the workflow file", and a pull request can edit the test workflow to pass in a secret or raise those permissions. A pull_request workflow runs when the pull request's head branch is updated, so with approval off the agent's next push could start that edited workflow before anyone had read the edit. Whoever clicks Approve and run workflows should read the diff first, workflow files included.

The production connection string belongs in a deployment environment, whose secrets reach only jobs that reference it. With required reviewers configured, "A workflow job cannot access environment secrets until approval is granted by a reviewer." That gate depends on the GitHub plan. On Free, Pro and Team, required reviewers "are only available for public repositories", so a private portal repository needs GitHub Enterprise for it. Pro and Team can still limit which branches deploy to an environment in a private repository. GitHub matches that rule against the run's GITHUB_REF, and a pull_request run carries the pull request's merge ref, so allowing only the default branch keeps the test workflow's runs away from the production secret. A pull_request_target workflow runs in the default branch's context and passes the same rule, which is why GitHub says to avoid that event "if you need to build or run code from the pull request." Administrators can bypass an environment's protection rules by default, so where the plan offers the setting we would clear Allow administrators to bypass configured protection rules.

Who may approve the agent's pull request?

The agent cannot approve its own work. Its pull requests open as drafts, and GitHub says it "cannot mark its pull requests as 'Ready for review' and cannot approve or merge a pull request." The developer who assigned the issue is held back too. GitHub prevents "the user who asked Copilot cloud agent to create a pull request" from approving it, and its review guide adds that this person's approval "won't count toward the required number." Each commit is authored by Copilot with that developer as co-author, so the history shows who started the task.

Both protections count against a rule the repository has to set. GitHub describes the requester block as one that "maintains the expected controls in the 'Required approvals' rule and branch protection." A repository that only requires a pull request before merging gets much less from it: that rule says the pull request "doesn't necessarily have to be approved, but it must be opened." In that repository nothing asks anyone to approve the late-fee pull request. The extra approval GitHub requires when the agent opens a pull request under its own app identity, a preview setting that is on by default, also "has no effect if the ruleset requires zero approvals."

For a business repository we would set a ruleset on the default branch that requires one approval and turns on Require approval of the most recent reviewable push, which asks for an approval "from someone other than the last person to push to a branch." One approval can meet both requirements. While only the agent has pushed, any eligible reviewer other than the requester can give it. Once a developer pushes fixes onto the agent's branch, as GitHub's review guide allows, that developer is the last person to push, so the approval has to come from someone else; an earlier reviewer can approve again after the push. The same ruleset requires status checks to pass and names the test workflow's check, so "all required status checks must pass before collaborators can merge changes."

Some files need a named reviewer no matter who pushed them: everything under .github/workflows/, .github/copilot-instructions.md, the files under .github/instructions, and every AGENTS.md. In an organization repository, rulesets can require approval from a named team "when a pull request changes certain files or directories", with gitignore-style patterns and the team's approval count set above zero. A repository under a personal account has no teams. There, a CODEOWNERS file in .github/ lists the same paths and itself, and the ruleset's option to require reviews from code owners turns those entries into a merge requirement.

The rules the agent reads live in the same repository

GitHub's agent reads three kinds of repository instruction files: .github/copilot-instructions.md for the whole repository, NAME.instructions.md files under .github/instructions with an applyTo glob that limits them to matching paths, and AGENTS.md files, where "the nearest AGENTS.md file in the directory tree will take precedence." The onboarding prompt GitHub publishes for the first file asks, for each build and test step, for "the sequence of steps to take to run it successfully" and the tool versions. For the portal, that file would name the .NET SDK version and give the restore, build and dotnet test commands in the order that works.

A path-specific file scoped to the ledger project would carry the rules a reviewer otherwise repeats in comments. A posted ledger entry is never edited; a correction is a new reversing entry. The late-fee rate comes from the lease record and never from a constant in code. Each rule also gets a test. For the posted-entry rule, the test posts an entry, runs the late-fee charge for that tenant, then reads the posted entry back and checks that it is unchanged. If the agent's change adjusted the posted entry, that test fails, and the required check shows the approver the failure while the merge is still blocked.

Package problems can show up in two places. While the agent works, its validation tools check newly introduced dependencies against the GitHub Advisory Database for "CVSS-rated High or Critical vulnerabilities", unless an administrator has turned those tools off. In the repository's own CI, a project targeting .NET 10 audits transitive packages by default, and their advisories "can cause restore failures" when the project treats warnings as errors, which we covered in NuGet Audit and transitive vulnerabilities. With approval on, the reviewer sees that CI result after starting the run.

Instruction files are text the agent follows, so editing them can change what the agent and its review do. Copilot code review reads instructions "from the head branch (the branch with your changes)", which means a pull request that edits .github/instructions also edits the instructions its own Copilot review runs under. That is the exposure described in our article on prompt injection in business documents, where text that reaches the model steers it, and the reason those files are on the named-review list. Issue text is input as well. GitHub only lets users with write access trigger the agent, never shows it comments from anyone else, and drops HTML comments from issues because GitHub treats "hidden messages in issues" as a form of prompt injection.

How IKRC would prepare a repository before the first assignment

On a custom software repository, the first change is to the repository's settings, and it happens before anyone assigns the agent an issue:

  • List every workflow that runs on pull requests, with its trigger, the ref it checks out, the secrets it passes to its jobs and the token permissions it grants. Move deployment credentials into an environment that only the default branch can deploy to, with required reviewers where the plan allows them, and keep any pull_request_target workflow from checking out pull-request code.
  • Set the default GITHUB_TOKEN permission to read, and grant write per job where a workflow needs it.
  • Add a default-branch ruleset with one required approval, approval of the most recent reviewable push, the test workflow as a required status check, and a named team or CODEOWNERS entries for the workflow and instruction files.
  • Write .github/copilot-instructions.md with the build and test commands, and run each one before committing the file.

Who may assign issues to the agent, and who may turn workflow approval off, are decisions we would record next to the ruleset as part of development process consulting. The first issues we would assign are ones whose acceptance a test can check, like the late fee. Before that first assignment, we would open a pull request that adds a job naming the production environment to a file under .github/workflows/ and confirm two results: the merge box lists the named reviewers as required, and the added job, run on the pull_request event, waits for a reviewer or is refused because the merge ref may not deploy.

Related Reading

Prompt injection in business documents covers text that steers a model, and NuGet Audit in .NET 10 covers why a build can fail on a package nobody added directly.

Contact IKRC

Your next software project.

Connection Lost

Attempting to reconnect to the server...