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:
@@ -11,6 +11,8 @@ on:
|
|||||||
- instructions
|
- instructions
|
||||||
- hooks
|
- hooks
|
||||||
- workflows
|
- workflows
|
||||||
|
- extensions
|
||||||
|
- .schemas/canvas.schema.json
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
@@ -6,130 +6,133 @@ on:
|
|||||||
types: [opened, synchronize, reopened]
|
types: [opened, synchronize, reopened]
|
||||||
paths:
|
paths:
|
||||||
- "extensions/**"
|
- "extensions/**"
|
||||||
|
- ".schemas/canvas.schema.json"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
validate:
|
validate:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout
|
||||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Validate changed canvas extensions
|
- name: Setup Node.js
|
||||||
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||||
with:
|
with:
|
||||||
script: |
|
node-version: "22"
|
||||||
const fs = require('fs');
|
cache: "npm"
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
// Collect changed extension directories from the PR diff
|
- name: Install dependencies
|
||||||
const { execSync } = require('child_process');
|
run: npm ci --ignore-scripts
|
||||||
const changedFiles = execSync(
|
|
||||||
`git diff --name-only origin/${{ github.base_ref }}...HEAD`
|
|
||||||
).toString().trim().split('\n').filter(Boolean);
|
|
||||||
|
|
||||||
const EXTENSIONS_DIR = 'extensions';
|
- name: Validate changed canvas extensions
|
||||||
const EXTERNAL_ASSETS_DIR = 'external-assets';
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
const changedExtDirs = new Set();
|
# Validate schema structure once, even for schema-only PRs.
|
||||||
for (const file of changedFiles) {
|
if ! node ./eng/validate-json-schema.mjs --schema .schemas/canvas.schema.json; then
|
||||||
const parts = file.split('/');
|
echo "❌ .schemas/canvas.schema.json failed schema compilation"
|
||||||
if (parts[0] === EXTENSIONS_DIR && parts.length >= 2) {
|
exit 1
|
||||||
const extName = parts[1];
|
fi
|
||||||
// Skip the external-assets directory — it's not a canvas extension
|
|
||||||
// Also skip external.json and other files at extensions root level
|
|
||||||
if (extName !== EXTERNAL_ASSETS_DIR && !extName.includes('.')) {
|
|
||||||
changedExtDirs.add(path.join(EXTENSIONS_DIR, extName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changedExtDirs.size === 0) {
|
# Collect changed extension directories.
|
||||||
console.log('No canvas extension directories changed — skipping validation.');
|
# Use null-terminated (-z) output from git diff so filenames containing newlines
|
||||||
return;
|
# or other special characters are read atomically (matches the pattern in skill-check.yml).
|
||||||
}
|
# Each extracted name is then validated against a strict allowlist regex before use,
|
||||||
|
# rejecting anything containing shell metacharacters ($, (, ), spaces, etc.).
|
||||||
|
declare -A seen_dirs=()
|
||||||
|
changed_extensions=()
|
||||||
|
errors=()
|
||||||
|
|
||||||
console.log(`Validating ${changedExtDirs.size} extension(s): ${[...changedExtDirs].join(', ')}`);
|
while IFS= read -r -d '' file; do
|
||||||
|
case "$file" in
|
||||||
|
extensions/*)
|
||||||
|
ext_name="${file#extensions/}"
|
||||||
|
ext_name="${ext_name%%/*}"
|
||||||
|
|
||||||
const errors = [];
|
if [ "$ext_name" = "external-assets" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
for (const extDir of changedExtDirs) {
|
# Allowlist: extension directory names must be lowercase alphanumeric + hyphens only.
|
||||||
if (!fs.existsSync(extDir)) {
|
# Fail for disallowed names so a PR cannot bypass validation by using a nonconforming folder.
|
||||||
// Directory was deleted — skip
|
if [[ ! "$ext_name" =~ ^[a-z0-9][a-z0-9-]*$ ]]; then
|
||||||
console.log(`${extDir} no longer exists (deleted?), skipping.`);
|
errors+=("\`extensions/$ext_name\`: invalid extension directory name (must match ^[a-z0-9][a-z0-9-]*$).")
|
||||||
continue;
|
continue
|
||||||
}
|
fi
|
||||||
|
|
||||||
const extName = path.basename(extDir);
|
if [ -z "${seen_dirs[$ext_name]+x}" ]; then
|
||||||
|
seen_dirs["$ext_name"]=1
|
||||||
|
changed_extensions+=("extensions/$ext_name")
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done < <(git diff --name-only -z "origin/${{ github.base_ref }}...HEAD")
|
||||||
|
|
||||||
// Rule 1: must contain extension.mjs
|
if [ "${#changed_extensions[@]}" -eq 0 ]; then
|
||||||
const mainFile = path.join(extDir, 'extension.mjs');
|
if [ "${#errors[@]}" -ne 0 ]; then
|
||||||
if (!fs.existsSync(mainFile)) {
|
echo "❌ Canvas extension validation failed:"
|
||||||
errors.push(
|
for error in "${errors[@]}"; do
|
||||||
`**\`${extDir}\`**: missing required \`extension.mjs\`. ` +
|
echo "- $error"
|
||||||
`Canvas extensions must have their entry point named \`extension.mjs\`.`
|
done
|
||||||
);
|
exit 1
|
||||||
}
|
fi
|
||||||
|
echo "No canvas extension directories changed — skipping validation."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
// Rule 2: must contain assets/preview.png
|
echo "Validating ${#changed_extensions[@]} extension(s): ${changed_extensions[*]}"
|
||||||
const previewFile = path.join(extDir, 'assets', 'preview.png');
|
|
||||||
if (!fs.existsSync(previewFile)) {
|
|
||||||
errors.push(
|
|
||||||
`**\`${extDir}\`**: missing required \`assets/preview.png\`. ` +
|
|
||||||
`Canvas extensions must include a screenshot at \`assets/preview.png\` ` +
|
|
||||||
`so reviewers and users can preview the extension before installing it.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errors.length === 0) {
|
for ext_dir in "${changed_extensions[@]}"; do
|
||||||
console.log('✅ All changed canvas extensions pass validation.');
|
if [ ! -d "$ext_dir" ]; then
|
||||||
return;
|
echo "$ext_dir no longer exists (deleted?), skipping."
|
||||||
}
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
const isFork = context.payload.pull_request.head.repo.fork;
|
if [ ! -f "$ext_dir/extension.mjs" ]; then
|
||||||
const body = [
|
errors+=("\`$ext_dir\`: missing required \`extension.mjs\`.")
|
||||||
'❌ **Canvas extension validation failed**',
|
fi
|
||||||
'',
|
|
||||||
'The following issue(s) were found in changed canvas extension(s):',
|
|
||||||
'',
|
|
||||||
...errors.map(e => `- ${e}`),
|
|
||||||
'',
|
|
||||||
'---',
|
|
||||||
'',
|
|
||||||
'### Required structure for canvas extensions',
|
|
||||||
'',
|
|
||||||
'Each extension folder under `extensions/` must contain:',
|
|
||||||
'',
|
|
||||||
'| Path | Required | Description |',
|
|
||||||
'|------|----------|-------------|',
|
|
||||||
'| `extension.mjs` | ✅ | Entry point for the canvas extension |',
|
|
||||||
'| `assets/preview.png` | ✅ | Screenshot shown on the website and in the marketplace |',
|
|
||||||
'',
|
|
||||||
'Please add the missing file(s) and push an update to this PR.',
|
|
||||||
].join('\n');
|
|
||||||
|
|
||||||
if (!isFork) {
|
if [ ! -f "$ext_dir/canvas.json" ]; then
|
||||||
try {
|
errors+=("\`$ext_dir\`: missing required \`canvas.json\`.")
|
||||||
await github.rest.pulls.createReview({
|
continue
|
||||||
owner: context.repo.owner,
|
fi
|
||||||
repo: context.repo.repo,
|
|
||||||
pull_number: context.issue.number,
|
|
||||||
event: 'REQUEST_CHANGES',
|
|
||||||
body
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
core.warning(`Could not post PR review: ${error.message}`);
|
|
||||||
core.warning(body);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
core.warning('PR is from a fork — skipping createReview to avoid permission errors.');
|
|
||||||
core.warning(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
core.setFailed(`Canvas extension validation failed with ${errors.length} error(s).`);
|
if [ ! -f "$ext_dir/assets/preview.png" ]; then
|
||||||
|
errors+=("\`$ext_dir\`: missing required \`assets/preview.png\`.")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! schema_output="$(node ./eng/validate-json-schema.mjs --schema .schemas/canvas.schema.json --data "$ext_dir/canvas.json" 2>&1)"; then
|
||||||
|
condensed_output="$(echo "$schema_output" | tr '\n' ' ' | sed 's/[[:space:]]\+/ /g')"
|
||||||
|
errors+=("\`$ext_dir/canvas.json\`: schema validation failed against \`.schemas/canvas.schema.json\` ($condensed_output).")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
mapfile -t screenshot_paths < <(
|
||||||
|
node -e 'const fs = require("fs"); const manifest = JSON.parse(fs.readFileSync(process.argv[1], "utf8")); const paths = [manifest?.screenshots?.icon?.path, manifest?.screenshots?.gallery?.path].filter((value) => typeof value === "string" && value.trim().length > 0); for (const value of [...new Set(paths)]) { console.log(value); }' "$ext_dir/canvas.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
for screenshot_path in "${screenshot_paths[@]}"; do
|
||||||
|
if [[ ! "$screenshot_path" =~ ^assets/([A-Za-z0-9_-]+/)*[A-Za-z0-9_-]+(\.[A-Za-z0-9_-]+)*\.(png|jpe?g|gif|webp|svg)$ ]]; then
|
||||||
|
errors+=("\`$ext_dir/canvas.json\`: screenshot path \`$screenshot_path\` is not a valid assets path.")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ ! -f "$ext_dir/$screenshot_path" ]; then
|
||||||
|
errors+=("\`$ext_dir/canvas.json\`: screenshot path \`$screenshot_path\` does not exist in the extension directory.")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "${#errors[@]}" -ne 0 ]; then
|
||||||
|
echo "❌ Canvas extension validation failed:"
|
||||||
|
for error in "${errors[@]}"; do
|
||||||
|
echo "- $error"
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ All changed canvas extensions passed validation."
|
||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import fs from "fs";
|
||||||
|
import path from "path";
|
||||||
|
import Ajv from "ajv";
|
||||||
|
import addFormats from "ajv-formats";
|
||||||
|
|
||||||
|
function parseArgs(argv) {
|
||||||
|
const args = { schema: null, data: null };
|
||||||
|
for (let i = 2; i < argv.length; i += 1) {
|
||||||
|
const arg = argv[i];
|
||||||
|
if (arg === "--schema") {
|
||||||
|
args.schema = argv[i + 1] || null;
|
||||||
|
i += 1;
|
||||||
|
} else if (arg === "--data") {
|
||||||
|
args.data = argv[i + 1] || null;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readJson(filePath) {
|
||||||
|
const content = fs.readFileSync(filePath, "utf8");
|
||||||
|
return JSON.parse(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
const args = parseArgs(process.argv);
|
||||||
|
if (!args.schema) {
|
||||||
|
console.error("Missing required argument: --schema <path>");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const schemaPath = path.resolve(process.cwd(), args.schema);
|
||||||
|
let schema;
|
||||||
|
try {
|
||||||
|
schema = readJson(schemaPath);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Invalid schema JSON at ${args.schema}: ${error.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ajv = new Ajv({ strict: false, allErrors: true });
|
||||||
|
addFormats(ajv);
|
||||||
|
|
||||||
|
let validate;
|
||||||
|
try {
|
||||||
|
validate = ajv.compile(schema);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Invalid schema at ${args.schema}: ${error.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args.data) {
|
||||||
|
console.log(`Schema is valid: ${args.schema}`);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataPath = path.resolve(process.cwd(), args.data);
|
||||||
|
let data;
|
||||||
|
try {
|
||||||
|
data = readJson(dataPath);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Invalid data JSON at ${args.data}: ${error.message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const valid = validate(data);
|
||||||
|
if (!valid) {
|
||||||
|
const message = ajv.errorsText(validate.errors, { separator: "; " });
|
||||||
|
console.error(`Schema validation failed for ${args.data}: ${message}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Schema validation passed: ${args.data}`);
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
// YAML parser for frontmatter parsing using vfile-matter
|
// YAML parser for frontmatter parsing using vfile-matter
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import yaml from "js-yaml";
|
import * as yaml from "js-yaml";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { VFile } from "vfile";
|
import { VFile } from "vfile";
|
||||||
import { matter } from "vfile-matter";
|
import { matter } from "vfile-matter";
|
||||||
|
|||||||
Generated
+120
-42
@@ -15,6 +15,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@microsoft/vally": "^0.6.0",
|
"@microsoft/vally": "^0.6.0",
|
||||||
|
"ajv": "^8.20.0",
|
||||||
|
"ajv-formats": "^3.0.1",
|
||||||
"all-contributors-cli": "^6.26.1"
|
"all-contributors-cli": "^6.26.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -29,9 +31,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@github/copilot": {
|
"node_modules/@github/copilot": {
|
||||||
"version": "1.0.64-3",
|
"version": "1.0.67",
|
||||||
"resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.64-3.tgz",
|
"resolved": "https://registry.npmjs.org/@github/copilot/-/copilot-1.0.67.tgz",
|
||||||
"integrity": "sha512-Q9nBMYEHX1bJLXzzJocQx2nZvORJ0E9gvK6ly/FCtmtA7ad96BWZvf4EHzkCNDsn56aI3zNaUSfKHUKcmIAzSg==",
|
"integrity": "sha512-5YEY9LNXBT9Q8uShjCdYcornJJJhGtdIzSYla2+pjfXYpHsDVibqYubzYjfgffOUKFChyzOpH7n/868+t56iIg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "SEE LICENSE IN LICENSE.md",
|
"license": "SEE LICENSE IN LICENSE.md",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -41,20 +43,20 @@
|
|||||||
"copilot": "npm-loader.js"
|
"copilot": "npm-loader.js"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@github/copilot-darwin-arm64": "1.0.64-3",
|
"@github/copilot-darwin-arm64": "1.0.67",
|
||||||
"@github/copilot-darwin-x64": "1.0.64-3",
|
"@github/copilot-darwin-x64": "1.0.67",
|
||||||
"@github/copilot-linux-arm64": "1.0.64-3",
|
"@github/copilot-linux-arm64": "1.0.67",
|
||||||
"@github/copilot-linux-x64": "1.0.64-3",
|
"@github/copilot-linux-x64": "1.0.67",
|
||||||
"@github/copilot-linuxmusl-arm64": "1.0.64-3",
|
"@github/copilot-linuxmusl-arm64": "1.0.67",
|
||||||
"@github/copilot-linuxmusl-x64": "1.0.64-3",
|
"@github/copilot-linuxmusl-x64": "1.0.67",
|
||||||
"@github/copilot-win32-arm64": "1.0.64-3",
|
"@github/copilot-win32-arm64": "1.0.67",
|
||||||
"@github/copilot-win32-x64": "1.0.64-3"
|
"@github/copilot-win32-x64": "1.0.67"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@github/copilot-darwin-arm64": {
|
"node_modules/@github/copilot-darwin-arm64": {
|
||||||
"version": "1.0.64-3",
|
"version": "1.0.67",
|
||||||
"resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.64-3.tgz",
|
"resolved": "https://registry.npmjs.org/@github/copilot-darwin-arm64/-/copilot-darwin-arm64-1.0.67.tgz",
|
||||||
"integrity": "sha512-wlV6mRoAd/wG2V08TG+BOJ0nyOjroya24FSyA5A49z7PnUUuQXYRpa/GljvI5j3PM8aUl0DyBkXuB/DcFU818g==",
|
"integrity": "sha512-CO3mpgFXcN6e7ZsSmjMkt1AKxMfb1+mjdn3yrf2DRnnWIURSK9kGvw+E+E1+YE37D1MBiUn/VOBmhRad5+vl0A==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -69,9 +71,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@github/copilot-darwin-x64": {
|
"node_modules/@github/copilot-darwin-x64": {
|
||||||
"version": "1.0.64-3",
|
"version": "1.0.67",
|
||||||
"resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.64-3.tgz",
|
"resolved": "https://registry.npmjs.org/@github/copilot-darwin-x64/-/copilot-darwin-x64-1.0.67.tgz",
|
||||||
"integrity": "sha512-mk48PIESL2keeemX7tLRmWRDxKwl0q3cFI1ORD2QcrieNK7pSqI3eVbfoB7MqoUUI27yzIkl67xqgl8Qq28IUQ==",
|
"integrity": "sha512-M20Hpn3bOJRkVwAIVRK4ZlX66AqtmGfXZRxZBRFQC045QIwcfmVUP45sTSgXDb4uHWeK0cZgdTdniHwKGtMplw==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -86,9 +88,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@github/copilot-linux-arm64": {
|
"node_modules/@github/copilot-linux-arm64": {
|
||||||
"version": "1.0.64-3",
|
"version": "1.0.67",
|
||||||
"resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.64-3.tgz",
|
"resolved": "https://registry.npmjs.org/@github/copilot-linux-arm64/-/copilot-linux-arm64-1.0.67.tgz",
|
||||||
"integrity": "sha512-rCgtK3/rofQW5StSbeU0TwDUlOl2bvS2HGKyapVxow1Nvz3Q/TDB+eFRQc5ocBdv5tNSor+Caw2JGkRx5v508w==",
|
"integrity": "sha512-b4ePtFBow+Ior+aVLKA1hHxhR5wF+ql5CD7TSg/NHGYgc1kwD+3a9uKSENy05J5Lit/G/DZ9C6JwowvvdMWSKg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -103,9 +105,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@github/copilot-linux-x64": {
|
"node_modules/@github/copilot-linux-x64": {
|
||||||
"version": "1.0.64-3",
|
"version": "1.0.67",
|
||||||
"resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.64-3.tgz",
|
"resolved": "https://registry.npmjs.org/@github/copilot-linux-x64/-/copilot-linux-x64-1.0.67.tgz",
|
||||||
"integrity": "sha512-FAiBMw1h07mURSBLi3ztj5yzbP+uTbo9mhxOym1Xysut5LDpO2kYUzTYk2DlIyLGZhmH/HDOZE+b6U7lOUQy0g==",
|
"integrity": "sha512-4ynZyfKnWAdvEPAFDDBIz1wpFttcOTJu4Y8Mlz5oXCBA0NM/rwr8K4l7Adp8UzwbfmdrMJ9y+zivqRBMDbPInA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -120,9 +122,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@github/copilot-linuxmusl-arm64": {
|
"node_modules/@github/copilot-linuxmusl-arm64": {
|
||||||
"version": "1.0.64-3",
|
"version": "1.0.67",
|
||||||
"resolved": "https://registry.npmjs.org/@github/copilot-linuxmusl-arm64/-/copilot-linuxmusl-arm64-1.0.64-3.tgz",
|
"resolved": "https://registry.npmjs.org/@github/copilot-linuxmusl-arm64/-/copilot-linuxmusl-arm64-1.0.67.tgz",
|
||||||
"integrity": "sha512-vn8P6grPf0y2mNskkdVbAz0i46b1sP9uSXv7z6kgycjprl0CdIYPDf3WEkG60vpyopfQna+iCqCLMWRnNyCk3g==",
|
"integrity": "sha512-IjezxBU8fYUr/b5hEiniXqzwoOrJ4egrQSBbG96M+roLTqd9txP0MgxZtcRtKV7phRIdIGE109wwrn4H6hSqmA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -137,9 +139,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@github/copilot-linuxmusl-x64": {
|
"node_modules/@github/copilot-linuxmusl-x64": {
|
||||||
"version": "1.0.64-3",
|
"version": "1.0.67",
|
||||||
"resolved": "https://registry.npmjs.org/@github/copilot-linuxmusl-x64/-/copilot-linuxmusl-x64-1.0.64-3.tgz",
|
"resolved": "https://registry.npmjs.org/@github/copilot-linuxmusl-x64/-/copilot-linuxmusl-x64-1.0.67.tgz",
|
||||||
"integrity": "sha512-atdHimNd6nzRRwHybXUY6/84bYzXeKbDOeYN/N/DsX23+AQOPSu5BD8MD8166I/5kNHui0XOmeTSydVNBUwcJw==",
|
"integrity": "sha512-Zy/rbja1lnhzDoNfn051H0EybCseCvjvH7WmbcHCayjXUjzXeKF6OmAt4hvqFZH87ttT3KbKtQ8/6oDUhhM2YQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -154,13 +156,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@github/copilot-sdk": {
|
"node_modules/@github/copilot-sdk": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@github/copilot-sdk/-/copilot-sdk-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@github/copilot-sdk/-/copilot-sdk-1.0.4.tgz",
|
||||||
"integrity": "sha512-ujnH2QVw3+xvjgo9cbpY0wik4fNxAmdMDSFnxGScDSvRuK2vUCL2xWW4V2ANc9pWwRHPBpEpMuNJMtmydmLCIQ==",
|
"integrity": "sha512-c6/gpatP7LAuP9stlc2uXXOrB+TJMFSs3Jrzu9FG8lJJYFGmdzbBvGz2UdL1jww84fp6D7cohEZa4UGq1+iuyA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@github/copilot": "^1.0.64-1",
|
"@github/copilot": "^1.0.65",
|
||||||
"vscode-jsonrpc": "^8.2.1",
|
"vscode-jsonrpc": "^8.2.1",
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
@@ -169,9 +171,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@github/copilot-win32-arm64": {
|
"node_modules/@github/copilot-win32-arm64": {
|
||||||
"version": "1.0.64-3",
|
"version": "1.0.67",
|
||||||
"resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.64-3.tgz",
|
"resolved": "https://registry.npmjs.org/@github/copilot-win32-arm64/-/copilot-win32-arm64-1.0.67.tgz",
|
||||||
"integrity": "sha512-jUTS9meoHEXQR8nMDOjwC0baqV273lYtLxY46W7TiOFszhsqhbhWxQMkNQBfT3GEfPp+40igzMPq3reaUTuvag==",
|
"integrity": "sha512-O3VFRS5v9NXRP8o+N1SvcFbBqECDzZP7XQBeBj2Vcrma80gdJc5GQub/w2mwmr1w5UbwgzJkRasm0Ec/jxbcoA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -186,9 +188,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@github/copilot-win32-x64": {
|
"node_modules/@github/copilot-win32-x64": {
|
||||||
"version": "1.0.64-3",
|
"version": "1.0.67",
|
||||||
"resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.64-3.tgz",
|
"resolved": "https://registry.npmjs.org/@github/copilot-win32-x64/-/copilot-win32-x64-1.0.67.tgz",
|
||||||
"integrity": "sha512-gHUhS500Q91hjtH9fqKDblaIs0mO09G4ifpZ1woDPXbkdKe/W29uwB7g2fn0+KczNRyPxFSWlqjnOon4Fe8svA==",
|
"integrity": "sha512-td5tQ/nve5dB7RPvNglBZwa/6DJqiOBgacXXa1GpYcohqpCzoI8gONNkeaeyr6oF4iu5wXJ9krUNr6QXL4yB5Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -221,6 +223,41 @@
|
|||||||
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
|
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/ajv": {
|
||||||
|
"version": "8.20.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
|
||||||
|
"integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"fast-uri": "^3.0.1",
|
||||||
|
"json-schema-traverse": "^1.0.0",
|
||||||
|
"require-from-string": "^2.0.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ajv-formats": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"ajv": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/all-contributors-cli": {
|
"node_modules/all-contributors-cli": {
|
||||||
"version": "6.26.1",
|
"version": "6.26.1",
|
||||||
"resolved": "https://registry.npmjs.org/all-contributors-cli/-/all-contributors-cli-6.26.1.tgz",
|
"resolved": "https://registry.npmjs.org/all-contributors-cli/-/all-contributors-cli-6.26.1.tgz",
|
||||||
@@ -473,6 +510,30 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fast-deep-equal": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/fast-uri": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fastify"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/fastify"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/figures": {
|
"node_modules/figures": {
|
||||||
"version": "3.2.0",
|
"version": "3.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
|
||||||
@@ -618,6 +679,13 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/json-schema-traverse": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/locate-path": {
|
"node_modules/locate-path": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
@@ -632,9 +700,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.18.1",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
@@ -817,6 +885,16 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/require-from-string": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/require-main-filename": {
|
"node_modules/require-main-filename": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
|
||||||
|
|||||||
@@ -38,6 +38,8 @@
|
|||||||
"author": "GitHub",
|
"author": "GitHub",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"ajv": "^8.20.0",
|
||||||
|
"ajv-formats": "^3.0.1",
|
||||||
"@microsoft/vally": "^0.6.0",
|
"@microsoft/vally": "^0.6.0",
|
||||||
"all-contributors-cli": "^6.26.1"
|
"all-contributors-cli": "^6.26.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -499,9 +499,8 @@ import PageHeader from '../components/PageHeader.astro';
|
|||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="center" size="13px" colspan="7">
|
<td align="center" size="13px" colspan="7">
|
||||||
<img src="https://raw.githubusercontent.com/all-contributors/all-contributors-cli/1b8533af435da9854653492b1327a23a4dbd0a10/assets/logo-small.svg">
|
<img src="https://raw.githubusercontent.com/all-contributors/all-contributors-cli/1b8533af435da9854653492b1327a23a4dbd0a10/assets/logo-small.svg" alt="" />
|
||||||
<a href="https://all-contributors.js.org/docs/en/bot/usage">Add your contributions</a>
|
<a href="https://all-contributors.js.org/docs/en/bot/usage">Add your contributions</a>
|
||||||
</img>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
|
|||||||
Reference in New Issue
Block a user