From 5331452456b698b2c059caa42f57537a6168b42e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 1 May 2026 16:08:30 +0000 Subject: [PATCH 1/5] Initial plan From 91555307284856cc78f9cd4c1f7dea2596ff452c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 1 May 2026 16:11:46 +0000 Subject: [PATCH 2/5] feat: add exclude selectors input to accessibility scanner Agent-Logs-Url: https://github.com/github/accessibility-scanner/sessions/13d504eb-d5cb-4e30-994f-b988560b788d Co-authored-by: abdulahmad307 <204748719+abdulahmad307@users.noreply.github.com> --- .github/actions/find/action.yml | 3 +++ .github/actions/find/src/findForUrl.ts | 10 ++++++++-- .github/actions/find/src/index.ts | 12 +++++++++++- README.md | 2 ++ action.yml | 4 ++++ 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.github/actions/find/action.yml b/.github/actions/find/action.yml index c4e1cc5..90fd9f3 100644 --- a/.github/actions/find/action.yml +++ b/.github/actions/find/action.yml @@ -22,6 +22,9 @@ inputs: color_scheme: description: 'Playwright colorScheme setting: https://playwright.dev/docs/api/class-browser#browser-new-context-option-color-scheme' required: false + exclude: + description: 'Stringified JSON array of CSS selectors to exclude from the Axe scan' + required: false outputs: findings_file: diff --git a/.github/actions/find/src/findForUrl.ts b/.github/actions/find/src/findForUrl.ts index e651779..2d9a78d 100644 --- a/.github/actions/find/src/findForUrl.ts +++ b/.github/actions/find/src/findForUrl.ts @@ -13,6 +13,7 @@ export async function findForUrl( includeScreenshots: boolean = false, reducedMotion?: ReducedMotionPreference, colorScheme?: ColorSchemePreference, + exclude?: string[], ): Promise { const browser = await playwright.chromium.launch({ headless: true, @@ -56,7 +57,7 @@ export async function findForUrl( } if (scansContext.shouldPerformAxeScan) { - await runAxeScan({page, addFinding}) + await runAxeScan({page, addFinding, exclude}) } } catch (e) { core.error(`Error during accessibility scan: ${e}`) @@ -69,13 +70,18 @@ export async function findForUrl( async function runAxeScan({ page, addFinding, + exclude, }: { page: playwright.Page addFinding: (findingData: Finding, options?: {includeScreenshots?: boolean}) => Promise + exclude?: string[] }) { const url = page.url() core.info(`Scanning ${url}`) - const rawFindings = await new AxeBuilder({page}).analyze() + const axeBuilder = exclude && exclude.length > 0 + ? exclude.reduce((builder, selector) => builder.exclude(selector), new AxeBuilder({page})) + : new AxeBuilder({page}) + const rawFindings = await axeBuilder.analyze() if (rawFindings) { for (const violation of rawFindings.violations) { diff --git a/.github/actions/find/src/index.ts b/.github/actions/find/src/index.ts index e581bcb..0569cf6 100644 --- a/.github/actions/find/src/index.ts +++ b/.github/actions/find/src/index.ts @@ -34,10 +34,20 @@ export default async function () { colorScheme = colorSchemeInput as ColorSchemePreference } + const excludeInput = core.getInput('exclude', {required: false}) + let exclude: string[] | undefined + if (excludeInput) { + try { + exclude = JSON.parse(excludeInput) as string[] + } catch { + throw new Error(`Input 'exclude' must be a valid JSON array of CSS selectors. Received: ${excludeInput}`) + } + } + const findings = [] for (const url of urls) { core.info(`Preparing to scan ${url}`) - const findingsForUrl = await findForUrl(url, authContext, includeScreenshots, reducedMotion, colorScheme) + const findingsForUrl = await findForUrl(url, authContext, includeScreenshots, reducedMotion, colorScheme, exclude) if (findingsForUrl.length === 0) { core.info(`No accessibility gaps were found on ${url}`) continue diff --git a/README.md b/README.md index 10ff503..5b6e2b4 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ jobs: # reduced_motion: no-preference # Optional: Playwright reduced motion configuration option # color_scheme: light # Optional: Playwright color scheme configuration option # scans: '["axe","reflow-scan"]' # Optional: An array of scans (or plugins) to be performed. If not provided, only Axe will be performed. + # exclude: '["iframe","#third-party-widget"]' # Optional: A JSON array of CSS selectors to exclude from the Axe scan. ``` > 👉 Update all `REPLACE_THIS` placeholders with your actual values. See [Action Inputs](#action-inputs) for details. @@ -130,6 +131,7 @@ Trigger the workflow manually or automatically based on your configuration. The | `reduced_motion` | No | Playwright `reducedMotion` setting for scan contexts. Allowed values: `reduce`, `no-preference` | `reduce` | | `color_scheme` | No | Playwright `colorScheme` setting for scan contexts. Allowed values: `light`, `dark`, `no-preference` | `dark` | | `scans` | No | An array of scans (or plugins) to be performed. If not provided, only Axe will be performed. | `'["axe", "reflow-scan", ...other plugins]'` | +| `exclude` | No | A stringified JSON array of CSS selectors to exclude from the Axe scan. Useful for iframes, third-party widgets, or user-generated content. | `'["iframe","#third-party-widget"]'` | --- diff --git a/action.yml b/action.yml index 054d6a4..0facf68 100644 --- a/action.yml +++ b/action.yml @@ -51,6 +51,9 @@ inputs: scans: description: 'Stringified JSON array of scans to perform. If not provided, only Axe will be performed' required: false + exclude: + description: 'Stringified JSON array of CSS selectors to exclude from the Axe scan' + required: false outputs: results: @@ -114,6 +117,7 @@ runs: reduced_motion: ${{ inputs.reduced_motion }} color_scheme: ${{ inputs.color_scheme }} scans: ${{ inputs.scans }} + exclude: ${{ inputs.exclude }} - name: File id: file uses: ./../../_actions/github/accessibility-scanner/current/.github/actions/file From 88d20c3f38ca037ed74b920e15e5199b5cb1a8ed Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 6 May 2026 16:02:52 +0000 Subject: [PATCH 3/5] feat: replace exclude input with urlConfig for per-URL selector exclusion Agent-Logs-Url: https://github.com/github/accessibility-scanner/sessions/3565f54a-5878-479d-8bcd-ef2b85413be6 Co-authored-by: abdulahmad307 <204748719+abdulahmad307@users.noreply.github.com> --- .github/actions/find/action.yml | 8 ++--- .github/actions/find/src/index.ts | 48 ++++++++++++++++++++--------- .github/actions/find/src/types.d.ts | 5 +++ README.md | 6 ++-- action.yml | 10 +++--- 5 files changed, 51 insertions(+), 26 deletions(-) diff --git a/.github/actions/find/action.yml b/.github/actions/find/action.yml index 90fd9f3..5d9ee07 100644 --- a/.github/actions/find/action.yml +++ b/.github/actions/find/action.yml @@ -4,8 +4,11 @@ description: 'Finds potential accessibility gaps.' inputs: urls: description: 'Newline-delimited list of URLs to check for accessibility issues' - required: true + required: false multiline: true + url_config: + description: "Stringified JSON array of URL config objects, each with a 'url' field and an optional 'excludeSelectors' field (array of CSS selectors to exclude from the Axe scan for that URL). When provided, takes precedence over the 'urls' input." + required: false auth_context: description: "Stringified JSON object containing 'username', 'password', 'cookies', and/or 'localStorage' from an authenticated session" required: false @@ -22,9 +25,6 @@ inputs: color_scheme: description: 'Playwright colorScheme setting: https://playwright.dev/docs/api/class-browser#browser-new-context-option-color-scheme' required: false - exclude: - description: 'Stringified JSON array of CSS selectors to exclude from the Axe scan' - required: false outputs: findings_file: diff --git a/.github/actions/find/src/index.ts b/.github/actions/find/src/index.ts index 0569cf6..52b17e3 100644 --- a/.github/actions/find/src/index.ts +++ b/.github/actions/find/src/index.ts @@ -1,4 +1,4 @@ -import type {AuthContextInput, ColorSchemePreference, ReducedMotionPreference} from './types.js' +import type {AuthContextInput, ColorSchemePreference, ReducedMotionPreference, UrlConfig} from './types.js' import fs from 'node:fs' import path from 'node:path' import * as core from '@actions/core' @@ -7,8 +7,37 @@ import {findForUrl} from './findForUrl.js' export default async function () { core.info("Starting 'find' action") - const urls = core.getMultilineInput('urls', {required: true}) - core.debug(`Input: 'urls: ${JSON.stringify(urls)}'`) + const urlConfigInput = core.getInput('url_config', {required: false}) + let urlConfigs: UrlConfig[] | undefined + if (urlConfigInput) { + try { + const parsed = JSON.parse(urlConfigInput) + if (!Array.isArray(parsed)) { + throw new Error("Input 'url_config' must be a JSON array.") + } + for (const item of parsed) { + if (typeof item !== 'object' || item === null || typeof item.url !== 'string') { + throw new Error("Each entry in 'url_config' must be an object with a 'url' string field.") + } + } + urlConfigs = parsed as UrlConfig[] + } catch (e) { + throw new Error(`Invalid 'url_config' input: ${(e as Error).message}`) + } + } + + let urls: string[] + if (urlConfigs) { + core.debug(`Input: 'url_config: ${JSON.stringify(urlConfigs)}'`) + urls = urlConfigs.map(c => c.url) + } else { + urls = core.getMultilineInput('urls', {required: false}) + core.debug(`Input: 'urls: ${JSON.stringify(urls)}'`) + if (urls.length === 0) { + throw new Error("Either 'urls' or 'url_config' input must be provided.") + } + } + const authContextInput: AuthContextInput = JSON.parse(core.getInput('auth_context', {required: false}) || '{}') const authContext = new AuthContext(authContextInput) @@ -34,20 +63,11 @@ export default async function () { colorScheme = colorSchemeInput as ColorSchemePreference } - const excludeInput = core.getInput('exclude', {required: false}) - let exclude: string[] | undefined - if (excludeInput) { - try { - exclude = JSON.parse(excludeInput) as string[] - } catch { - throw new Error(`Input 'exclude' must be a valid JSON array of CSS selectors. Received: ${excludeInput}`) - } - } - const findings = [] for (const url of urls) { core.info(`Preparing to scan ${url}`) - const findingsForUrl = await findForUrl(url, authContext, includeScreenshots, reducedMotion, colorScheme, exclude) + const excludeSelectors = urlConfigs?.find(c => c.url === url)?.excludeSelectors + const findingsForUrl = await findForUrl(url, authContext, includeScreenshots, reducedMotion, colorScheme, excludeSelectors) if (findingsForUrl.length === 0) { core.info(`No accessibility gaps were found on ${url}`) continue diff --git a/.github/actions/find/src/types.d.ts b/.github/actions/find/src/types.d.ts index f8fb720..dcbc860 100644 --- a/.github/actions/find/src/types.d.ts +++ b/.github/actions/find/src/types.d.ts @@ -37,3 +37,8 @@ export type AuthContextInput = { export type ReducedMotionPreference = 'reduce' | 'no-preference' | null export type ColorSchemePreference = 'light' | 'dark' | 'no-preference' | null + +export type UrlConfig = { + url: string + excludeSelectors?: string[] +} diff --git a/README.md b/README.md index 5b6e2b4..775261d 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ jobs: # reduced_motion: no-preference # Optional: Playwright reduced motion configuration option # color_scheme: light # Optional: Playwright color scheme configuration option # scans: '["axe","reflow-scan"]' # Optional: An array of scans (or plugins) to be performed. If not provided, only Axe will be performed. - # exclude: '["iframe","#third-party-widget"]' # Optional: A JSON array of CSS selectors to exclude from the Axe scan. + # url_config: '[{"url":"https://example.com","excludeSelectors":["iframe","#widget"]}]' # Optional: Per-URL config with CSS selectors to exclude from the Axe scan. When provided, takes precedence over 'urls'. ``` > 👉 Update all `REPLACE_THIS` placeholders with your actual values. See [Action Inputs](#action-inputs) for details. @@ -116,7 +116,7 @@ Trigger the workflow manually or automatically based on your configuration. The | Input | Required | Description | Example | | ------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | -| `urls` | Yes | Newline-delimited list of URLs to scan | `https://primer.style`
`https://primer.style/octicons` | +| `urls` | No* | Newline-delimited list of URLs to scan. Required unless `url_config` is provided. | `https://primer.style`
`https://primer.style/octicons` | | `repository` | Yes | Repository (with owner) for issues and PRs | `primer/primer-docs` | | `token` | Yes | PAT with write permissions (see above) | `${{ secrets.GH_TOKEN }}` | | `cache_key` | Yes | Key for caching results across runs
Allowed: `A-Za-z0-9._/-` | `cached_results-primer.style-main.json` | @@ -131,7 +131,7 @@ Trigger the workflow manually or automatically based on your configuration. The | `reduced_motion` | No | Playwright `reducedMotion` setting for scan contexts. Allowed values: `reduce`, `no-preference` | `reduce` | | `color_scheme` | No | Playwright `colorScheme` setting for scan contexts. Allowed values: `light`, `dark`, `no-preference` | `dark` | | `scans` | No | An array of scans (or plugins) to be performed. If not provided, only Axe will be performed. | `'["axe", "reflow-scan", ...other plugins]'` | -| `exclude` | No | A stringified JSON array of CSS selectors to exclude from the Axe scan. Useful for iframes, third-party widgets, or user-generated content. | `'["iframe","#third-party-widget"]'` | +| `url_config` | No | A stringified JSON array of URL config objects. Each object must have a `url` field and may have an optional `excludeSelectors` field (array of CSS selectors to exclude from the Axe scan for that URL). When provided, takes precedence over the `urls` input. | `'[{"url":"https://example.com","excludeSelectors":["iframe","#widget"]}]'` | --- diff --git a/action.yml b/action.yml index 0facf68..3b1fd24 100644 --- a/action.yml +++ b/action.yml @@ -4,8 +4,11 @@ description: 'Finds potential accessibility gaps, files GitHub issues to track t inputs: urls: description: 'Newline-delimited list of URLs to check for accessibility issues' - required: true + required: false multiline: true + url_config: + description: "Stringified JSON array of URL config objects, each with a 'url' field and an optional 'excludeSelectors' field (array of CSS selectors to exclude from the Axe scan for that URL). When provided, takes precedence over the 'urls' input." + required: false repository: description: 'Repository (with owner) to file issues in' required: true @@ -51,9 +54,6 @@ inputs: scans: description: 'Stringified JSON array of scans to perform. If not provided, only Axe will be performed' required: false - exclude: - description: 'Stringified JSON array of CSS selectors to exclude from the Axe scan' - required: false outputs: results: @@ -112,12 +112,12 @@ runs: uses: ./../../_actions/github/accessibility-scanner/current/.github/actions/find with: urls: ${{ inputs.urls }} + url_config: ${{ inputs.url_config }} auth_context: ${{ inputs.auth_context || steps.auth.outputs.auth_context }} include_screenshots: ${{ inputs.include_screenshots }} reduced_motion: ${{ inputs.reduced_motion }} color_scheme: ${{ inputs.color_scheme }} scans: ${{ inputs.scans }} - exclude: ${{ inputs.exclude }} - name: File id: file uses: ./../../_actions/github/accessibility-scanner/current/.github/actions/file From 7ca02011edbee102f2b36d8f4cd32b6af317f1fe Mon Sep 17 00:00:00 2001 From: Abdul Ahmad Date: Wed, 6 May 2026 12:46:24 -0400 Subject: [PATCH 4/5] adjust code - refactor input loading to keep main function scope limited and easier to read - change url_config to url_configs - change some ternaries and conditional logic from copilot to be easier to understand --- .github/actions/find/action.yml | 2 +- .github/actions/find/src/findForUrl.ts | 18 ++-- .github/actions/find/src/index.ts | 125 ++++++++++++++----------- README.md | 38 ++++---- action.yml | 4 +- 5 files changed, 103 insertions(+), 84 deletions(-) diff --git a/.github/actions/find/action.yml b/.github/actions/find/action.yml index 5d9ee07..fb53d90 100644 --- a/.github/actions/find/action.yml +++ b/.github/actions/find/action.yml @@ -6,7 +6,7 @@ inputs: description: 'Newline-delimited list of URLs to check for accessibility issues' required: false multiline: true - url_config: + url_configs: description: "Stringified JSON array of URL config objects, each with a 'url' field and an optional 'excludeSelectors' field (array of CSS selectors to exclude from the Axe scan for that URL). When provided, takes precedence over the 'urls' input." required: false auth_context: diff --git a/.github/actions/find/src/findForUrl.ts b/.github/actions/find/src/findForUrl.ts index 2d9a78d..d9f1ea8 100644 --- a/.github/actions/find/src/findForUrl.ts +++ b/.github/actions/find/src/findForUrl.ts @@ -1,4 +1,4 @@ -import type {ColorSchemePreference, Finding, ReducedMotionPreference} from './types.d.js' +import type {ColorSchemePreference, Finding, ReducedMotionPreference, UrlConfig} from './types.d.js' import {AxeBuilder} from '@axe-core/playwright' import playwright from 'playwright' import {AuthContext} from './AuthContext.js' @@ -8,13 +8,13 @@ import {getScansContext} from './scansContextProvider.js' import * as core from '@actions/core' export async function findForUrl( - url: string, + urlConfig: UrlConfig, authContext?: AuthContext, includeScreenshots: boolean = false, reducedMotion?: ReducedMotionPreference, colorScheme?: ColorSchemePreference, - exclude?: string[], ): Promise { + const {url, excludeSelectors} = urlConfig const browser = await playwright.chromium.launch({ headless: true, executablePath: process.env.CI ? '/usr/bin/google-chrome' : undefined, @@ -57,7 +57,7 @@ export async function findForUrl( } if (scansContext.shouldPerformAxeScan) { - await runAxeScan({page, addFinding, exclude}) + await runAxeScan({page, addFinding, excludeSelectors}) } } catch (e) { core.error(`Error during accessibility scan: ${e}`) @@ -70,17 +70,17 @@ export async function findForUrl( async function runAxeScan({ page, addFinding, - exclude, + excludeSelectors, }: { page: playwright.Page addFinding: (findingData: Finding, options?: {includeScreenshots?: boolean}) => Promise - exclude?: string[] + excludeSelectors?: string[] }) { const url = page.url() core.info(`Scanning ${url}`) - const axeBuilder = exclude && exclude.length > 0 - ? exclude.reduce((builder, selector) => builder.exclude(selector), new AxeBuilder({page})) - : new AxeBuilder({page}) + const axeBuilder = new AxeBuilder({page}) + excludeSelectors?.forEach(selector => axeBuilder.exclude(selector)) + const rawFindings = await axeBuilder.analyze() if (rawFindings) { diff --git a/.github/actions/find/src/index.ts b/.github/actions/find/src/index.ts index 52b17e3..797be16 100644 --- a/.github/actions/find/src/index.ts +++ b/.github/actions/find/src/index.ts @@ -7,67 +7,22 @@ import {findForUrl} from './findForUrl.js' export default async function () { core.info("Starting 'find' action") - const urlConfigInput = core.getInput('url_config', {required: false}) - let urlConfigs: UrlConfig[] | undefined - if (urlConfigInput) { - try { - const parsed = JSON.parse(urlConfigInput) - if (!Array.isArray(parsed)) { - throw new Error("Input 'url_config' must be a JSON array.") - } - for (const item of parsed) { - if (typeof item !== 'object' || item === null || typeof item.url !== 'string') { - throw new Error("Each entry in 'url_config' must be an object with a 'url' string field.") - } - } - urlConfigs = parsed as UrlConfig[] - } catch (e) { - throw new Error(`Invalid 'url_config' input: ${(e as Error).message}`) - } - } + let urlConfigs = loadUrlConfigs() + let urls = loadUrls({urlConfigs}) + let reducedMotion = loadReducedMotion() + let colorScheme = loadColorScheme() - let urls: string[] - if (urlConfigs) { - core.debug(`Input: 'url_config: ${JSON.stringify(urlConfigs)}'`) - urls = urlConfigs.map(c => c.url) - } else { - urls = core.getMultilineInput('urls', {required: false}) - core.debug(`Input: 'urls: ${JSON.stringify(urls)}'`) - if (urls.length === 0) { - throw new Error("Either 'urls' or 'url_config' input must be provided.") - } - } + const actualUrls = urlConfigs || urls || [] const authContextInput: AuthContextInput = JSON.parse(core.getInput('auth_context', {required: false}) || '{}') const authContext = new AuthContext(authContextInput) - const includeScreenshots = core.getInput('include_screenshots', {required: false}) !== 'false' - const reducedMotionInput = core.getInput('reduced_motion', {required: false}) - let reducedMotion: ReducedMotionPreference | undefined - if (reducedMotionInput) { - if (!['reduce', 'no-preference', null].includes(reducedMotionInput)) { - throw new Error( - "Input 'reduced_motion' must be one of: 'reduce', 'no-preference', or null per Playwright documentation.", - ) - } - reducedMotion = reducedMotionInput as ReducedMotionPreference - } - const colorSchemeInput = core.getInput('color_scheme', {required: false}) - let colorScheme: ColorSchemePreference | undefined - if (colorSchemeInput) { - if (!['light', 'dark', 'no-preference', null].includes(colorSchemeInput)) { - throw new Error( - "Input 'color_scheme' must be one of: 'light', 'dark', 'no-preference', or null per Playwright documentation.", - ) - } - colorScheme = colorSchemeInput as ColorSchemePreference - } const findings = [] - for (const url of urls) { + for (const urlConfig of actualUrls) { + const {url} = urlConfig core.info(`Preparing to scan ${url}`) - const excludeSelectors = urlConfigs?.find(c => c.url === url)?.excludeSelectors - const findingsForUrl = await findForUrl(url, authContext, includeScreenshots, reducedMotion, colorScheme, excludeSelectors) + const findingsForUrl = await findForUrl(urlConfig, authContext, includeScreenshots, reducedMotion, colorScheme) if (findingsForUrl.length === 0) { core.info(`No accessibility gaps were found on ${url}`) continue @@ -84,3 +39,67 @@ export default async function () { core.info(`Found ${findings.length} findings in total`) core.info("Finished 'find' action") } + +function loadUrlConfigs() { + const urlConfigInput = core.getInput('url_configs', {required: false}) + + if (!urlConfigInput) return + + try { + const parsed = JSON.parse(urlConfigInput) + + if (!Array.isArray(parsed)) { + throw new Error("Input 'url_configs' must be a JSON array.") + } + + for (const item of parsed) { + if (typeof item !== 'object' || item === null || typeof item.url !== 'string') { + throw new Error("Each entry in 'url_configs' must be an object with a 'url' string field.") + } + } + + return parsed as UrlConfig[] + } catch (e) { + throw new Error(`Invalid 'url_configs' input: ${(e as Error).message}`) + } +} + +function loadUrls({urlConfigs}: {urlConfigs?: UrlConfig[]} = {}) { + // - no need to process this input if url_configs is provided + if (urlConfigs) return + + let urls: string[] + urls = core.getMultilineInput('urls', {required: false}) + core.debug(`Input: 'urls: ${JSON.stringify(urls)}'`) + + if (urls.length === 0) { + throw new Error("Either 'urls' or 'url_configs' input must be provided.") + } + + return urls.map(url => ({url})) as UrlConfig[] +} + +function loadReducedMotion() { + const reducedMotionInput = core.getInput('reduced_motion', {required: false}) + if (!reducedMotionInput) return + + if (!['reduce', 'no-preference', null].includes(reducedMotionInput)) { + throw new Error( + "Input 'reduced_motion' must be one of: 'reduce', 'no-preference', or null per Playwright documentation.", + ) + } + return reducedMotionInput as ReducedMotionPreference +} + +function loadColorScheme() { + const colorSchemeInput = core.getInput('color_scheme', {required: false}) + if (!colorSchemeInput) return + + if (!['light', 'dark', 'no-preference', null].includes(colorSchemeInput)) { + throw new Error( + "Input 'color_scheme' must be one of: 'light', 'dark', 'no-preference', or null per Playwright documentation.", + ) + } + + return colorSchemeInput as ColorSchemePreference +} diff --git a/README.md b/README.md index 775261d..88b68c1 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ jobs: # reduced_motion: no-preference # Optional: Playwright reduced motion configuration option # color_scheme: light # Optional: Playwright color scheme configuration option # scans: '["axe","reflow-scan"]' # Optional: An array of scans (or plugins) to be performed. If not provided, only Axe will be performed. - # url_config: '[{"url":"https://example.com","excludeSelectors":["iframe","#widget"]}]' # Optional: Per-URL config with CSS selectors to exclude from the Axe scan. When provided, takes precedence over 'urls'. + # url_configs: '[{"url":"https://example.com","excludeSelectors":["iframe","#widget"]}]' # Optional: Per-URL config with CSS selectors to exclude from the Axe scan. When provided, takes precedence over 'urls'. ``` > 👉 Update all `REPLACE_THIS` placeholders with your actual values. See [Action Inputs](#action-inputs) for details. @@ -114,24 +114,24 @@ Trigger the workflow manually or automatically based on your configuration. The ## Action inputs -| Input | Required | Description | Example | -| ------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | -| `urls` | No* | Newline-delimited list of URLs to scan. Required unless `url_config` is provided. | `https://primer.style`
`https://primer.style/octicons` | -| `repository` | Yes | Repository (with owner) for issues and PRs | `primer/primer-docs` | -| `token` | Yes | PAT with write permissions (see above) | `${{ secrets.GH_TOKEN }}` | -| `cache_key` | Yes | Key for caching results across runs
Allowed: `A-Za-z0-9._/-` | `cached_results-primer.style-main.json` | -| `base_url` | No | GitHub API base URL used by Octokit. Set this for GitHub Enterprise Server (format: `https://HOSTNAME/api/v3`). Defaults to `https://api.github.com` | `https://ghe.example.com/api/v3` | -| `login_url` | No | If scanned pages require authentication, the URL of the login page | `https://github.com/login` | -| `username` | No | If scanned pages require authentication, the username to use for login | `some-user` | -| `password` | No | If scanned pages require authentication, the password to use for login | `${{ secrets.PASSWORD }}` | -| `auth_context` | No | If scanned pages require authentication, a stringified JSON object containing username, password, cookies, and/or localStorage from an authenticated session | `{"username":"some-user","password":"***","cookies":[...]}` | -| `skip_copilot_assignment` | No | Whether to skip assigning filed issues to GitHub Copilot. Set to `true` if you don't have GitHub Copilot or prefer to handle issues manually | `true` | -| `include_screenshots` | No | Whether to capture screenshots of scanned pages and include links to them in filed issues. Screenshots are stored on the `gh-cache` branch of the repository running the workflow. Default: `false` | `true` | -| `open_grouped_issues` | No | Whether to create a tracking issue which groups filed issues together by violation type. Default: `false` | `true` | -| `reduced_motion` | No | Playwright `reducedMotion` setting for scan contexts. Allowed values: `reduce`, `no-preference` | `reduce` | -| `color_scheme` | No | Playwright `colorScheme` setting for scan contexts. Allowed values: `light`, `dark`, `no-preference` | `dark` | -| `scans` | No | An array of scans (or plugins) to be performed. If not provided, only Axe will be performed. | `'["axe", "reflow-scan", ...other plugins]'` | -| `url_config` | No | A stringified JSON array of URL config objects. Each object must have a `url` field and may have an optional `excludeSelectors` field (array of CSS selectors to exclude from the Axe scan for that URL). When provided, takes precedence over the `urls` input. | `'[{"url":"https://example.com","excludeSelectors":["iframe","#widget"]}]'` | +| Input | Required | Description | Example | +| ------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | +| `urls` | No\* | Newline-delimited list of URLs to scan. Required unless `url_configs` is provided. | `https://primer.style`
`https://primer.style/octicons` | +| `repository` | Yes | Repository (with owner) for issues and PRs | `primer/primer-docs` | +| `token` | Yes | PAT with write permissions (see above) | `${{ secrets.GH_TOKEN }}` | +| `cache_key` | Yes | Key for caching results across runs
Allowed: `A-Za-z0-9._/-` | `cached_results-primer.style-main.json` | +| `base_url` | No | GitHub API base URL used by Octokit. Set this for GitHub Enterprise Server (format: `https://HOSTNAME/api/v3`). Defaults to `https://api.github.com` | `https://ghe.example.com/api/v3` | +| `login_url` | No | If scanned pages require authentication, the URL of the login page | `https://github.com/login` | +| `username` | No | If scanned pages require authentication, the username to use for login | `some-user` | +| `password` | No | If scanned pages require authentication, the password to use for login | `${{ secrets.PASSWORD }}` | +| `auth_context` | No | If scanned pages require authentication, a stringified JSON object containing username, password, cookies, and/or localStorage from an authenticated session | `{"username":"some-user","password":"***","cookies":[...]}` | +| `skip_copilot_assignment` | No | Whether to skip assigning filed issues to GitHub Copilot. Set to `true` if you don't have GitHub Copilot or prefer to handle issues manually | `true` | +| `include_screenshots` | No | Whether to capture screenshots of scanned pages and include links to them in filed issues. Screenshots are stored on the `gh-cache` branch of the repository running the workflow. Default: `false` | `true` | +| `open_grouped_issues` | No | Whether to create a tracking issue which groups filed issues together by violation type. Default: `false` | `true` | +| `reduced_motion` | No | Playwright `reducedMotion` setting for scan contexts. Allowed values: `reduce`, `no-preference` | `reduce` | +| `color_scheme` | No | Playwright `colorScheme` setting for scan contexts. Allowed values: `light`, `dark`, `no-preference` | `dark` | +| `scans` | No | An array of scans (or plugins) to be performed. If not provided, only Axe will be performed. | `'["axe", "reflow-scan", ...other plugins]'` | +| `url_configs` | No | A stringified JSON array of URL config objects. Each object must have a `url` field and may have an optional `excludeSelectors` field (array of CSS selectors to exclude from the Axe scan for that URL). When provided, takes precedence over the `urls` input. | `'[{"url":"https://example.com","excludeSelectors":["iframe","#widget"]}]'` | --- diff --git a/action.yml b/action.yml index 3b1fd24..b86a45e 100644 --- a/action.yml +++ b/action.yml @@ -6,7 +6,7 @@ inputs: description: 'Newline-delimited list of URLs to check for accessibility issues' required: false multiline: true - url_config: + url_configs: description: "Stringified JSON array of URL config objects, each with a 'url' field and an optional 'excludeSelectors' field (array of CSS selectors to exclude from the Axe scan for that URL). When provided, takes precedence over the 'urls' input." required: false repository: @@ -112,7 +112,7 @@ runs: uses: ./../../_actions/github/accessibility-scanner/current/.github/actions/find with: urls: ${{ inputs.urls }} - url_config: ${{ inputs.url_config }} + url_configs: ${{ inputs.url_configs }} auth_context: ${{ inputs.auth_context || steps.auth.outputs.auth_context }} include_screenshots: ${{ inputs.include_screenshots }} reduced_motion: ${{ inputs.reduced_motion }} From 95a7f8b4ed68bcb8534daf6711fbd1a90d3c6aea Mon Sep 17 00:00:00 2001 From: Abdul Ahmad Date: Wed, 6 May 2026 12:51:17 -0400 Subject: [PATCH 5/5] fix linting --- .github/actions/find/src/index.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/actions/find/src/index.ts b/.github/actions/find/src/index.ts index 797be16..675dff6 100644 --- a/.github/actions/find/src/index.ts +++ b/.github/actions/find/src/index.ts @@ -7,10 +7,10 @@ import {findForUrl} from './findForUrl.js' export default async function () { core.info("Starting 'find' action") - let urlConfigs = loadUrlConfigs() - let urls = loadUrls({urlConfigs}) - let reducedMotion = loadReducedMotion() - let colorScheme = loadColorScheme() + const urlConfigs = loadUrlConfigs() + const urls = loadUrls({urlConfigs}) + const reducedMotion = loadReducedMotion() + const colorScheme = loadColorScheme() const actualUrls = urlConfigs || urls || [] @@ -42,7 +42,6 @@ export default async function () { function loadUrlConfigs() { const urlConfigInput = core.getInput('url_configs', {required: false}) - if (!urlConfigInput) return try { @@ -68,8 +67,7 @@ function loadUrls({urlConfigs}: {urlConfigs?: UrlConfig[]} = {}) { // - no need to process this input if url_configs is provided if (urlConfigs) return - let urls: string[] - urls = core.getMultilineInput('urls', {required: false}) + const urls: string[] = core.getMultilineInput('urls', {required: false}) core.debug(`Input: 'urls: ${JSON.stringify(urls)}'`) if (urls.length === 0) {