You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
safe-settings can't manage CodeQL default setup today. Orgs that want default setup on (or off) across their repos have to click through each repo or use a separate mechanism, outside the config that manages everything else.
#891 is related but different: it restricts which languages a repo that already uses default setup may scan. It never turns default setup on or off.
Change
A new code_scanning plugin, configured like any other repository setting at the org, suborg or repo level:
code_scanning:
default_setup:
state: configured # or not-configuredquery_suite: extended # default | extendedthreat_model: remote # remote | remote_and_locallanguages: [csharp, actions] # omit to let GitHub analyze the languages it detects# runner_type / runner_label
On each sync it reads GET /repos/{owner}/{repo}/code-scanning/default-setup and, if needed, calls PATCH on the same endpoint:
Only the declared fields are compared and sent. Fields left out stay as GitHub has them.
A languages list from a higher layer replaces the inherited one instead of being concatenated by the generic merge, so a suborg or repo can narrow or clear it.
languages are compared regardless of order.
With state: not-configured, only the state is compared and applied, since GitHub keeps no other settings once default setup is off.
In NOP mode the plugin reports the PATCH it would send, like the Repository plugin: GitHub's current value for each differing field goes in deletions (rendered as before), and the new value in modifications (after). A field cleared to []/null appears only in deletions, so the report shows it as removed instead of dropping it as empty. Errors become ERROR results, and a 404 is ignored as in Diffable, because the repo may not exist yet in a dry run.
On a real sync, a GitHub error (for example 403 when Code Security isn't enabled on a private repo) is recorded with logError for that repo. The rest of the sync continues.
Also included:
code_scanning in the settings, suborgs and repos schemas. The $ref points to GitHub's code-scanning-default-setup-update schema, the same way autolinks does.
code_scanning added to the disable_plugins names. It's not an additive plugin.
A README section and an entry in docs/sample-settings/settings.yml.
The dereferenced schemas only gain the code_scanning parts. Running npm run build:schema today also pulls unrelated description changes from GitHub's current OpenAPI description (ruleset parameters and the like), so I left those out to keep this PR focused.
Relation to #891: both use the code_scanning.default_setup key. The schema here only accepts the API's fields, so #891's enabled/allowed-language options would need adding to that schema if both land.
Tests
test/unit/lib/plugins/code_scanning.test.js: no config; enabling with the declared fields; no update when the fields match, in any language order; duplicate languages; updating a single differing field and a different language list; disabling (sends only the state); a disabled repo with extra fields declared (no update); a rejected update recorded as an error; declaredLanguages(); and in NOP mode, the reported change, clearing languages/runner_label reported as deletions that the report keeps, ERROR results (both named code_scanning), and an ignored 404.
test/unit/lib/settings.test.js: a code_scanning section creates the plugin, a repo file overrides the org default_setup, and languages from a higher layer replace the inherited list (narrowed, cleared with [], and set at the suborg level).
test/unit/lib/settings-results.test.js: the plugin's NOP output through handleResults() renders before/after for a modified field and a removed row for a cleared one.
test/unit/schema.test.js: all three schemas accept a valid default_setup, and reject an unknown state, an unknown language, and unknown fields.
npm run test:unit passes (1048 tests, 12 skipped as before). The new and changed files are clean under eslint and standard, apart from errors that lib/settings.js and test/unit/lib/settings.test.js already had on main-enterprise.
Not yet exercised against a live org. I haven't confirmed which GitHub App permission the default setup endpoints require, so app.yml is unchanged. Happy to add one if they need a permission safe-settings doesn't request yet.
Add a code_scanning plugin that reconciles a repository's CodeQL default
setup with code_scanning.default_setup in settings, suborg or repo files.
Only the declared fields (state, query_suite, threat_model, languages,
runner_type, runner_label) are compared and sent, languages are compared
regardless of order, and with state: not-configured only the state is
applied. GitHub errors such as a missing Code Security license are
recorded for the repository without stopping the sync.
Add the section to the settings, suborgs and repos schemas and to the
disable_plugins names, and document it in the README and sample settings.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
CodeQL language lists are concatenated rather than overridden, blocking repository-level narrowing or clearing and risking repeated PATCHes, while an incorrect plugin identifier causes unrelated settings PRs to report pre-existing drift.
Adds CodeQL default setup management to safe-settings through a new code_scanning plugin, allowing configuration at organization, suborganization, and repository levels.
Changes:
Reconciles declared default setup fields, with dry-run reporting and repository-level error handling.
Adds schema support and registers code_scanning as a disableable, non-additive plugin.
Documents configuration and adds plugin, inheritance, and schema tests.
File
Description
test/unit/schema.test.js
Tests accepted and rejected code scanning configurations.
test/unit/lib/settings.test.js
Tests plugin creation and repository overrides.
test/unit/lib/plugins/code_scanning.test.js
Tests reconciliation, dry runs, and errors.
schema/suborgs.json
Adds suborganization configuration support.
schema/settings.json
Adds organization configuration and disable-plugin entries.
schema/repos.json
Adds repository configuration support.
schema/dereferenced/suborgs.json
Expands the suborganization code scanning schema.
schema/dereferenced/settings.json
Expands organization schema and disable-plugin entries.
…by section
The generic deep merge concatenates arrays, so a repo's languages were
appended to the org's instead of replacing them: a repo could not narrow
or clear the list, and the duplicates never matched GitHub's list, so the
plugin updated the repo on every sync. The highest-priority layer that
declares default_setup.languages now replaces the inherited list, and
languages are compared as sets.
NOP results used the class name as their plugin. The dry-run drift filter
lowercases it to find the config section, and 'codescanning' matched no
section, so pre-existing code scanning drift was reported on unrelated
settings PRs. They now use the section name, code_scanning.
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Explicitly clearing languages or runner_label is omitted from PR/check-run reports even though the sync applies it, leaving a reporting bug that needs a fix and regression test.
Clearing languages to [] or runner_label to null was reported as a
modification holding the empty value. Settings.isEmptyChange() treats
that as no change, so the PR and check-run report left it out even
though a real sync sends the update. Cleared fields are now deletions
that hold GitHub's previous value.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Changes to query_suite omit the previous value, causing dry-run PR/check-run reports to show an empty before-value and potentially misclassify modifications as additions.
No open issues 🎉
1 previously missed issue
In code that hasn't changed since last review
Preserve before-values for modified settings in dry-run reports
lib/plugins/code_scanning.js:103
For a query_suite change from default to extended, this retains only the new value. The renderer in lib/settings.js obtains before-values from deletions, so the PR/check-run report shows an empty before instead of default; combining a modification with a clear can also make the modification appear as an addition. Preserve current[field] for ordinary modifications too so the dry-run report has accurate before/after values.
…orts
The NOP report reads deletions as before values and modifications as
after values, as the Repository plugin reports them. Only cleared fields
kept GitHub's value in deletions, so an ordinary change such as
query_suite default -> extended rendered with an empty before value.
Every changed field now keeps GitHub's value in deletions.
Fixed the before-values issue from the latest Copilot review in dcbd5bd. Every changed field now keeps GitHub's value in deletions, which the NOP report reads as the before value, the same way the Repository plugin reports its changes. A new test in settings-results.test.js runs the plugin's NOP output through handleResults() and checks the rendered report: query_suite shows before default and after extended, and a cleared languages shows as removed with its previous values. It fails without the fix.
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Organization-wide CodeQL enable/disable operations lack live validation, leaving endpoint permissions and asynchronous setup transitions unverified before rollout.
No open issues 🎉
Review effort: Balanced
This branch has not been deployed
No deployments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
safe-settings can't manage CodeQL default setup today. Orgs that want default setup on (or off) across their repos have to click through each repo or use a separate mechanism, outside the config that manages everything else.
#891 is related but different: it restricts which languages a repo that already uses default setup may scan. It never turns default setup on or off.
Change
A new
code_scanningplugin, configured like any other repository setting at the org, suborg or repo level:On each sync it reads
GET /repos/{owner}/{repo}/code-scanning/default-setupand, if needed, callsPATCHon the same endpoint:languageslist from a higher layer replaces the inherited one instead of being concatenated by the generic merge, so a suborg or repo can narrow or clear it.languagesare compared regardless of order.state: not-configured, only the state is compared and applied, since GitHub keeps no other settings once default setup is off.deletions(rendered as before), and the new value inmodifications(after). A field cleared to[]/nullappears only indeletions, so the report shows it as removed instead of dropping it as empty. Errors becomeERRORresults, and a 404 is ignored as inDiffable, because the repo may not exist yet in a dry run.logErrorfor that repo. The rest of the sync continues.Also included:
code_scanningin thesettings,suborgsandreposschemas. The$refpoints to GitHub'scode-scanning-default-setup-updateschema, the same wayautolinksdoes.code_scanningadded to thedisable_pluginsnames. It's not an additive plugin.docs/sample-settings/settings.yml.The dereferenced schemas only gain the
code_scanningparts. Runningnpm run build:schematoday also pulls unrelated description changes from GitHub's current OpenAPI description (ruleset parameters and the like), so I left those out to keep this PR focused.Relation to #891: both use the
code_scanning.default_setupkey. The schema here only accepts the API's fields, so #891'senabled/allowed-language options would need adding to that schema if both land.Tests
test/unit/lib/plugins/code_scanning.test.js: no config; enabling with the declared fields; no update when the fields match, in any language order; duplicate languages; updating a single differing field and a different language list; disabling (sends only the state); a disabled repo with extra fields declared (no update); a rejected update recorded as an error;declaredLanguages(); and in NOP mode, the reported change, clearinglanguages/runner_labelreported as deletions that the report keeps,ERRORresults (both namedcode_scanning), and an ignored 404.test/unit/lib/settings.test.js: acode_scanningsection creates the plugin, a repo file overrides the orgdefault_setup, andlanguagesfrom a higher layer replace the inherited list (narrowed, cleared with[], and set at the suborg level).test/unit/lib/settings-results.test.js: the plugin's NOP output throughhandleResults()renders before/after for a modified field and a removed row for a cleared one.test/unit/schema.test.js: all three schemas accept a validdefault_setup, and reject an unknown state, an unknown language, and unknown fields.npm run test:unitpasses (1048 tests, 12 skipped as before). The new and changed files are clean undereslintandstandard, apart from errors thatlib/settings.jsandtest/unit/lib/settings.test.jsalready had onmain-enterprise.Not yet exercised against a live org. I haven't confirmed which GitHub App permission the default setup endpoints require, so
app.ymlis unchanged. Happy to add one if they need a permission safe-settings doesn't request yet.🤖 Generated with Claude Code