mirror of
https://github.com/github/awesome-copilot.git
synced 2026-07-14 01:51:02 +00:00
Add canvas schema validation to extension submission workflow (#2161)
* 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>
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Canvas Extension Manifest",
|
||||
"description": "Schema for extensions/<name>/canvas.json files",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"id",
|
||||
"name",
|
||||
"description",
|
||||
"version",
|
||||
"keywords",
|
||||
"screenshots"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"description": "Unique identifier for the canvas extension",
|
||||
"pattern": "^[a-z0-9-]+$",
|
||||
"minLength": 1,
|
||||
"maxLength": 100
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Display name for the extension",
|
||||
"minLength": 1,
|
||||
"maxLength": 100
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Human-friendly description of what the extension does",
|
||||
"minLength": 1,
|
||||
"maxLength": 500
|
||||
},
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "Semantic version of the extension metadata",
|
||||
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$"
|
||||
},
|
||||
"author": {
|
||||
"type": "object",
|
||||
"description": "Optional author metadata",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 100
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"maxLength": 2048
|
||||
}
|
||||
}
|
||||
},
|
||||
"keywords": {
|
||||
"type": "array",
|
||||
"description": "Keywords used for search and filtering",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9-]+$",
|
||||
"minLength": 1,
|
||||
"maxLength": 50
|
||||
},
|
||||
"minItems": 1,
|
||||
"maxItems": 20,
|
||||
"uniqueItems": true
|
||||
},
|
||||
"screenshots": {
|
||||
"type": "object",
|
||||
"description": "Screenshot metadata for icon and gallery cards",
|
||||
"required": [
|
||||
"icon",
|
||||
"gallery"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"icon": {
|
||||
"$ref": "#/definitions/screenshot"
|
||||
},
|
||||
"gallery": {
|
||||
"$ref": "#/definitions/screenshot"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"screenshot": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"path",
|
||||
"type"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "Path relative to the extension root",
|
||||
"pattern": "^assets/(?:[A-Za-z0-9_-]+/)*[A-Za-z0-9_-]+(?:\\.[A-Za-z0-9_-]+)*\\.(png|jpg|jpeg|gif|webp|svg)$",
|
||||
"minLength": 1,
|
||||
"maxLength": 200
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "MIME type for the referenced image",
|
||||
"enum": [
|
||||
"image/png",
|
||||
"image/jpeg",
|
||||
"image/gif",
|
||||
"image/webp",
|
||||
"image/svg+xml"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user