Agent-merge audit · SOC 2 CC8.1 · updated
SOC 2 CC8.1 evidence from GitHub
CC8.1 is the SOC 2 criterion for change management: changes to your software are authorised, tested and approved before they are put in place. On GitHub the evidence is the merged pull request. An auditor takes a sample of merges in the period and checks, for each, who wrote it, that someone else approved it before the merge, which checks ran, and that the branch's rules required it. Every merge that does not fit is an exception you explain.
What a sampled pull request should show
- The change: the repository, the pull request number and the commits that merged.
- Who wrote it, and who approved it, with the time of each approval: an approval from someone other than the author, before the merge.
- That the approval covers the code that merged. An approval followed by new commits is a gap unless stale approvals are dismissed or the last push needs someone else's approval (OneUptime, 4 Aug 2026).
- The rules in force, not the ones the team assumes: a branch rule requiring review, and who could bypass it.
- The merge, and, for a full chain, the deployment it reached.
What the GRC tools test
- Vanta's "Application changes reviewed" test needs the branch setting "Require approvals" at 1 or more, and reads each pull request's approval count and approvers (help article). The article does not say how it treats a bot's approval or an agent's pull request.
- Drata's "Formal code review process" test reads branch configurations and fails when one user can merge their own change with no one else involved (help article).
- Both test the branch setting and the count. Neither says who or what wrote the change, which is the question an agent's merge raises.
Check a period by hand
Merged pull requests, who opened, merged and approved each
$ gh pr list --repo OWNER/REPO --state merged --search "merged:2026-07-01..2026-09-30" --limit 1000 --json number,author,mergedBy,reviews --jq '.[] | [.number, .author.login, .mergedBy.login, ([.reviews[] | select(.state == "APPROVED") | .author.login] | unique | join(" "))] | @tsv'One line a pull request: number, who opened it, who merged it, and who approved it. A line with no approver, or whose only approver opened it, is an exception to explain. It does not tell an approval given before the last commit, or a person from a bot.
The branch's review rule, as it is now
$ gh api repos/OWNER/REPO/rules/branches/main --jq '.[] | select(.type == "pull_request" or .type == "copilot_code_review") | {type, parameters}'Rulesets only; classic branch protection needs gh api repos/OWNER/REPO/branches/main/protection with an admin's token. This is the rule today, not at each merge.
The exceptions
| Exception | The question to answer |
|---|---|
| An agent wrote or co-wrote it, and no independent person approved it | Who reviewed this agent's change before it merged, and where is that recorded? |
| Merged with no approval | Why did it merge without review? |
| Approved only by its author, a commit author or a co-author | Who other than the people who wrote it reviewed it? |
| Approved only by a bot or an AI reviewer | Is an automated approval part of your documented review control? |
| Approved before its last commit | Who reviewed the commits added after the approval? |
| Merged by a bot account, with no person queueing it | Which person authorised this merge? |
| No approval, though the branch rule now requires one | Was the rule added after this merge, or was it bypassed or exempted? |
| A commit on the branch that no merged pull request accounts for | Why did it reach the branch without a reviewed pull request? |
A bot's approval is not a person's review unless your control was designed that way, and the auditor will ask who designed it. Since 1 September 2026, Copilot code review can be allowed to approve pull requests and count toward the required approvals (GitHub changelog).
All of it in one run, free
$ npx --allow-git=root github:agentwares/agent-merge-audit OWNER/REPO --period 2026-Q3Every merged pull request in the period, with whether an agent wrote it, whether a person other than its authors approved it on the final code, who merged it, the rule, and the exceptions, as a dated CSV and markdown pair. Your own GitHub token, or none for a public repo; GETs to GitHub's API only. Also as a GitHub Action, uses: agentwares/agent-merge-audit@main, and a local MCP server: github.com/agentwares/agent-merge-audit.
A continuous, hash-chained record of every agent change, kept across your audit window, is not built
It would record each merge as it happens (who or what wrote it, who approved it, who merged it, under which rule) in okgate's hash-chained log, with a quarterly CC8.1 export and a read-only link for your auditor, so the rule at a merge eleven months ago is on record.
What works today, free: okgate's hook mode holds an agent's git push or merge in Claude Code, Codex and Gemini CLI until a person types the go-ahead, and logs each decision in a hash-chained log on your machine.
$ npx -p @agentwares/agentguard okgate hooks installWhat okgate sells today keeps your agents' tool calls through its proxy, not merges: 90 days of hash-chained log on Pro ($99/month), 365 days with a compliance export on Team ($299/month).
Sources, each read on 9 October 2026
- OneUptime: Can GitHub pull requests prove SOC 2 change management? (4 Aug 2026)
- Vanta help: Application changes reviewed test (GitHub), updated 25 Nov 2025
- Drata help: Formal code review process test
- GitHub changelog: Copilot code review can now approve pull requests (1 Sep 2026)
- GitHub REST API: rules for a branch