Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions governance/apply.sh
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,20 @@ for r in $REPOS; do
expect_ok "repo '$r' 基线" "$code"
done

echo "==> 6/6 merge queue(repo 级 ruleset;ADR-0042——REST 不支持 merge_queue 规则,写入走 GraphQL)"
for r in $(jq -r '.merge_queue.repos // [] | .[]' "$EXPECTED"); do
SRC_ID=$(curl -sS -H "Authorization: Bearer ${GH_TOKEN}" -H "Content-Type: application/json" -d '{"query":"{repository(owner:\"Cloudbird-Software\", name:\"'"$r"'\" ){id}}"}' https://api.github.com/graphql | jq -r '.data.repository.id')
RID=$(curl -sS -H "Authorization: Bearer ${GH_TOKEN}" -H "Content-Type: application/json" -d '{"query":"query($r:String!){repository(owner:\"Cloudbird-Software\", name:$r){rulesets(first:50){nodes{name databaseId}}}}","variables":{"r":"'"$r"'"}}' https://api.github.com/graphql | jq -r '.data.repository.rulesets.nodes[]? | select(.name == "merge-queue") | .databaseId')
Comment on lines +145 to +146

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

6. Configured organization is ignored 🐞 Bug ≡ Correctness

Step 6 hardcodes Cloudbird-Software in both GraphQL lookups instead of using the script’s
configurable ORG. Running with an overridden organization makes earlier steps operate on the
requested organization while merge-queue creation fails against, or targets repositories in,
Cloudbird-Software.
Agent Prompt
## Issue description
The merge-queue GraphQL calls ignore the configured `ORG` and always query Cloudbird-Software.

## Issue Context
`apply.sh` explicitly supports overriding `ORG`, and all preceding REST operations use that value. Pass owner and repository name as GraphQL variables rather than interpolating literals.

## Fix Focus Areas
- governance/apply.sh[26-32]
- governance/apply.sh[143-146]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

if [[ -n "$RID" && "$RID" != "null" ]]; then
echo " repo '$r' merge-queue ruleset 已存在(id=$RID;参数对账由 drift-check §14 执法)"
continue
fi
MUT='mutation($src: ID!) { createRepositoryRuleset(input: { sourceId: $src, name: "merge-queue", target: BRANCH, enforcement: ACTIVE, conditions: { refName: { include: ["~DEFAULT_BRANCH"], exclude: [] } }, rules: [ { type: PULL_REQUEST, parameters: { pullRequest: { requiredApprovingReviewCount: 0, dismissStaleReviewsOnPush: true, requireCodeOwnerReview: false, requireLastPushApproval: false, requiredReviewThreadResolution: false, allowedMergeMethods: [SQUASH] } } }, { type: REQUIRED_STATUS_CHECKS, parameters: { requiredStatusChecks: { requiredStatusChecks: [{ context: "gate", integrationId: null }], strictRequiredStatusChecksPolicy: false } } }, { type: MERGE_QUEUE, parameters: { mergeQueue: { mergeMethod: SQUASH, checkResponseTimeoutMinutes: 60, maxEntriesToBuild: 5, minEntriesToMerge: 1, maxEntriesToMerge: 1, minEntriesToMergeWaitMinutes: 0, groupingStrategy: ALLGREEN } } } ] }) { ruleset { databaseId } } }'
RESP=$(jq -n --arg q "$MUT" --arg src "$SRC_ID" '{query:$q, variables:{src:$src}}')
Comment on lines +151 to +152

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

7. Apply ignores declared parameters 🐞 Bug ⚙ Maintainability

The creation mutation hardcodes every merge-queue parameter rather than reading
.merge_queue.params from expected-state.json. A future parameter change in the declared single
source creates the old configuration, after which drift-check immediately rejects the result.
Agent Prompt
## Issue description
Merge-queue creation duplicates all expected parameters as hardcoded GraphQL values instead of consuming the expected-state declaration.

## Issue Context
The expected-state file describes itself as the source used by both drift-check and apply. Drift-check already reads these parameters dynamically, while apply does not.

## Fix Focus Areas
- governance/apply.sh[151-153]
- governance/expected-state.json[83-97]
- governance/drift-check.sh[575-580]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

OUT=$(curl -sS -H "Authorization: Bearer ${GH_TOKEN}" -H "Content-Type: application/json" -d "$RESP" https://api.github.com/graphql)
echo "$OUT" | jq -e '.data.createRepositoryRuleset.ruleset.databaseId' >/dev/null 2>&1 && echo " repo '$r' merge-queue: created" || { echo " repo '$r' merge-queue: FAIL $(echo "$OUT" | jq -r '.errors[0].message // "未知"')" >&2; FAILS=$((FAILS+1)); }
done

echo "----------------------------------------"
if [[ $FAILS -gt 0 ]]; then
echo "结果: $FAILS 项 FAIL(见上方 stderr)。部分应用——修复后重跑本脚本(幂等)。验证: bash $DIR/drift-check.sh" >&2
Expand Down
33 changes: 33 additions & 0 deletions governance/drift-check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,39 @@ for r in $REPOS; do
done
[[ $STUCK_TOTAL -eq 0 ]] && ok "pr-liveness(全部受管仓 open PR 无卡死,阈值 ${LIVENESS_H}h)"

# ---------- 14. merge queue 对账(P2-7,ADR-0042;repo 级 ruleset)----------
# org rulesets API 不支持 merge_queue 规则类型(实测 422)——merge queue 只能以
# repo 级 ruleset 存在(须与 pull_request/required_status_checks 同集)。期望状态
# expected-state.json#merge_queue 声明仓清单与参数;REST 读 repo ruleset 可见
# merge_queue 规则(读支持,写须 GraphQL——apply.sh step6)。
MQ_REPOS=$(jq -r '.merge_queue.repos // [] | .[]' "$EXPECTED")
for r in $MQ_REPOS; do
RS=$(api "https://api.github.com/repos/$ORG/$r/rulesets?per_page=100")
if ! jq -e 'type == "array"' <<<"$RS" >/dev/null 2>&1; then
drift "repo '$r' rulesets 清单拉取失败,merge queue 对账无法执行(fail-closed)"; continue
fi
row=$(jq -c --arg n "merge-queue" '.[] | select(.name == $n)' <<<"$RS")
if [[ -z "$row" || "$row" == "null" ]]; then
drift "repo '$r' 期望启用 merge queue(ADR-0042)但无 'merge-queue' ruleset"; continue
fi
rid=$(jq -r .id <<<"$row")
detail=$(api "https://api.github.com/repos/$ORG/$r/rulesets/$rid")
want_p=$(jq -c '.merge_queue.params' "$EXPECTED")
got_p=$(jq -c '.rules[] | select(.type == "merge_queue") | .parameters
| {merge_method, check_response_timeout_minutes, max_entries_to_build,
min_entries_to_merge, max_entries_to_merge, min_entries_to_merge_wait_minutes,
grouping_strategy}' <<<"$detail")
Comment on lines +576 to +579

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

3. Disabled queue passes reconciliation 🐞 Bug ≡ Correctness

Section 14 compares only the merge_queue rule parameters and never verifies ruleset enforcement,
target, or default-branch conditions. A ruleset changed to disabled evaluation or made inapplicable
to the default branch therefore still produces an OK result despite the expected merge queue no
longer being enforced.
Agent Prompt
## Issue description
The merge-queue drift check validates only queue parameters, allowing disabled or inapplicable rulesets to pass.

## Issue Context
The creation mutation explicitly requires active enforcement, a branch target, and the default-branch condition, so these fields are part of the effective desired state even though §14 ignores them.

## Fix Focus Areas
- governance/drift-check.sh[573-581]
- governance/apply.sh[151-151]
- governance/expected-state.json[83-97]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

[[ "$got_p" == "$want_p" ]] || drift "repo '$r' merge-queue 参数漂移: got=$got_p 期望=$want_p"
ok "merge-queue '$r'(参数与期望一致)"
done
# 未声明仓不得私自开队列(期望清单外的仓出现 merge-queue ruleset = 漂移)
for r in $REPOS; do
jq -e --arg r "$r" '.merge_queue.repos // [] | index($r) != null' "$EXPECTED" >/dev/null && continue
RS=$(api "https://api.github.com/repos/$ORG/$r/rulesets?per_page=100")
jq -e 'type == "array"' <<<"$RS" >/dev/null 2>&1 || continue
Comment on lines +586 to +587

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

5. Undeclared scan fails open 🐞 Bug ☼ Reliability

When an undeclared repository’s rulesets request fails or returns an error object, line 587 silently
skips that repository without recording drift. The overall check can therefore exit successfully
while being unable to determine whether that repository has an unauthorized merge queue.
Agent Prompt
## Issue description
The undeclared merge-queue scan silently skips repositories whose rulesets cannot be read, allowing an unverifiable run to pass.

## Issue Context
The declared-repository branch already records the same non-array response as drift. Apply equivalent fail-closed behavior to the undeclared scan.

## Fix Focus Areas
- governance/drift-check.sh[583-588]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

jq -e '.[] | select(.name == "merge-queue")' <<<"$RS" >/dev/null 2>&1 && drift "repo '$r' 存在未声明的 merge-queue ruleset(expected-state.merge_queue.repos 未列——扩围须修订 ADR-0042)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

4. Renamed queues evade detection 🐞 Bug ≡ Correctness

The undeclared-repository check identifies merge queues solely by the arbitrary ruleset name
merge-queue, rather than by a contained rule whose type is merge_queue. An undeclared repository
can therefore enable a queue under any other ruleset name without producing drift.
Agent Prompt
## Issue description
Unauthorized merge queues evade detection when their repository ruleset has a name other than `merge-queue`.

## Issue Context
Ruleset names are labels; merge-queue behavior is represented by a rule with type `merge_queue`. The list response does not include full rules, so matching candidates must be fetched and inspected by rule type.

## Fix Focus Areas
- governance/drift-check.sh[583-588]
- governance/drift-check.sh[569-580]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

done

echo "----------------------------------------"
if [[ $DRIFTS -gt 0 ]]; then
echo "结果: $DRIFTS 项漂移。修复: bash governance/apply.sh 或手动改回"
Expand Down
18 changes: 17 additions & 1 deletion governance/expected-state.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,21 @@
"60bd1557481fa89d0358302e150a8f7d9381309c",
"e9424d220ded331c221b37135faa9d6e9cd1ecac"
]
},
"merge_queue": {
"comment": "P2-7 ADR-0042:merge queue 为 repo 级 ruleset(org rulesets API 不支持 merge_queue 规则类型)。串行保守起步;扩围须修订 ADR-0042。",
"repos": [
"agent-registry",
"template-service"
],
"params": {
"merge_method": "squash",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Merge method always mismatches 🐞 Bug ≡ Correctness

The expected state stores merge_method as lowercase squash, while GitHub’s merge-queue REST
representation uses the uppercase enum SQUASH. Consequently §14 reports parameter drift for the
GraphQL-created ruleset even when it has exactly the intended merge method.
Agent Prompt
## Issue description
The expected merge-queue method uses lowercase `squash`, but the REST ruleset response uses the uppercase merge-queue enum `SQUASH`, causing permanent false drift.

## Issue Context
GraphQL creates the rule with `mergeMethod: SQUASH`, and drift-check compares the REST response directly with expected-state JSON.

## Fix Focus Areas
- governance/expected-state.json[89-96]
- governance/drift-check.sh[575-580]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

"check_response_timeout_minutes": 60,
"max_entries_to_build": 5,
"min_entries_to_merge": 1,
"max_entries_to_merge": 1,
"min_entries_to_merge_wait_minutes": 0,
"grouping_strategy": "ALLGREEN"
}
}
}
}
38 changes: 0 additions & 38 deletions governance/rulesets/merge-queue.json

This file was deleted.