* fix(website): remediate WCAG accessibility issues and add axe regression guardrail
Fixes accessibility violations found by an axe-core sweep of every website
page in both light and dark themes:
- aria-allowed-role (WCAG 1.3.1, 4.1.2): the shared resource card rendered
an <article> with role="listitem", which is not an allowed role for that
element. Switched the wrapper to a <div role="listitem"> so the listitem
role is valid (affected every card, e.g. #arcade-canvas on /extensions/).
- aria-required-children (WCAG 1.3.1): removed role="list" from the tools,
contributors, and cookbook containers whose children are not list items.
- nested-interactive (WCAG 4.1.2): removed tabIndex=0 from extension cards
and rendered the author as a non-interactive span so no interactive
control is nested inside another (the author link remains in the modal).
- color-contrast (WCAG 1.4.3): gave .btn-primary explicit white text with an
AA-compliant hover (#7326d6), and bumped the dark-theme secondary text gray
(--sl-color-gray-3) to #84849c (5.32:1) so ToC / meta / footer text passes.
Adds a checked-in regression guardrail:
- website/scripts/a11y-audit.mjs runs axe-core over all routes in both themes
against the production build and fails on critical/serious violations only
(moderate/minor are reported but non-blocking). Transitions/animations are
disabled before sampling so axe measures settled, steady-state colors
instead of mid-theme-transition frames.
- Adds npm scripts (website:a11y at the root, a11y in website/) and README
docs. The matching Build Website CI step is proposed in the PR description
(omitted from this commit because the authoring token lacks workflow scope).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* fix(website): harden a11y audit per PR review
- Fail fast when a route navigation returns a non-2xx response, so the
guardrail can't silently pass against a broken/missing route (page.goto
resolves even for 4xx/5xx).
- Launch the Astro preview server via `node <astro-bin>` instead of
`spawn(..., { shell: true })`. Removing the shell layer keeps signal
delivery / detached-PGID shutdown predictable; resolving Astro's bin and
running it with process.execPath also avoids the EINVAL that modern Node
raises when spawning the npx.cmd shim without a shell on Windows.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: David Pine <7679720+IEvangelist@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Add canvas schema and extension submission checks
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* fix: use namespace import for js-yaml
Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com>
* Fix contributors page build markup
Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com>
* Address PR feedback on canvas schema validation
- Add ajv-cli@5 as a pinned devDependency; install via npm ci in CI instead of npx --yes
- Fix screenshot path regex to prevent .. traversal segments
- Validate canvas.schema.json is parseable JSON even on schema-only PRs
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Harden canvas extension workflow against injection attacks
Switch from newline to null-terminated git diff output (git diff -z) so filenames
containing newlines are read atomically, matching the existing skill-check.yml pattern.
Add an allowlist regex guard on the extracted extension directory name immediately after
it is parsed from git diff output. Any name not matching ^[a-z0-9][a-z0-9-]*$ (e.g.
names containing dollar signs, parentheses, spaces, or other shell metacharacters) is
silently skipped before being used anywhere in the script.
Add a matching allowlist guard on each screenshot path extracted from canvas.json before
the file-existence check, so a crafted manifest cannot supply a path with shell
metacharacters or traversal segments even after the schema check passes.
Follows the same defence-in-depth pattern introduced after the injection PoCs in #1236
and #1240.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Replace ajv-cli with in-repo schema validator
- Remove ajv-cli to avoid vulnerable/deprecated transitive dependencies
- Add eng/validate-json-schema.mjs using ajv + ajv-formats
- Update validate-canvas-extensions workflow to use local script
- Use npm ci --ignore-scripts in PR validation job
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Switch skill CI checks to vally lint
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Adding Vally to allowed words
* case sensitivity
* Migrate external plugin quality gates from skill-validator to vally lint
Replace the downloaded skill-validator binary with
px @microsoft/vally-cli lint
in the external plugin quality gates pipeline:
- Remove downloadSkillValidator() and SKILL_VALIDATOR_ARCHIVE_URL constant
- Replace uildSkillValidatorArgs() +
unSkillValidatorGate() with
uildVallyLintArgs() +
unVallyLintGate() that run
px vally-cli lint
per resolved skill directory (falling back to the full plugin root when no
specific skill paths can be resolved from plugin.json)
- Rename result keys skill_validator_status / skill_validator_output
to ally_lint_status / ally_lint_output throughout both
ng/external-plugin-quality-gates.mjs and ng/external-plugin-intake.mjs
- Update PR comment markdown to show 'vally lint' instead of 'skill-validator'
- Update CONTRIBUTING.md prose references accordingly
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Use @microsoft/vally library directly instead of vally-cli subprocess
Replace the npx-spawned vally-cli process with a direct call to the
@microsoft/vally core library in the external plugin quality gates scripts:
- Add @microsoft/vally as a devDependency in package.json
- Import runLint and LintConsoleReporter from @microsoft/vally
- Replace runVallyLintGate() process spawn with async API call:
- runLint({ rootPath }) returns structured LintResults
- LintConsoleReporter with a Writable capture stream collects
text output without printing to stdout
- Make runExternalPluginQualityGates() async (propagated to
runExternalPluginPrQualityGates() and both main entry points)
- Use Promise.all in runExternalPluginPrQualityGates() for parallel
plugin checks
- Fix remaining skill_validator_status reference in pr-quality-gates
summary string (now vally-lint=...) and YAML workflow table header
- Add 'npm install @microsoft/vally' step to both calling workflows
This removes a layer of indirection (Node -> npx -> CLI -> library)
and replaces it with a direct in-process library call, which is faster,
more reliable, and gives structured access to lint results.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds eng/clean-materialized-plugins.mjs which removes agents/, commands/,
and skills/ subdirectories from plugin folders. These are generated by CI
via eng/materialize-plugins.mjs during publish and should not be tracked on
the staged branch.
Runnable via: npm run plugin:clean
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Removed re-added collections/ path triggers from CI
- Merged plugin checklist improvements from both branches
- Kept plugin:generate-marketplace script from main
- Removed new ospo-sponsorship collection file (plugin already exists)
- Dropped obsolete plugin:migrate and plugin:refresh scripts
Replace Collections with Plugins as first-class citizens in the repo.
With the Copilot CLI v0.409 release making plugins an on-by-default
marketplace, collections are redundant overhead.
## What changed
### Plugin Infrastructure
- Created eng/validate-plugins.mjs (replaces validate-collections.mjs)
- Created eng/create-plugin.mjs (replaces create-collection.mjs)
- Enhanced all 42 plugin.json files with tags, featured, display, and
items metadata from their corresponding collection.yml files
### Build & Website
- Updated eng/update-readme.mjs to generate plugin docs
- Updated eng/generate-website-data.mjs to emit plugins.json with full
items array for modal rendering
- Renamed website collections page to plugins (/plugins/)
- Fixed plugin modal to use <div> instead of <pre> for proper styling
- Updated README.md featured section from Collections to Plugins
### Documentation & CI
- Updated CONTRIBUTING.md, AGENTS.md, copilot-instructions.md, PR template
- Updated CI workflows to validate plugins instead of collections
- Replaced docs/README.collections.md with docs/README.plugins.md
### Cleanup
- Removed eng/validate-collections.mjs, eng/create-collection.mjs,
eng/collection-to-plugin.mjs
- Removed entire collections/ directory (41 .collection.yml + .md files)
- Removed parseCollectionYaml from yaml-parser.mjs
- Removed COLLECTIONS_DIR from constants.mjs
Closes#711
- Remove old website:build-old and website:serve-old scripts
- Rename website:build-data to website:data
- Update paths from website-astro to website
- Simplify website:dev and website:build scripts
- Replace all inline scripts with TypeScript modules
- Create page-specific modules for agents, prompts, instructions, skills, collections, index
- Create core modules: utils.ts, search.ts, modal.ts, choices.ts, jszip.ts, theme.ts
- Remove window global exports, use proper ES module imports
- Add type interfaces for all data structures
- Use data-base-path attribute on body for base URL handling
- Bundle Choices.js and JSZip via npm instead of CDN
- Astro pages now just have single script import each
* Convert build scripts from CommonJS to ES Modules
- Convert all eng/*.js files to ES Modules (.mjs)
- Update package.json scripts to reference .mjs files
- Fix ERR_REQUIRE_ESM error with vfile v6.0.3
- Add __dirname polyfills for ES Modules
* completing the migration of all files to es modules
---------
Co-authored-by: Lyubomir Filipov <lyubomir.filipov@jakala.com>
Co-authored-by: Aaron Powell <me@aaron-powell.com>
* initial prototype of partners collection with featured collection support
* Starting to add the partners
* Preparing the repo for how the custom agents will work
* moving some files around
* Moving a bunch of stuff around to make the file easier to read
* improving the front matter parsing by using a real library
* Some verbage updates
* some more verbage
* Fixing spelling mistake
* tweaking badges
* Updating contributing guide to be correct
* updating casing to match product
* More agents
* Better handling link to mcp registry
* links to install mcp servers fixed up
* Updating collection tags
* writing the mcp registry url out properly
* Adding custom agents for C# and WinForms
Expert custom agents to improve your experience when working with C# and WinForms in Copilot
* Adding to agents readme
* Adding PagerDuty agent
* Fixing description for terraform agent
* Adding custom agents to the README usage
* Removing the button to make the links more obvious
* docs: relocate category READMEs to /docs and update generation + internal links
* Updating prompts for new path
* formatting
---------
Co-authored-by: Chris Patterson <chrispat@github.com>