diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 81a02deea..ddae0acd7 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,10 +13,10 @@ concurrency: # Key on the full ref so each PR/branch has its own group. Do NOT cancel # in-progress runs: the repo ruleset's code_scanning gate evaluates CodeQL # against the PR merge commit, which regenerates whenever main moves. Cancelling - # in-flight PR runs (esp. the ~30min swift build) made the gate unsatisfiable - # under merge load — every main move murdered the run before it could report. - # Letting runs finish (and queueing the next) preserves full 5-language required - # coverage and dissolves that deadlock, at the cost of some extra runner minutes. + # in-flight PR runs made the gate unsatisfiable under merge load — every main + # move murdered the run before it could report. Letting runs finish (and + # queueing the next) preserves required coverage and dissolves that deadlock, + # at the cost of some extra runner minutes. group: codeql-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: false @@ -51,11 +51,43 @@ jobs: build-mode: none runner: ubuntu-latest timeout: 20 - # swift/macos-15 leg removed from PR CI: GitHub-hosted macOS minutes - # were exhausting the org Actions limit and queuing indefinitely, - # making the Analyze (swift) check unsatisfiable. Restore - # this entry once macOS Actions budget is sorted. + # swift is NOT in this matrix on purpose. It runs out-of-band in the + # analyze-swift-audit job below (schedule/dispatch only, no upload). + # Gate-parity invariant: the ruleset's code_scanning rule derives its + # "expected" analysis categories from what has been uploaded to main. + # Uploading swift from main-only runs while PRs analyze four languages + # made the gate permanently unsatisfiable — every PR merge stalled on + # "still expecting 1 result from CodeQL" (issue #3285). Only re-add a + # swift matrix entry if it runs on pull_request too (macOS budget). + steps: + - name: Checkout repository + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Initialize CodeQL + uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + + - name: Perform CodeQL analysis + uses: github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 + with: + # Default setup rejects advanced SARIF uploads. Keep the migration + # workflow green in analysis-only mode until an administrator + # disables default setup and sets this repository variable to always. + upload: ${{ vars.CODEQL_ADVANCED_UPLOAD || 'never' }} + + # Out-of-band swift security audit: weekly + on demand. Scans the generated + # iOS project on a macOS runner but NEVER uploads to code scanning, so the + # swift category stays out of the merge gate's expected set (see the matrix + # comment above). Findings surface in the run's step summary and as a SARIF + # artifact. Cost: one macOS run per week (~30 min) instead of one per PR. + analyze-swift-audit: + name: Analyze (swift audit) + if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' + runs-on: macos-15 + timeout-minutes: 40 steps: - name: Checkout repository uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 @@ -63,17 +95,15 @@ jobs: # Install build tooling before CodeQL initializes its Swift tracer. On # Apple Silicon, Homebrew rejects installs invoked through Rosetta. - name: Install XcodeGen - if: matrix.language == 'swift' run: brew install xcodegen - name: Initialize CodeQL uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 with: - languages: ${{ matrix.language }} - build-mode: ${{ matrix.build-mode }} + languages: swift + build-mode: manual - name: Generate and build the iOS project - if: matrix.language == 'swift' env: DEVELOPER_DIR: /Applications/Xcode_16.4.app/Contents/Developer run: | @@ -90,10 +120,34 @@ jobs: ARCHS=arm64 \ build - - name: Perform CodeQL analysis + - name: Perform CodeQL analysis (no upload) uses: github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 with: - # Default setup rejects advanced SARIF uploads. Keep the migration - # workflow green in analysis-only mode until an administrator - # disables default setup and sets this repository variable to always. - upload: ${{ vars.CODEQL_ADVANCED_UPLOAD || 'never' }} + # Hard-coded on purpose — do NOT switch to the repository variable. + # An uploaded swift analysis on main re-poisons the merge gate for + # every four-language PR run (gate-parity invariant above). + upload: never + output: swift-sarif + + - name: Summarize swift findings + run: | + set -euo pipefail + SARIF=swift-sarif/swift.sarif + COUNT=$(jq '[.runs[].results[]] | length' "$SARIF") + { + echo "## CodeQL swift audit" + echo + echo "Findings: **$COUNT** (SARIF attached as a run artifact)" + if [ "$COUNT" -gt 0 ]; then + echo + jq -r '.runs[].results[] | "- `\(.ruleId)` \(.locations[0].physicalLocation.artifactLocation.uri // "?"):\(.locations[0].physicalLocation.region.startLine // 0)"' "$SARIF" + fi + } >> "$GITHUB_STEP_SUMMARY" + + - name: Upload swift SARIF artifact + if: always() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: codeql-swift-sarif + path: swift-sarif + retention-days: 30 diff --git a/docs/codeql.md b/docs/codeql.md index 0fb2a4362..05762ba19 100644 --- a/docs/codeql.md +++ b/docs/codeql.md @@ -1,38 +1,71 @@ # CodeQL configuration -The advanced workflow is configured to scan GitHub Actions, -JavaScript/TypeScript, Python, Rust, and Swift. It is required because the -native iOS project is generated from -`apps/ios/CovenCave/project.yml`; default setup cannot run `xcodegen` before -Swift autobuild searches for an Xcode project. - -## Activating advanced setup - -GitHub default setup overrides checked-in CodeQL workflows and rejects their -result uploads. Until cutover, the advanced workflow defaults -`CODEQL_ADVANCED_UPLOAD` to `never`, so it can prove that every language builds -and analyzes without making the migration pull request fail at upload time. A -repository administrator must perform this transition after -`.github/workflows/codeql.yml` reaches `main`: - -1. In **Settings > Security > Code security**, disable CodeQL default setup. -2. In **Settings > Secrets and variables > Actions > Variables**, create the - repository variable `CODEQL_ADVANCED_UPLOAD` with value `always`. -3. In **Actions**, enable the **CodeQL Advanced** workflow if GitHub left it - disabled, then run it with **Run workflow** on `main`. -4. Confirm all five `Analyze (...)` jobs succeed and that the latest code - scanning analyses contain these categories: - `/language:actions`, `/language:javascript-typescript`, `/language:python`, - `/language:rust`, and `/language:swift`. -5. Add an active branch ruleset for `main` with **Require code scanning - results** set to tool `CodeQL`, security threshold **High or higher**, and - alerts threshold **None**. Do not remove the existing required CI checks. -6. Open a pull request and confirm merge is blocked until the CodeQL analysis - finishes, and when a new High or Critical security result is reported. - -If the advanced workflow cannot upload results, first verify that default setup -is disabled and `CODEQL_ADVANCED_UPLOAD` is `always`. For rollback, set the -variable to `never` before re-enabling default setup so the two configurations -do not compete. Re-enable default setup immediately if the advanced workflow -cannot be made healthy, so the existing four-language security coverage is not -left inactive. +CodeQL runs through the checked-in advanced workflow +(`.github/workflows/codeql.yml`); GitHub default setup is disabled. The +migration and enforcement work is tracked in issue #3285. + +## Current state + +- **Gated languages (push + PR, ubuntu):** GitHub Actions, + JavaScript/TypeScript, Python, Rust. These upload SARIF (repository variable + `CODEQL_ADVANCED_UPLOAD=always`) and feed the merge gate. +- **Swift (audit-only, weekly + on demand):** the `Analyze (swift audit)` job + builds the generated iOS project (`xcodegen` from + `apps/ios/CovenCave/project.yml`, then `xcodebuild`) on `macos-15` for + `schedule`/`workflow_dispatch` events only, with `upload: never`. Findings + appear in the run's step summary and as a `codeql-swift-sarif` artifact + (30-day retention). Swift needs the advanced workflow because default setup + cannot run `xcodegen` before Swift autobuild looks for an Xcode project. +- **Merge gate:** branch ruleset **CodeQL merge gate** (id 19123333) on `main` + requires code scanning results from CodeQL with security threshold **High or + higher** (alerts threshold **None**), plus the standard required CI checks. + Repository admins can bypass for pull requests; direct pushes cannot bypass. + +## The gate-parity invariant (read before touching the matrix) + +The ruleset's `code_scanning` rule derives the set of *expected* analysis +categories from what has been uploaded to `main`. A pull request only +satisfies the gate when its merge/head commit has results for **every** +expected category. + +Uploading a category from main-only runs while PRs don't produce it makes the +gate **permanently unsatisfiable**: every PR fails with *"Code scanning is +still expecting N results from CodeQL"*, and only admin bypass can merge. This +happened when the swift matrix leg was removed from PR runs (macOS budget) +while its analyses remained on `main` — see issue #3285. Recovery required +deleting the stale swift analyses from `main` via +`DELETE /repos/{owner}/{repo}/code-scanning/analyses/{id}?confirm_delete=true`. + +Rules that follow from this: + +1. Every category uploaded on `push` to `main` must also be produced by + `pull_request` runs (keep the trigger pair symmetric for gated legs). +2. Audit-only legs (swift) must keep `upload: never` hard-coded. +3. To promote swift to a gated language, add it back to the matrix for both + push **and** PR events — accepting one macOS run per PR — and never + main-only. + +The workflow also sets `cancel-in-progress: false`: the gate evaluates the PR +*merge commit*, which regenerates whenever `main` moves, so cancelling +in-flight runs under merge load re-creates the same deadlock from the other +side. Expect the gate to lag `main` by one CodeQL run (~10 min) during rapid +merge trains; re-running the PR's CodeQL workflow (or waiting for the +merge-commit run) clears it. + +## Verifying the gate + +- List recent evaluations: `gh api repos/{owner}/{repo}/rulesets/rule-suites` + — merges show `result: pass` (or `bypass` with the `code_scanning` rule's + failure detail while a run is still in flight). +- A PR with all analyses uploaded and no open High/Critical alerts merges + without bypass; a PR whose CodeQL run is still executing is blocked with + *"still expecting N results"*. + +## Rollback + +If the advanced workflow cannot be kept healthy: set +`CODEQL_ADVANCED_UPLOAD=never`, re-enable default setup (Settings > Security > +Code security) so the four ubuntu languages stay covered, and delete or +deactivate the **CodeQL merge gate** ruleset (default setup categories differ, +so the old expected set would block PRs). Never run default setup and advanced +uploads side by side — they compete for the same categories. diff --git a/marketplace/plugins/pptx-generator/skills/pptx-generator/cookbook/carousels/quote-slide.py b/marketplace/plugins/pptx-generator/skills/pptx-generator/cookbook/carousels/quote-slide.py index 52f4cd33e..5c9289a71 100644 --- a/marketplace/plugins/pptx-generator/skills/pptx-generator/cookbook/carousels/quote-slide.py +++ b/marketplace/plugins/pptx-generator/skills/pptx-generator/cookbook/carousels/quote-slide.py @@ -85,7 +85,7 @@ def main() -> None: Inches(2.0), Inches(2.0) ) p = open_quote.text_frame.paragraphs[0] - p.text = """ + p.text = "\u201C" # Left double quote mark p.font.name = BRAND_HEADING_FONT p.font.size = Pt(180) p.font.bold = True