From 3835fdedf22463376d3d8de8ca8ef0b472d60cc9 Mon Sep 17 00:00:00 2001 From: Max Schaefer <54907921+max-schaefer@users.noreply.github.com> Date: Mon, 25 Mar 2024 18:17:34 +0000 Subject: [PATCH] Add autofix coverage information for CodeQL queries (#49781) Co-authored-by: Peter Bengtsson Co-authored-by: Peter Bengtsson --- .github/actions/install-cocofix/action.yml | 21 +++++++++++++ .../generate-code-scanning-query-lists.yml | 4 +++ .github/workflows/lint-code.yml | 4 +++ .../generate-code-scanning-query-list.ts | 31 +++++++++++++++++-- 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 .github/actions/install-cocofix/action.yml diff --git a/.github/actions/install-cocofix/action.yml b/.github/actions/install-cocofix/action.yml new file mode 100644 index 0000000000..8cd9b69d1c --- /dev/null +++ b/.github/actions/install-cocofix/action.yml @@ -0,0 +1,21 @@ +name: Install CocoFix + +description: Installs the private package `@github/cocofix` from the GitHub Package Registry. + +inputs: + token: + description: PAT + required: true + +runs: + using: 'composite' + steps: + - name: Install CoCoFix + shell: bash + env: + TOKEN: ${{ inputs.token }} + run: | + npm install --no-save \ + '--@github:registry=https://npm.pkg.github.com' \ + '--//npm.pkg.github.com/:_authToken=${TOKEN}' \ + @github/cocofix diff --git a/.github/workflows/generate-code-scanning-query-lists.yml b/.github/workflows/generate-code-scanning-query-lists.yml index 823e19f7d3..f130d28f60 100644 --- a/.github/workflows/generate-code-scanning-query-lists.yml +++ b/.github/workflows/generate-code-scanning-query-lists.yml @@ -60,6 +60,10 @@ jobs: sleep 3 codeql --version + - uses: ./.github/actions/install-cocofix + with: + token: ${{ secrets.DOCS_BOT_PAT_WORKFLOW }} + - name: Build code scanning query list run: | for lang in "cpp" "csharp" "go" "java" "javascript" "python" "ruby" "swift"; do diff --git a/.github/workflows/lint-code.yml b/.github/workflows/lint-code.yml index 041d2cd7e6..b9938cbc4c 100644 --- a/.github/workflows/lint-code.yml +++ b/.github/workflows/lint-code.yml @@ -45,5 +45,9 @@ jobs: - name: Run Prettier run: npm run prettier-check + - uses: ./.github/actions/install-cocofix + with: + token: ${{ secrets.DOCS_BOT_PAT_WORKFLOW }} + - name: Run TypeScript run: npm run tsc diff --git a/src/code-scanning/scripts/generate-code-scanning-query-list.ts b/src/code-scanning/scripts/generate-code-scanning-query-list.ts index d0c4041e04..406f7a652e 100644 --- a/src/code-scanning/scripts/generate-code-scanning-query-list.ts +++ b/src/code-scanning/scripts/generate-code-scanning-query-list.ts @@ -29,6 +29,15 @@ * * /Users/peterbe/.local/share/gh/extensions/gh-codeql/dist/nightly/codeql-bundle-20231204/codeql * + * Finally, you need to install `@github/cocofix`. This is a private package, + * so you first need to get the `DOCS_BOT_PAT_WORKFLOW` PAT from the vault and + * store it in the environment variable `DOCS_BOT_PAT_WORKFLOW`. + * Then run the following command from the root of this repo: + * + * ```sh + * npm i --no-save '--@github:registry=https://npm.pkg.github.com' '--//npm.pkg.github.com/:_authToken=${DOCS_BOT_PAT_WORKFLOW}' @github/cocofix + * ``` + * * If you've git cloned github/codeql in /tmp/ now you can execute this script. * For example, to generate the Markdown * for Python: @@ -44,6 +53,10 @@ import { execFileSync } from 'child_process' import chalk from 'chalk' import { program } from 'commander' +// We don't want to introduce a global dependency on @github/cocofix, so we install it by hand +// as described above and suppress the import warning. +import { getSupportedQueries } from '@github/cocofix/dist/querySuites' // eslint-disable-line import/no-unresolved +import { type Language } from '@github/cocofix/dist/codeql' // eslint-disable-line import/no-unresolved program .description('Generate a reusable Markdown for for a code scanning query language') @@ -74,6 +87,7 @@ type Query = { url: string packs: string[] cwes: string[] + autofixSupport: 'none' | 'default' } const opts = program.opts() @@ -105,6 +119,12 @@ async function main(options: Options, language: string) { [id: string]: Query } = {} + const autofixSupportedQueryIds = await getSupportedQueries( + 'default', + language as Language, + 'CodeQL', + ) + for (const pack of options.packs) { const languagePack = `${language}-${pack}.qls` if (options.verbose) console.log(chalk.dim(`Searching for queries in ${languagePack}`)) @@ -123,12 +143,13 @@ async function main(options: Options, language: string) { if (id && name) { const cwes = getCWEs(tags || '') const url = getDocsLink(language, id) + const autofixSupport = autofixSupportedQueryIds.includes(id) ? 'default' : 'none' // Only include queries that have CWEs, since the other queries deal with code scanning // metadata and metrics (e.g. counting lines of code or number of files) and have no docs link if (cwes.length) { if (!(id in queries)) { - queries[id] = { url, name, packs: [], cwes } + queries[id] = { url, name, packs: [], cwes, autofixSupport } } queries[id].packs.push(pack) } else { @@ -150,7 +171,7 @@ function printQueries(options: Options, queries: Query[]) { const markdown = [] markdown.push('{% rowheaders %}') markdown.push('') // blank line - const header = ['Query name', 'Related CWEs', 'Default', 'Extended'] + const header = ['Query name', 'Related CWEs', 'Default', 'Extended', 'Autofix'] markdown.push(`| ${header.join(' | ')} |`) markdown.push(`| ${header.map(() => '---').join(' | ')} |`) @@ -161,14 +182,18 @@ function printQueries(options: Options, queries: Query[]) { const markdownLink = `[${query.name}](${query.url})` let defaultIcon = notIncludedOcticon let extendedIcon = notIncludedOcticon + let autofixIcon = notIncludedOcticon if (query.packs.includes('code-scanning')) { defaultIcon = includedOcticon } if (query.packs.includes('security-extended')) { extendedIcon = includedOcticon } + if (query.autofixSupport === 'default') { + autofixIcon = includedOcticon + } markdown.push( - `| ${markdownLink} | ${query.cwes.join(', ')} | ${defaultIcon} | ${extendedIcon} |`, + `| ${markdownLink} | ${query.cwes.join(', ')} | ${defaultIcon} | ${extendedIcon} | ${autofixIcon} |`, ) } markdown.push('') // blank line