Rules / GRN-T002

diffwarnimplemented

GRN-T002 publisher-changed

Default severity warn
Kind diff rule: fires only when the trusted version had the property and the new version lost it, or the new version gained a risky property the trusted version lacked.
Status Implemented in 0.1

What it checks

The source repository named in the new version's verified attestations differs from the one named in the trusted version's attestations.

Repository renames that GitHub redirects don't fire: the rule compares GitHub's repository id, which survives a rename.

Why it matters

An attestation names the repository whose CI built the release. A different repository means a different CI published this version. That can be a fork, a move to a new organization, or an attacker's repository that has been granted publishing rights.

Example finding

Illustrative; not from a real release.

examplelib 2.6.1 → 2.6.2: WARN
  WARN  GRN-T002 publisher-changed: 2.6.2 was published from github.com/someone-else/examplelib, not github.com/example/examplelib
           - examplelib-2.6.2-py3-none-any.whl: github.com/someone-else/examplelib

How to resolve it

  1. Confirm the move from the old home: release notes, the README, or an announcement in the old repository. Don't rely on what the new repository says about itself.
  2. If the move is real, merge and add an ignore for this version. Later releases from the new repository compare against this one and stay quiet.

Allowlisting

Once you've reviewed a release, ignore this rule for that package and version range. Every ignore needs a reason and an expiry date; after until it stops applying and the report notes that it expired.

[[garnet.ignore]]
package = "examplelib"
versions = "==2.6.2"
rules = ["GRN-T002"]
reason = "project moved to the example-org organization (announced in example/examplelib#200)"
until = "2027-06-30"

To change the rule's severity for every package instead:

[garnet.rules]
"GRN-T002" = "block"   # "off" | "info" | "warn" | "block"

Suppressed findings still appear in JSON and SARIF output, marked with the ignore that matched. The policy format is in SPEC §7; 0.1's garnet diff doesn't read policy files yet.

See also