Skip to content

Add github.code_scanning for CodeQL default setup - #122

Open
ppkarwasz wants to merge 7 commits into
apache:mainfrom
ppkarwasz:code-scanning
Open

ppkarwasz wants to merge 7 commits into
apache:mainfrom
ppkarwasz:code-scanning

Conversation

@ppkarwasz

@ppkarwasz ppkarwasz commented Aug 13, 2026 •

Copy link
Copy Markdown
Member

Allows projects to self-service enable GitHub code scanning (CodeQL default setup) from .asf.yaml, as requested in #94 (code scanning part only; secret scanning can be a follow-up):

github:
  code_scanning: true

or, for more control:

github:
  code_scanning:
    query_suite: extended       # "default" or "extended"
    threat_model: remote        # "remote" or "remote_and_local"
    languages:                  # restricts analysis; auto-detected when omitted
      - java-kotlin

Design notes:

  • The section's presence is the toggle (no enabled key), matching how rulesets works; a plain boolean is accepted for the simple case.
  • The directive GETs /repos/{org}/{repo}/code-scanning/default-setup first and only PATCHes when the desired settings differ, so unrelated .asf.yaml edits do not re-trigger analysis runs, and both 200 and 202 (async validation run) are treated as success.
  • Removing (or commenting out) the section disables the setup only if it was previously managed via .asf.yaml (same previous_yaml semantics as Clear branch protection rules when protected_branches is removed #121); a setup enabled manually through the GitHub UI is left untouched.
  • languages values are deliberately not validated client-side, since GitHub extends the CodeQL language set over time; invalid values surface as a GitHub 422 relayed to the committer by email, as are the 403/409 cases (archived repo, setup change in progress, Actions disabled).
  • Tests follow the github_copilot_code_review.py fake-requester pattern; README documents the new section.

Fixes #94

🤖 Generated with Claude Code

Allow projects to self-service enable GitHub code scanning (CodeQL
default setup) from .asf.yaml, as requested in apache#94:

    github:
      code_scanning: true

or, for more control:

    github:
      code_scanning:
        query_suite: extended
        threat_model: remote
        languages:
          - java-kotlin

The directive reads the current default setup configuration first and
only issues a PATCH when the desired settings differ, avoiding
redundant analysis runs. Removing the section disables the setup only
if it was previously managed via .asf.yaml, following the semantics
established in apache#121. Language identifiers are deliberately not
validated client-side, as GitHub extends the CodeQL language set over
time.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread asfyaml/feature/github/code_scanning.py Outdated
Comment thread asfyaml/feature/github/code_scanning.py
Comment thread asfyaml/feature/github/code_scanning.py
Comment thread asfyaml/feature/github/code_scanning.py Outdated
Comment thread asfyaml/feature/github/code_scanning.py Outdated
An explicit `code_scanning: false` now returns early unless the setup
was previously managed through `.asf.yaml`, matching the guard used by
the sibling directives, so a default setup enabled by INFRA is left
untouched. Document the disable semantics in the README.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HG2YkEme3CUshbsNKK1GRH
Send query_suite in the PATCH payload only when the user set it,
like threat_model and languages, and drop the strictyaml-injected
"default" default so an omitted key truly leaves the suite unmanaged.
This prevents .asf.yaml from silently downgrading a default setup
that INFRA configured with the extended suite.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HG2YkEme3CUshbsNKK1GRH
Accept any 2xx status for the default setup PATCH, matching the
sibling directives, so an unexpected success code is not reported as
an error (which would also skip writing the settings cache and repeat
on every push). Guard the JSON parse of the GET response so a 200
with a non-JSON body produces a helpful message instead of a raw
JSONDecodeError.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HG2YkEme3CUshbsNKK1GRH
Removing a key from the code_scanning map keeps its last applied
value on GitHub's side; document this and the disable/re-enable
cycle as the way to return to automatic language selection.
Verified against the live API on a scratch repository: omitted
PATCH fields keep their previous values, "languages": [] means
"no languages selected" rather than a reset to auto-detection,
and a disable/re-enable cycle resets the whole configuration.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HG2YkEme3CUshbsNKK1GRH
Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HG2YkEme3CUshbsNKK1GRH
@ppkarwasz

Copy link
Copy Markdown
Member Author

@potiuk all five of your review comments are now addressed (each thread has a reply with the corresponding commit; the sticky-fields one includes results of testing the API semantics on a scratch repo). Could you take another look when you have a moment?

@potiuk

potiuk commented Sep 18, 2026

Copy link
Copy Markdown
Member

Sandbox-tested against my own sandbox (rebased onto current main first — the branch predates the --branch flag #127 added to asfyaml-run). Committed a small Python file so CodeQL had a supported language to detect, then applied query_suite: extended with languages: [python].

Note for anyone testing this: immediately after the PATCH, the API still reports languages: [] and updated_at: null while CodeQL Setup runs. It settles a minute later. Your 409 handler covers the window where a second apply lands mid-setup.

One gap. code_scanning: false cannot turn off a setup that is currently on, unless the cached previous .asf.yaml already had a code_scanning key. The guard

if not configured and not was_previously_configured:
    return

returns before the get_default_setup call, so with a cold /x1/asfyaml cache — as in CI and sandbox runs — or when CodeQL was enabled by hand in repository settings, the disable is a silent no-op. Verified: with state: configured, applying code_scanning: false produced no Disabling line and left it configured.

This is the same shape as a bug I just fixed in #111, and the same fix applies: the scanning is None case already returns earlier, so the guard can drop the not was_previously_configured half and let the live currently_configured check decide.

Smaller thing: if self.noop("code_scanning"): return sits before any printing, so a dry run says nothing at all about this directive. Other directives print their intent and then "not applying changes, noop mode active", which is what makes --noop useful for review.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow enabling secret and code scanning

2 participants