{"id":21327879,"url":"https://github.com/advanced-security/monorepo-code-scanning-action","last_synced_at":"2025-04-14T23:42:14.140Z","repository":{"id":262866955,"uuid":"811884630","full_name":"advanced-security/monorepo-code-scanning-action","owner":"advanced-security","description":"Focus SAST scans (with CodeQL) on just the changed parts of your monorepo, split up as you define","archived":false,"fork":false,"pushed_at":"2025-04-03T16:33:12.000Z","size":172,"stargazers_count":6,"open_issues_count":5,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-03T17:32:07.078Z","etag":null,"topics":["actions","advanced-security","code-scanning-ready","codeql","monorepo","sast"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/advanced-security.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":"SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-07T13:57:39.000Z","updated_at":"2025-04-03T16:27:13.000Z","dependencies_parsed_at":"2025-04-03T17:36:40.246Z","dependency_job_id":null,"html_url":"https://github.com/advanced-security/monorepo-code-scanning-action","commit_stats":null,"previous_names":["advanced-security/monorepo-code-scanning-action"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fmonorepo-code-scanning-action","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fmonorepo-code-scanning-action/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fmonorepo-code-scanning-action/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/advanced-security%2Fmonorepo-code-scanning-action/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/advanced-security","download_url":"https://codeload.github.com/advanced-security/monorepo-code-scanning-action/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248981257,"owners_count":21193143,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actions","advanced-security","code-scanning-ready","codeql","monorepo","sast"],"created_at":"2024-11-21T21:20:20.642Z","updated_at":"2025-04-14T23:42:14.131Z","avatar_url":"https://github.com/advanced-security.png","language":"JavaScript","funding_links":[],"categories":["CodeQL Actions Helpers"],"sub_categories":[],"readme":"# Monorepo Code Scanning Action\n\n\u003e [!NOTE]\n\u003e This is an _unofficial_ tool created by Field Security Specialists, and is not officially supported by GitHub.\n\nFocus Code Scanning with GitHub Advanced Security on parts of your monorepo, split up as you define. This can minimize CI work and time and allow scanning a monorepo in parallel for scheduled scans.\n\nFor an example of how to use it for PR scans, see the [`./samples/sample-codeql-monorepo-pr-workflow.yml`](./samples/sample-codeql-monorepo-pr-workflow.yml) in this repository. For a scheduled scan example, see [`./samples/sample-codeql-monorepo-whole-repo-workflow.yml`](./samples/sample-codeql-monorepo-whole-repo-workflow.yml)\n\nThe steps pass information along to each other to work properly, so you need to use the format defined in that workflow, altering the inputs as required.\n\nSee [Alternatives](#alternatives) for other ways to achieve the same goal.\n\n\u003e [!NOTE]\n\u003e This is an _unofficial_ tool created by Field Security Specialists, and is not officially supported by GitHub.\n\n## Overview\n\nYou must define a project structure for your repo, with each project being a specific language and subset of paths of directories, to use this tool to split up scans of your monorepo.\n\nIf you use C# and an existing [MSBuild project file](https://learn.microsoft.com/en-us/visualstudio/msbuild/walkthrough-creating-an-msbuild-project-file-from-scratch?view=vs-2022), you can directly use that to define the project structure.\n\nFor other cases you need to create a JSON file that describes that structure, like so:\n\n```json\n{\n  \"\u003clanguage\u003e\":\n    \"projects\": {\n      \"\u003cproject name\u003e\": {\n        \"paths\":\n          [\n            \"\u003cfolder path 1\u003e\",\n            \"\u003cfolder path 2\u003e\",\n            ...\n          ]\n      },\n    ...\n  },\n  ...\n}\n```\n\nIn the description of the `changes` Action you can see more optional keys that can be set at language or project level.\n\nThis project definition lets a workflow use the `changes` Action to look for changes in the defined project structure; the `scan` Action then scans any changed projects using CodeQL (or another tool); and lastly `republish-sarif` allows the unscanned parts of the project to pass the required CodeQL checks by republishing the SARIF.\n\n```mermaid\ngraph TD\n  PR --\u003e |triggers| workflow[Workflow]\n  workflow[Workflow] --\u003e|runs| changes[changes]\n  changes[Changes] --\u003e|triggers| scan[Scan]\n  changes[Changes] --\u003e|trigger| republish-sarif[Republish SARIF]\n  scan[Scan] --\u003e|matrix| project-a[Project A]\n  scan[Scan] --\u003e|matrix| project-b[Project B]\n  scan[Scan] --\u003e|matrix| ...\n```\n\n## Using the Action\n\n\u003e [!NOTE]\n\u003e This is an _unofficial_ tool created by Field Security Specialists, and is not officially supported by GitHub.\n\nThe steps pass information along to each other to work properly, so you need to use the format defined in that sample workflow, altering the inputs as required.\n\n### Branch protection\n\nTo make sure you cover all code changes without needing to scan pushes to your default branch, ensure you use a repository ruleset to restrict direct pushes to your default branch.\n\nThis will also need a rule to require branches to be up to date before merging.\n\nYou may wish to bypass this rule occasionally, so remember to allow for that appropriately, and consider whether you will require a full scan of the repository at that time to ensure changes are scanned. You can use a `workflow_dispatch` trigger on a full scheduled workflow to allow for this.\n\n### Scanning changes in PRs\n\nThe `changes` Action looks for changes in your defined project structure.\n\nIt also sets the CodeQL configuration to use for the rest of the workflow.\n\nFor an example of how to use it for PR scans, see [`./samples/sample-codeql-monorepo-pr-workflow.yml`](./samples/sample-codeql-monorepo-pr-workflow.yml)\n\n#### Setting project structure\n\nThe project structure can either be defined in a JSON file and provided by name in the `projects-json` input, or can be parsed out of an MSBuild XML file in the `build-xml` input.\n\nIt has several purposes - it defines the paths that are watched for changes, and checked out, and also defines CodeQL configuration options.\n\n##### MSBuild file parsing\n\nYou can see an example of this XML format in this repository in `./samples/build-projects.xml`.\n\nCurrently parsing relies on the projects being defined in exactly the format in the example - with an `ItemGroup` structure.\n\nIf you use a `PropertyGroup` or have targets that don't conform to a simple structure that is defined in this way, you may need to write custom parsing of your MSBuild files to properly extract and group the folders and files needed to successfully build the projects.\n\nWhen using `build-xml` you will need to define any variables used in the input file with concrete values, in a `variables` input, defining them in a YAML format dictionary. A variable looks like `$(FolderADir)`, for example.\n\n##### JSON project structure\n\n\u003e [!NOTE]\n\u003e Do not use `./` to lead path or file names\n\nThe basic required structure has a top-level key for each language, named as CodeQL does (or with an arbitrary name for non-CodeQL languages). Each language has a `projects` key, and under that each project is a named key that contains `paths`, which is a list of folder names (without a leading `./` - e.g. `src/FolderA`).\n\nIn the JSON version, you can optionally specify the build-mode for CodeQL, as `none`, `auto` or `manual` to select that mode, or use `other` to allow scanning with a different code scanning tool than CodeQL. That can be done at language or project level by supplying a `build-mode` key at the appropriate level. A suitable build-mode is defaulted if you do not provide one, and if you use one at the project level it overrides any set at the language level.\n\nYou can also include individual files using a `files` key in the project. These files are _not watched_ for changes, but will be included in the sparse checkout along with the folders in the `paths` key. This is to prevent triggering a scan of every project if a top-level build file is changed. If it is necessary, a full-rescan of the repository can be triggered manually at any time using a full-repo workflow. Again, do not use `./` to lead file names.\n\nThe `paths` and `files` lists are evaluated by two different engines - one is the `dorny/paths-filter` Action, and the other is the `actions/checkout` Action. The former uses [picomatch](https://github.com/micromatch/picomatch) and the latter uses the [gitignore](https://git-scm.com/docs/gitignore)-style matching and the, so wildcards can be used, but their exact behaviour may differ slightly - it is best to use exact paths where possible.\n\nYou can also optionally specify a set of CodeQL queries to use with the `queries` key, again either at language or project level. This is a list of inputs valid for the `queries` input of the `codeql/init` step, as [documented here](https://docs.github.com/en/enterprise-cloud@latest/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#specifying-additional-queries).\n\nIf you do not want to specify `queries` in this way you can also set a global `queries` input to the Action - see below.\n\nAn example of a JSON file using a `queries`, `build-mode` and `files` keys is:\n\n```json\n{\n  \"\u003clanguage\u003e\":\n    \"build-mode\": \"none\",\n    \"queries\": [\n      \"security-extended\",\n      \"./local/path/to/a/query.qls\",\n    ]\n    \"projects\": {\n      \"\u003cproject name\u003e\": {\n        \"build-mode\": \"auto\",\n        \"paths\": [\n          \"\u003cfolder path 1\u003e\",\n          \"\u003cfolder path 2\u003e\",\n          ...\n        ],\n        \"files\": [\n          \"\u003cfile 1\u003e\",\n          \"\u003cfile 2\u003e\",\n          ...\n        ]\n      },\n    ...\n  },\n  ...\n}\n```\n\nIf you dynamically generate the project JSON file, then it is best to save it outside of the Actions workspace, such as in `$RUNNER_TEMP`, since a checkout may overwrite it.\n\n###### Setting custom language globs\n\nThe files checked for changes in the project `paths` are not all of the files in that path, but a subset, defined per language. There is a bundled set of globs defined for each language, which are searched for in the project paths defined for the project.\n\nYou can add to that with `extra-globs` input to the `changes` Action, which takes an inline YAML input, of the form:\n\n```yaml\n\u003clanguage\u003e:\n  - \u003cglob1\u003e\n  - \u003cglob2\u003e\n  ...\n```\n\n###### Configuring CodeQL\n\nIn addition to settings the `queries` key at the language or project level, you can also set it globally.\n\nIf you pass a global `queries` input, as a comma separated list of strings, it allows setting the queries to use for all languages and projects. They use the same format as the `queries` input for the `codeql/init` step, as [documented here](https://docs.github.com/en/enterprise-cloud@latest/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#specifying-additional-queries), comma separated just as in that case.\n\nSimilarly, you can pass in a global `config` or `config-file` input, which use the same format as  [documented here](https://docs.github.com/en/enterprise-cloud@latest/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#using-a-custom-configuration-file) and [here](https://docs.github.com/en/enterprise-cloud@latest/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#specifying-configuration-details-using-the-config-input). This _cannot_ currently be set at the language or project level, only globally.\n\nThe effective config used is a combination of the inputs created from the paths of the project, and any queries set in the separate `queries` input to this Action, overlaid with the content of the `config` or `config-file` inputs.\n\n### Whole repo scanning\n\nIn contrast to the `changes` Action, the `whole-repo` Action allows scanning the entire monorepo in a scheduled scan.\n\nThis is useful for taking advantage of new CodeQL queries or 3rd party SAST improvements, on existing code.\n\nDoing this parallel scan can make scanning the whole monorepo feasible on much smaller runners, and cut the wall-clock time for a scan to acceptable levels.\n\nIt is also a way to ensure all code has been scanned recently, which may be required for compliance purposes.\n\nThe Action takes much the same inputs as the `changes` Action, but does not accept an `extra-globs` input, as it is not looking for changes in the repository. There is also no need to use the `republish-sarif` Action with it.\n\nEach project, as defined in the projects input, is scanned in parallel, and the results are uploaded independently.\n\nFor a scheduled scan example, see [`./samples/sample-codeql-monorepo-whole-repo-workflow.yml`](./samples/sample-codeql-monorepo-whole-repo-workflow.yml)\n\n### Scan\n\nThe `scan` Action scans any changed projects using CodeQL (or optionally another tool), using just the changes to the defined projects.\n\nA sparse checkout of the project in which changes happened is used to speed up the checkout, and target scans at just that project.\n\nThe scan can use a local custom code scanning Action to do manual build steps and any required preparation steps before the scanning, which must be located at `.github/actions/code-scanning-custom-analysis/` in your repository. This is used for the `build-mode` of `manual` or `other`.\n\nYou can see an example of this custom workflow in this repository in [`./samples/code-scanning-custom-analysis/`](./samples/code-scanning-custom-analysis/).\n\nThis must have conditional checks to apply the correct build steps for the language and project.\n\n### Project Annotator\n\nThe `sarif-project-annotator` action is used to add project tagging information to SARIF output files from a CodeQL analysis. When scanning multiple projects in a monorepo, this action helps to identify which alerts belong to which project by adding project tags to alert rules.\n\nThis action processes CodeQL SARIF files and modifies the `properties.tags` array for each rule to include a `project/{project-name}` tag. This tag allows you to more easily filter and identify the project of origin in an alert.\n\nThe project annotator requires three inputs:\n\n- `project`: The name of the project to annotate as a tag (required)\n- `sarif_file`: The path to the CodeQL SARIF result file (required)\n- `output_file`: The path where the modified SARIF file should be saved (required)\n\nHere's an example of how to use the action within your workflow:\n\n```yaml\n    # Perform CodeQL scan but do not upload results (for further SARIF processing)\n    - name: Perform CodeQL Analysis\n      id: codeql-analyze\n      uses: github/codeql-action/analyze@v3\n      with:\n        category: \"/language:${{ matrix.project.language }};project:${{ matrix.project.name }}\"\n        upload: false\n        output: sarif-results\n\n    # Parse the db-locations output and get the sarif file name from the analysis\n    - name: Set SARIF file name\n      id: set-sarif-file-name\n      uses: actions/github-script@v7\n      with:\n        result-encoding: string\n        script: |\n          const dbLocations = JSON.parse('${{ steps.codeql-analyze.outputs.db-locations }}');\n          const language = Object.keys(dbLocations)[0];\n          const sarifFilePath = `${language}.sarif`;  \n          return sarifFilePath;\n\n    # Annotate the SARIF with project tags\n    - name: Annotate CodeQL Alert SARIF with Project tag\n      uses: advanced-security/monorepo-code-scanning-action/sarif-project-annotator@main #Recommended: pin to a hash instead of `main`\n      with:\n        project: ${{ matrix.project.name }}\n        sarif_file: ${{ steps.codeql-analyze.outputs.sarif-output }}/${{ steps.set-sarif-file-name.outputs.result }}\n        output_file: ${{ steps.codeql-analyze.outputs.sarif-output }}/${{ matrix.project.name }}-${{ steps.set-sarif-file-name.outputs.result }}\n```\n\nKnown limitations:\n- The ability to filter the Advanced Security Code Scanning dashboards by tag is globally implemented per rule - this design limits the ability to filter by unique tags.  Viewing or API/Webhook export of the Alert will contain the proper data.\n\n### Republish\n\nThe  `republish-sarif` Action allows the unscanned parts of the project to pass the required CodeQL checks.\n\nThe SARIF is republished, meaning a complete set of Code Scanning results is attached to the PR, copied from the target branch, whether or not the project was changed during the PR.\n\nIt will also republish the scanning results onto the target branch, on merge. This saves running a full repo scan on the target branch.\n\nTo allow this, you need to give the workflow the `closed` type on the `pull_request` trigger to be able run on PR merge, as shown in the sample workflow, and here:\n\n```yaml\n  pull_request:\n    branches: [\"main\"]\n    types:\n      - opened\n      - reopened\n      - synchronize\n      - closed\n```\n\n## Limitations\n\nActions can create matrix jobs with a maximum of 256 targets. This means that monorepos with more than 256 projects must be divided up into more than one workflow, until something is done to deal with this in this Action (if that is possible).\n\nThe checks feature of GitHub can take a maximum of 1000 checks with the same name. That means that monorepos with more than 1000 projects cannot be scanned with them all scanned individually; so several must be grouped together to get under this 1000 threshold.\n\nThe custom CodeQL/other tool analysis requires manual control over which build steps are applied to which project, in a single workflow, in contrast to the declarative design of the rest of the workflow.\n\nThis tool cannot help with a monolith that cannot be split up into smaller projects.\n\nIf you have a monorepo with lots of languages that exist in the same projects you will need to duplicate that project structure multiple times for each affected language. A future option could take a single named project with several paths and languages - raise an issue if that would be helpful, please.\n\n## Tests\n\nLocal tests for the scripts this relies on are located in the `tests` folder. They are run with `./run.sh`, vs using a testing framework.\n\nTesting is also done end-to-end using the private [`advanced-security/sample-csharp-monorepo`](https://github.com/advanced-security/sample-csharp-monorepo/) repository.\n\n## License\n\nThis project is licensed under the terms of the MIT open source license. Please refer to the [LICENSE](LICENSE) for the full terms.\n\n## Maintainers\n\nSee [CODEOWNERS](CODEOWNERS) for the list of maintainers.\n\n## Support\n\n\u003e [!NOTE]\n\u003e This is an _unofficial_ tool created by Field Security Specialists, and is not officially supported by GitHub.\n\nSee the [SUPPORT](SUPPORT.md) file.\n\n## Background and acknowledgements\n\nThe `changes` Action relies on the [`dorny/paths-filter`](https://github.com/dorny/paths-filter/) Action.\n\nSee the [CHANGELOG](CHANGELOG.md), [CONTRIBUTING](CONTRIBUTING.md), [SECURITY](SECURITY.md), [SUPPORT](SUPPORT.md), [CODE OF CONDUCT](CODE_OF_CONDUCT.md) and [PRIVACY](PRIVACY.md) files for more information.\n\n### Alternatives\n\nThis tool is designed to provide a build-system-agnostic way to split up a monorepo for scanning, but it is far from the only way to efficiently scan a monorepo.\n\nA monorepo-friendly build tool can be used to define build targets and dependencies, check out only the required code to build the target, and run custom commands on that target.\n\nYou can inject CodeQL into the build tool as such as custom command; for compiled languages you can instrument the build process to watch for the build commands and run CodeQL on the output; or you can run CodeQL on the subset of the checked out code that is required to build the target.\n\nIt will be necessary to keep track of the CodeQL category assigned to each build target, to avoid clashes.\n\nSee the GitHub documentation on [Using code scanning with your existing CI system](https://docs.github.com/en/enterprise-cloud@latest/code-security/code-scanning/integrating-with-code-scanning/using-code-scanning-with-your-existing-ci-system)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadvanced-security%2Fmonorepo-code-scanning-action","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadvanced-security%2Fmonorepo-code-scanning-action","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadvanced-security%2Fmonorepo-code-scanning-action/lists"}