Skip to content

🐛 fix(sentinel): judge the hive's superseding PR by the adopted author - #14354

Merged
hivecommons-hive[bot] merged 1 commit into
hivecommons:v6from
Danathar:fix/sentinel-adopted-pr-keeps-alert
Oct 26, 2026
Merged

hivecommons-hive[bot] merged 1 commit into
hivecommons:v6from
Danathar:fix/sentinel-adopted-pr-keeps-alert

Conversation

@Danathar

Copy link
Copy Markdown
Contributor

Summary

The hive can supersede a flagged contributor PR with a PR of its own that starts at the same commit. Sentinel then judged that PR by its author, the App, so a blocking alert turned into an "author is trusted (hive agent)" notice and nothing stopped a merge lane.

Live case, on a hive running 92878ca, 2026-10-26:

That shape came from a fork. Since #14306 a fork PR is no longer re-homed into the base repository, so it does not recur. Every other supersede path still exists for a same-repo branch whose author is not a repository maintainer (#14305 excludes maintainers):

  • grace or offline adoption when in-place adoption is off or impossible (for example, the base changed .github/workflows/);
  • dco-rehome;
  • signoff-rehome;
  • in-place-stalled.

Every one of them opens an App-authored PR through supersedeAdoptedPR and gets the same notice. An in-place adoption is unaffected, because the PR keeps its contributor author.

The adoption code already guards the same laundering for the contributor lane's diff fences (automerge_adoption_fence.go: "a fenced diff re-homed into an App-authored PR that the self-authored lane then merges on its own"). The Sentinel decision had no such guard.

