Skip to content

✨ Add opt-in redteam lane that measures attacks on hive defenses - #17421

Merged
clubanderson merged 4 commits into
hivecommons:v5from
Karibhou:feat/red-team-agent-17420
Nov 9, 2026
Merged

clubanderson merged 4 commits into
hivecommons:v5from
Karibhou:feat/red-team-agent-17420

Conversation

@Karibhou

@Karibhou Karibhou commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

What

A new opt-in redteam lane at L5/L6. It plays the malicious contributor from #17420: a human, an AI, or one posing as the other. It writes the issues, PR bodies, review comments and RFC text such an actor would use to get agents to write malicious code or lower the hive's defenses. Hive's deterministic defenses then get tested against that text on a schedule.

Decision taken by hive: measured attacks only, no live drills

The lane adds attack cases and benign controls to the existing ioscan red-team corpus (src/pkg/ioscan/redteam_test.go) in hold-labelled PRs. It records each outcome as CI observes it, recounts the scorecard baseline, and republishes src/docs/ioscan-red-team.md. It does not file live payloads at other agents. Text from the hive's own App identity reaches other lanes as trusted input (pkg/scheduler/ioscan_enforce.go, trusted authors only block at High). A live drill would therefore poison the hive rather than test the untrusted-author line a real attacker hits. A realistic live drill needs an outside GitHub identity, which is a credential only an owner can provision. src/docs/redteam.md lists that under "What it does not cover".

The policy (redteam-holdgated.md, used at both levels) adds three corpus families that match the issue: impersonation, defense-lowering and malicious-change. It requires a benign control alongside each family's attacks, so false positives are measured too. Payload text is allowed only inside the corpus file; issues, PRs, comments, commits and beads cite case IDs only. A gap outside text detection (proxy, relay, hold/review gate, credential) is treated as a vulnerability and goes to SECURITY: private report needed for private reporting instead of a public item.

Deterministic guard: an unscoped red-team agent serves nothing

  • Config.AgentServesRepo gives an agent whose role or base name is redteam (replicas included) no repository until it has a repos: scope. That covers unnamed repos too. The proxy and the PR, merge, issue and push-branch relays all ask this predicate.
  • ReposForAgent returns an empty non-nil list for that agent. crux.ProjectContext.ReposFor treats nil as "unscoped", so a nil here would have put every repo in $HIVE_REPOS.
  • Kick assembly (templates.go, kickmessage.go) filters its work to nothing and tells it to stand down. AgentRepoScopeWarnings adds a boot-log warning.
  • The lane ships with a paused cadence in every governor mode at L5/L6. To turn it on, an operator scopes it to the repo holding the corpus and gives it a cadence. Both steps are in src/docs/redteam.md.

Wiring

  • Packs: redteam added to L5 and L6 (ISSUES_AND_PRS, redteam-holdgated.md, 28h stale timeout). Pack descriptions and TestACMMPacksAgentCounts updated (15/16).
  • KnownOriginLanes gains redteam, so its issues get agent/redteam, not origin/redteam. The dashboard knownRoles gains redteam.
  • The template is mirrored byte-identically into pkg/policies/defaults/ and added to the publishable-content guard list.
  • Docs: new src/docs/redteam.md (linked from the docs map). Also updated: the ACMM policy matrix, agent configuration roster, per-repo agents (the exception), the policies README and a pointer in ioscan-red-team.md. Changelog fragment added.

Tests

  • pkg/config/redteam_lane_test.go:
    • The lane exists at L5/L6 only and is paused in every mode with the right role and template.
    • An unscoped redteam agent is refused every repo, including unnamed repos. This holds for role-less entries matched by name, for replicas, and for odd role spellings.
    • ReposForAgent returns a non-nil empty list for it.
    • Ordinary agents are unchanged.
    • A scoped redteam agent serves exactly its scope.
    • The warning fires only while it is unscoped.
  • pkg/scheduler/agent_repo_scope_test.go: the kick for an unscoped redteam agent lists no repos, no queue and no issues, and says why. This fails without the AgentRepoRestricted change, because QUEUE_ISSUES would be 2.
  • I ran no tests locally: the repository's AGENTS.md makes CI the verdict and forbids local go test/go build. Locally I ran gofmt -l on the changed Go files (clean) and parsed both packs with a YAML parser to confirm 15/16 agents and redteam: paused in all four modes.

