Free tool Tier a model against OSFI E-23 in about five minutes — seven risk dimensions, the controls your tier requires, and a report you can print. Open it →
osfi-gate

Personal information in evidence

Evidence about changes is evidence about people: who wrote a change, who approved it, who accepted a risk. It cannot be anonymous and remain evidence — CM-01 is a control about independent approval, and an approval by nobody in particular is not one.

What follows is measured, not asserted. It comes from grepping a real estate — 60 bundles and a generated regulator pack — rather than from reading the code and describing the intent. Where the two disagreed, the measurement was right: see "What the measurement found" below.

What a bundle contains

Personal information Why it is there
gate-input.jsonmetadata.pull_request Platform logins: author, approvers, stale approvers, commit authors CM-01, CM-02 and CM-05 are controls about who did what. Removing this removes the control.
PR title, URL, number; changed file paths Traceability (CM-05). Titles are written by people and can contain anything.
gate-input.jsonfindings File paths and line numbers Locating a finding.
raw/ Scanner output See sanitising, below.
context.json CI run URL, policy commit Provenance. No person.
decision.json, manifest.json, statement.json None Controls, hashes, signatures.

No email addresses. A commit the platform cannot resolve to an account is recorded as unlinked:<digest> rather than as the git author address — see osfi_gate.platforms.author_id.

Raw scanner output is sanitised before it is hashed or stored (osfi_gate.sanitize): every secret gitleaks reported is replaced with [REDACTED], and every code snippet is replaced by the digest of its content, so fingerprints stay stable without keeping source text. This matters more here than anywhere else, because a bundle goes to immutable storage and what gets in cannot be taken out.

What the measurement found

Two things the code's intent did not match.

  1. Both platform adapters fell back to storing the git author's email address when a commit could not be resolved to an account. That is a contact detail entering evidence held under COMPLIANCE retention for years, which nothing was scrubbing.
  2. The same line was a control weakness. approvers are logins; an email can never equal one. So CM-02's "an approver also authored commits in this change" check could not see such an author, and a self-approval by someone whose commits carried only an address passed in silence. A test in tests/test_platforms.py had encoded the old behaviour as expected.

Both are fixed. Commit authorship now reduces to a login or a stable digest, and CM-01 warns when authorship could not be attributed — because independence for those commits is assumed rather than established, and that is a fact about the change rather than an absence.

Who can read it

Bundles The risk and auditor roles only. Every download is written to ui_actions with the actor, the role and the run.
The console UI Any signed-in role. It shows control status, findings and current state — not raw scanner output.
The regulator pack Whoever is given it. It carries no raw scanner output, no commit authorship and no email addresses.

The pack names people in exactly two places, both load-bearing: waivers.json (risk_owner — WV-01 is a control about who accepted a risk) and model-inventory.json (owner, assessed_by — E-23 requires a named owner). tests/test_console.py asserts that as an allowlist, so a new field that starts carrying a person fails a test rather than reaching a regulator.

Access review

Two questions, and both are answerable from what is already true rather than from a spreadsheet.

Who can write the evidence. docs/audit-trail.md names protecting the evidence branch as the second-strongest defence against a forged history, and docs/operations.md tells whoever onboards a repository to set it up — and until now nothing checked that they had. The gate reads branch protection on the branch it is evaluating (CM-03) and never on the branch its own evidence lives in, which is the one whose rewritability is the entire reason anchoring and WORM storage exist.

FORGE_TOKEN=... osfi-gate access-review --platform github \
    --api-url https://git.internal/api/v3 --repo owner/name \
    --evidence-branch osfi-evidence --expect osfi-ci

Exit 1 on a finding, 2 when the review could not see everything — those are different answers, and in a job whose output ends up in an access-review file they must not share an exit code. Reading protection and collaborators needs more permission than reading code, and a token without it gets a 403, not an empty list. A review that turned "I could not look" into "nobody has access" would produce a clean report with a signature under it.

It also distinguishes two things ordinary branch protection blurs: protection is about review, and this is about immutability. A branch that is protected but permits a force push protects nothing here, because the attack is replacing the branch rather than appending to it.

Who can read the bundles. /api/access-review reports the entitlement (which groups the role map gives a bundle-reading role) beside the use (ui_actions, which has recorded every download since the feature existed). The comparison is the point: an entitlement nobody has exercised is a candidate for removal, and a group mapped to a reading role that nobody is in is a permission waiting for somebody to be added to it. Under dev auth there is no entitlement model, and it says so rather than reporting that no group can read.

Cadence. Run both on a schedule. The job's own history is the record of when a review last happened — an access review nobody can date is not a cadence.

Retention, and what it forecloses

How long evidence is kept is retention.bundle_days in the policy repository, owned by second-line risk. See audit-trail.md for the mechanism and this consequence, which belongs here too:

Once a bundle is under COMPLIANCE retention, it cannot be deleted before its date. By anyone. An erasure request cannot be satisfied for that copy.

A legal hold extends that indefinitely. So the decision that matters is what goes into a bundle, not what can be taken out of one — which is why sanitising and author_id are not hygiene, they are the control.

What this document is not

It is not a PIPEDA compliance assessment, and nothing here is legal advice. The lawful basis for holding this information, the period it may be held, and how an access or correction request is handled are decisions for the institution and its counsel. What is written above is what the software does, what it stores and what it forecloses — so that those decisions can be made about something accurate.