Skip to content
Merged
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
1ea01f7
feat: initial BMad Operations Suite module
Apr 4, 2026
1a73ed5
refactor: rename module from ops to bmad-bgreat-suite (bgr)
Apr 4, 2026
e3f5d3b
feat: add CI workflows, dependabot config, and CODEOWNERS (#29)
don-petry Apr 5, 2026
c40e5b9
chore: add Claude Code workflow per org CI standard (#39)
don-petry Apr 5, 2026
5557279
feat: split Claude workflow into interactive + issue automation jobs …
don-petry Apr 6, 2026
c230f9b
feat: switch to org-level reusable Claude Code workflow
don-petry Apr 6, 2026
b97e403
chore(workflows): adopt centralized stubs from petry-projects/.github…
don-petry Apr 8, 2026
70580eb
chore(workflows): adopt centralized claude.yml stub (#81)
don-petry Apr 8, 2026
619bde8
ci: add auto-rebase workflow and check_run trigger to claude.yml (#126)
don-petry Apr 21, 2026
43d1865
chore(dev-lead): remove claude.yml — replaced by dev-lead.yml (#151)
don-petry May 16, 2026
e2d7c11
chore: remove stray codeql.yml workflow (#96)
don-petry May 16, 2026
0c69d9b
chore: remove stray codeql.yml (CodeQL via default setup) (#105)
don-petry May 20, 2026
bbd39d0
feat: implement issue #146 — Compliance: secret_scanning_non_provider…
don-petry May 20, 2026
6b54991
feat: implement issue #84 — Compliance: unpinned-actions-claude.yml (…
don-petry May 21, 2026
e6f3839
feat: implement issue #83 — Compliance: unpinned-actions-agent-shield…
don-petry May 21, 2026
c6f64d1
feat: implement issue #85 — Compliance: unpinned-actions-dependabot-a…
don-petry May 21, 2026
81fa323
feat: implement issue #86 — Compliance: unpinned-actions-dependency-a…
don-petry May 21, 2026
c648d51
feat: implement issue #140 — Compliance: check-suite-auto-trigger-347…
don-petry May 21, 2026
49a1c44
feat: implement issue #200 — [Fleet Monitor] petry-projects/bmad-bgre…
don-petry May 24, 2026
ba791a7
chore(deps): bump petry-projects/.github/.github/workflows/claude-cod…
dependabot[bot] May 24, 2026
f497af1
chore(compliance): add in-progress label to labels.yml (#117)
don-petry May 24, 2026
76e25f8
rollout: deploy pr-review-mention standard workflow (#236)
don-petry May 31, 2026
52e4eb6
chore(deps): bump gitleaks/gitleaks-action from 2.3.9 to 3.0.0 (#235)
dependabot[bot] May 31, 2026
c21a0d9
feat: add pr-auto-review.yml workflow (compliance automation Phase 2)…
don-petry Jun 1, 2026
a830b24
chore(deps): bump petry-projects/.github/.github/workflows/pr-review-…
dependabot[bot] Jun 1, 2026
2eab8f1
fix: correct pr-auto-review reusable workflow reference (#238)
don-petry Jun 1, 2026
3797532
feat: implement issue #216 — Compliance: copilot-instructions-missing…
don-petry Jun 2, 2026
bcc8b73
chore(deps): bump SonarSource/sonarqube-scan-action from 7.1.0 to 8.0…
dependabot[bot] Jun 2, 2026
77e36cc
feat: implement issue #83 — Compliance: unpinned-actions-agent-shield…
don-petry Jun 10, 2026
157af6a
feat: implement issue #212 — Compliance: non-stub-agent-shield.yml (#…
don-petry Jun 10, 2026
c7acb6c
feat: implement issue #217 — Compliance: check-suite-auto-trigger-123…
don-petry Jun 10, 2026
ead905f
feat: implement issue #135 — Compliance: check-suite-auto-trigger-347…
don-petry Jun 10, 2026
1143e0a
feat: implement issue #91 — Compliance: stray-codeql-workflow (#241)
don-petry Jun 10, 2026
7cd59ab
feat: implement issue #84 — Compliance: unpinned-actions-claude.yml (…
don-petry Jun 10, 2026
8037169
feat: implement issue #293 — Compliance: non-stub-dependabot-automerg…
don-petry Jun 10, 2026
61b0c62
feat: implement issue #90 — Compliance: codeql-default-setup-not-conf…
don-petry Jun 10, 2026
6d7ad4f
feat: implement issue #271 — Compliance: secret_scanning_ai_detection…
don-petry Jun 10, 2026
60dd370
feat: implement issue #214 — Compliance: copilot-setup-steps-invalid-…
don-petry Jun 14, 2026
2105836
feat: implement issue #219 — Compliance: secret_scanning_non_provider…
don-petry Jun 14, 2026
6f12cfb
feat: implement issue #144 — Compliance: non-stub-dependabot-rebase.y…
don-petry Jun 14, 2026
5b6eac3
feat: implement issue #314 — [Fleet Monitor] petry-projects/bmad-bgre…
don-petry Jun 14, 2026
ababf5f
feat: implement issue #184 — [Fleet Monitor] petry-projects/bmad-bgre…
don-petry Jun 16, 2026
0b5a6e1
feat: implement issue #88 — Compliance: delete_branch_on_merge (#240)
don-petry Jun 19, 2026
a68c1a0
chore(deps): bump petry-projects/.github/.github/workflows/claude-cod…
dependabot[bot] Jun 21, 2026
2ef5da5
feat: implement issue #141 — Compliance: secret_scan_ci_job_present (…
don-petry Jun 21, 2026
4d82436
feat: implement issue #92 — Compliance: security_and_analysis_unavail…
don-petry Jun 25, 2026
0784e9a
feat: implement issue #279 — [Fleet Monitor] petry-projects/bmad-bgre…
don-petry Jul 1, 2026
4939472
feat: implement issue #305 — [Fleet Monitor] petry-projects/bmad-bgre…
don-petry Jul 4, 2026
86c3245
chore(deps): bump petry-projects/.github/.github/workflows/claude-cod…
dependabot[bot] Jul 5, 2026
70800d8
ci: remove deprecated claude.yml (decommission claude-code, #665) (#365)
don-petry Jul 11, 2026
66213d5
ci: migrate pr-auto-review → @pr-auto-review/ring1 (canary) (#367)
don-petry Jul 11, 2026
f076f0f
chore: major-scope repin self-consumer stubs [#657 F5] (#370)
don-petry Jul 14, 2026
82d4159
feat: implement issue #360 — SonarCloud: shell script hygiene
donpetry-bot Jul 14, 2026
fa4e171
chore: dev-lead update (review-changes) [skip ci-relay]
donpetry-bot Jul 15, 2026
09529a9
fix(bot): address bot feedback [skip ci-relay]
donpetry-bot Jul 15, 2026
1e8aacc
fix(validate): remove duplicate checks and fix variable name errors
donpetry-bot Jul 16, 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
2 changes: 1 addition & 1 deletion tools/test-ci-secret-scan.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ echo "$DONE_MARK"

# Check 4: continue-on-error must NOT be set on the gitleaks step
# (having it would allow gitleaks findings to silently pass the build)
echo "Check 4: gitleaks step does not use continue-on-error"
echo "Check 4: continue-on-error must NOT be set on the gitleaks step" # NOSONAR
# Use /^[[:space:]]+-[[:space:]]/ as the step delimiter so the check is
# order-independent: continue-on-error is caught whether it appears before or
# after the uses: line within the same step.
Expand Down
222 changes: 222 additions & 0 deletions tools/test-repo-settings.sh
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,228 @@
fi
echo "$DONE_MARK"

# Check that check-suite auto-trigger is disabled for Claude app (1236702)
echo ""
echo "Check 2: check-suite auto-trigger disabled for Claude app (1236702)"
if ! grep -q 'check-suites/preferences' "$SCRIPT"; then
error "$SCRIPT does not contain a check-suite preferences API call"
elif ! grep -E -q '"app_id"[[:space:]]*:[[:space:]]*1236702' "$SCRIPT"; then
error "$SCRIPT references check-suites/preferences but does not configure app_id 1236702"
elif ! grep -E -q '"app_id"[[:space:]]*:[[:space:]]*1236702[[:space:]]*,[[:space:]]*"setting"[[:space:]]*:[[:space:]]*false' "$SCRIPT"; then
error "$SCRIPT configures app_id 1236702 but does not set setting to false"
fi
echo "$DONE_MARKER"
Comment thread
don-petry marked this conversation as resolved.
Resolved

# Check that check-suite auto-trigger is disabled for CodeRabbit (app_id 347564)
echo ""
echo "Check 3: check-suite auto-trigger disabled for CodeRabbit (app_id 347564)"
if ! grep -q 'check-suites/preferences' "$SCRIPT"; then

Check warning on line 194 in tools/test-repo-settings.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of using the literal 'check-suites/preferences' 4 times.

See more on https://sonarcloud.io/project/issues?id=petry-projects_bmad-bgreat-suite&issues=AZ9pEm3Ypb-PQPyHR8J_&open=AZ9pEm3Ypb-PQPyHR8J_&pullRequest=377
error "$SCRIPT does not contain a check-suites/preferences API call"
Comment thread
don-petry marked this conversation as resolved.
Resolved
elif ! grep -E -q '"app_id"[[:space:]]*:[[:space:]]*347564' "$SCRIPT"; then
error "$SCRIPT does not configure auto-trigger for CodeRabbit (app_id 347564)"
elif ! grep -E -q '"app_id"[[:space:]]*:[[:space:]]*347564[[:space:]]*,[[:space:]]*"setting"[[:space:]]*:[[:space:]]*false' "$SCRIPT"; then
error "$SCRIPT does not disable auto-trigger for CodeRabbit (app_id 347564)"
fi
echo "$DONE_MARKER"

# Check that the workflow has no paths: filter so it runs on every push to main
echo ""
echo "Check 4: apply-repo-settings.yml triggers on every push to main (no paths: filter)"
WORKFLOW=".github/workflows/apply-repo-settings.yml"
if [[ ! -f "$WORKFLOW" ]]; then
error "Missing $WORKFLOW"
elif grep -q '^[[:space:]]*paths:' "$WORKFLOW"; then
error "$WORKFLOW has a 'paths:' filter — the workflow will only run when the script itself changes, not on every push; the security setting may not be applied after a new merge"
fi
echo "$DONE_MARKER"

echo ""

# Check that CodeQL default setup is configured in the script
echo "Check 5: CodeQL default setup is configured"
if ! grep -q 'code-scanning/default-setup' "$SCRIPT"; then
error "$SCRIPT does not contain a code-scanning/default-setup API call"
elif ! grep -E -q 'state=configured|"state":"configured"' "$SCRIPT"; then
error "$SCRIPT references code-scanning/default-setup but does not set state to configured"
elif ! grep -E -q 'query_suite=default|"query_suite":"default"' "$SCRIPT"; then
error "$SCRIPT references code-scanning/default-setup but does not set query_suite to default"
fi
echo "$DONE_MARKER"

# Check that delete_branch_on_merge is enabled in the script
echo ""
echo "Check 6: delete_branch_on_merge is enabled"
if ! grep -q 'delete_branch_on_merge' "$SCRIPT"; then
error "$SCRIPT does not contain a delete_branch_on_merge API call"
elif ! grep -E -q '"delete_branch_on_merge"[[:space:]]*:[[:space:]]*true' "$SCRIPT"; then
error "$SCRIPT references delete_branch_on_merge but does not set it to true"
fi
echo "$DONE_MARKER"

echo ""

# Check that secret_scanning_non_provider_patterns is enabled in the script
echo "Check 7: secret_scanning_non_provider_patterns is set to enabled"
if ! grep -q 'secret_scanning_non_provider_patterns' "$SCRIPT"; then
error "$SCRIPT does not contain a secret_scanning_non_provider_patterns API call"
elif ! grep -E -q '"secret_scanning_non_provider_patterns"[[:space:]]*:[[:space:]]*\{[[:space:]]*"status"[[:space:]]*:[[:space:]]*"enabled"[[:space:]]*\}' "$SCRIPT"; then
error "$SCRIPT references secret_scanning_non_provider_patterns but does not set status to enabled"
fi
echo "$DONE_MARKER"

# Check that every permissions: scope in the workflow is a valid GitHub Actions
# scope. An invalid scope (e.g. `administration`, which is not a GITHUB_TOKEN
# permission) makes the whole file an "invalid workflow file" that fails at
# startup with 0s duration on every run.
echo ""
echo "Check 8: apply-repo-settings.yml uses only valid permissions scopes"
if [[ ! -f "$WORKFLOW" ]]; then
error "Missing $WORKFLOW"
elif ! command -v python3 >/dev/null 2>&1 || ! python3 -c "import yaml" >/dev/null 2>&1; then
echo " python3/PyYAML unavailable — skipping permissions-scope validation"
else
invalid_scopes=$(python3 - "$WORKFLOW" <<'PY'
import sys, yaml

# Valid GITHUB_TOKEN permission scopes accepted in a workflow `permissions:` block.
ALLOWED = {
"actions", "attestations", "checks", "contents", "deployments",
"discussions", "id-token", "issues", "models", "packages", "pages",
"pull-requests", "repository-projects", "security-events", "statuses",
}

with open(sys.argv[1]) as fh:
wf = yaml.safe_load(fh)

if not isinstance(wf, dict):
wf = {}

def scopes(perms):
# A mapping of scope -> level; a bare string ("read-all"/"write-all") or
# empty mapping declares no individual scopes to validate.
return set(perms) if isinstance(perms, dict) else set()

bad = set()
bad |= scopes(wf.get("permissions"))
jobs = wf.get("jobs")
if isinstance(jobs, dict):
for job in jobs.values():
if isinstance(job, dict):
bad |= scopes(job.get("permissions"))
bad -= ALLOWED
print("\n".join(sorted(bad)))
PY
)
if [[ -n "$invalid_scopes" ]]; then
while IFS= read -r scope; do
[[ -z "$scope" ]] && continue
error "$WORKFLOW declares invalid permissions scope '$scope' — GitHub rejects this as an invalid workflow file, causing every run to fail at startup"
done <<< "$invalid_scopes"
fi
fi
echo "$DONE_MARKER"

echo ""
echo "Check 9: secret_scanning is set to enabled"
if ! grep -q '"secret_scanning":' "$SCRIPT"; then
error "$SCRIPT does not contain a secret_scanning API call"
elif ! grep -q '"secret_scanning":{"status":"enabled"}' "$SCRIPT"; then
error "$SCRIPT references secret_scanning but does not set status to enabled"
fi
echo "$DONE_MARKER"

echo ""
echo "Check 10: secret_scanning_push_protection is set to enabled"
if ! grep -q 'secret_scanning_push_protection' "$SCRIPT"; then
error "$SCRIPT does not contain a secret_scanning_push_protection API call"
elif ! grep -q '"secret_scanning_push_protection":{"status":"enabled"}' "$SCRIPT"; then
error "$SCRIPT references secret_scanning_push_protection but does not set status to enabled"
fi
echo "$DONE_MARKER"

echo ""
echo "Check 11: dependabot automated security fixes are enabled"
if ! grep -q 'automated-security-fixes' "$SCRIPT"; then
error "$SCRIPT does not contain an automated-security-fixes API call"
fi
echo "$DONE_MARKER"

echo ""

# Check that CodeQL default setup is configured in the script
echo "Check 4: CodeQL default setup is configured"
if ! grep -q 'code-scanning/default-setup' "$SCRIPT"; then
error "$SCRIPT does not contain a code-scanning/default-setup API call"
elif ! grep -E -q 'state=configured|"state":"configured"' "$SCRIPT"; then
error "$SCRIPT references code-scanning/default-setup but does not set state to configured"
elif ! grep -E -q 'query_suite=default|"query_suite":"default"' "$SCRIPT"; then
error "$SCRIPT references code-scanning/default-setup but does not set query_suite to default"
fi
echo "$DONE_MARKER"

echo ""

# Check that secret_scanning_non_provider_patterns is enabled in the script
echo "Check 3: secret_scanning_non_provider_patterns is set to enabled"
if ! grep -q 'secret_scanning_non_provider_patterns' "$SCRIPT"; then
error "$SCRIPT does not contain a secret_scanning_non_provider_patterns API call"
elif ! grep -E -q '"secret_scanning_non_provider_patterns"[[:space:]]*:[[:space:]]*\{[[:space:]]*"status"[[:space:]]*:[[:space:]]*"enabled"[[:space:]]*\}' "$SCRIPT"; then
error "$SCRIPT references secret_scanning_non_provider_patterns but does not set status to enabled"
fi
echo "$DONE_MARKER"

# Check that every permissions: scope in the workflow is a valid GitHub Actions
# scope. An invalid scope (e.g. `administration`, which is not a GITHUB_TOKEN
# permission) makes the whole file an "invalid workflow file" that fails at
# startup with 0s duration on every run.
echo ""
echo "Check 6: apply-repo-settings.yml uses only valid permissions scopes"
if [[ ! -f "$WORKFLOW" ]]; then
error "Missing $WORKFLOW"
elif ! command -v python3 >/dev/null 2>&1 || ! python3 -c "import yaml" >/dev/null 2>&1; then
echo " python3/PyYAML unavailable — skipping permissions-scope validation"
else
invalid_scopes=$(python3 - "$WORKFLOW" <<'PY'
import sys, yaml

# Valid GITHUB_TOKEN permission scopes accepted in a workflow `permissions:` block.
ALLOWED = {
"actions", "attestations", "checks", "contents", "deployments",
"discussions", "id-token", "issues", "models", "packages", "pages",
"pull-requests", "repository-projects", "security-events", "statuses",
}

with open(sys.argv[1]) as fh:
wf = yaml.safe_load(fh)

if not isinstance(wf, dict):
wf = {}

def scopes(perms):
# A mapping of scope -> level; a bare string ("read-all"/"write-all") or
# empty mapping declares no individual scopes to validate.
return set(perms) if isinstance(perms, dict) else set()

bad = set()
bad |= scopes(wf.get("permissions"))
jobs = wf.get("jobs")
if isinstance(jobs, dict):
for job in jobs.values():
if isinstance(job, dict):
bad |= scopes(job.get("permissions"))
bad -= ALLOWED
print("\n".join(sorted(bad)))
PY
)
if [[ -n "$invalid_scopes" ]]; then
while IFS= read -r scope; do
[[ -z "$scope" ]] && continue
error "$WORKFLOW declares invalid permissions scope '$scope' — GitHub rejects this as an invalid workflow file, causing every run to fail at startup"
done <<< "$invalid_scopes"
fi
fi
echo "$DONE_MARKER"

echo ""
if [[ "$ERRORS" -gt 0 ]]; then
echo "Settings coverage check failed with $ERRORS error(s)" >&2
Expand Down
52 changes: 52 additions & 0 deletions tools/validate-skills.sh
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,58 @@
fi
echo "$DONE_MARK"

# ---------------------------------------------------------------------------
# Check 11: Every agent, workflow, and standalone skill directory is registered
# in module-help.csv
# ---------------------------------------------------------------------------
echo "Check 11: Agent, workflow, and skill directories registered in module-help.csv"
if [[ -f "$SRC/module-help.csv" ]]; then
for dir in "$SRC"/agents/*/; do
[[ -d "$dir" ]] || continue
skill_name=$(basename "$dir")
if ! awk -F',' -v name="$skill_name" '{ gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); if ($2 == name) { found=1; exit } } END { exit !found }' "$SRC/module-help.csv"; then
error "Agent '$skill_name' not registered in module-help.csv"
fi
done
for dir in "$SRC"/workflows/*/; do
[[ -d "$dir" ]] || continue
skill_name=$(basename "$dir")
if ! awk -F',' -v name="$skill_name" '{ gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); if ($2 == name) { found=1; exit } } END { exit !found }' "$SRC/module-help.csv"; then
error "Workflow '$skill_name' not registered in module-help.csv"
fi
done
for dir in "$SRC"/skills/*/; do
[[ -d "$dir" ]] || continue
skill_name=$(basename "$dir")
if ! awk -F',' -v name="$skill_name" '{ gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); if ($2 == name) { found=1; exit } } END { exit !found }' "$SRC/module-help.csv"; then

Check warning on line 331 in tools/validate-skills.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of using the literal '{ gsub(/^[[:space:]]+|[[:space:]]+$/, \"\", $2); if ($2 == name) { found=1; exit } } END { exit !found }' 6 times.

See more on https://sonarcloud.io/project/issues?id=petry-projects_bmad-bgreat-suite&issues=AZ9pEmyppb-PQPyHR8J-&open=AZ9pEmyppb-PQPyHR8J-&pullRequest=377
Comment thread
don-petry marked this conversation as resolved.
Resolved
error "Skill '$skill_name' not registered in module-help.csv"
fi
done
else
error "Missing $SRC/module-help.csv"
fi
echo "$DONE_MARKER"

# ---------------------------------------------------------------------------
# Check 12: copilot-setup-steps.yml has the required job name
# GitHub requires the job to be named exactly `copilot-setup-steps` to pick
# up the file for the Copilot cloud agent.
# ---------------------------------------------------------------------------
echo "Check 12: .github/workflows/copilot-setup-steps.yml has job named copilot-setup-steps"
COPILOT_WF=".github/workflows/copilot-setup-steps.yml"
if [[ ! -f "$COPILOT_WF" ]]; then
error "Missing $COPILOT_WF"
elif ! awk '
BEGIN { in_jobs=0; found=0 }
/^[[:space:]]*jobs:[[:space:]]*$/ { in_jobs=1; next }
in_jobs && /^[^[:space:]]/ { in_jobs=0 }
in_jobs && /^[[:space:]]+copilot-setup-steps[[:space:]]*:/ { found=1; exit }
END { exit(found ? 0 : 1) }
' "$COPILOT_WF"; then
error "$COPILOT_WF does not contain a job named 'copilot-setup-steps' (GitHub requires this exact name)"
fi
echo "$DONE_MARKER"

# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
Expand Down
Loading