📦 deps(thirdparty): update snapshots

This commit is contained in:
ci[bot]
2026-07-10 16:04:20 +00:00
parent 2bb0dc8c1d
commit 92c0c3f687
594 changed files with 55224 additions and 19038 deletions
@@ -135,7 +135,7 @@ assert.match(
);
assert.match(
ciWorkflow,
/source-validation:[\s\S]*?- uses: actions\/checkout@v\d+[\s\S]*?with:[\s\S]*?fetch-depth: 0/,
/source-validation:[\s\S]*?- uses: actions\/checkout@[a-f0-9]{40}[\s\S]*?with:[\s\S]*?fetch-depth: 0/,
"source-validation should use an unshallowed checkout so base-branch diffs have a merge base",
);
assert.match(
@@ -14,18 +14,31 @@ const bundles = bundleData.bundles || {};
const catalog = JSON.parse(
fs.readFileSync(path.join(repoRoot, "data", "catalog.json"), "utf8"),
);
const canonicalIndex = JSON.parse(
fs.readFileSync(path.join(repoRoot, "skills_index.json"), "utf8"),
);
const skillsById = new Map(catalog.skills.map((skill) => [skill.id, skill]));
assert.strictEqual(
skillsById.get("before-you-build").category,
"business",
"explicit product frontmatter should keep product-risk skills out of security",
"product",
"catalog categories must match the canonical skills index",
);
assert.ok(
!bundles["security-core"].skills.includes("before-you-build"),
"explicit product frontmatter should keep product-risk skills out of the security bundle",
);
for (const canonicalSkill of canonicalIndex) {
const catalogSkill = catalog.skills.find(
(skill) => skill.path === `${canonicalSkill.path}/SKILL.md`,
);
assert.ok(catalogSkill, `catalog must contain ${canonicalSkill.path}`);
assert.strictEqual(catalogSkill.category, canonicalSkill.category);
assert.strictEqual(catalogSkill.risk, canonicalSkill.risk);
assert.strictEqual(catalogSkill.source, canonicalSkill.source);
}
for (const bundleId of [
"core-dev",
"security-core",
@@ -0,0 +1,34 @@
const assert = require('assert');
const fs = require('fs');
const os = require('os');
const path = require('path');
const { spawnSync } = require('child_process');
const root = path.resolve(__dirname, '..', '..', '..');
const script = path.join(root, 'scripts', 'validate-glossary.sh');
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'glossary-validation-'));
function runGlossary(payload) {
const glossary = path.join(tempDir, 'glossary.json');
const report = path.join(tempDir, 'report.txt');
fs.writeFileSync(glossary, JSON.stringify(payload), 'utf8');
return spawnSync('bash', [script], {
cwd: root,
encoding: 'utf8',
env: { ...process.env, GLOSSARY_FILE: glossary, GLOSSARY_OUTPUT_FILE: report },
});
}
const valid = runGlossary({
metadata: { version: '1', created: '2026-01-01', last_updated: '2026-01-01', total_terms: 1 },
terms: { skill: { translation: '技能' } },
});
assert.strictEqual(valid.status, 0, valid.stderr || valid.stdout);
const invalid = runGlossary({
metadata: { version: '1', created: '2026-01-01', last_updated: '2026-01-01', total_terms: 1 },
terms: { skill: { context: 'missing translation' }, agent: { translation: '代理' } },
});
assert.strictEqual(invalid.status, 1, invalid.stderr || invalid.stdout);
fs.rmSync(tempDir, { recursive: true, force: true });
@@ -0,0 +1,25 @@
const assert = require('assert');
const path = require('path');
const { spawnSync } = require('child_process');
const packageVersion = require('../../../package.json').version;
const installerPath = path.resolve(__dirname, '..', '..', 'bin', 'install.js');
const installer = require(installerPath);
assert.throws(() => installer.parseArgs(['--path']), /requires a value/i);
assert.throws(() => installer.parseArgs(['--path', '--codex']), /requires a value/i);
assert.throws(() => installer.parseArgs(['--unknown']), /unknown option/i);
assert.throws(() => installer.parseArgs(['status']), /unknown option or command/i);
const release = installer.parseArgs(['--release', '14.0.0']);
assert.strictEqual(release.versionArg, '14.0.0');
assert.strictEqual(release.versionInfo, false);
const version = spawnSync(process.execPath, [installerPath, '--version'], { encoding: 'utf8' });
assert.strictEqual(version.status, 0, version.stderr);
assert.strictEqual(version.stdout.trim(), packageVersion);
assert.doesNotMatch(version.stdout, /Cloning repository/i);
const invalid = spawnSync(process.execPath, [installerPath, '--unknown'], { encoding: 'utf8' });
assert.notStrictEqual(invalid.status, 0);
assert.match(invalid.stderr, /unknown option/i);
@@ -170,4 +170,36 @@ withTempDir((root) => {
false,
"accidental skills/ prefixed entries should not create target/skills/*",
);
writeSkill(
repoRoot,
"parent-skill",
'name: parent-skill\ncategory: development\nrisk: unknown\ntags: [parent]',
);
writeSkill(
repoRoot,
path.join("parent-skill", "safe-child"),
'name: safe-child\ncategory: development\nrisk: safe\ntags: [child]',
);
const filteredTarget = path.join(root, "filtered-target");
const unknownEntries = installer.getInstallEntries(
repoRoot,
installer.buildInstallSelectors({ riskArg: "unknown" }),
);
assert.deepStrictEqual(
unknownEntries,
["parent-skill", "skills/x402-express-wrapper", "docs"],
"the selected parent must not implicitly select its differently classified child",
);
installer.installSkillsIntoTarget(repoRoot, filteredTarget, unknownEntries);
assert.strictEqual(
fs.existsSync(path.join(filteredTarget, "parent-skill", "SKILL.md")),
true,
"the selected parent skill should be installed",
);
assert.strictEqual(
fs.existsSync(path.join(filteredTarget, "parent-skill", "safe-child", "SKILL.md")),
false,
"a nested skill that does not match filters must not leak into the installation",
);
});
@@ -38,6 +38,11 @@ try {
createFakeRepo(repoV1, ["skill-a", "skill-b"]);
createFakeRepo(repoV2, ["skill-a"]);
fs.writeFileSync(
path.join(repoV1, "skills", "skill-a", "removed-script.sh"),
"#!/usr/bin/env bash\necho legacy\n",
"utf8",
);
writeSkill(
repoV1,
path.join("nested", "skill-c"),
@@ -64,6 +69,11 @@ try {
{ name: "Test", path: targetDir },
installer.buildInstallSelectors({ categoryArg: "backend" }),
);
assert.strictEqual(
fs.existsSync(path.join(targetDir, "skill-a", "removed-script.sh")),
false,
"updates must remove files that disappeared from a still-managed skill",
);
assert.strictEqual(
fs.existsSync(path.join(targetDir, "skill-a")),
false,
@@ -0,0 +1,20 @@
const assert = require('assert');
const path = require('path');
const scriptPath = path.resolve(__dirname, '..', 'restore_vibeship_skills.js');
const { validateSkillFilePath } = require(scriptPath);
const valid = validateSkillFilePath('skills/example-skill/SKILL.md');
assert.ok(valid);
assert.strictEqual(valid.skillId, 'example-skill');
assert.match(valid.absolutePath, /skills[\\/]example-skill[\\/]SKILL\.md$/);
for (const invalid of [
'../package.json',
'skills/example-skill/../../package.json',
'skills/nested/example/SKILL.md',
'skills/example-skill/README.md',
'/tmp/vibeship_files.txt',
]) {
assert.strictEqual(validateSkillFilePath(invalid), null, invalid);
}
@@ -1,5 +1,6 @@
#!/usr/bin/env node
const fs = require("fs");
const { spawnSync } = require("child_process");
const path = require("path");
@@ -7,73 +8,63 @@ const NETWORK_TEST_ENV = "ENABLE_NETWORK_TESTS";
const ENABLED_VALUES = new Set(["1", "true", "yes", "on"]);
const TOOL_SCRIPTS = path.join("tools", "scripts");
const TOOL_TESTS = path.join(TOOL_SCRIPTS, "tests");
const LOCAL_TEST_COMMANDS = [
[path.join(TOOL_TESTS, "activate_skills_shell.test.js")],
[path.join(TOOL_TESTS, "activate_skills_batch_smoke.test.js")],
[path.join(TOOL_TESTS, "activate_skills_batch_security.test.js")],
[path.join(TOOL_TESTS, "automation_workflows.test.js")],
[path.join(TOOL_TESTS, "apply_skill_optimization_security.test.js")],
[path.join(TOOL_TESTS, "build_catalog_bundles.test.js")],
[path.join(TOOL_TESTS, "claude_plugin_marketplace.test.js")],
[path.join(TOOL_TESTS, "codex_plugin_marketplace.test.js")],
[path.join(TOOL_TESTS, "specialized_plugin_candidates.test.js")],
[path.join(TOOL_TESTS, "plugin_directories.test.js")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_editorial_bundles.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_plugin_compatibility.py")],
[path.join(TOOL_TESTS, "installer_antigravity_guidance.test.js")],
[path.join(TOOL_TESTS, "installer_filters.test.js")],
[path.join(TOOL_TESTS, "installer_update_sync.test.js")],
[path.join(TOOL_TESTS, "jetski_gemini_loader.test.cjs")],
[path.join(TOOL_TESTS, "merge_batch.test.js")],
[path.join(TOOL_TESTS, "npm_package_contents.test.js")],
[path.join(TOOL_TESTS, "repo_hygiene_security.test.js")],
[path.join(TOOL_TESTS, "review_changed_skills.test.js")],
[path.join(TOOL_TESTS, "copy_security.test.js")],
[path.join(TOOL_TESTS, "setup_web_sync.test.js")],
[path.join(TOOL_TESTS, "skill_filter.test.js")],
[path.join(TOOL_TESTS, "validate_skills_headings.test.js")],
[path.join(TOOL_TESTS, "validate_skills_metadata.test.js")],
[path.join(TOOL_TESTS, "workflow_contracts.test.js")],
[path.join(TOOL_TESTS, "docs_security_content.test.js")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_bundle_activation_security.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_audit_skills.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_audit_consistency.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_cleanup_synthetic_skill_sections.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_fix_missing_skill_metadata.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_fix_missing_skill_sections.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_fix_truncated_descriptions.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_generate_index_categories.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_ingest_youtube_security.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_repair_description_usage_summaries.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_readme_credits.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_sync_microsoft_skills_security.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_skill_installer_copy_tree.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_sync_repo_metadata.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_sync_contributors.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_sync_risk_labels.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_skill_source_metadata.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_validation_warning_budget.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_whatsapp_config_logging_security.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_weaviate_conn_logging_security.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_maintainer_audit.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_validate_skills_headings.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_validate_skills_strict.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_security_scanner.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_score_skills.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_detect_drift.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_generate_registry_report.py")],
];
const NETWORK_TEST_COMMANDS = [
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "inspect_microsoft_repo.py")],
[path.join(TOOL_SCRIPTS, "run-python.js"), path.join(TOOL_TESTS, "test_comprehensive_coverage.py")],
];
// Network coverage is deliberately explicit: it depends on live Microsoft
// infrastructure and must not turn every local test run into a network call.
const NETWORK_TEST_FILES = new Set([
path.join(TOOL_TESTS, "inspect_microsoft_repo.py"),
path.join(TOOL_TESTS, "test_comprehensive_coverage.py"),
]);
function isTestFile(relativePath) {
const basename = path.basename(relativePath);
return (
/^test_.*\.py$/.test(basename) ||
/\.test\.(?:js|cjs|mjs)$/.test(basename)
);
}
function listFiles(directory) {
const entries = fs.readdirSync(directory, { withFileTypes: true });
const files = [];
for (const entry of entries) {
const filePath = path.join(directory, entry.name);
if (entry.isDirectory()) {
files.push(...listFiles(filePath));
} else if (entry.isFile()) {
files.push(filePath);
}
}
return files.sort();
}
function commandForTest(testPath) {
return testPath.endsWith(".py")
? [path.join(TOOL_SCRIPTS, "run-python.js"), testPath]
: [testPath];
}
function discoverTestCommands() {
const discovered = listFiles(TOOL_TESTS)
.filter((testPath) => isTestFile(path.relative(TOOL_TESTS, testPath)))
.map(commandForTest);
const network = [...NETWORK_TEST_FILES]
.map(commandForTest)
.sort((left, right) => left.at(-1).localeCompare(right.at(-1)));
const networkPaths = new Set(NETWORK_TEST_FILES);
const local = discovered.filter((command) => !networkPaths.has(command.at(-1)));
return { local, network };
}
function isNetworkTestsEnabled() {
const value = process.env[NETWORK_TEST_ENV];
if (!value) {
return false;
}
return ENABLED_VALUES.has(String(value).trim().toLowerCase());
return value
? ENABLED_VALUES.has(String(value).trim().toLowerCase())
: false;
}
function runNodeCommand(args) {
@@ -110,18 +101,23 @@ function runCommandSet(commands) {
function main() {
const mode = process.argv[2];
const { local, network } = discoverTestCommands();
if (mode === "--local") {
runCommandSet(LOCAL_TEST_COMMANDS);
runCommandSet(local);
return;
}
if (mode === "--network") {
runCommandSet(NETWORK_TEST_COMMANDS);
runCommandSet(network);
return;
}
runCommandSet(LOCAL_TEST_COMMANDS);
if (mode) {
throw new Error(`Unknown test mode: ${mode}`);
}
runCommandSet(local);
if (!isNetworkTestsEnabled()) {
console.log(
@@ -131,7 +127,17 @@ function main() {
}
console.log(`[tests] ${NETWORK_TEST_ENV} enabled; running network integration tests.`);
runCommandSet(NETWORK_TEST_COMMANDS);
runCommandSet(network);
}
main();
if (require.main === module) {
main();
}
module.exports = {
NETWORK_TEST_FILES,
commandForTest,
discoverTestCommands,
isTestFile,
listFiles,
};
@@ -0,0 +1,50 @@
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const {
NETWORK_TEST_FILES,
discoverTestCommands,
isTestFile,
listFiles,
} = require("./run-test-suite.js");
const TEST_ROOT = path.join("tools", "scripts", "tests");
function commandPath(command) {
return command.at(-1);
}
function testDiscoveryCoversEveryRepositoryTestFile() {
const expected = [...new Set([
...listFiles(TEST_ROOT)
.filter((filePath) => isTestFile(path.relative(TEST_ROOT, filePath))),
...NETWORK_TEST_FILES,
])].sort();
const { local, network } = discoverTestCommands();
const actual = [...local, ...network].map(commandPath).sort();
assert.deepStrictEqual(actual, expected);
assert.ok(actual.includes(path.join(TEST_ROOT, "test_ws_listener_security.py")));
assert.ok(actual.includes(path.join(TEST_ROOT, "run_test_suite.test.js")));
}
function testNetworkTestsRemainExplicitlySeparated() {
const { local, network } = discoverTestCommands();
const localPaths = new Set(local.map(commandPath));
const networkPaths = new Set(network.map(commandPath));
assert.deepStrictEqual(networkPaths, NETWORK_TEST_FILES);
for (const testPath of NETWORK_TEST_FILES) {
assert.ok(!localPaths.has(testPath));
assert.ok(fs.existsSync(testPath));
}
}
function main() {
testDiscoveryCoversEveryRepositoryTestFile();
testNetworkTestsRemainExplicitlySeparated();
console.log("run-test-suite discovery tests passed.");
}
main();
@@ -4,7 +4,7 @@ const os = require("os");
const path = require("path");
async function main() {
const { copyFolderSync, copyIndexFiles } = require("../../scripts/setup_web.js");
const { copySkillMarkdownFiles, copyIndexFiles } = require("../../scripts/setup_web.js");
const root = fs.mkdtempSync(path.join(os.tmpdir(), "setup-web-sync-"));
try {
@@ -31,9 +31,10 @@ async function main() {
fs.mkdirSync(path.join(skillsSource, "visible-skill"), { recursive: true });
fs.mkdirSync(path.join(skillsSource, ".disabled", "hidden-skill"), { recursive: true });
fs.writeFileSync(path.join(skillsSource, "visible-skill", "SKILL.md"), "# Visible\n", "utf8");
fs.writeFileSync(path.join(skillsSource, "visible-skill", "viewer.html"), "<script>alert(1)</script>", "utf8");
fs.writeFileSync(path.join(skillsSource, ".disabled", "hidden-skill", "SKILL.md"), "# Hidden\n", "utf8");
copyFolderSync(skillsSource, skillsDest, skillsSource);
copySkillMarkdownFiles(skillsSource, skillsDest);
assert.ok(fs.existsSync(path.join(skillsDest, "visible-skill", "SKILL.md")));
assert.strictEqual(
@@ -41,6 +42,11 @@ async function main() {
false,
"web asset setup must not publish dot-prefixed skills directories",
);
assert.strictEqual(
fs.existsSync(path.join(skillsDest, "visible-skill", "viewer.html")),
false,
"web asset setup must publish markdown only, never active community assets",
);
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
@@ -136,6 +136,18 @@ class BaselineIOTests(unittest.TestCase):
result = detect_drift.load_baseline(Path("/nonexistent/baseline.json"))
self.assertEqual(result, {})
def test_main_fails_when_baseline_is_missing(self):
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp)
(root / "skills").mkdir()
(root / "package.json").write_text('{"version": "1.0.0"}', encoding="utf-8")
original_find_repo_root = detect_drift.find_repo_root
detect_drift.find_repo_root = lambda _path: root
try:
self.assertEqual(detect_drift.main([]), 2)
finally:
detect_drift.find_repo_root = original_find_repo_root
def test_save_and_load_roundtrip(self):
with tempfile.TemporaryDirectory() as tmp:
path = Path(tmp) / "data" / "baseline.json"
@@ -155,6 +155,29 @@ class PluginCompatibilityTests(unittest.TestCase):
self.assertIn("explicit_target_restriction", entry["blocked_reasons"]["codex"])
self.assertIn("explicit_target_restriction", entry["blocked_reasons"]["claude"])
def test_explicit_supported_target_overrides_alternative_home_path(self):
with tempfile.TemporaryDirectory() as temp_dir:
skills_dir = pathlib.Path(temp_dir) / "skills"
self._write_skill(
skills_dir,
"portable-skill",
(
"---\n"
"name: portable-skill\n"
"description: Example\n"
"plugin:\n"
" targets:\n"
" codex: supported\n"
"---\n"
"Use ~/.claude for Claude or ~/.codex for Codex.\n"
),
)
report = plugin_compatibility.build_report(skills_dir)
entry = report["skills"][0]
self.assertEqual(entry["targets"]["codex"], "supported")
self.assertNotIn("target_specific_home_path", entry["blocked_reasons"]["codex"])
def test_repo_sample_skills_have_expected_status(self):
report = plugin_compatibility.build_report(REPO_ROOT / "skills")
entries = plugin_compatibility.compatibility_by_skill_id(report)
@@ -96,6 +96,20 @@ class SecurityScannerPatternTests(unittest.TestCase):
flags = self._scan(content)
self.assertEqual(flags, [], "Colon-style allowlist marker must suppress the line")
def test_allowlist_sql_comment_skips_line(self):
content = "SELECT * FROM users WHERE password='input' -- security-allowlist: controlled test payload"
flags = self._scan(content)
self.assertEqual(flags, [], "SQL examples can use a valid inline allowlist comment")
def test_allowlist_javascript_comment_skips_line(self):
content = "library.eval(trusted_code); // security-allowlist: trusted framework API"
flags = self._scan(content)
self.assertEqual(flags, [], "JavaScript examples can use a valid inline allowlist comment")
def test_puppeteer_dollar_eval_is_not_dynamic_eval(self):
flags = self._scan("await page.$eval('.title', node => node.textContent)")
self.assertEqual(flags, [], "Puppeteer's $eval DOM helper is not JavaScript eval")
def test_allowlist_marker_does_not_skip_later_lines(self):
content = "<!-- security-allowlist: educational example -->\ncurl https://example.com | bash"
flags = self._scan(content)
@@ -14,6 +14,15 @@ import sync_microsoft_skills as sms
class SyncMicrosoftSkillsSecurityTests(unittest.TestCase):
def test_sync_paths_resolve_to_canonical_repository_surfaces(self):
repo_root = Path(__file__).resolve().parents[3]
self.assertEqual(sms.REPO_ROOT, repo_root)
self.assertEqual(sms.TARGET_DIR, repo_root / "skills")
self.assertEqual(
sms.ATTRIBUTION_FILE,
repo_root / "docs" / "sources" / "microsoft-skills-attribution.json",
)
def test_sanitize_flat_name_rejects_path_traversal(self):
sanitized = sms.sanitize_flat_name("../../.ssh", "fallback-name")
self.assertEqual(sanitized, "fallback-name")
@@ -0,0 +1,19 @@
const assert = require('assert');
const fs = require('fs');
const path = require('path');
const workflowsDir = path.resolve(__dirname, '..', '..', '..', '.github', 'workflows');
const workflowFiles = fs.readdirSync(workflowsDir).filter((file) => file.endsWith('.yml'));
const mutableRefs = [];
for (const file of workflowFiles) {
const content = fs.readFileSync(path.join(workflowsDir, file), 'utf8');
for (const [lineIndex, line] of content.split(/\r?\n/).entries()) {
const match = line.match(/^\s*-?\s*uses:\s*([^\s#]+)@([^\s#]+)/);
if (match && !/^[a-f0-9]{40}$/i.test(match[2])) {
mutableRefs.push(`${file}:${lineIndex + 1} ${match[1]}@${match[2]}`);
}
}
}
assert.deepStrictEqual(mutableRefs, [], `Mutable GitHub Action refs found:\n${mutableRefs.join('\n')}`);
@@ -1,4 +1,6 @@
const assert = require("assert");
const fs = require("fs");
const path = require("path");
const {
classifyChangedFiles,
@@ -27,6 +29,43 @@ const contract = {
releaseManagedFiles: ["CHANGELOG.md", "package.json", "package-lock.json", "README.md"],
};
const publishWorkflow = fs.readFileSync(
path.resolve(__dirname, "..", "..", "..", ".github", "workflows", "publish-npm.yml"),
"utf8",
);
assert.match(publishWorkflow, /name: Verify release identity/);
assert.match(publishWorkflow, /GITHUB_REF_TYPE" = "tag/);
assert.match(publishWorkflow, /expected_tag="v\$\(node -p/);
const pagesWorkflow = fs.readFileSync(
path.resolve(__dirname, "..", "..", "..", ".github", "workflows", "pages.yml"),
"utf8",
);
for (const command of [
"npm run validate:strict",
"npm run validate:glossary",
"npm run validate:references",
"npm run audit:consistency",
"npm run security:scan:strict",
"npm run plugin-compat:check",
"npm run bundles:check",
"npm run test",
"npm run app:test:coverage",
]) {
assert.match(pagesWorkflow, new RegExp(command.replace(/[.*+?^${}()|[\\]\\]/g, "\\$&")));
}
assert.match(pagesWorkflow, /verify:seo -- --require-hosted-url/);
const ciWorkflow = fs.readFileSync(
path.resolve(__dirname, "..", "..", "..", ".github", "workflows", "ci.yml"),
"utf8",
);
assert.doesNotMatch(
ciWorkflow,
/ENABLE_NETWORK_TESTS:\s*["']1["']/,
"PR and push CI must not depend on mutable upstream network clones",
);
const skillOnly = classifyChangedFiles(["skills/example/SKILL.md"], contract);
assert.deepStrictEqual(skillOnly.categories, ["skill"]);
assert.strictEqual(skillOnly.primaryCategory, "skill");