Part of #17420 (needs-human: live drills against agents/review swarm require an outside GitHub identity an owner must provision; the semantic classifier and review swarm remain untested by this lane — see src/docs/redteam.md "What it does not cover")

— hive: backend=omp model=anthropic/claude-opus-5-5


🐝 Hive Agent: contributor | SHA: ab2d6b394

Add a `redteam` agent to the L5 and L6 packs. It plays a malicious
contributor (a human, an AI, or one posing as the other) and writes the
issues, PR bodies, review comments and RFC text such an actor would use to
get agents to write malicious code or lower the hive's defenses. It
measures them against the deterministic defenses by adding attack cases
and benign controls to the ioscan red-team corpus in hold-labelled PRs,
recording each outcome as CI observes it, and never posts attack text
anywhere else: hive-authored text reaches other lanes as trusted input,
so a live drill would poison the hive rather than test it.

Safety is deterministic, not only prompt-level:

- The lane ships paused in every governor mode at L5/L6 and is absent
  below L5.
- An agent whose role or base name is `redteam` and has no `repos:` scope
  serves no repository. Config.AgentServesRepo (asked by the proxy and the
  PR, merge, issue and push-branch relays) refuses it, ReposForAgent
  returns an empty non-nil list so $HIVE_REPOS is empty, kick assembly
  filters its work to nothing and says why, and the boot log warns.

Also registers `redteam` as a known origin lane (agent/redteam label)
and dashboard role, adds the PR-capable template to the publishable
content guard, and documents the lane and its opt-in.

Closes hivecommons#17420

Hive-Run: hivecommons#17420
Hive-Plan: issue-17420 opt-in red-team lane over the ioscan corpus
Hive-Spec: hive#17420#issue-body
Signed-off-by: Karibhou <Karibhou@users.noreply.github.com>
@kubestellar-prow kubestellar-prow Bot added dco-signoff: yes Indicates the PR's author has signed the DCO. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Nov 9, 2026
@hivecommons-hive

hivecommons-hive Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

@Karibhou this PR is back in your court (stage/072-returned-to-contributor). The hive will not merge it until the head changes.

Failing checks:

  • native-queue-policy

Reply here or push a new head to this branch (same sign-off); CI and the review swarm re-run automatically and the PR returns to the normal path.

Queued in your relay fix queue (1 waiting): fixes are handed out before new work as soon as you have capacity.

@hivecommons-hive

Copy link
Copy Markdown
Contributor
e70e94d

⚠️ Sentinel alert — maintainer review required

Hive flagged this PR (author @Karibhou, head e70e94d92514) because it matches behaviors that can override security controls, escalate privileges or damage the codebase. This is a heuristic, not an accusation — a maintainer should confirm the change is intended before it merges.

  • sensitive_path — changes 4 sensitive path(s) (Touches a sensitive path (OWNERS, workflows, policies, hive config, security docs, …))
    • src/pkg/policies/content_boundary_test.go
    • src/pkg/policies/defaults/redteam-holdgated.md
    • src/policies/README.md
    • src/policies/redteam-holdgated.md

Hive added the sentinel-alert label. While it is present, Hive will not approve this PR, apply LGTM/approval labels, or merge it through any auto-merge lane. Remove the label once reviewed; Hive will not re-apply it unless new commits are pushed. Tune paths and behaviors under sentinel in hive.yaml or the dashboard Security tab.

TestIssueFilingPoliciesParkDecisionIssues requires every issue-filing
policy to carry the shared parking rule.

Signed-off-by: Karibhou <Karibhou@users.noreply.github.com>
@Karibhou

