Skip to content

Mirror required status checks into classic branch protection for tide - #171

Merged
eliorerz merged 2 commits into
osac-project:mainfrom
eliorerz:sync-classic-branch-protection-status-checks
Aug 5, 2026
Merged

Mirror required status checks into classic branch protection for tide#171
eliorerz merged 2 commits into
osac-project:mainfrom
eliorerz:sync-classic-branch-protection-status-checks

Conversation

@eliorerz

@eliorerz eliorerz commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Why

Prow's tide merges PRs based purely on labels here, blind to e2e status entirely -- confirmed on a real merge, not theorized.

osac-project/osac#85 was merged by openshift-merge-bot[bot] at 21:11:20Z, while all three of its required e2e checks (e2e-bmaas-full-install / e2e, e2e-vmaas-full-install / e2e, e2e-caas-full-install / e2e) were still running -- they didn't complete until 22:03:04Z, 22:26:11Z, and 22:33:41Z respectively (52-82 minutes after the merge). All three eventually passed, but only well after the fact.

Root cause, confirmed at the source level, not guessed: osac's Prow config relies on the org-wide tide.context_options.from-branch-protection default (no per-repo override in openshift/release) to derive which contexts tide should wait for. Checked tide's actual implementation (kubernetes-sigs/prow, pkg/config/tide.go):

if options.FromBranchProtection != nil && *options.FromBranchProtection {
    bp, err := c.GetBranchProtection(org, repo, branch, presubmits)
    ...
    if bp.Protect != nil && *bp.Protect && bp.RequiredStatusChecks != nil {
        required.Insert(bp.RequiredStatusChecks.Contexts...)
    }
}

bp.RequiredStatusChecks maps directly to GitHub's classic branch-protection API -- there's no repository-rulesets-aware code path anywhere in this function. And classic branch protection on osac/main has never had required_status_checks set -- only the newer ruleset (github_repository_ruleset.status_checks) does:

$ gh api repos/osac-project/osac/branches/main/protection --jq '.required_status_checks'
null

So tide's computed required-context set for every repo managed by this Terraform has always been empty. It merges the instant approved+jira/valid-reference+lgtm labels are present, with no blocking labels -- it was never actually waiting for e2e, on any PR, ever. Most PRs happen to look compliant only because reviewers naturally wait to see CI pass before approving, as a matter of habit, not because anything enforces it.

(Checked 5 other recently-merged PRs for comparison: 4 were fully compliant, e2e finishing well before merge. The one other match, #170, turned out to be an unrelated, legitimate mechanism -- merged directly by a human wg-infra team member via the UI, using their own explicitly-configured ruleset bypass rights, not tide.)

What

Mirror the same contexts already enforced by github_repository_ruleset.status_checks into github_branch_protection.repo_protection's own required_status_checks block -- both generated from the same var.required_status_checks input, so there's one list to maintain per repo, not two independently-drifting ones. strict = true matches the ruleset's own strict_required_status_checks_policy = true.

Why this over the alternative (editing openshift/release directly)

Considered setting context-options.required-contexts explicitly in osac's own _prowconfig.yaml in openshift/release instead. Went with this approach because:

  • It requires no PR against an external repo tide's config actually needs a human with openshift/release merge rights to review.
  • It keeps a single source of truth (var.required_status_checks in repositories.tf) instead of three (the workflow file names, the ruleset, and now a separate Prow config entry) -- exactly the kind of drift that caused the CaaS-Netris rename to silently break tide's gating in the first place, if it had needed a third place to update.
  • It fixes this for every repo managed by this module that sets required_status_checks, not just osac -- osac-installer and fulfillment-service have the same latent gap today, just not yet observed on a real PR.

Blast radius

Only affects repos where required_status_checks is non-empty in repositories.tf (currently osac, osac-installer, fulfillment-service). No change for repos without required checks configured (the dynamic block stays empty for them, matching the existing ruleset's own conditional).

Behavioral change to expect: any PR currently sitting with approved+lgtm but incomplete e2e will stop being tide-mergeable until those checks actually finish. This was already GitHub's own ruleset-enforced behavior for a human clicking "Merge" in the UI -- this closes the gap specifically for tide's automated merges, which is where it was actually being skipped.

Test plan

  • tofu init -backend=false && tofu validate -- passes (same pre-existing deprecation warnings as always)
  • Confirm via gh api repos/osac-project/osac/branches/main/protection --jq '.required_status_checks' that it reflects the three e2e contexts once applied
  • Confirm on the next real PR that tide waits for all three e2e checks before merging

Summary by CodeRabbit

  • New Features
    • Added configurable required status checks for protected branches.
    • Supports strict status-check enforcement based on configured settings.
    • Automatically applies the configured status-check contexts.

Prow's tide derives its merge-gating required contexts exclusively from
the classic branch-protection API (pkg/config/tide.go's
FromBranchProtection reads bp.RequiredStatusChecks, which maps to that
API specifically) -- it has no knowledge of repository rulesets at all.

osac-project's Prow config relies on the org-wide
tide.context_options.from-branch-protection default (no per-repo
override in openshift/release), but classic branch protection here has
never set required_status_checks -- only the ruleset did. Confirmed via
GitHub's API directly:

  $ gh api repos/osac-project/osac/branches/main/protection \
      --jq '.required_status_checks'
  null

So tide's computed required-context set for every repo managed here has
always been empty, and it merges purely on labels
(approved+jira/valid-reference+lgtm), completely blind to e2e status.
Confirmed on a real merge: PR osac-project#85 was merged by openshift-merge-bot at
21:11:20Z while its three required e2e checks (which all eventually
passed) didn't finish until 22:03:04Z, 22:26:11Z, and 22:33:41Z --
52 to 82 minutes later.

Mirror the same contexts already enforced by the ruleset into classic
branch protection's own required_status_checks block, generated from
the same var.required_status_checks input so there's still only one
list to maintain per repo, not two independently-drifting ones.

Signed-off-by: Elior Erez <eerez@redhat.com>
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 2b91432e-3975-44f7-b2f0-5b9cfe56165c

📥 Commits

Reviewing files that changed from the base of the PR and between 3ca2652 and da0a130.

📒 Files selected for processing (1)
  • modules/common_repository/main.tf
🚧 Files skipped from review as they are similar to previous changes (1)
  • modules/common_repository/main.tf

Walkthrough

The branch protection resource conditionally configures classic required status checks from var.required_status_checks, enables strict checking, and maps each configured check context.

Changes

Branch protection checks

Layer / File(s) Summary
Configure required status checks
modules/common_repository/main.tf
Adds a conditional required_status_checks block that enables strict checks and maps contexts from var.required_status_checks.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 11
✅ Passed checks (11 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: mirroring required status checks into classic branch protection for Tide.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No-Hardcoded-Secrets ✅ Passed The PR adds only Terraform status-check contexts and strictness; scans found no hardcoded credentials, private keys, credential URLs, or secret-shaped literals.
No-Weak-Crypto ✅ Passed The PR adds Terraform status-check configuration only; the changed file contains no MD5, SHA1, DES, RC4, Blowfish, ECB, custom crypto, or secret comparison.
No-Injection-Vectors ✅ Passed The PR only adds a Terraform dynamic status-check block and context mapping. Scans found no SQL concatenation, shell=True, eval/exec, unsafe deserialization, os.system, or dangerouslySetInnerHTML.
Container-Privileges ✅ Passed The PR changes only Terraform branch protection settings. No container/Kubernetes manifest or flagged privilege setting appears in the diff.
No-Sensitive-Data-In-Logs ✅ Passed The PR changes only Terraform branch-protection configuration and comments; it adds no logging or output of passwords, tokens, PII, hostnames, or customer data.
Ai-Attribution ✅ Passed The authored PR description and its two commits do not mention use of an AI tool; no AI attribution trailer is therefore required, and no Co-Authored-By trailer is present.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
modules/common_repository/main.tf (1)

117-123: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Align branch protection with the repository default branch. If the default branch is not main, github_branch_protection.repo_protection does not mirror the contexts enforced by github_repository_ruleset.status_checks on ~DEFAULT_BRANCH. Derive pattern from the repository default branch or enforce main as the default.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@modules/common_repository/main.tf` around lines 117 - 123, Update the
github_branch_protection.repo_protection configuration to target the
repository’s actual default branch by deriving its pattern from the repository
default-branch value, or explicitly enforce main as that default. Ensure its
protected contexts remain aligned with github_repository_ruleset.status_checks
on ~DEFAULT_BRANCH.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@modules/common_repository/main.tf`:
- Around line 104-116: Add the required Red Hat AI attribution trailer to the
commit message, using either Assisted-by: or Generated-by:. Do not use an AI
Co-Authored-By: trailer.

---

Nitpick comments:
In `@modules/common_repository/main.tf`:
- Around line 117-123: Update the github_branch_protection.repo_protection
configuration to target the repository’s actual default branch by deriving its
pattern from the repository default-branch value, or explicitly enforce main as
that default. Ensure its protected contexts remain aligned with
github_repository_ruleset.status_checks on ~DEFAULT_BRANCH.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 60ec4012-4a36-4b55-9938-2be49f924142

📥 Commits

Reviewing files that changed from the base of the PR and between fc9725c and 3ca2652.

📒 Files selected for processing (1)
  • modules/common_repository/main.tf

Comment thread modules/common_repository/main.tf Outdated
Comment on lines +104 to +116
# Prow's tide only derives its own merge-gating required contexts from
# this (classic) branch-protection API -- it has no knowledge of
# repository rulesets at all (confirmed against tide's actual source,
# pkg/config/tide.go: FromBranchProtection reads bp.RequiredStatusChecks,
# which maps to this exact API, not rulesets). Since every repo here
# already relies on org-wide tide.context_options.from-branch-protection
# (the global default in openshift/release, no per-repo override), tide
# was merging PRs on labels alone the moment none of these contexts were
# ever mirrored here -- confirmed on a real PR (#85) that merged with all
# 3 required e2e checks still 50+ minutes from completing. Mirror the
# same contexts already enforced by the ruleset below so tide actually
# waits, without introducing a second, independently-maintained list --
# both come from the same var.required_status_checks.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

git log -1 --format='%B'

Repository: osac-project/github-config

Length of output: 1637


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- commit metadata ---'
git log -1 --format=fuller
printf '%s\n' '--- target module files ---'
git ls-files 'modules/common_repository/*'
printf '%s\n' '--- main.tf relevant section ---'
sed -n '85,145p' modules/common_repository/main.tf
printf '%s\n' '--- variables.tf relevant declarations ---'
rg -n -A18 -B5 'required_status_checks|integration_id|DEFAULT_BRANCH' modules/common_repository/variables.tf modules/common_repository/main.tf
printf '%s\n' '--- module callers and required checks ---'
rg -n -A12 -B8 'common_repository|required_status_checks|integration_id' --glob '*.tf' --glob '*.yaml' --glob '*.yml' .

Repository: osac-project/github-config

Length of output: 40315


Add the required AI attribution trailer.

If an AI tool contributed to this commit, add a Red Hat Assisted-by: or Generated-by: trailer. Do not add an AI Co-Authored-By: trailer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@modules/common_repository/main.tf` around lines 104 - 116, Add the required
Red Hat AI attribution trailer to the commit message, using either Assisted-by:
or Generated-by:. Do not use an AI Co-Authored-By: trailer.

Source: Coding guidelines

Signed-off-by: Elior Erez <eerez@redhat.com>
@eliorerz
eliorerz merged commit 7712196 into osac-project:main Aug 5, 2026
1 of 2 checks passed
@eliorerz
eliorerz deleted the sync-classic-branch-protection-status-checks branch August 5, 2026 23:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant