From 929531622d377b9c044e1dad6a1eaf8f2004ab5c Mon Sep 17 00:00:00 2001 From: don-petry <36422719+don-petry@users.noreply.github.com> Date: Thu, 9 Apr 2026 00:12:38 -0700 Subject: [PATCH 1/3] feat(security): replace per-repo CodeQL workflows with GitHub default setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The org standard previously required every repo to carry a codeql.yml workflow file. In practice the fleet used a minimal advanced configuration that added maintenance overhead (SHA pinning, Dependabot bumps, manual language matrix) without providing anything GitHub's managed default setup doesn't already cover. This commit: - Rewrites ci-standards.md §2 to make default setup the standard - Deletes .github/workflows/codeql.yml from this repo (added in #100) - Updates compliance-audit.sh: replaces codeql.yml file existence check with code-scanning/default-setup API probe, and flags stray codeql.yml files as drift - Updates apply-rulesets.sh: derives the `CodeQL` required-status-check context from the default-setup API instead of workflow file parsing - Updates apply-repo-settings.sh: adds apply_codeql_default_setup() so `--all` runs enable default setup fleet-wide Repos with a concrete need for advanced setup (custom query packs, path filters, compiled-language build modes) may opt out by filing a standards PR documenting the exception. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/codeql.yml | 35 -------- scripts/apply-repo-settings.sh | 40 +++++++++ scripts/apply-rulesets.sh | 30 ++++--- scripts/compliance-audit.sh | 56 ++++++++++++- standards/ci-standards.md | 148 +++++++++++++++++++++++++-------- 5 files changed, 226 insertions(+), 83 deletions(-) delete mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index aba8f95..0000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,35 +0,0 @@ -# CodeQL SAST analysis for the .github standards repository. -# This repo contains GitHub Actions workflows, so 'actions' is the configured language. -# Standard: https://github.com/petry-projects/.github/blob/main/standards/ci-standards.md#2-codeql-analysis-codeqlyml -name: CodeQL Analysis - -permissions: {} - -on: - push: - branches: [main] - pull_request: - branches: [main] - schedule: - - cron: '0 17 * * 5' # Weekly scan (Friday 12:00 PM EST / 17:00 UTC) - -jobs: - analyze: - name: Analyze (actions) - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - - name: Initialize CodeQL - uses: github/codeql-action/init@0e9f55954318745b37b7933c693bc093f7336125 # v4.35.1 - with: - languages: actions - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@0e9f55954318745b37b7933c693bc093f7336125 # v4.35.1 - with: - category: /language:actions diff --git a/scripts/apply-repo-settings.sh b/scripts/apply-repo-settings.sh index 7461143..dd6dc89 100644 --- a/scripts/apply-repo-settings.sh +++ b/scripts/apply-repo-settings.sh @@ -166,6 +166,44 @@ apply_settings() { ok "$ORG/$repo settings updated successfully" } +# --------------------------------------------------------------------------- +# apply_codeql_default_setup — enable GitHub-managed CodeQL default setup +# +# Per standards/ci-standards.md#2-codeql-analysis-github-managed-default-setup, +# CodeQL is configured via the code-scanning/default-setup endpoint, not a +# per-repo workflow file. Languages are auto-detected from the default branch. +# +# Idempotent: if state is already "configured", we no-op. If "not-configured", +# we PATCH to enable. The API rejects updates on repos without code scanning +# capability (e.g. private repos without GHAS); we surface that as a warning. +# --------------------------------------------------------------------------- +apply_codeql_default_setup() { + local repo="$1" + info "Configuring CodeQL default setup for $ORG/$repo ..." + + local current_state + current_state=$(gh api "repos/$ORG/$repo/code-scanning/default-setup" --jq '.state' 2>/dev/null || echo "") + + if [ "$current_state" = "configured" ]; then + ok " CodeQL default setup already configured" + return 0 + fi + + if [ "$DRY_RUN" = "true" ]; then + skip "DRY_RUN=true — would enable CodeQL default setup (current state: ${current_state:-unknown})" + return 0 + fi + + if gh api -X PATCH "repos/$ORG/$repo/code-scanning/default-setup" \ + -F state=configured \ + -F query_suite=default > /dev/null 2>&1; then + ok " CodeQL default setup enabled" + else + err " Failed to enable CodeQL default setup — repo may lack code scanning capability (private without GHAS, archived, or empty default branch). Manual review required." + return 1 + fi +} + # --------------------------------------------------------------------------- # Main # --------------------------------------------------------------------------- @@ -194,6 +232,7 @@ if [ "$1" = "--all" ]; then apply_settings "$repo" || failed=$((failed + 1)) apply_labels "$repo" pp_apply_security_and_analysis "$repo" || failed=$((failed + 1)) + apply_codeql_default_setup "$repo" || failed=$((failed + 1)) done if [ "$failed" -gt 0 ]; then @@ -206,4 +245,5 @@ else apply_settings "$1" apply_labels "$1" pp_apply_security_and_analysis "$1" + apply_codeql_default_setup "$1" fi diff --git a/scripts/apply-rulesets.sh b/scripts/apply-rulesets.sh index 5028033..60033e0 100755 --- a/scripts/apply-rulesets.sh +++ b/scripts/apply-rulesets.sh @@ -6,7 +6,7 @@ # # Rulesets managed: # pr-quality — pull request review requirements and merge policy -# code-quality — required status checks (CI, SonarCloud, CodeQL, Claude Code) +# code-quality — required status checks (CI, SonarCloud, CodeQL default setup, Claude Code) # # Usage: # # Apply to a specific repo: @@ -78,17 +78,23 @@ detect_required_checks() { fi fi - # --- CodeQL --- - if echo "$workflows" | grep -qx "codeql.yml"; then - local cq_wf_name - cq_wf_name=$(workflow_name "codeql.yml") - if [ -n "$cq_wf_name" ]; then - # CodeQL uses "Analyze" or "Analyze ()" as job names; - # add the generic "Analyze" and language-specific variants below - checks+=("$cq_wf_name / Analyze") - else - checks+=("Analyze") - fi + # --- CodeQL (GitHub-managed default setup) --- + # CodeQL is no longer driven by a per-repo workflow file. We probe the + # default-setup API: if the state is "configured", GitHub publishes results + # under the required-status-check context name `CodeQL` (single context, + # regardless of how many languages are detected). See + # standards/ci-standards.md#2-codeql-analysis-github-managed-default-setup. + # + # Note: a stray .github/workflows/codeql.yml is drift and will be flagged + # by compliance-audit.sh#check_codeql_default_setup. We do NOT fall back + # to a workflow-derived check name here, because doing so would let drift + # silently satisfy the rule and bypass remediation. + local codeql_state + codeql_state=$(gh api "repos/$ORG/$repo/code-scanning/default-setup" --jq '.state' 2>/dev/null || echo "") + if [ "$codeql_state" = "configured" ]; then + checks+=("CodeQL") + else + info " CodeQL default setup not configured for $repo (state: ${codeql_state:-unknown}) — skipping CodeQL required check. Run apply-repo-settings.sh first." fi # --- Tier 1 centralized workflows --- diff --git a/scripts/compliance-audit.sh b/scripts/compliance-audit.sh index be59393..e7c9a41 100755 --- a/scripts/compliance-audit.sh +++ b/scripts/compliance-audit.sh @@ -33,7 +33,12 @@ FINDINGS_FILE="$REPORT_DIR/findings.json" SUMMARY_FILE="$REPORT_DIR/summary.md" ISSUES_FILE="$REPORT_DIR/issues.json" -REQUIRED_WORKFLOWS=(ci.yml codeql.yml sonarcloud.yml claude.yml dependabot-automerge.yml dependency-audit.yml agent-shield.yml) +REQUIRED_WORKFLOWS=(ci.yml sonarcloud.yml claude.yml dependabot-automerge.yml dependency-audit.yml agent-shield.yml) +# Note: codeql.yml is intentionally NOT in REQUIRED_WORKFLOWS. CodeQL is now +# configured via GitHub-managed default setup (Settings → Code security → +# Code scanning), not a per-repo workflow file. The check_codeql_default_setup +# function below verifies the API state and treats stray codeql.yml files +# as drift to be removed. See standards/ci-standards.md#2-codeql-analysis-github-managed-default-setup. # name:hex-color:description (color without leading #) REQUIRED_LABEL_SPECS=( @@ -406,6 +411,54 @@ check_sonarcloud() { fi } +# --------------------------------------------------------------------------- +# Check: CodeQL default setup is configured (and no stray codeql.yml exists) +# +# After petry-projects/.github#, CodeQL is configured via GitHub's +# managed default setup, not a per-repo workflow file. Two distinct findings: +# +# 1. codeql-default-setup-not-configured (error): the repo has not enabled +# default setup. Remediate by running: +# gh api -X PATCH repos///code-scanning/default-setup \ +# -F state=configured -F query_suite=default +# (or by running scripts/apply-repo-settings.sh against the repo). +# +# 2. stray-codeql-workflow (error): the repo still ships a codeql.yml +# workflow file. Default setup and an inline workflow are mutually +# exclusive at the GitHub level — leaving the file behind double-bills +# CI minutes and creates two competing analyses. Remediation: delete +# .github/workflows/codeql.yml. +# --------------------------------------------------------------------------- +check_codeql_default_setup() { + local repo="$1" + + # Query the default-setup state. The endpoint returns 200 with a JSON body + # describing the state, OR a 4xx if the repo has no code scanning capability + # (e.g. private without GHAS, archived). Treat any non-"configured" state + # as a finding so the audit surfaces what needs remediation. + local state + state=$(gh_api "repos/$ORG/$repo/code-scanning/default-setup" --jq '.state' 2>/dev/null || echo "") + + if [ "$state" != "configured" ]; then + local detail + if [ -z "$state" ]; then + detail="CodeQL default setup query returned no state — either the repo has code scanning disabled or the API call failed. Enable via \`gh api -X PATCH repos/$ORG/$repo/code-scanning/default-setup -F state=configured -F query_suite=default\`." + else + detail="CodeQL default setup is in state \`$state\` (expected \`configured\`). Run \`apply-repo-settings.sh $repo\` or \`gh api -X PATCH repos/$ORG/$repo/code-scanning/default-setup -F state=configured -F query_suite=default\`." + fi + add_finding "$repo" "ci-workflows" "codeql-default-setup-not-configured" "error" \ + "$detail" \ + "standards/ci-standards.md#2-codeql-analysis-github-managed-default-setup" + fi + + # Stray workflow check: any codeql.yml under .github/workflows is drift. + if gh_api "repos/$ORG/$repo/contents/.github/workflows/codeql.yml" --jq '.name' > /dev/null 2>&1; then + add_finding "$repo" "ci-workflows" "stray-codeql-workflow" "error" \ + "Repo still ships \`.github/workflows/codeql.yml\`. The org standard now uses GitHub-managed CodeQL default setup; per-repo workflow files are drift and run a duplicate analysis alongside default setup. Delete the file. If a documented exception applies (custom query pack, build mode, path filters), open a standards PR against \`standards/ci-standards.md\` to record the exception before re-adding the workflow." \ + "standards/ci-standards.md#2-codeql-analysis-github-managed-default-setup" + fi +} + # --------------------------------------------------------------------------- # Check: Workflow permissions follow least-privilege # --------------------------------------------------------------------------- @@ -1150,6 +1203,7 @@ main() { check_rulesets "$repo" check_codeowners "$repo" check_sonarcloud "$repo" + check_codeql_default_setup "$repo" check_workflow_permissions "$repo" check_claude_workflow_checkout "$repo" check_centralized_workflow_stubs "$repo" diff --git a/standards/ci-standards.md b/standards/ci-standards.md index fbb506d..7411be6 100644 --- a/standards/ci-standards.md +++ b/standards/ci-standards.md @@ -23,7 +23,8 @@ where to send a fix when behavior needs to change. | Tier | Examples | What lives in `standards/workflows/` | Where logic lives | Edits allowed in adopting repo | |---|---|---|---|---| | **1. Stub** | `claude.yml`, `dependency-audit.yml`, `dependabot-automerge.yml`, `dependabot-rebase.yml`, `agent-shield.yml`, `feature-ideation.yml` | A thin caller stub that delegates via `uses: petry-projects/.github/.github/workflows/-reusable.yml@v1` | The matching `*-reusable.yml` in this repo (single source of truth) | **None** in normal use. May tune `with:` inputs where the reusable exposes them (e.g. `agent-shield` accepts `min-severity`, `required-files`; `feature-ideation` requires `project_context`). To change behavior, open a PR against the reusable in this repo — the change propagates everywhere on next run. | -| **2. Per-repo template** | `ci.yml`, `codeql.yml`, `sonarcloud.yml` | _(no template — see the patterns documented below)_ | In each repo, because the workflow is tech-stack-specific (language matrix, build tool, test framework) | **Limited.** Each adopting repo carries its own copy. Stay within the patterns in this document; do not change action SHAs, permission scopes, trigger events, or job names without raising a standards PR first. | +| **2. Per-repo template** | `ci.yml`, `sonarcloud.yml` | _(no template — see the patterns documented below)_ | In each repo, because the workflow is tech-stack-specific (language matrix, build tool, test framework) | **Limited.** Each adopting repo carries its own copy. Stay within the patterns in this document; do not change action SHAs, permission scopes, trigger events, or job names without raising a standards PR first. | +| **GitHub-managed** | CodeQL default setup | _(no workflow file — managed via repo Settings → Code security)_ | GitHub | None. Configured via `apply-repo-settings.sh`; per-repo `codeql.yml` files are treated as drift by the compliance audit. See [§2 CodeQL Analysis](#2-codeql-analysis-github-managed-default-setup). | | **3. Free per-repo** | `release.yml`, project-specific automation | _(out of scope for this standard)_ | Per-repo | Free, but must still comply with the [Action Pinning Policy](#action-pinning-policy) and the [Required Workflows](#required-workflows) constraints. | Tier 1 stubs all carry an identical `SOURCE OF TRUTH` header block telling @@ -65,10 +66,12 @@ gh api repos/petry-projects/.github/contents/standards/workflows/.yml \ ## Required Workflows -Every repository MUST have these 7 workflows. Reusable templates for Dependabot +Every repository MUST have these 6 workflows. Reusable templates for Dependabot and AgentShield workflows are in [`standards/workflows/`](workflows/). The CI, -CodeQL, SonarCloud, and Claude Code workflows are documented as patterns -below — copy and adapt the examples to each repo's tech stack. +SonarCloud, and Claude Code workflows are documented as patterns +below — copy and adapt the examples to each repo's tech stack. CodeQL is +**not** a workflow file: it is configured via GitHub-managed default setup +(see [§2](#2-codeql-analysis-github-managed-default-setup)). In addition, BMAD Method-enabled repositories MUST also include the conditional [Feature Ideation workflow](#8-feature-ideation-feature-ideationyml--bmad-method-repos) @@ -110,27 +113,82 @@ concurrency: cancel-in-progress: true ``` -### 2. CodeQL Analysis (`codeql.yml`) +### 2. CodeQL Analysis (GitHub-managed default setup) -Static Application Security Testing (SAST) via GitHub's CodeQL. +Static Application Security Testing (SAST) via GitHub's CodeQL, configured +through **default setup** (Settings → Code security → Code scanning), not via +a per-repo workflow file. -**Standard configuration:** +**Why default setup, not a `codeql.yml` workflow:** -```yaml -on: - push: - branches: [main] - pull_request: - branches: [main] - schedule: - - cron: '0 17 * * 5' # Weekly scan (Friday 12:00 PM EST / 17:00 UTC) +Every prior version of this standard required each repo to carry an +`advanced` CodeQL workflow file. In practice the workflow we copied across +the fleet did nothing that default setup doesn't already do — no custom +query packs, no path filters, no build steps, no language matrix beyond a +single auto-detected ecosystem. The advanced setup gave us SHA-pinned +`github/codeql-action` references and an explicit `permissions: {}` block, +but `github/codeql-action` is a first-party GitHub action and the +permissions are managed by GitHub when default setup is enabled. The cost +of maintaining N copies of a workflow that re-derives what GitHub already +detects automatically outweighed the marginal supply-chain benefit. + +**Default setup also gives us behavior the workflow file did not:** + +- **Automatic language re-detection.** When a repo gains a new supported + language (e.g. a Python utility lands in a TypeScript repo), default + setup picks it up on the next scan. The static workflow file would + silently miss it until somebody edited the YAML. +- **Managed analyzer versions.** No Dependabot bumps, no SHA churn, no + drift between repos. +- **Lower CI surface area.** One fewer workflow file per repo to lint, + audit, and centralize. + +**Standard configuration (per repo):** + +| Setting | Required value | +|---|---| +| Code scanning → Default setup | **Configured** (state = `"configured"`) | +| Languages | All CodeQL-supported languages auto-detected from the default branch | +| Query suite | `default` (use `extended` only when a documented threat model justifies the noise) | +| Schedule | Weekly (managed by GitHub; not configurable) | +| Triggers | Push to default branch and PRs targeting it (managed by GitHub) | + +**Enabling default setup:** + +```bash +# State the desired configuration. Languages may be omitted to let +# GitHub auto-detect, or enumerated explicitly. +gh api -X PATCH "repos/petry-projects//code-scanning/default-setup" \ + -F state=configured \ + -F query_suite=default ``` -**Language configuration rule:** All ecosystems present in the repository MUST -be configured as CodeQL languages. If a repo contains `package.json`, add -`javascript-typescript`. If it contains `go.mod`, add `go`. If it contains -`.github/workflows/*.yml`, add `actions`. Multi-language repos configure -multiple languages via a matrix strategy. +> **Required token scope:** `repo` (classic) or `Administration: write` + +> `Code scanning alerts: write` (fine-grained). The org `apply-repo-settings.sh` +> script will run this automatically when onboarding new repos. + +**`.github/workflows/codeql.yml` is now drift, not a requirement.** The +weekly compliance audit (`check_codeql_default_setup`) flags any repo whose +default setup is not in the `configured` state, **and** flags any repo that +still ships an inline `codeql.yml` workflow file as a remediation: delete +the file and enable default setup. The two configurations are mutually +exclusive at the GitHub level — leaving the workflow file behind after +flipping default setup on causes both to run and double-bills CI minutes. + +**Status check name:** GitHub publishes default setup results under the +required-status-check context name **`CodeQL`** (single context, regardless +of how many languages are detected). The org `apply-rulesets.sh` script +adds this context to the `code-quality` ruleset for any repo where default +setup is configured. + +**Escape hatch — when advanced setup is justified:** A repo MAY revert to +an inline `codeql.yml` workflow only when it has a concrete need that +default setup cannot serve: a custom query pack, path filters to exclude +generated code, a build mode for a compiled language that needs a +non-default toolchain, or a language CodeQL supports only via manual +build. **Document the reason in the workflow file's header and open a +standards PR against this document** so the exception is recorded +alongside the rule. ### 3. SonarCloud Analysis (`sonarcloud.yml`) @@ -578,7 +636,7 @@ steps: # Project-specific: pip install, pytest, etc. ``` -**Repos using this pattern:** TalkTerm (CodeQL only currently) +**Repos using this pattern:** _(none currently — Python coverage in TalkTerm previously came from its `codeql.yml`, which has been removed in favor of GitHub default setup)_ --- @@ -659,9 +717,13 @@ For single-job workflows, top-level least-privilege permissions are acceptable | CI (build/test) | `contents: read` | | SonarCloud | `contents: read`, `pull-requests: read` | | Claude Code | `contents: write`, `id-token: write`, `pull-requests: write`, `issues: write`, `actions: read`, `checks: read` | -| CodeQL | `actions: read`, `security-events: write`, `contents: read` | | Dependabot auto-merge | `contents: read`, `pull-requests: read` (+ app token for merge) | +> **CodeQL is not in this table** because it is configured via GitHub +> default setup, not a workflow file. GitHub manages the analyzer's +> permissions internally; no `permissions:` block exists in this repo to +> audit. See [§2 CodeQL Analysis](#2-codeql-analysis-github-managed-default-setup). + > **Note on admin operations from Claude Code:** GitHub Actions does **not** > expose an `administration` permission scope. The valid set is documented at > [docs.github.com](https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs). @@ -704,7 +766,7 @@ references. Use consistent, descriptive names: |---------|---------|-------| | Language / tool name | `TypeScript`, `Go`, `SonarCloud` | For multi-language repos | | `build-and-test` | `build-and-test` | For single-language repos | -| `Analyze` or `Analyze ()` | `Analyze`, `Analyze (Python)` | CodeQL jobs | +| `CodeQL` | `CodeQL` | Default-setup CodeQL — single context regardless of language count | | `claude` | `claude` | Claude Code Action | These names are referenced in branch protection required status checks. @@ -766,7 +828,7 @@ autofix: 1. **Determine tech stack** and select the matching workflow patterns above 2. **Create `ci.yml`** with lint, format, typecheck, and test stages -3. **Add `codeql.yml`** with the appropriate language(s) +3. **Enable CodeQL default setup** via `apply-repo-settings.sh` (or `gh api -X PATCH repos///code-scanning/default-setup -F state=configured`) — do **not** add a `codeql.yml` workflow file 4. **Add `sonarcloud.yml`** and configure `sonar-project.properties` 5. **Add `claude.yml`** for AI code review 6. **Add `dependabot.yml`** from the appropriate template in [`standards/dependabot/`](dependabot/) @@ -785,24 +847,37 @@ All five check categories are **required on every repository** (see [GitHub Settings — code-quality ruleset](github-settings.md#code-quality--required-checks-ruleset-all-repositories)). The specific ecosystems configured in each check depend on the repo's stack. -| Repository | CI | CodeQL | SonarCloud | Claude | Coverage | Dep Auto-merge | Dep Audit | Dependabot Config | +The **CodeQL** column reflects GitHub default setup state (`configured` vs +`not-configured`), not the presence of a workflow file. Repos still +carrying a per-repo `codeql.yml` after this standard lands are flagged as +drift, not as compliant. + +| Repository | CI | CodeQL† | SonarCloud | Claude | Coverage | Dep Auto-merge | Dep Audit | Dependabot Config | |------------|:--:|:------:|:----------:|:------:|:--------:|:--------------:|:---------:|:-----------------:| -| **broodly** | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | -| **markets** | — | Yes | Yes | Yes | — | Yes | Yes | Partial | -| **google-app-scripts** | Yes | Yes | Yes | Yes | Yes | Yes (older) | — | Non-standard | -| **TalkTerm** | Yes | — | — | — | Yes | — | — | — | -| **ContentTwin** | — | — | Yes | — | — | — | — | — | -| **bmad-bgreat-suite** | — | — | — | — | — | — | — | — | +| **broodly** | Yes | Pending | Yes | Yes | Yes | Yes | Yes | Yes | +| **markets** | — | Pending | Yes | Yes | — | Yes | Yes | Partial | +| **google-app-scripts** | Yes | Pending | Yes | Yes | Yes | Yes (older) | — | Non-standard | +| **TalkTerm** | Yes | Pending | — | — | Yes | — | — | — | +| **ContentTwin** | — | Pending | Yes | — | — | — | — | — | +| **bmad-bgreat-suite** | — | Pending | — | — | — | — | — | — | + +† **CodeQL** values are listed as `Pending` for every repo because the +default-setup migration is the work this standard introduces; the next +weekly compliance audit (after `apply-repo-settings.sh` runs against the +fleet) will flip the cells to `Yes` or surface specific failures via the +`codeql-default-setup-not-configured` finding category. There is no +`codeql.yml` workflow column anymore — that file is drift, not signal. ### Gaps to Address Every `—` in the table above is a gap that must be remediated. Priority order: -1. **bmad-bgreat-suite:** Missing all CI workflows — needs full onboarding -2. **ContentTwin:** Missing CI, CodeQL, Claude, Coverage, Dependabot — 5 of 8 categories missing -3. **TalkTerm:** Missing CodeQL, SonarCloud, Claude, Dependabot — 4 of 8 categories missing +1. **bmad-bgreat-suite:** Missing all CI workflows — needs full onboarding (CodeQL default setup will be enabled as part of onboarding) +2. **ContentTwin:** Missing CI, Claude, Coverage, Dependabot — 4 of 8 categories missing +3. **TalkTerm:** Missing SonarCloud, Claude, Dependabot — 3 of 8 categories missing 4. **markets:** Missing CI pipeline and Coverage; Dependabot config only covers `github-actions` (missing `npm` ecosystem) 5. **google-app-scripts:** Missing dependency audit; Dependabot npm `limit:10` (should be `0` per policy); auto-merge uses older `--admin` bypass pattern +6. **All repos:** Enable CodeQL default setup via `apply-repo-settings.sh` and remove any pre-existing `codeql.yml` workflow file ### Version Inconsistencies @@ -811,5 +886,8 @@ All repos MUST align to the latest version of each action: | Action | Target Version | Repos Needing Update | |--------|---------------|---------------------| | **SonarCloud action** | v7.0.0 | ContentTwin, google-app-scripts (currently v6) | -| **CodeQL action** | v4 | markets (currently v3) | | **Claude Code Action** | v1.0.89 (`6e2bd528`) | All repos should use the same pinned SHA | + +> **`github/codeql-action` is no longer pinned per repo** because the +> standard no longer ships a `codeql.yml` workflow. GitHub manages the +> analyzer version internally for default-setup repos. From 59850cdc382fb1c77f50917e9e0cd77fa344771a Mon Sep 17 00:00:00 2001 From: don-petry <36422719+don-petry@users.noreply.github.com> Date: Thu, 9 Apr 2026 05:01:35 -0700 Subject: [PATCH 2/3] fix: address review comments from Copilot and CodeRabbit on #103 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace placeholder # with #103 in compliance-audit.sh - Fix apply-repo-settings.sh: docstring now matches behavior (warn and continue on failure, not hard fail); add CODEQL_ADVANCED_EXCEPTIONS list so approved advanced-setup repos are skipped - Fix apply-rulesets.sh: distinguish API probe errors from explicit "not-configured" state — probe failures now exit nonzero instead of silently omitting CodeQL from required checks - Fix ci-standards.md: remove misleading "coverage" wording from Python section; fix MD028 blank line inside blockquote (Lint failure) - Update github-settings.md: CodeQL check name is now `CodeQL` (default setup context), not `Analyze` / `Analyze ()` Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/apply-repo-settings.sh | 32 ++++++++++++++++++++++++++------ scripts/apply-rulesets.sh | 16 +++++++++++----- scripts/compliance-audit.sh | 2 +- standards/ci-standards.md | 4 ++-- standards/github-settings.md | 2 +- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/scripts/apply-repo-settings.sh b/scripts/apply-repo-settings.sh index dd6dc89..09dbdb6 100644 --- a/scripts/apply-repo-settings.sh +++ b/scripts/apply-repo-settings.sh @@ -174,13 +174,29 @@ apply_settings() { # per-repo workflow file. Languages are auto-detected from the default branch. # # Idempotent: if state is already "configured", we no-op. If "not-configured", -# we PATCH to enable. The API rejects updates on repos without code scanning -# capability (e.g. private repos without GHAS); we surface that as a warning. +# we PATCH to enable. Repos listed in CODEQL_ADVANCED_EXCEPTIONS are skipped +# (they are approved to keep an inline codeql.yml; see the escape hatch in +# ci-standards.md §2). The API rejects updates on repos without code scanning +# capability (e.g. private repos without GHAS); we log a warning and continue +# so that --all runs are not blocked by a single unsupported repo. # --------------------------------------------------------------------------- + +# Repos approved for advanced CodeQL setup (inline codeql.yml). +# Each entry must have a corresponding standards PR documenting the exception. +CODEQL_ADVANCED_EXCEPTIONS=() + apply_codeql_default_setup() { local repo="$1" info "Configuring CodeQL default setup for $ORG/$repo ..." + # Skip repos approved for advanced (inline workflow) CodeQL setup. + for exception in "${CODEQL_ADVANCED_EXCEPTIONS[@]}"; do + if [ "$repo" = "$exception" ]; then + skip " $repo is in CODEQL_ADVANCED_EXCEPTIONS — skipping default setup" + return 0 + fi + done + local current_state current_state=$(gh api "repos/$ORG/$repo/code-scanning/default-setup" --jq '.state' 2>/dev/null || echo "") @@ -194,13 +210,17 @@ apply_codeql_default_setup() { return 0 fi - if gh api -X PATCH "repos/$ORG/$repo/code-scanning/default-setup" \ + local api_err + if api_err=$(gh api -X PATCH "repos/$ORG/$repo/code-scanning/default-setup" \ -F state=configured \ - -F query_suite=default > /dev/null 2>&1; then + -F query_suite=default 2>&1); then ok " CodeQL default setup enabled" else - err " Failed to enable CodeQL default setup — repo may lack code scanning capability (private without GHAS, archived, or empty default branch). Manual review required." - return 1 + # Non-fatal: log warning and continue so --all runs are not blocked by + # repos that lack code scanning capability (private without GHAS, + # archived, or empty default branch). + warn " Failed to enable CodeQL default setup for $repo — manual review required. API response: $api_err" + return 0 fi } diff --git a/scripts/apply-rulesets.sh b/scripts/apply-rulesets.sh index 60033e0..3a95921 100755 --- a/scripts/apply-rulesets.sh +++ b/scripts/apply-rulesets.sh @@ -89,12 +89,18 @@ detect_required_checks() { # by compliance-audit.sh#check_codeql_default_setup. We do NOT fall back # to a workflow-derived check name here, because doing so would let drift # silently satisfy the rule and bypass remediation. - local codeql_state - codeql_state=$(gh api "repos/$ORG/$repo/code-scanning/default-setup" --jq '.state' 2>/dev/null || echo "") - if [ "$codeql_state" = "configured" ]; then - checks+=("CodeQL") + local codeql_state codeql_err + if codeql_err=$(gh api "repos/$ORG/$repo/code-scanning/default-setup" --jq '.state' 2>&1); then + codeql_state="$codeql_err" # on success, stdout holds the state value + if [ "$codeql_state" = "configured" ]; then + checks+=("CodeQL") + else + info " CodeQL default setup not configured for $repo (state: $codeql_state) — skipping CodeQL required check. Run apply-repo-settings.sh first." + fi else - info " CodeQL default setup not configured for $repo (state: ${codeql_state:-unknown}) — skipping CodeQL required check. Run apply-repo-settings.sh first." + err " Failed to probe CodeQL default-setup state for $repo. API error: $codeql_err" + err " Check that GH_TOKEN has code-scanning scope and the repo exists." + return 1 fi # --- Tier 1 centralized workflows --- diff --git a/scripts/compliance-audit.sh b/scripts/compliance-audit.sh index e7c9a41..084aa4a 100755 --- a/scripts/compliance-audit.sh +++ b/scripts/compliance-audit.sh @@ -414,7 +414,7 @@ check_sonarcloud() { # --------------------------------------------------------------------------- # Check: CodeQL default setup is configured (and no stray codeql.yml exists) # -# After petry-projects/.github#, CodeQL is configured via GitHub's +# After petry-projects/.github#103, CodeQL is configured via GitHub's # managed default setup, not a per-repo workflow file. Two distinct findings: # # 1. codeql-default-setup-not-configured (error): the repo has not enabled diff --git a/standards/ci-standards.md b/standards/ci-standards.md index 7411be6..6f2d7b5 100644 --- a/standards/ci-standards.md +++ b/standards/ci-standards.md @@ -636,7 +636,7 @@ steps: # Project-specific: pip install, pytest, etc. ``` -**Repos using this pattern:** _(none currently — Python coverage in TalkTerm previously came from its `codeql.yml`, which has been removed in favor of GitHub default setup)_ +**Repos using this pattern:** _(none currently)_ --- @@ -723,7 +723,7 @@ For single-job workflows, top-level least-privilege permissions are acceptable > default setup, not a workflow file. GitHub manages the analyzer's > permissions internally; no `permissions:` block exists in this repo to > audit. See [§2 CodeQL Analysis](#2-codeql-analysis-github-managed-default-setup). - +> > **Note on admin operations from Claude Code:** GitHub Actions does **not** > expose an `administration` permission scope. The valid set is documented at > [docs.github.com](https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs). diff --git a/standards/github-settings.md b/standards/github-settings.md index f7d0586..04ec2f6 100644 --- a/standards/github-settings.md +++ b/standards/github-settings.md @@ -151,7 +151,7 @@ categories are universal. | Check | Required | Check Name(s) | Notes | |-------|----------|---------------|-------| | **SonarCloud** | All repos | `SonarCloud` | Code quality, maintainability, security hotspots | -| **CodeQL** | All repos | `Analyze` or `Analyze ()` | SAST — all ecosystems present in the repo must be configured | +| **CodeQL** | All repos | `CodeQL` | SAST via GitHub-managed default setup — auto-detects all supported languages (see [ci-standards.md §2](ci-standards.md#2-codeql-analysis-github-managed-default-setup)) | | **Claude Code** | All repos | `claude` | AI code review on every PR | | **CI Pipeline** | All repos | Repo-specific (e.g., `build-and-test`, `TypeScript`, `Go`) | Lint, format, typecheck, test | | **Coverage** | All repos | `coverage` or embedded in CI job | Must meet repo-defined thresholds | From 16e8314f0d41f45fd5a19dce90591ad9e8efd06f Mon Sep 17 00:00:00 2001 From: don-petry <36422719+don-petry@users.noreply.github.com> Date: Thu, 9 Apr 2026 05:06:41 -0700 Subject: [PATCH 3/3] chore: trigger CodeQL default setup scan on PR