Karibhou commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

Fixed test (rest 1/4): TestIssueFilingPoliciesParkDecisionIssues failed because redteam-holdgated.md files issues without the shared --needs-decision parking rule. Added the canonical rule to both copies (src/pkg/policies/defaults/ and src/policies/) at 2185fff.


🐝 Hive Agent: contributor | SHA: unknown

@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.

Security perspective (read at head e70e94d92): no blocker. The Go changes only narrow access — AgentServesRepo now fails closed for an unscoped redteam agent (src/pkg/config/agent_repos.go:100-102), ReposForAgent returns a non-nil empty slice (:150-154), and the proxy/relays already route through this predicate (src/crux/proxy/github_proxy_policy.go:96-101, src/cmd/hive/github_client_config.go:131). No new permissions, tokens, workflows or secrets.

Two advisories, neither blocking:

  1. hold at L6 is prompt-enforced only. src/policies/redteam-holdgated.md says every redteam PR "carries hold at every ACMM level, including L6", but the server-side hold in the relay is level-keyed to L3/L4/L5 (src/pkg/github/pr_request_watcher.go:578-605); at L6 it depends on the agent passing --label "security,hold". Since this lane's whole input is adversarial text it is the lane most likely to be talked out of a label. Consider making the hold predicate deterministic for RedTeamRole (e.g. holdByLevel || cfg.AgentRequiresRepoScope(req.Agent) in the prHoldLabel wiring), so the corpus PR cannot land unlabelled regardless of what the model writes.

  2. The kick text "every write is refused" (src/pkg/scheduler/kickmessage.go:832) is slightly stronger than the proxy guarantees: scope refusal applies to REST write methods with a repo in the path only; POST /graphql is the documented pre-existing seam (src/crux/proxy/rules.go:534-537, 543-548). Not new to this PR, but the unscoped-redteam guard inherits it.

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

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Review follow-ups (below review.backlog.min_severity: P2)

Non-blocking findings below the backlog filing line are listed here instead of as issues, one comment per PR, updated in place. Tick them off as they are fixed; set review.backlog.min_severity: P3 to file every finding.

  • P3 info security — Unscoped-redteam refusal inherits the pre-existing GraphQL scope seam (src/crux/proxy/rules.go:547): The kick text for an unscoped redteam agent says 'every write is refused' (kickmessage.go:832), but AgentRepoScopeRefusal only gates REST write methods whose path names a repo; POST /graphql (repo in…

@hivecommons-hive

hivecommons-hive Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Hive status — updated in place; edits do not notify. Full history is in the Activity Monitor.

Review findings from ci-maintainer (folded here because this head already carries its hive review):

Intent alignment vs #17420 (read at head e70e94d).

The guard and wiring do what the body says: AgentServesRepo fails closed for an unscoped redteam (src/pkg/config/agent_repos.go:101), ReposForAgent returns a non-nil empty list (agent_repos.go:151-155), kick assembly filters via AgentRepoRestricted (src/pkg/scheduler/templates.go:323), and the policy's references (TestRedTeamCorpusOutcomesAreStable, scorecard_baseline.json fields, new ID letters R/I/W not colliding with the existing D/E/M/S/U/X/B) all check out against src/pkg/ioscan/redteam_test.go.

One in-scope gap — the closing keyword overstates what lands. #17420 (by hanthor) asks that hive be routinely tested against contributors "prompt engineering agents to create malicious code or lower defenses". This PR measures only the deterministic ioscan text rules: src/docs/redteam.md:8 ("It never sends that text to another agent") and redteam.md:86-93 list the semantic classifier, the review swarm and any outside-identity drill as not covered. Whether an agent or reviewer actually falls for the text — the issue's central question — is never exercised. That is a defensible design choice (the trusted-author argument in the body is right), but it is a deliberately partial fix, and the repo's own convention (src/policies/quality-holdgated.md:184) says such a PR uses Part of/Refs and names the remainder.

Suggested PR-body change (line 33):

Part of #17420 (needs-human: live drills against agents/review swarm require an outside GitHub identity an owner must provision; the semantic classifier and review swarm remain untested by this lane — see `src/docs/redteam.md` "What it does not cover")

With that, nothing else from this perspective blocks.

Review findings from reviewer-2 (folded here because this head already carries its hive review):

Read the Go changes at the PR head against the v5 tree and traced the enforcement points. The code does what the policy text promises; I am routing rather than confirming because adding a role whose entire output is attack text to the shipped ACMM packs is a role-policy decision, and the PR already carries both approved and hold.

Verified against the tree (head 8818adb)

  • Fail-closed scope. AgentServesRepo (src/pkg/config/agent_repos.go:108-110) now returns !requiresRepoScope(...) for an unscoped agent, so an unscoped redteam answers false everywhere. That predicate is the one all write gates use: pr_request_watcher.go, issue_request_watcher.go, merge_request_watcher.go, push_branch_request_watcher.go and agent_repo_scope.go all call it; no relay path bypasses it.
  • No work handed out. ReposForAgent (agent_repos.go:159-163) returns a non-nil empty slice for the unscoped lane; crux.ProjectContext.ReposFor (src/crux/project.go:103) treats only nil as "unscoped", so the non-nil empty slice is required and is correct. templates.go:323 switches the filter from AgentRepoScope != nil to AgentRepoRestricted, so the kick lists are filtered down to nothing, and kickmessage.go:831 tells the lane to stand down.
  • Level-independent hold. shouldHoldAgentPR (src/cmd/hive/merge_eligibility.go:310-313) checks alwaysHold first; main.go:2063 is the only non-test caller and passes b.cfg.IsRedTeamAgent. Matching is by role or base name (agent_repos.go:76-79), so a roster entry named redteam without role: redteam is still held.
  • Packs: redteam: paused in all four modes of both level-5.yaml and level-6.yaml; knownRoles and KnownOriginLanes updated; the two policy copies (src/policies/ and src/pkg/policies/defaults/) are byte-identical.

Observation (info, not a defect)

PrimaryRepoForAgent (agent_repos.go:219-224) falls through to the hive primary when the lane has no scope, so an unscoped redteam's $HIVE_REPO still names a repo the proxy will refuse. That is exactly the "footgun" the function's own doc comment describes; it is harmless here because the kick text tells the lane to stand down and every write gate refuses it, but a maintainer may prefer $HIVE_REPO to be empty for this lane.

Open item

hive-gh pr view reports native-queue-policy as FAILURE on this head while the main test matrix was still running; I have not read that job's log, so I am not asserting a cause.

I have not changed anything; the question above is the one an approver needs to answer.

Review findings from reviewer (folded here because this head already carries its hive review):

This adds an agent role to the ACMM packs, a new policy template and a new branch in shouldHoldAgentPR, so the trust decision belongs to a maintainer. I read the enforcement paths rather than the lane prompt; what I verified:

  • src/cmd/hive/merge_eligibility.go:310-313 — alwaysHold is checked first and a nil func adds no reason; the only non-test caller is main.go:2063, which wires b.cfg.IsRedTeamAgent. Existing outreach/ownsRepo logic below is untouched.
  • src/pkg/config/agent_repos.go:108-109 — AgentServesRepo now returns !requiresRepoScope(...) for an unscoped agent, so an unscoped red-team agent is refused every repo including "". ReposForAgent (:159-163) returns a non-nil empty slice so crux.ProjectContext.ReposFor does not read it as "unscoped". TestAgentServesRepo_UnscopedRedTeamServesNothing covers role match, base-name match, replica and whitespace/case in Role.
  • level-5.yaml / level-6.yaml — redteam: paused is present in all four governor modes on both levels, and TestRedTeamPausedAtEveryLevel-style check (redteam_lane_test.go:56) fails if an entry is absent rather than treating absence as paused.
  • KnownOriginLanes (src/crux/config/origin_labels.go:92-95) gains redteam, keeping the list sorted.

Low / open question — roster-absent name. IsRedTeamAgent's comment (agent_repos.go:66-67) says an agent absent from the roster is still matched by name. That holds for the hold path, but AgentServesRepo returns true at :102-105 (!ok) before reaching the requiresRepoScope check, so an agent named redteam with no roster entry at all is served everywhere by the scope predicate while still being held by the PR path. Today nothing starts an agent that is not in config, so I could not identify a live route to this; noting it so the two predicates' comments can be made to agree or the !ok branch can consult requiresRepoScope(c.BaseAgentName(agent), AgentConfig{}) too.

The red native-queue-policy check reads #17421: head/base moved, draft, closed, or held — it is failing on the hold label itself, not on the diff.

Review findings from adjudicator (folded here because this head already carries its hive review):

Correctness delta re-review at 02938c8 (vs 2185fff); current head 8818adb is a rebase with an identical tree. Previous finding (needs_decision_filing_test.go:40) remains fixed. The alwaysHold wiring is sound: src/cmd/hive/merge_eligibility.go:310-313 short-circuits before the outreach/level logic, both callers (main.go:2063, tests) are updated, build is clean, and TestShouldHoldAgentPRHoldsRedTeamAtEveryLevel covers role, base-name, replica, non-match and nil.

One small gap between the new doc comment and the code (advisory, non-blocking):

src/pkg/config/agent_repos.go:64-72 — IsRedTeamAgent now ignores ok from scopeSourceFor, so an agent absent from the roster named redteam is treated as the lane ("cannot slip through"). But AgentServesRepo (agent_repos.go:102-105) still returns true early for any unknown agent, so for that same name ReposForAgent returns [] while AgentServesRepo says it serves everything. Practically unreachable today because prAuthz (pkg/github/pr_request_watcher.go:400) rejects agents not in the roster first, but if the by-name-even-when-absent behavior is intended, the scope predicate should agree:

	ac, ok := c.scopeSourceFor(agent)
	if !ok {
		return !requiresRepoScope(c.BaseAgentName(agent), ac)
	}

Note: go test is disabled in this environment; test adequacy judged by reading. CI native-queue-policy failure is a "head moved" queue error, not a test failure.

Review findings from adjudicator-2 (folded here because this head already carries its hive review):

Security delta re-review (2185fff → 02938c8) — the delta tightens the trust boundary: shouldHoldAgentPR gains a level-independent alwaysHold reason (src/cmd/hive/merge_eligibility.go:309-312), wired to config.IsRedTeamAgent (src/cmd/hive/main.go:2063), and req.Agent is already bound to the spool file owner via prAuthz(req.Agent, fileUID) before the hold is computed (src/pkg/github/pr_request_watcher.go:400, :605). No new exploitable path. One advisory:

Low / in-scope — operator release_level_holds=true lifts the red-team hold too. The red-team hold is stamped as a bare hold with no distinguishing notice (pr_request_watcher.go:635-643), and ReleaseLevelHoldsOnce removes hold from every pending level-held PR (src/pkg/github/pr_level_hold.go:158-183); levelHoldReleaseBlockedByOtherPolicy (:205-247) only protects reporter-trust and self-authorization holds. So the policy's "held at every level, including L6" promise (src/docs/redteam.md:42) has one lawful bypass: a routine L5→L6 promotion with the one-off release flag drops the red-team corpus PR into auto-merge. Same pre-existing property as the outreach cross-repo hold, and the release is a deliberate operator act, so not blocking — but since this PR introduces a lane whose output is attack text, consider excluding it from the bulk release:

--- a/src/pkg/github/pr_level_hold.go
+++ b/src/pkg/github/pr_level_hold.go
@@ func (c *Client) ReleaseLevelHoldsOnce(ctx context.Context, level int, actor string) ([]LevelHoldPR, error) {
 	for _, pr := range pending {
+		if c.alwaysHoldAgent != nil && c.alwaysHoldAgent(pr.Agent) {
+			c.logger.Info("level hold release skipped: agent is held at every level", "repo", pr.Repo, "number", pr.Number, "agent", pr.Agent)
+			continue
+		}
 		owner, repo := c.splitRepo(pr.Repo)

(with alwaysHoldAgent set alongside prHoldLabel in StartPRRequestWatcher, or passed from cfg.IsRedTeamAgent at boot). Alternatively, document the bypass in src/docs/redteam.md under "What it does not cover".

Prior finding [correctness] needs_decision_filing_test.go:40 — fixed at 2185fff, untouched by this delta, still fixed.

@hivecommons-hive

Copy link
Copy Markdown
Contributor

Needs a decision, not a merge:

  • the reviewer swarm returned requires_human @2185fff
  • the review found: the reviewer marked this change high-risk
  • reviewer question: @clubanderson should decide whether hive ships a built-in redteam lane (new policy template redteam-holdgated.md + L5/L6 pack entries) whose job is authoring hostile issue/PR/review text, given it lands paused and fail-closed but is one repos: + cadence edit from running.
  • a sentinel alert is open on this PR

Head: verdict requires_human @2185fff, 15/33 checks green, 18 pending, DCO yes, sentinel alert, soak 0s of 10m0s.

How to release it:

  • After reading the verdict, a trusted merger can submit a GitHub Approve review for the current head and the lane clears the hold on its next pass; /hive approve replies on a PR are acknowledged but not consumed. An ordinary contributor cannot release their own PR.
  • Resolve the sentinel alert and have a maintainer clear its label.

Clear the cause and the hive re-evaluates on its next pass; the stage moves to stage/090-ready-for-human-merge, stage/095-pre-merge-soak or the merge queue on its own. Approval does not bypass CI, hold labels or other merge gates.

@github-actions

github-actions Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Open PR overlap check

Base branch: v5

Conflicts are checked with every PR merged onto the current tip of v5, so a PR that only needs a rebase is not reported as conflicting with its siblings.

PR Title Relation Files
#17434 🐛 fix(heartbeat): bound the forge health probe and back off fleet-stats retries when the forge host is unreachable same files src/cmd/hive/main.go

Signed-off-by: Karibhou <Karibhou@users.noreply.github.com>
@Karibhou

Karibhou commented Nov 9, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the remaining review notes at ab2d6b3:

  • Closing keyword (ci-maintainer): the PR body now says Part of #17420 with the needs-human note you suggested, so red team malicious actor agent #17420 stays open for the live-drill and semantic-layer work this lane does not cover.
  • GraphQL scope seam (reviewer-2, P3 follow-up): the absolute "every write is refused" wording is gone. The kick text (kickmessage.go) and both byte-identical redteam-holdgated.md copies now say the proxy and relays refuse its repository writes. src/docs/redteam.md scopes the proxy claim to REST writes whose path names a repository and lists GraphQL writes under "What it does not cover". Closing the seam itself stays a separate change, as the AgentRepoScopeRefusal comment says. TestKickForUnscopedRedTeamOffersNothing matches only the unchanged serves no repository until… prefix.

The decision on shipping the lane stays with @clubanderson.


🐝 Hive Agent: contributor | SHA: ab2d6b394


🐝 Hive Agent: contributor | SHA: unknown

@kubestellar-prow kubestellar-prow Bot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Nov 9, 2026
@clubanderson

Copy link
Copy Markdown
Member

Sentinel sensitive_path reviewed — policy decision: accepted. Lane is default-paused, fails closed without repos: scope, corpus-only. Server-side hold for role redteam added/required (pushed 02938c847: shouldHoldAgentPR now takes an alwaysHold predicate wired to Config.IsRedTeamAgent, so the hive-open-pr relay labels redteam PRs hold at every ACMM level incl. L6; unit test in outreach_hold_test.go).

@clubanderson clubanderson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maintainer approval for head 02938c8 — redteam lane accepted; server-side hold added.

@clubanderson

Copy link
Copy Markdown
Member

/lgtm
/approve

@kubestellar-prow kubestellar-prow Bot added lgtm Indicates that a PR is ready to be merged. labels Nov 9, 2026
@kubestellar-prow

Copy link
Copy Markdown
Contributor

LGTM label has been added.

DetailsGit tree hash: f9a9f13b696832927680ac49de5eb0412809e389

1 similar comment
@kubestellar-prow

Copy link
Copy Markdown
Contributor

LGTM label has been added.

DetailsGit tree hash: f9a9f13b696832927680ac49de5eb0412809e389

@kubestellar-prow

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: clubanderson

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

The pull request process is described 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 approved Indicates a PR has been approved by an approver from all required OWNERS files. label Nov 9, 2026
@hivecommons-hive

Copy link
Copy Markdown
Contributor

🔒 Hold-gate integrity: branch changed while hold-gated — fresh review required

This PR's branch moved while it sat hold-gated: the head recorded when the hold was applied was 2185fff05fb6, but the branch now sits at 02938c847d34. The diff a reviewer saw under the hold is no longer the diff that would merge, so auto-merge is blocked and the hold label has been re-applied.

Commits not present in the hold-time snapshot (2):

  • ab2d6b394123 by Karibhou — redteam: qualify write-refusal claims; document GraphQL scope seam
  • 02938c847d34 by clubanderson — redteam: hold PRs server-side at every ACMM level

Authors not in the hold-time author set: clubanderson

A human should review the FULL diff at the current head — a rebase or force-push renames every commit, so everything above needs eyes even if it looks familiar. Removing the hold label after that review is the fresh approval: the guard has re-pinned its snapshot to the current head, so a clean lift re-opens the merge lanes.

@hivecommons-hive hivecommons-hive Bot added the hold label Nov 9, 2026
shouldHoldAgentPR gains an alwaysHold predicate wired to the new
Config.IsRedTeamAgent, so the hive-open-pr relay labels any PR from a
redteam-role (or redteam-named/replica) agent hold at L6 too, instead of
relying on the policy prompt alone.

Signed-off-by: Andrew Anderson <andy@clubanderson.com>
Signed-off-by: Karibhou <Karibhou@users.noreply.github.com>
@Karibhou
Karibhou force-pushed the feat/red-team-agent-17420 branch from 02938c8 to 8818adb Compare November 9, 2026 20:35

@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.

Intent-alignment delta review (2185fff → 02938c8; note the PR has since moved to 8818adbd, not read here).

The delta does one thing and it fits the PR's own contract: the policy (src/policies/redteam-holdgated.md) promises "hold at every ACMM level, including L6", and the relay now enforces it server-side via alwaysHold → Config.IsRedTeamAgent (src/cmd/hive/merge_eligibility.go:310-313, src/cmd/hive/main.go:2063). IsRedTeamAgent dropping the ok check (src/pkg/config/agent_repos.go:66-72) is safe: the zero AgentConfig has an empty role and the base-name match still applies. Level-hold release is operator-only (src/pkg/github/pr_level_hold.go:155-180), so the new hold is not auto-lifted on promotion. No scope creep.

Prior finding [correctness] needs_decision_filing_test.go:40 — fixed at 2185fff, untouched by this delta, still fixed.

Advisory (low, in-scope): the notice posted alongside the new hold still explains only the L3–L5 gate and the outreach case (src/pkg/github/pr_level_hold.go:28). A red-team PR held at L6 gets a comment whose stated reasons don't apply to it. Suggested wording:

> This PR was opened by the %q agent while Hive policy required a human checkpoint for that agent. Agent PRs are held at ACMM L3–L5; an `+"`outreach`"+` PR that targets a repository this hive does not manage, and any PR from the `+"`redteam`"+` lane (whose output is adversarial text that changes the ioscan red-team corpus and published block rate), is held at every level.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. dco-signoff: yes Indicates the PR's author has signed the DCO. hold lgtm Indicates that a PR is ready to be merged. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants