Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
c11fb65
fix(governance): require central reviews for stacked prs
seonghobae Aug 20, 2026
ab65fcc
docs(governance): record restored approval contract
seonghobae Aug 20, 2026
bc2c93a
docs(governance): refresh stacked review rollout ledger
seonghobae Aug 20, 2026
501fe54
fix(router): permit exact-head dispatch enqueue
seonghobae Aug 20, 2026
aa63517
fix(router): preserve every trusted mention with least privilege
seonghobae Aug 20, 2026
a7aeb56
fix(workflows): remove unsupported concurrency queue
seonghobae Aug 20, 2026
c18d8c0
Merge remote-tracking branch 'refs/remotes/origin/main' into fix/stac…
seonghobae Aug 20, 2026
158f090
fix(governance): enforce exact central ref scope
seonghobae Aug 20, 2026
b873e71
fix(router): use reviewer token for sibling acknowledgements
seonghobae Aug 20, 2026
a56bf7f
fix(strix): classify caido sandbox startup failure
seonghobae Aug 20, 2026
33b85a8
fix(strix): require trusted caido traceback marker
seonghobae Aug 20, 2026
08f0f04
Merge main into stacked PR governance fix
seonghobae Aug 21, 2026
b628e88
fix(governance): preserve proposal branch create transition
seonghobae Aug 21, 2026
cf94d18
chore(governance): synchronize protected main
seonghobae Aug 21, 2026
f0bef61
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 21, 2026
8923bad
fix(ci): refresh audit lock and scheduler assertion
seonghobae Aug 21, 2026
d6be648
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 21, 2026
c6e1ba3
chore(governance): restore canonical pip lock ownership
seonghobae Aug 21, 2026
6bf0447
fix(governance): avoid misleading multi-rule drift
seonghobae Aug 21, 2026
5d64102
ci: refresh dependency and scheduler contracts
seonghobae Aug 21, 2026
4eedfa4
Merge remote-tracking branch 'origin/main' into codex/pr1176-restack
seonghobae Aug 21, 2026
5b2a216
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 21, 2026
49f6988
merge(main): retain only proposal-branch governance repair
seonghobae Aug 23, 2026
2f16ea9
merge(main): refresh proposal-branch governance repair
seonghobae Aug 24, 2026
cc941b2
merge(main): refresh create-transition audit after Strix hotfix
seonghobae Aug 24, 2026
55a6a79
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 24, 2026
27a686b
Merge protected main into fix/stacked-pr-central-required-workflows
seonghobae Aug 25, 2026
366fe2f
merge: converge governance create-transition owner with protected main
seonghobae Aug 25, 2026
437ea84
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 26, 2026
d6bb951
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 26, 2026
5486790
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 26, 2026
2701cf9
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 26, 2026
8664a7c
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 26, 2026
36d4fec
Merge branch 'main' into fix/stacked-pr-central-required-workflows
seonghobae Aug 26, 2026
6b09d65
Merge branch 'main' into fix/stacked-pr-central-required-workflows
seonghobae Aug 27, 2026
31e00c1
Merge branch 'main' into fix/stacked-pr-central-required-workflows
seonghobae Aug 28, 2026
940511d
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 28, 2026
f94292a
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 28, 2026
482d4c0
Merge protected main into proposal-branch governance repair
seonghobae Aug 28, 2026
2a9d115
fix(governance): audit owner repository review ruleset
seonghobae Aug 30, 2026
4ae3c61
fix(governance): reject hidden ruleset drift
seonghobae Aug 30, 2026
d222401
fix(governance): audit organization bypass actors
seonghobae Aug 30, 2026
0b0a45b
fix(governance): fail closed on missing bypass evidence
seonghobae Aug 30, 2026
63ca5e7
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 30, 2026
8ea2ec5
Retrigger required checks against refreshed main (no new main commits…
claude Aug 30, 2026
8dea465
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 30, 2026
ce108e7
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 30, 2026
8a7c5b1
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 30, 2026
faf1dd6
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 30, 2026
36ade87
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 30, 2026
53f99d7
Merge branch 'main' into fix/stacked-pr-central-required-workflows
seonghobae Aug 30, 2026
dc8d7d9
Merge branch 'main' into fix/stacked-pr-central-required-workflows
seonghobae Aug 30, 2026
718ae19
Merge protected main into fix/stacked-pr-central-required-workflows
seonghobae Aug 30, 2026
c1b31b2
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 31, 2026
2bc22cc
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 31, 2026
73b5b28
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 31, 2026
135f16f
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 31, 2026
5acc547
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 31, 2026
a14822c
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 31, 2026
3407ca6
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 31, 2026
df92a2e
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 31, 2026
d33dd13
Merge branch 'main' into fix/stacked-pr-central-required-workflows
opencode-agent[bot] Aug 31, 2026
d435f88
Merge protected main into fix/stacked-pr-central-required-workflows
seonghobae Aug 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/workflows/audit-central-ruleset.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ jobs:
ORG_LOGIN: ContextualWisdomLab
RULESET_ID: "18156473"
STACKED_RULESET_ID: "21732164"
REPOSITORY_RULESET_ID: "17921150"
RULESET_SENTINEL_REPOSITORY: naruon
run: |
set -euo pipefail
Expand Down Expand Up @@ -91,6 +92,16 @@ jobs:
"$ruleset_json" >"$ruleset_with_scope_json"
python3 scripts/ci/audit_central_required_workflows.py "$ruleset_with_scope_json"

repository_ruleset_json="$RUNNER_TEMP/owner-repository-ruleset.json"
repository_ruleset_error="$RUNNER_TEMP/owner-repository-ruleset.error"
repository_ruleset_endpoint="repos/${ORG_LOGIN}/.github/rulesets/${REPOSITORY_RULESET_ID}?includes_parents=true"
if ! gh api "$repository_ruleset_endpoint" >"$repository_ruleset_json" 2>"$repository_ruleset_error"; then
echo "::error::Ruleset audit could not read owner repository ruleset ${REPOSITORY_RULESET_ID}."
sed 's/^/ /' "$repository_ruleset_error"
exit 1
fi
python3 scripts/ci/audit_central_required_workflows.py --repository "$repository_ruleset_json"

stacked_ruleset_json="$RUNNER_TEMP/stacked-opencode-ruleset.json"
stacked_ruleset_error="$RUNNER_TEMP/stacked-opencode-ruleset.error"
stacked_endpoint="repos/${ORG_LOGIN}/${RULESET_SENTINEL_REPOSITORY}/rulesets/${STACKED_RULESET_ID}?includes_parents=true"
Expand Down
114 changes: 101 additions & 13 deletions scripts/ci/audit_central_required_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@

import argparse
import json
from pathlib import Path
import sys
from pathlib import Path
from typing import Any, TextIO


RULESET_ID = 18156473
RULESET_NAME = "CWL Central required workflows"
STACKED_RULESET_ID = 21732164
STACKED_RULESET_NAME = "CWL Stacked OpenCode required workflow"
REPOSITORY_RULESET_ID = 17921150
REPOSITORY_RULESET_NAME = "Lock default branch"
REPOSITORY_RULESET_SOURCE = "ContextualWisdomLab/.github"
SOURCE_REPOSITORY_ID = 1274066402
SOURCE_REF = "refs/heads/main"
SOURCE_ORGANIZATION = "ContextualWisdomLab"
Expand Down Expand Up @@ -59,6 +61,8 @@ def audit_ruleset(payload: dict[str, Any]) -> list[str]:
errors.append("central ruleset target is not branch")
if payload.get("enforcement") != "active":
errors.append("central ruleset enforcement is not active")
if payload.get("bypass_actors") != []:
Comment thread
seonghobae marked this conversation as resolved.
errors.append("central ruleset must not configure bypass actors")

conditions = payload.get("conditions")
conditions = conditions if isinstance(conditions, dict) else {}
Expand Down Expand Up @@ -115,25 +119,47 @@ def audit_ruleset(payload: dict[str, Any]) -> list[str]:

ref_names = conditions.get("ref_name")
ref_names = ref_names if isinstance(ref_names, dict) else {}
if "~DEFAULT_BRANCH" not in (ref_names.get("include") or []):
errors.append("central ruleset does not target every default branch")
if (
ref_names.get("include") != ["~DEFAULT_BRANCH"]
or ref_names.get("exclude") != []
):
errors.append("central ruleset ref scope must be exactly the default branch")
Comment thread
seonghobae marked this conversation as resolved.

workflow_rules = _typed_rules(payload, "workflows")
workflow_parameters: dict[str, Any] = {}
if len(workflow_rules) != 1:
errors.append(f"expected one workflows rule, found {len(workflow_rules)}")
workflows: list[Any] = []
else:
parameters = workflow_rules[0].get("parameters")
parameters = parameters if isinstance(parameters, dict) else {}
workflows = parameters.get("workflows")
workflow_parameters = parameters if isinstance(parameters, dict) else {}
workflows = workflow_parameters.get("workflows")
workflows = workflows if isinstance(workflows, list) else []
Comment thread
seonghobae marked this conversation as resolved.

if len(workflow_rules) == 1 and workflow_parameters.get("do_not_enforce_on_create") is not True:
errors.append("central required workflows block the branch create transition")
Comment thread
seonghobae marked this conversation as resolved.

malformed_workflows = sum(
1
for workflow in workflows
if not isinstance(workflow, dict) or not isinstance(workflow.get("path"), str)
)
if malformed_workflows:
suffix = "entry" if malformed_workflows == 1 else "entries"
errors.append(
f"central required workflows contain {malformed_workflows} malformed {suffix}"
)

workflows_by_path: dict[str, list[dict[str, Any]]] = {}
for workflow in workflows:
if not isinstance(workflow, dict) or not isinstance(workflow.get("path"), str):
continue
workflows_by_path.setdefault(workflow["path"], []).append(workflow)

unexpected_workflows = sorted(set(workflows_by_path) - set(REQUIRED_WORKFLOW_PATHS))
if unexpected_workflows:
errors.append(f"unexpected central required workflows: {unexpected_workflows}")

for path in REQUIRED_WORKFLOW_PATHS:
matches = workflows_by_path.get(path, [])
if not matches:
Expand Down Expand Up @@ -167,8 +193,8 @@ def audit_ruleset(payload: dict[str, Any]) -> list[str]:
if parameters.get("required_review_thread_resolution") is not True:
errors.append("review-thread resolution protection is disabled")
allowed_methods = set(parameters.get("allowed_merge_methods") or [])
if not {"merge", "squash"}.issubset(allowed_methods):
errors.append("merge and squash are not both allowed merge methods")
if allowed_methods != {"merge", "squash"}:
errors.append("only merge and squash may be allowed merge methods")

if not _typed_rules(payload, "deletion"):
errors.append("default-branch deletion protection is missing")
Expand Down Expand Up @@ -237,6 +263,55 @@ def audit_stacked_ruleset(payload: dict[str, Any]) -> list[str]:
return errors


def audit_repository_ruleset(payload: dict[str, Any]) -> list[str]:
"""Return drift reasons for the owner repository's default-branch policy."""

errors: list[str] = []
if payload.get("id") != REPOSITORY_RULESET_ID:
errors.append(f"expected repository ruleset id {REPOSITORY_RULESET_ID}")
if payload.get("name") != REPOSITORY_RULESET_NAME:
errors.append(f"expected repository ruleset name {REPOSITORY_RULESET_NAME}")
if payload.get("source_type") != "Repository" or payload.get("source") != REPOSITORY_RULESET_SOURCE:
errors.append("repository ruleset source is not ContextualWisdomLab/.github")
if payload.get("target") != "branch":
errors.append("repository ruleset target is not branch")
if payload.get("enforcement") != "active":
errors.append("repository ruleset enforcement is not active")
if payload.get("bypass_actors") != []:
errors.append("repository ruleset must not configure bypass actors")

conditions = payload.get("conditions")
conditions = conditions if isinstance(conditions, dict) else {}
ref_names = conditions.get("ref_name")
ref_names = ref_names if isinstance(ref_names, dict) else {}
if ref_names != {"include": ["~DEFAULT_BRANCH"], "exclude": []}:
errors.append("repository ruleset ref scope must be exactly the default branch")

review_rules = _typed_rules(payload, "pull_request")
if len(review_rules) != 1:
errors.append(f"expected one repository pull_request rule, found {len(review_rules)}")
else:
raw_parameters = review_rules[0].get("parameters")
parameters = raw_parameters if isinstance(raw_parameters, dict) else {}
if parameters.get("required_approving_review_count") != 2:
errors.append("repository ruleset does not require exactly two approving reviews")
if parameters.get("dismiss_stale_reviews_on_push") is not True:
errors.append("repository ruleset stale-review dismissal on push is disabled")
if parameters.get("require_last_push_approval") is not True:
errors.append("repository ruleset last-push approval protection is disabled")
if parameters.get("required_review_thread_resolution") is not True:
errors.append("repository ruleset review-thread resolution protection is disabled")
allowed_methods = set(parameters.get("allowed_merge_methods") or [])
if allowed_methods != {"merge", "squash"}:
errors.append("repository ruleset must allow only merge and squash")

if not _typed_rules(payload, "deletion"):
errors.append("repository default-branch deletion protection is missing")
if not _typed_rules(payload, "non_fast_forward"):
errors.append("repository default-branch non-fast-forward protection is missing")
return errors
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.


def load_payload(path: Path | None, stdin: TextIO) -> dict[str, Any]:
"""Load a ruleset object from ``path`` or standard input."""
if path is None:
Expand All @@ -252,7 +327,9 @@ def load_payload(path: Path | None, stdin: TextIO) -> dict[str, Any]:
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
"""Parse the optional ruleset JSON path."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--stacked", action="store_true")
mode = parser.add_mutually_exclusive_group()
mode.add_argument("--stacked", action="store_true")
mode.add_argument("--repository", action="store_true")
parser.add_argument("ruleset_json", nargs="?", type=Path)
return parser.parse_args(argv)

Expand All @@ -266,9 +343,18 @@ def main(argv: list[str] | None = None) -> int:
print(f"ERROR: unable to load ruleset JSON: {exc}", file=sys.stderr)
return 2

auditor = audit_stacked_ruleset if args.stacked else audit_ruleset
ruleset_id = STACKED_RULESET_ID if args.stacked else RULESET_ID
workflow_count = 1 if args.stacked else len(REQUIRED_WORKFLOW_PATHS)
if args.repository:
auditor = audit_repository_ruleset
ruleset_id = REPOSITORY_RULESET_ID
workflow_count = 0
elif args.stacked:
auditor = audit_stacked_ruleset
ruleset_id = STACKED_RULESET_ID
workflow_count = 1
else:
auditor = audit_ruleset
ruleset_id = RULESET_ID
workflow_count = len(REQUIRED_WORKFLOW_PATHS)
errors = auditor(payload)
if errors:
for error in errors:
Expand All @@ -279,7 +365,9 @@ def main(argv: list[str] | None = None) -> int:
)
return 1

if args.stacked:
if args.repository:
print(f"PASS: repository ruleset {ruleset_id} protects the default branch")
elif args.stacked:
print(
f"PASS: ruleset {ruleset_id} audits {workflow_count} "
"central required workflows in evaluate mode"
Expand Down
Loading
Loading