Skip to content

fix(release): harden branch-protection drift signal classification#22205

Closed
BrianCLong wants to merge 3 commits intomainfrom
codex/reassess-summit-state-and-prompt-codex-actions
Closed

fix(release): harden branch-protection drift signal classification#22205
BrianCLong wants to merge 3 commits intomainfrom
codex/reassess-summit-state-and-prompt-codex-actions

Conversation

@BrianCLong
Copy link
Copy Markdown
Owner

Motivation

  • Reduce false GA blockers by distinguishing inability to verify GitHub branch-protection metadata from confirmed policy drift so CI/ops signals remain actionable.
  • Make the drift checker explicit about verification state so downstream gates and dashboards can make correct decisions.

Description

  • Updated scripts/release/check_branch_protection_drift.sh to detect missing gh, add a --fail-on-unknown flag, and emit a drift_status enum (in_sync|drift_detected|unknown) while preserving drift_detected for real mismatches.
  • Added an explanatory markdown section for unknown verification state and improved API error text when gh or permissions are unavailable.
  • Added a focused regression test scripts/release/tests/check_branch_protection_drift.test.sh to validate unknown behavior and the --fail-on-unknown exit semantics.
  • Updated docs/roadmap/STATUS.json with a new initiative branch-protection-drift-signal-hardening documenting the change.

Testing

  • Ran the new regression suite ./scripts/release/tests/check_branch_protection_drift.test.sh, which executed 3 tests and all passed (validating drift_status=unknown when gh is inaccessible and --fail-on-unknown exit behavior).
  • Executed the checker manually with ./scripts/release/check_branch_protection_drift.sh --repo BHG/summit --branch main --out-dir artifacts/release-train --verbose, which produced drift_status: unknown and wrote artifacts/release-train/branch_protection_drift_report.json as expected in environments without gh.
  • Verified JSON output keys with jq '{drift_status,drift_detected,api_accessible,api_error}' artifacts/release-train/branch_protection_drift_report.json to confirm fields and error messaging.

Codex Task

@BrianCLong BrianCLong added the codex Codex-owned implementation work label Mar 29, 2026 — with ChatGPT Codex Connector
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 29, 2026

Warning

Rate limit exceeded

@BrianCLong has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 19 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 3 minutes and 19 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ad9bff30-2f5c-4df9-8a06-10a73d199873

📥 Commits

Reviewing files that changed from the base of the PR and between 12cad4a and 0d75387.

📒 Files selected for processing (4)
  • docker-compose.dev.yaml
  • docs/roadmap/STATUS.json
  • scripts/release/check_branch_protection_drift.sh
  • scripts/release/tests/check_branch_protection_drift.test.sh
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/reassess-summit-state-and-prompt-codex-actions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request enhances the branch-protection drift detection script by introducing a distinct 'unknown' status for cases where GitHub metadata is inaccessible, preventing false drift positives. It adds a --fail-on-unknown flag to control exit behavior in these scenarios and includes a new regression test suite. The review feedback recommends using trap in the test script to ensure temporary directories are cleaned up even if tests fail.

Comment on lines +37 to +60
test_unknown_when_gh_unavailable() {
setup

local out_dir="${TEMP_DIR}/out"
mkdir -p "${out_dir}"

# Ensure gh is not discoverable for this test process.
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
"${RELEASE_SCRIPTS}/check_branch_protection_drift.sh" \
--repo BHG/summit \
--branch main \
--out-dir "${out_dir}" >/dev/null 2>&1 || true

local report="${out_dir}/branch_protection_drift_report.json"
local drift_status
local drift_detected
drift_status=$(jq -r '.drift_status' "${report}")
drift_detected=$(jq -r '.drift_detected' "${report}")

assert_eq "unknown" "${drift_status}" "drift_status is unknown when gh metadata is inaccessible"
assert_eq "false" "${drift_detected}" "drift_detected is false when status is unknown"

teardown
}
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.

medium

The current test structure can leak temporary directories if a test fails before teardown is called. This can happen if a command fails and the script exits due to set -e. To make the test more robust, you can use trap to ensure the cleanup logic in teardown is always executed when the function returns. This also allows you to remove the explicit call to teardown at the end of the function.

test_unknown_when_gh_unavailable() {
  setup
  trap teardown RETURN

  local out_dir="${TEMP_DIR}/out"
  mkdir -p "${out_dir}"

  # Ensure gh is not discoverable for this test process.
  PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
    "${RELEASE_SCRIPTS}/check_branch_protection_drift.sh" \
      --repo BHG/summit \
      --branch main \
      --out-dir "${out_dir}" >/dev/null 2>&1 || true

  local report="${out_dir}/branch_protection_drift_report.json"
  local drift_status
  local drift_detected
  drift_status=$(jq -r '.drift_status' "${report}")
  drift_detected=$(jq -r '.drift_detected' "${report}")

  assert_eq "unknown" "${drift_status}" "drift_status is unknown when gh metadata is inaccessible"
  assert_eq "false" "${drift_detected}" "drift_detected is false when status is unknown"
}

Comment on lines +62 to +81
test_fail_on_unknown_exits_nonzero() {
setup

local out_dir="${TEMP_DIR}/out"
mkdir -p "${out_dir}"

set +e
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
"${RELEASE_SCRIPTS}/check_branch_protection_drift.sh" \
--repo BHG/summit \
--branch main \
--fail-on-unknown \
--out-dir "${out_dir}" >/dev/null 2>&1
local exit_code=$?
set -e

assert_eq "1" "${exit_code}" "--fail-on-unknown exits with status 1 when status is unknown"

teardown
}
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.

medium

To improve robustness and prevent resource leaks, this test should also use trap to guarantee that teardown is called. This ensures the temporary directory is cleaned up even if an error causes the test to exit prematurely.

Suggested change
test_fail_on_unknown_exits_nonzero() {
setup
local out_dir="${TEMP_DIR}/out"
mkdir -p "${out_dir}"
set +e
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
"${RELEASE_SCRIPTS}/check_branch_protection_drift.sh" \
--repo BHG/summit \
--branch main \
--fail-on-unknown \
--out-dir "${out_dir}" >/dev/null 2>&1
local exit_code=$?
set -e
assert_eq "1" "${exit_code}" "--fail-on-unknown exits with status 1 when status is unknown"
teardown
}
test_fail_on_unknown_exits_nonzero() {
setup
trap teardown RETURN
local out_dir="${TEMP_DIR}/out"
mkdir -p "${out_dir}"
set +e
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
"${RELEASE_SCRIPTS}/check_branch_protection_drift.sh" \
--repo BHG/summit \
--branch main \
--fail-on-unknown \
--out-dir "${out_dir}" >/dev/null 2>&1
local exit_code=$?
set -e
assert_eq "1" "${exit_code}" "--fail-on-unknown exits with status 1 when status is unknown"
}

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0c329f1a02

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +44 to +45
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
"${RELEASE_SCRIPTS}/check_branch_protection_drift.sh" \
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Make gh-unavailable tests actually hide GitHub CLI

The regression test claims to make gh undiscoverable, but this PATH still includes standard bins (/usr/local/bin, /usr/bin, etc.) where gh is commonly installed. In environments with GitHub CLI available, the script will take the live API path instead of the intended unknown path, so the assertions become flaky and no longer validate the new unknown-state behavior deterministically.

Useful? React with 👍 / 👎.

@BrianCLong
Copy link
Copy Markdown
Owner Author

Queue note: branch-local issues have been reduced to the dependency on docker-compose.dev.yaml from main. The compose correction was synced here, and the regression test cleanup trap was added in 0d753877d2b536eae593682d7478caa551302955, so current CI is exercising the intended branch state. Remaining DIRTY status is intentionally constrained to the compose base repair in #22220; once that merges, refresh this branch from main and rerun build, evidence, test, and tests.

@BrianCLong
Copy link
Copy Markdown
Owner Author

Closing in favor of #22241, which absorbs the drift-classification fix into the clean convergence train.

@BrianCLong BrianCLong closed this Mar 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex Codex-owned implementation work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant