From e8bd96f1eb491d0cffadeeda6559655cee48bb4b Mon Sep 17 00:00:00 2001 From: Joyce Zhu Date: Fri, 21 Aug 2026 02:51:40 -0400 Subject: [PATCH] Overhaul plugin docs - new issue template for allowlisting third-party issues from NPM - plugin documentation reorganized and rewritten to organize information about all plugins vs. NPM plugins only vs. local plugins only --- .../allowlist-npm-plugin-request.yml | 15 ++++++ PLUGINS.md | 52 ++++++++++++------- 2 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/allowlist-npm-plugin-request.yml diff --git a/.github/ISSUE_TEMPLATE/allowlist-npm-plugin-request.yml b/.github/ISSUE_TEMPLATE/allowlist-npm-plugin-request.yml new file mode 100644 index 0000000..bf5489a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/allowlist-npm-plugin-request.yml @@ -0,0 +1,15 @@ +name: Allowlist Third Party NPM Plugin Request +description: Fill out the details to request allowlisting your third party plugin hosted on NPM in the scanner. +labels: 'allowlist-plugin-request' +body: + - type: input + attributes: + label: Link to your plugin on NPM + validations: + required: true + - type: textarea + attributes: + label: What does your plugin do? + description: Please provide a brief description of your plugin's functionality. + validations: + required: true diff --git a/PLUGINS.md b/PLUGINS.md index 0ed1262..e1334a2 100644 --- a/PLUGINS.md +++ b/PLUGINS.md @@ -1,12 +1,17 @@ # Plugins -The plugin system allows teams to create custom scans/tests to run on their pages. An example of this is Axe interaction tests. In some cases, it might be desirable to perform specific interactions on elements of a given page before doing an Axe scan. These interactions are usually unique to each page that is scanned, so it would require the owning team to write a custom plugin that can interact with the page and run the Axe scan when ready. See the existing plugins under [.github/scanner-plugins](https://github.com/github/accessibility-scanner/tree/main/.github/scanner-plugins) for examples of plugin structure. +The plugin system allows teams to create custom scans/tests to run on their pages. An example of this is Axe interaction tests. In some cases, it might be desirable to perform specific interactions on elements of a given page before doing an Axe scan. These interactions are usually unique to each page that is scanned, so it would require the owning team to write a custom plugin that can interact with the page and run the Axe scan when ready. -Some plugins come built-in with the scanner and can be enabled via [actions inputs](https://github.com/github/accessibility-scanner/tree/main/action.yml#L48-L50). +Some first-party plugins come built-in with the scanner repository and can be enabled via [actions inputs](https://github.com/github/accessibility-scanner/tree/main/action.yml#L48-L50). +There are also some [allowlisted](https://github.com/github/accessibility-scanner/blob/7ec4b73ca2fdb471ad6f71a48a88e7b1a84ab3ad/.github/actions/find/src/pluginManager/index.ts#L92) first-party plugins hosted in a different repository; we also have the ability to support loading approved third-party plugins [from NPM](./loading-plugins-from-npm-packages). -## How plugins work +## How to create plugins + +### Plugin folder structure for all plugins -Plugins are dynamically loaded by the scanner when it runs. The scanner will look into the `./.github` folder in your repo (where you run the workflow from) and search for a `scanner-plugins` folder. If it finds it, it will assume each folder under that is a plugin, and attempt to load the `index.ts` (first) or `index.js` (second) file inside it. Once loaded, the scanner will invoke the exported default function from the `index.js/index.ts` file. +- Each plugin should have one `index.ts` OR `index.js` file inside its folder. +- The `index.ts/index.js` file must export a `name` field. This is the name used to pass to the `scans` input. So if the plugin exports a name value of `my-custom-plugin` and we pass the following to the scanner action inputs: `scans: ['my-custom-plugin']`, it would cause the scanner to only run that plugin. +- The `index.ts/index.js` file must export a default function (see [below](./default-function-api)). This is the function that the scanner uses to run the plugin. This can be an async function. ### Default function API @@ -22,15 +27,23 @@ A async function (you must use `await` or `.then` when invoking this function) t - An object that should match the [`Finding` type](https://github.com/github/accessibility-scanner/blob/main/.github/actions/find/src/types.d.ts#L1-L9). -## How to create plugins +### NPM-hosted plugins -As mentioned above, plugins need to exist under `./.github/scanner-plugins`. For a plugin to work, it needs to meet the following criteria: +Create a repository containing the required files/functions mentioned above, then publish it as an NPM package (with a public URL). -- Each separate plugin should be contained in it's own directory in `./.github/scanner-plugins`. For example, `./.github/scanner-plugins/plugin-1` would be 1 plugin loaded by the scanner. -- Each plugin should have one `index.ts` OR `index.js` file inside its folder. -- The `index.ts/index.js` file must export a `name` field. This is the name used to pass to the `scans` input. So if the plugin exports a name value of `my-custom-plugin` and we pass the following to the scanner action inputs: `scans: ['my-custom-plugin']`, it would cause the scanner to only run that plugin. -- The `index.ts/index.js` file must export a default function. This is the function that the scanner uses to run the plugin. This can be an async function. -- In your workflow file, before the scanner step, add `- uses: actions/checkout@v6` (or whatever the current version is). This allows the current repository's files (where your custom plugin's file exists) to be read: +Once the public URL is live, please fill out [this issue template](./.github/ISSUE_TEMPLATE/allowlist-npm-plugin-request.yml) so we can allowlist your plugin in future versions of the scanner. + +To then enable an NPM plugin in the `scans` input, follow the instructions in the [loading plugins from NPM](./loading-plugins-from-npm-packages) section. + +An example of a plugin which can be loaded from NPM is our [alt text scanning plugin](https://github.com/github/accessibility-scanner-alt-text-plugin). + +### Local plugins (located in your repository) + +If you wish, you can create _local plugins_ by creating a folder containing plugin code in `./.github/scanner-plugins/`. Each separate plugin should be contained in its own directory. For example, `./.github/scanner-plugins/plugin-1` would be 1 plugin loaded by the scanner. + +Enabled local plugins (i.e. those listed in the `scans` Action input) are dynamically loaded by the scanner when it runs. The scanner will search for a `./.github/scanner-plugins` folder in your repo (where you run the workflow from). If it finds one, it will assume each folder under that is a plugin, and attempt to load the `index.ts` (first) or `index.js` (second) file inside it. Once loaded, the scanner will invoke the exported default function from the `index.js/index.ts` file. + +In your workflow file, before the scanner step, add `- uses: actions/checkout@v6` (or whatever the current version is). This allows the current repository's files (where your custom plugin's file exists) to be read: ```yaml jobs: @@ -45,8 +58,10 @@ jobs: ## Loading plugins from NPM packages -In addition to local plugins under `./.github/scanner-plugins`, the scanner can install and load plugins published as NPM packages. This avoids having to vendor a plugin's source into your repo. -NPM package loading requires scanner v3.4.1 or later. +> [!IMPORTANT] +> NPM package loading requires scanner v3.4.1 or later. + +The scanner can install and load plugins published as NPM packages. This avoids having to vendor a plugin's source into your repo. To use an NPM plugin, pass an object (instead of a plain string) in the `scans` input with the following fields: @@ -54,7 +69,7 @@ To use an NPM plugin, pass an object (instead of a plain string) in the `scans` - `package` — the NPM package name to install. - `version` — (optional) a version or dist-tag to pin. If omitted, the latest version is installed. -Only the set of [first-party packages](.github/actions/find/src/pluginManager/index.ts#L91) may be loaded from NPM. Any other package is skipped with a warning. +Only the set of [approved packages](.github/actions/find/src/pluginManager/index.ts#L91) may be loaded from NPM. Any other package is skipped with a warning. ```yaml jobs: @@ -68,11 +83,10 @@ jobs: ["axe", {"name": "alt-text-scan", "package": "@github/accessibility-scanner-alt-text-plugin", "version": "1.1.0"}] ``` -Notes: - -- Packages are installed at runtime with `npm install --ignore-scripts`, so install/postinstall scripts in the package will not run. Pin a `version` to avoid silently picking up future releases. -- If an NPM plugin shares a name with a built-in or local plugin, the built-in/local plugin wins and the NPM one is skipped. -- Plugin configuration works the same as local plugins: place a config-only folder at `./.github/scanner-plugins//config.json` in your repo (the plugin reads its config relative to the repo you run the workflow from). +> [!NOTE] +> - Packages are installed at runtime with `npm install --ignore-scripts`, so install/postinstall scripts in the package will not run. Pin a `version` to avoid silently picking up future releases. +> - If an NPM plugin shares a name with a built-in or local plugin, the built-in/local plugin wins and the NPM one is skipped. +> - Plugin configuration works the same as local plugins: place a config-only folder at `./.github/scanner-plugins//config.json` in your repo (the plugin reads its config relative to the repo you run the workflow from). ## Things to look out for