# Compliance evidence

> Seal change-management evidence for every merged pull request, write policies as code, map them to SOC 2, ISO 27001 and PCI DSS, and report to auditors.

Auditors testing change management ask the same questions about every change: who wrote it, who approved it, what was checked, what was found and what happened to it. MergeHarbor already knows most of the answers. Compliance evidence collects them for each pull request, checks the pull request against your policies, and seals the result when it merges.

Compliance evidence is part of the Advanced and Enterprise plans.

## What a pull request's evidence contains

- **People**: who opened the pull request, who approved it on the code host and on which commit, and who merged it (and whether it was merged from the MergeHarbor console).
- **What MergeHarbor checked**: every review with its tier, the models it used, the categories and built-in checks in force, and the rules that applied.
- **Findings and their resolution**: fixed in a later commit, marked addressed (by whom), or dismissed (by whom, with the reason and note).
- **Proof runs** and the **requirements check** of linked tickets, when you use them.
- **Controls**: the result of each of your policies, with the details of every check.
- **Exceptions**: failed controls someone accepted, with their written justification.

Approvals and the merger are read from GitHub and GitLab. On other code hosts they are reported as unavailable, and approval checks fail rather than pass silently.

## Sealing

When a pull request merges, MergeHarbor seals its evidence within a few minutes into an append-only ledger. Each record carries the SHA-256 hash of the previous one, so changing, removing or reordering a record breaks the chain. **Verify ledger** on the Compliance page recomputes it. Turning compliance evidence on also seals pull requests merged in the 30 days before.

Sealed evidence never changes. If a control failed and the change is acceptable, someone with the **Manage compliance** permission can record an exception with a justification. The exception is added next to the evidence and appears in reports.

## Turn it on

Go to **Settings → Compliance**:

1. Turn on **Seal evidence for merged pull requests**.
2. Pick the starter packs for the frameworks you report against: SOC 2, ISO/IEC 27001:2022, PCI DSS v4.0.
3. Optionally add your own policies in the editor. Problems are shown with their line as you type.

Every save creates a new policy version; each sealed record names the version it was checked against.

## Starter packs

| Control                                   | What it requires                                                                               | SOC 2        | ISO 27001 | PCI DSS        |
| ----------------------------------------- | ---------------------------------------------------------------------------------------------- | ------------ | --------- | -------------- |
| Peer approval before merge                | Someone other than the author approved before merging into the default branch                  | CC8.1        | A.8.32    |                |
| Independent approval of the final change  | The approval was given on the commit that merged                                               |              |           | 6.2.3.1, 6.5.1 |
| Automated code review of the final change | A MergeHarbor review finished on the commit that merged                                        | CC8.1        | A.8.29    | 6.2.3          |
| No unresolved critical findings           | Critical findings were fixed or dismissed with a reason                                        | CC7.1, CC8.1 |           | 6.2.3          |
| Security findings resolved                | Major and critical security findings were fixed or dismissed with a reason                     | CC7.1        | A.8.28    | 6.2.4          |
| No hard-coded secrets                     | Detected secrets were removed (or dismissed as false positives)                                | CC6.1        | A.5.17    | 8.6.2          |
| Back-out plan for database migrations     | A changed migration ships with a rollback, a "Rollback" section in the description, or a label | CC8.1        | A.8.32    | 6.5.1          |
| Linked requirements met (advisory)        | No acceptance criterion of a linked ticket was found unmet                                     | CC8.1        | A.8.25    |                |

References show which requirements the evidence helps support. They are not a certification of your organization or of MergeHarbor, and your auditor decides what evidence a control needs.

## Write your own policies

Policies are YAML. Each one says when it applies, what it requires, and which requirements it supports:

```yaml
version: 1
disable: [migration-backout] # turn off a starter control
policies:
  - id: payments-security-review
    name: Security review for payment code
    severity: blocking # or advisory: reported, never fails the change
    applies_to:
      branches: [$default, "release/*"] # $default is the repository's default branch
      paths: ["payments/**"]
    require:
      - review_completed: { min_tier: deep }
      - approvals: { min: 1, from_teams: [security] }
      - no_open_findings: { min_severity: major, categories: [security] }
    frameworks:
      pci_dss: ["6.2.4"]
```

Reusing a starter control's `id` replaces it. The checks:

| Check                | Options                                                                   | Passes when                                                               |
| -------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `approvals`          | `min`, `exclude_author` (default true), `on_final_commit`, `from_teams`   | Enough people approved on the code host; automation accounts never count  |
| `no_open_findings`   | `min_severity` (default critical), `categories`, `dismissals_need_reason` | No finding at that severity is still open                                 |
| `review_completed`   | `on_final_commit` (default true), `min_tier`                              | A MergeHarbor review finished on the commit that merged                   |
| `category_reviewed`  | `category`, `min_severity` (default major)                                | The review covered the category and left no unresolved findings in it     |
| `no_secrets`         |                                                                           | Every detected secret was removed or dismissed as a false positive        |
| `migration_rollback` | `paths`, `rollback`, `or_label`, `or_section`                             | Changed migrations come with a rollback, a rollback section or a label    |
| `proof_run`          | `outcomes` (default passed), `on_final_commit`                            | The latest [proof run](https://mergeharbor.com/docs/proof-runs) ended as required                |
| `requirements_met`   | `allow_unclear`, `require_linked`                                         | No acceptance criterion of a [linked ticket](https://mergeharbor.com/docs/integrations) is unmet |
| `labels`             | `any_of`                                                                  | The pull request has one of the labels                                    |
| `merge_gate`         |                                                                           | The merge gate passed or was overridden                                   |

### Policies in a repository

A repository can add its own policies in a `compliance:` block of the root `.mergeharbor.yml`. They are read from the base branch, so a pull request cannot change the policies it is checked against, and they cannot turn off or replace your organization's policies.

```yaml
compliance:
  policies:
    - id: schema-rollback
      require:
        - migration_rollback: { paths: ["db/schema/**"], rollback: ["db/rollback/**"] }
```

## On the pull request

The **Compliance** tab of a pull request in the console shows how it does against your policies while it is open, and its sealed record after it merges. Download the evidence as PDF (for people) or JSON (complete, for tools).

## Reports for auditors

On **Settings → Compliance**, filter by period, repository, status or control to see pass rates and every sealed change. **Request report** builds a ZIP in the background with:

- the **population**: every pull request merged in the period, with its evidence status, approvers, merger and record hash;
- a **random sample** of the size you choose. The seed is recorded (reuse it to draw the same sample), and the method is described in the manifest so anyone can redraw it from the population;
- **pass rates per control** and every **exception** with its justification;
- the full sealed evidence of each sampled change, and a PDF with the same content;
- a **manifest** listing the SHA-256 of every file, a `SHA256SUMS` file for `sha256sum -c`, and MergeHarbor's signature of the manifest.

Reports are kept for 30 days; download links last 15 minutes. Self-hosted installations need object storage for reports.

## Permissions

- **View compliance evidence** (`compliance.read`): the Compliance tab, the Compliance page, policies and reports. Included in the Owner, Admin, Member and Viewer roles; you can create an Auditor role with only this permission.
- **Manage compliance** (`compliance.manage`): change policies and record exceptions. Owners and admins.

Policy changes, exceptions, exports, report requests and downloads, and ledger verifications are recorded in the audit log (Settings → Audit log).