Change

  • trySentinelPR: on a PR the App opened whose body carries the supersede line AdoptionPRBody writes (Supersedes #N (…; original commits by @login preserved).), the trust decision uses the adopted PR's author (sentinelCodeAuthor, AdoptedFrom in the new sentinel_adopted.go).
    • An untrusted author's flagged head gets sentinel-alert on the App's PR as well.
    • A trusted author still gets the notice.
    • The marker comment adds one sentence naming the adopted PR and the author whose code it is.
  • Clearance carries over: when the adopted PR carries the hive's own alert for the same head and no longer has the label, a maintainer has already reviewed that head. The App's PR then records the clearance (sentinelOriginCleared, the proof sentinelClearedByMaintainer already uses) instead of asking again.
    • A later head is judged afresh.
    • If the adopted PR still carries the label, or cannot be read, nothing is cleared.
  • PRs already open: an existing App PR with a notice for its current head (like feat: add lightweight Dockerfile.hub for hub mode #936 after an upgrade) gets the label and its notice rewritten as an alert on the next evaluation.
  • Docs: the sentinel.trusted_authors_block row in operator-reference.md describes the rule.
  • Changelog: a new fragment.

Unchanged:

  • the hive's own PRs without that line;
  • PRs not opened by the App;
  • a hive with no known App login;
  • exempt_logins (still read for the PR author);
  • the findings themselves.

Testing

Tests run from src/, with -count=1:

  • go test ./pkg/github/... ./pkg/sentinel/... ./cmd/hive/...: all ok.
  • go vet ./pkg/github/ is clean.
  • gofmt is clean.
  • src/scripts/check-changelog-fragment.sh v6 passes.

New tests in sentinel_adopted_test.go run the real sweep against the fake GitHub:

Test Shape
TestSweepSentinelAdoptedPRJudgedByAdoptedAuthor #930 → #936 on a same-repo branch: the App PR at the same head gets sentinel-alert and an alert naming #930 and its author. A second case replaces a notice an older hive already posted for that head.
TestSweepSentinelAdoptedPRCarriesOriginClearanceForSameHead Clearance on the adopted PR at the same head: no label, the clearance is recorded, and a restart stays quiet. A hive commit on top (new head) is alerted. An adopted PR that still carries the label clears nothing.
TestSweepSentinelAdoptedPRUnchangedCases A trusted adopted author keeps the notice (with the adoption sentence). The hive's own PR, a non-App PR carrying the line, and a hive with no App login all keep today's behaviour.
TestAdoptedFrom The parser: fence marker first, a line added above it later, [bot] authors. A quoted line, prose, and the bot-takeover body are not matched.
TestAdoptionPRBodyNamesTheAdoptedAuthorForSentinel (automerge) Every adoption reason × fence × DCO re-home body that AdoptionPRBody writes parses back to the adopted PR and author, so the two cannot drift apart.

Mutation checks

Each part of the fix was broken in turn and restored from a backup, and each break failed the expected tests:

  • Trust read from the PR author again: the three sweep tests fail.
  • No origin-clearance check: the clearance test fails.
  • An origin that still carries the label counted as cleared: the clearance test's last case and the adopted-author test fail.

Not verified

Contributor checklist

  • Changelog: changelog.d/fixed-sentinel-adopted-pr-judged-by-adopted-author.md.
  • Targets v6.
  • The title uses the emoji convention.
  • Commits include DCO sign-off.
  • Docs updated.
  • No secrets, credentials or local runtime state are committed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BQYnPGFJx81c8JXR3o1sg1

A PR the hive opens to supersede an adopted contributor PR starts at the
contributor's head, unchanged, but Sentinel judged it by its author, the
App: a blocking alert on the contributor's PR became an "author is trusted
(hive agent)" notice on the App's copy of the same commit, and no merge
lane was stopped. Since hivecommons#14306 forks are no longer re-homed, but every
supersede path still runs for a same-repo branch of a non-maintainer.

The sweep now reads the adopted PR and its author from the supersede line
AdoptionPRBody writes and decides trust by that author. A maintainer's
clearance of the same head on the adopted PR carries over; later heads
are judged afresh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BQYnPGFJx81c8JXR3o1sg1
Signed-off-by: Danathar <Danathar@users.noreply.github.com>
@kubestellar-prow kubestellar-prow Bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label Oct 26, 2026
@kubestellar-prow

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign kellyaa for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubestellar-prow kubestellar-prow Bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Oct 26, 2026
@hivecommons-hive hivecommons-hive Bot added author/clanker A contributor's own hive authored this PR under their login dco All commits are DCO signed-off role/trusted Author is trusted for unattended merge (trusted-author role or registry/claim tier in require_tiers) stage/050-review-pending Review swarm requested; awaiting a verdict for the current head labels Oct 26, 2026

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read the diff against the tree at e905277, plus automerge_contributor_adopt.go (the body writer), sentinel_clearance.go and pkg/sentinel/sentinel.go. The trust re-pointing looks correct to me; one gap worth a follow-up.

Verified correct

  • AdoptedFrom (sentinel_adopted.go:23) matches exactly the line AdoptionPRBody writes at automerge_contributor_adopt.go:349, and every supersede path (grace/offline, dco-rehome, signoff-rehome, in-place-stalled) goes through that function. The other Supersedes #N (adopted; re-pushed …) text at :323 is a commit message, not a PR body, so it does not need to parse. The bot-takeover body (automerge_bot_takeover.go:230) deliberately does not match — consistent with "Not verified" in the body.
  • sentinelOriginCleared (sentinel_adopted.go:70-81) fails closed on every read error and on a label still present, and reuses sentinelClearedByMaintainer, so the origin check is the same proof the PR itself would need.
  • The upgrade case (existing App PR with a notice for its current head) falls through to the label-add + EditComment branch at sentinel_sweep.go:507-511 because posted is true and the notice body lacks sentinelAlertHeading, so it is not mistaken for a clearance. Matches the body's claim.

Finding (low): the evaluator still sees the App as the author. sentinel_sweep.go:418 passes sentinel.PR{Author: author, …} — the PR author, not codeAuthor. checkOwnerSelfNomination (pkg/sentinel/sentinel.go:265-285) compares added OWNERS/CODEOWNERS lines against that login, so on a superseding App PR a contributor adding their own login to OWNERS no longer produces the owner-self-nomination finding; only the generic sensitive-path finding fires (OWNERS is in DefaultSensitivePaths, sentinel.go:67). The alert and label still happen, so nothing is laundered — but the alert loses the one line a maintainer most wants to see ("@login adds their own login to OWNERS"), and the finding text would name the App if it did fire. sentinel_adopted_test.go has no OWNERS case, so this is untested. Suggest passing codeAuthor as sentinel.PR.Author (keeping Exempt(author) on the PR author as the body intends), or stating the limitation in the "Not verified" list.

No duplicate in the queue; docs row and changelog fragment match the behaviour. I have not approved or closed anything.

— hive: agent=reviewer-2 backend=copilot model=claude-fable-5.1 copilot=1.0.88

@hivecommons-hive hivecommons-hive Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read the diff against v6 at a08007f, plus the callers: AdoptionPRBody (automerge_contributor_adopt.go:349), recordSentinelClearance (sentinel_clearance.go:301), sentinelClearedByMaintainer, and sentinel.Evaluate. The trust switch and the clearance carry-over look correct to me:

  • adoptedFromRE matches the exact line AdoptionPRBody writes, including when CarriedFenceMarker precedes it (the (?m)^ anchor handles that), and TestAdoptionPRBodyNamesTheAdoptedAuthorForSentinel pins the two together. The other two Supersedes # writers (automerge_contributor_adopt.go:323 is a commit message, automerge_bot_takeover.go:230 is the github-actions[bot] re-author path) are correctly not in scope.
  • The new early return in trySentinelPR (sentinel_sweep.go:444-452) runs before the !posted branch and goes through recordSentinelClearance, which edits the newest own marker or creates one, so both the fresh-PR and the "older hive left a notice" cases are covered. sentinelOriginCleared fails closed on any read error.

One verified gap, same laundering shape (medium, narrow): sentinel_sweep.go:418 still passes the App login as sentinel.PR.Author (and :407 / sentinel.go:218 still exempt on it). checkOwnerSelfNomination (sentinel.go:265-276) compares that login against the added OWNERS lines, so on the App's superseding copy a contributor adding @login to OWNERS no longer produces owner-self-nomination — only the generic sensitive-path hit. With default sentinel.sensitive_paths the PR is still labelled, just with a weaker headline; but sensitive_paths replaces the defaults when set (operator-reference.md:1093), so an operator whose list omits OWNERS gets no alert at all on the App copy, which is exactly the "author is trusted" escape this PR closes for the trust decision. The body lists "the findings themselves" as deliberately unchanged, so this may be intended scope — but passing codeAuthor into sentinel.Evaluate at :418 is a one-token change that makes the judgement consistent (and would make exempt_logins follow the code author too, which seems the right reading of "judged by the adopted PR's author"). Fine as a follow-up if you'd rather keep this PR tight; I'd note it in the fragment either way.

No other findings. Docs row and changelog fragment match the behaviour. I have not approved or changed anything.

— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88

@hivecommons-hive
hivecommons-hive Bot merged commit 728197b into hivecommons:v6 Oct 26, 2026
62 of 65 checks passed
@hivecommons-hive

Copy link
Copy Markdown
Contributor
Evidence bundle `#14354e905277` sha256:253e24453e14a3a7df30e0e4f2c3171685265021aa90533ebde9b7f898103ce9 — download from the dashboard or `hivectl review evidence #14354`.

@hivecommons-hive

Copy link
Copy Markdown
Contributor

merged by Hive trusted-author auto-merge: author @Danathar holds role owner and GitHub permission maintain on repo; CI green at e905277.

@hivecommons-hive hivecommons-hive Bot removed role/trusted Author is trusted for unattended merge (trusted-author role or registry/claim tier in require_tiers) stage/050-review-pending Review swarm requested; awaiting a verdict for the current head labels Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author/clanker A contributor's own hive authored this PR under their login dco All commits are DCO signed-off dco-signoff: yes Indicates the PR's author has signed the DCO. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant