📦 deps(thirdparty): update snapshots
This commit is contained in:
@@ -5,7 +5,7 @@ const path = require("path");
|
||||
const repoRoot = path.resolve(__dirname, "..", "..", "..");
|
||||
|
||||
function readText(relativePath) {
|
||||
return fs.readFileSync(path.join(repoRoot, relativePath), "utf8");
|
||||
return fs.readFileSync(path.join(repoRoot, relativePath), "utf8").replace(/\r\n/g, "\n");
|
||||
}
|
||||
|
||||
const packageJson = JSON.parse(readText("package.json"));
|
||||
|
||||
@@ -5,6 +5,7 @@ const os = require("os");
|
||||
const path = require("path");
|
||||
|
||||
const { copyRecursiveSync } = require("../../bin/install");
|
||||
const { createSymlinkOrSkip } = require("./symlink-test-utils");
|
||||
|
||||
async function main() {
|
||||
const { copyFolderSync, copyIndexFile } = await import("../../scripts/setup_web.js");
|
||||
@@ -22,22 +23,31 @@ async function main() {
|
||||
fs.writeFileSync(path.join(safeRoot, "nested", "ok.txt"), "ok");
|
||||
fs.writeFileSync(path.join(outsideDir, "secret.txt"), "secret");
|
||||
fs.writeFileSync(path.join(outsideDir, "symlink-secret.txt"), "do-not-touch");
|
||||
fs.symlinkSync(path.join(outsideDir, "symlink-secret.txt"), symlinkDestination);
|
||||
fs.symlinkSync(outsideDir, path.join(safeRoot, "escape-link"));
|
||||
const createdSymlinkDestination = createSymlinkOrSkip(
|
||||
path.join(outsideDir, "symlink-secret.txt"),
|
||||
symlinkDestination,
|
||||
);
|
||||
const createdEscapeLink = createSymlinkOrSkip(
|
||||
outsideDir,
|
||||
path.join(safeRoot, "escape-link"),
|
||||
"dir",
|
||||
);
|
||||
|
||||
copyRecursiveSync(safeRoot, path.join(destRoot, "install-copy"), safeRoot);
|
||||
copyFolderSync(safeRoot, path.join(destRoot, "web-copy"), safeRoot);
|
||||
|
||||
assert.strictEqual(
|
||||
fs.existsSync(path.join(destRoot, "install-copy", "escape-link", "secret.txt")),
|
||||
false,
|
||||
"installer copy must not follow symlinks outside the cloned root",
|
||||
);
|
||||
assert.strictEqual(
|
||||
fs.existsSync(path.join(destRoot, "web-copy", "escape-link", "secret.txt")),
|
||||
false,
|
||||
"web setup copy must not follow symlinks outside the skills root",
|
||||
);
|
||||
if (createdEscapeLink) {
|
||||
assert.strictEqual(
|
||||
fs.existsSync(path.join(destRoot, "install-copy", "escape-link", "secret.txt")),
|
||||
false,
|
||||
"installer copy must not follow symlinks outside the cloned root",
|
||||
);
|
||||
assert.strictEqual(
|
||||
fs.existsSync(path.join(destRoot, "web-copy", "escape-link", "secret.txt")),
|
||||
false,
|
||||
"web setup copy must not follow symlinks outside the skills root",
|
||||
);
|
||||
}
|
||||
assert.strictEqual(
|
||||
fs.readFileSync(path.join(destRoot, "install-copy", "nested", "ok.txt"), "utf8"),
|
||||
"ok",
|
||||
@@ -46,34 +56,38 @@ async function main() {
|
||||
fs.readFileSync(path.join(destRoot, "web-copy", "nested", "ok.txt"), "utf8"),
|
||||
"ok",
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
copyRecursiveSync(
|
||||
path.join(safeRoot, "nested", "ok.txt"),
|
||||
symlinkDestination,
|
||||
safeRoot,
|
||||
),
|
||||
/Skipping unsafe destination symlink/i,
|
||||
"installer copy should refuse writing into existing destination symlinks",
|
||||
);
|
||||
assert.strictEqual(
|
||||
fs.readFileSync(path.join(outsideDir, "symlink-secret.txt"), "utf8"),
|
||||
"do-not-touch",
|
||||
);
|
||||
if (createdSymlinkDestination) {
|
||||
assert.throws(
|
||||
() =>
|
||||
copyRecursiveSync(
|
||||
path.join(safeRoot, "nested", "ok.txt"),
|
||||
symlinkDestination,
|
||||
safeRoot,
|
||||
),
|
||||
/Skipping unsafe destination symlink/i,
|
||||
"installer copy should refuse writing into existing destination symlinks",
|
||||
);
|
||||
assert.strictEqual(
|
||||
fs.readFileSync(path.join(outsideDir, "symlink-secret.txt"), "utf8"),
|
||||
"do-not-touch",
|
||||
);
|
||||
}
|
||||
|
||||
const indexSource = path.join(root, "skills_index.json");
|
||||
const outsideIndexTarget = path.join(outsideDir, "index-target.json");
|
||||
const symlinkedIndexDest = path.join(destRoot, "skills.json");
|
||||
fs.writeFileSync(indexSource, "[]");
|
||||
fs.writeFileSync(outsideIndexTarget, "outside");
|
||||
fs.symlinkSync(outsideIndexTarget, symlinkedIndexDest);
|
||||
const createdIndexSymlink = createSymlinkOrSkip(outsideIndexTarget, symlinkedIndexDest);
|
||||
|
||||
assert.throws(
|
||||
() => copyIndexFile(indexSource, symlinkedIndexDest),
|
||||
/symlink/i,
|
||||
"web setup index copy must reject destination symlinks",
|
||||
);
|
||||
assert.strictEqual(fs.readFileSync(outsideIndexTarget, "utf8"), "outside");
|
||||
if (createdIndexSymlink) {
|
||||
assert.throws(
|
||||
() => copyIndexFile(indexSource, symlinkedIndexDest),
|
||||
/symlink/i,
|
||||
"web setup index copy must reject destination symlinks",
|
||||
);
|
||||
assert.strictEqual(fs.readFileSync(outsideIndexTarget, "utf8"), "outside");
|
||||
}
|
||||
|
||||
const repoRoot = path.resolve(__dirname, "..", "..", "..");
|
||||
const repoTmp = path.join(repoRoot, ".tmp", `copy-security-${process.pid}`);
|
||||
@@ -83,25 +97,27 @@ async function main() {
|
||||
fs.mkdirSync(repoTmp, { recursive: true });
|
||||
fs.writeFileSync(copySource, "new content");
|
||||
fs.writeFileSync(outsideCopyTarget, "outside");
|
||||
fs.symlinkSync(outsideCopyTarget, copyDest);
|
||||
const createdCopyDestSymlink = createSymlinkOrSkip(outsideCopyTarget, copyDest);
|
||||
|
||||
const copyResult = spawnSync(
|
||||
process.execPath,
|
||||
[
|
||||
path.join(repoRoot, "tools", "scripts", "copy-file.js"),
|
||||
path.relative(repoRoot, copySource),
|
||||
path.relative(repoRoot, copyDest),
|
||||
],
|
||||
{ cwd: repoRoot, encoding: "utf8" },
|
||||
);
|
||||
if (createdCopyDestSymlink) {
|
||||
const copyResult = spawnSync(
|
||||
process.execPath,
|
||||
[
|
||||
path.join(repoRoot, "tools", "scripts", "copy-file.js"),
|
||||
path.relative(repoRoot, copySource),
|
||||
path.relative(repoRoot, copyDest),
|
||||
],
|
||||
{ cwd: repoRoot, encoding: "utf8" },
|
||||
);
|
||||
|
||||
assert.notStrictEqual(copyResult.status, 0, "copy-file must fail for destination symlinks");
|
||||
assert.match(
|
||||
`${copyResult.stdout}\n${copyResult.stderr}`,
|
||||
/symlink/i,
|
||||
"copy-file failure should explain that symlink destinations are refused",
|
||||
);
|
||||
assert.strictEqual(fs.readFileSync(outsideCopyTarget, "utf8"), "outside");
|
||||
assert.notStrictEqual(copyResult.status, 0, "copy-file must fail for destination symlinks");
|
||||
assert.match(
|
||||
`${copyResult.stdout}\n${copyResult.stderr}`,
|
||||
/symlink/i,
|
||||
"copy-file failure should explain that symlink destinations are refused",
|
||||
);
|
||||
assert.strictEqual(fs.readFileSync(outsideCopyTarget, "utf8"), "outside");
|
||||
}
|
||||
fs.rmSync(repoTmp, { recursive: true, force: true });
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
const assert = require("assert");
|
||||
const fs = require("fs");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
|
||||
const installer = require(path.resolve(__dirname, "..", "..", "bin", "install.js"));
|
||||
@@ -61,6 +63,19 @@ assert.ok(
|
||||
antigravityMessages.some((message) => message.includes("activate-skills.bat")),
|
||||
"Antigravity installs should mention the Windows activation flow",
|
||||
);
|
||||
assert.ok(
|
||||
antigravityMessages.some((message) => message.includes("--agy")),
|
||||
"Antigravity installs should point agy CLI users to the flat CLI layout",
|
||||
);
|
||||
|
||||
const agyMessages = installer.getPostInstallMessages([
|
||||
{ name: "Antigravity CLI", path: "/tmp/.gemini/antigravity-cli/skills", layout: "flat-markdown" },
|
||||
]);
|
||||
|
||||
assert.ok(
|
||||
agyMessages.some((message) => message.includes("/skills")),
|
||||
"Antigravity CLI installs should tell users how to verify slash commands",
|
||||
);
|
||||
|
||||
const codexMessages = installer.getPostInstallMessages([
|
||||
{ name: "Codex CLI", path: "/tmp/.codex/skills" },
|
||||
@@ -71,3 +86,44 @@ assert.strictEqual(
|
||||
false,
|
||||
"Non-Antigravity installs should not emit the Antigravity-specific overload hint",
|
||||
);
|
||||
|
||||
const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), "agy-install-fixture-"));
|
||||
try {
|
||||
const tempDir = path.join(fixtureRoot, "repo");
|
||||
const targetDir = path.join(fixtureRoot, "agy-skills");
|
||||
const alphaDir = path.join(tempDir, "skills", "alpha");
|
||||
const nestedDir = path.join(tempDir, "skills", "security", "audit");
|
||||
fs.mkdirSync(alphaDir, { recursive: true });
|
||||
fs.mkdirSync(nestedDir, { recursive: true });
|
||||
fs.mkdirSync(targetDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(alphaDir, "SKILL.md"), "---\nname: alpha\n---\n\n# Alpha\n", "utf8");
|
||||
fs.writeFileSync(path.join(nestedDir, "SKILL.md"), "---\nname: audit\n---\n\n# Audit\n", "utf8");
|
||||
|
||||
assert.deepStrictEqual(
|
||||
installer.getManagedEntries(["alpha", "security/audit", "docs"], { layout: "flat-markdown" }),
|
||||
["alpha.md", "audit.md"],
|
||||
"agy CLI flat installs should track markdown skill files instead of skill directories",
|
||||
);
|
||||
|
||||
installer.installSkillsIntoFlatMarkdownTarget(tempDir, targetDir, [
|
||||
"alpha",
|
||||
"security/audit",
|
||||
"docs",
|
||||
]);
|
||||
|
||||
assert.strictEqual(
|
||||
fs.readFileSync(path.join(targetDir, "alpha.md"), "utf8"),
|
||||
"---\nname: alpha\n---\n\n# Alpha\n",
|
||||
);
|
||||
assert.strictEqual(
|
||||
fs.readFileSync(path.join(targetDir, "audit.md"), "utf8"),
|
||||
"---\nname: audit\n---\n\n# Audit\n",
|
||||
);
|
||||
assert.strictEqual(
|
||||
fs.existsSync(path.join(targetDir, "docs")),
|
||||
false,
|
||||
"agy CLI flat installs should not copy docs as a slash-command entry",
|
||||
);
|
||||
} finally {
|
||||
fs.rmSync(fixtureRoot, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ const os = require("os");
|
||||
const path = require("path");
|
||||
const { spawnSync } = require("child_process");
|
||||
|
||||
const { createSymlinkOrSkip } = require("./symlink-test-utils");
|
||||
const installer = require(path.resolve(__dirname, "..", "..", "bin", "install.js"));
|
||||
|
||||
function writeSkill(repoRoot, skillName, content = "# Skill\n") {
|
||||
@@ -143,7 +144,10 @@ installer.installForTarget(${JSON.stringify(repoV2)}, { name: "BadTarget", path:
|
||||
const symlinkRealTarget = path.join(tmpRoot, "symlink-real-target");
|
||||
const symlinkTargetPath = path.join(tmpRoot, "symlink-target");
|
||||
fs.mkdirSync(path.join(symlinkRealTarget, ".git"), { recursive: true });
|
||||
fs.symlinkSync(symlinkRealTarget, symlinkTargetPath, "dir");
|
||||
const createdSymlinkTarget = createSymlinkOrSkip(symlinkRealTarget, symlinkTargetPath, "dir");
|
||||
if (!createdSymlinkTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
const symlinkTargetCheck = spawnSync(
|
||||
process.execPath,
|
||||
|
||||
@@ -3,6 +3,8 @@ const fs = require("fs");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
|
||||
const { createSymlinkOrSkip } = require("./symlink-test-utils");
|
||||
|
||||
async function main() {
|
||||
const repoRoot = path.resolve(__dirname, "..", "..", "..");
|
||||
const loaderPath = path.join(
|
||||
@@ -111,18 +113,20 @@ async function main() {
|
||||
fs.mkdirSync(symlinkedDir, { recursive: true });
|
||||
fs.mkdirSync(outsideDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(outsideDir, "secret.md"), "# secret\n", "utf8");
|
||||
fs.symlinkSync(
|
||||
const createdSymlink = createSymlinkOrSkip(
|
||||
path.join(outsideDir, "secret.md"),
|
||||
path.join(symlinkedDir, "SKILL.md"),
|
||||
);
|
||||
|
||||
await assert.rejects(
|
||||
() =>
|
||||
loadSkillBodies(fixtureRoot, [
|
||||
{ id: "symlinked", path: "skills/symlinked", name: "symlinked" },
|
||||
]),
|
||||
/symlink|outside the skills root|regular file/i,
|
||||
);
|
||||
if (createdSymlink) {
|
||||
await assert.rejects(
|
||||
() =>
|
||||
loadSkillBodies(fixtureRoot, [
|
||||
{ id: "symlinked", path: "skills/symlinked", name: "symlinked" },
|
||||
]),
|
||||
/symlink|outside the skills root|regular file/i,
|
||||
);
|
||||
}
|
||||
console.log("✅ All Jetski Loader Security Checks Passed!");
|
||||
} finally {
|
||||
fs.rmSync(fixtureRoot, { recursive: true, force: true });
|
||||
|
||||
@@ -4,6 +4,8 @@ const fs = require("fs");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
|
||||
const { createSymlinkOrSkip } = require("./symlink-test-utils");
|
||||
|
||||
const repoRoot = path.resolve(__dirname, "../..", "..");
|
||||
const pycacheDir = path.join(repoRoot, "skills", "ui-ux-pro-max", "scripts", "__pycache__");
|
||||
const nestedSkillsDir = path.join(repoRoot, "skills", "skills");
|
||||
@@ -41,7 +43,12 @@ assert.doesNotMatch(alphaVantage, /--- Unknown/, "alpha-vantage frontmatter shou
|
||||
"[absolute](/etc/passwd)\n[traversal](../../etc/passwd)\n[symlink](linked-secret)\n[missing](docs/missing.md)\n",
|
||||
"utf8",
|
||||
);
|
||||
fs.symlinkSync("/etc/passwd", path.join(targetRepo, "linked-secret"));
|
||||
const outsideSecret = path.join(tempDir, "outside-secret");
|
||||
fs.writeFileSync(outsideSecret, "secret", "utf8");
|
||||
const createdSymlink = createSymlinkOrSkip(outsideSecret, path.join(targetRepo, "linked-secret"));
|
||||
if (!createdSymlink) {
|
||||
return;
|
||||
}
|
||||
const fakeBin = path.join(tempDir, "bin");
|
||||
fs.mkdirSync(fakeBin);
|
||||
const fakeRg = path.join(fakeBin, "rg");
|
||||
|
||||
@@ -4,6 +4,7 @@ const os = require("os");
|
||||
const path = require("path");
|
||||
|
||||
const { listSkillIds, listSkillIdsRecursive, readSkill } = require("../../lib/skill-utils");
|
||||
const { createSymlinkOrSkip } = require("./symlink-test-utils");
|
||||
|
||||
function withTempDir(fn) {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "skill-utils-security-"));
|
||||
@@ -25,7 +26,10 @@ withTempDir((root) => {
|
||||
fs.writeFileSync(path.join(skillsDir, "safe-skill", "SKILL.md"), "# safe\n");
|
||||
|
||||
fs.writeFileSync(path.join(outsideDir, "SKILL.md"), "# secret\n");
|
||||
fs.symlinkSync(outsideDir, path.join(skillsDir, "linked-secret"));
|
||||
const createdSymlink = createSymlinkOrSkip(outsideDir, path.join(skillsDir, "linked-secret"), "dir");
|
||||
if (!createdSymlink) {
|
||||
return;
|
||||
}
|
||||
|
||||
const skillIds = listSkillIds(skillsDir);
|
||||
|
||||
@@ -47,7 +51,14 @@ withTempDir((root) => {
|
||||
fs.writeFileSync(path.join(skillsDir, "nested", "safe-skill", "SKILL.md"), "# safe\n");
|
||||
|
||||
fs.mkdirSync(path.join(outsideDir, "loop-target"), { recursive: true });
|
||||
fs.symlinkSync(outsideDir, path.join(skillsDir, "nested", "linked-secret"));
|
||||
const createdSymlink = createSymlinkOrSkip(
|
||||
outsideDir,
|
||||
path.join(skillsDir, "nested", "linked-secret"),
|
||||
"dir",
|
||||
);
|
||||
if (!createdSymlink) {
|
||||
return;
|
||||
}
|
||||
|
||||
const skillIds = listSkillIdsRecursive(skillsDir);
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
const fs = require("fs");
|
||||
|
||||
function isSymlinkPrivilegeError(error) {
|
||||
return (
|
||||
error &&
|
||||
(error.code === "EPERM" ||
|
||||
error.code === "EACCES" ||
|
||||
error.errno === -4048 ||
|
||||
/privilege|WinError 1314/i.test(String(error.message || "")))
|
||||
);
|
||||
}
|
||||
|
||||
function createSymlinkOrSkip(target, linkPath, type) {
|
||||
try {
|
||||
fs.symlinkSync(target, linkPath, type);
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (process.platform === "win32" && isSymlinkPrivilegeError(error)) {
|
||||
console.warn(`[tests] Skipping symlink assertion; Windows denied symlink creation: ${linkPath}`);
|
||||
return false;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createSymlinkOrSkip,
|
||||
isSymlinkPrivilegeError,
|
||||
};
|
||||
@@ -4,6 +4,7 @@ const os = require("os");
|
||||
const path = require("path");
|
||||
|
||||
const { resolveSafeRealPath } = require("../../lib/symlink-safety");
|
||||
const { createSymlinkOrSkip } = require("./symlink-test-utils");
|
||||
|
||||
function withTempDir(fn) {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "symlink-safety-"));
|
||||
@@ -26,8 +27,11 @@ withTempDir((root) => {
|
||||
fs.writeFileSync(path.join(internalDir, "data.txt"), "ok");
|
||||
fs.writeFileSync(path.join(outsideDir, "secret.txt"), "secret");
|
||||
|
||||
fs.symlinkSync(internalDir, internalLink);
|
||||
fs.symlinkSync(outsideDir, outsideLink);
|
||||
const createdInternalLink = createSymlinkOrSkip(internalDir, internalLink, "dir");
|
||||
const createdOutsideLink = createSymlinkOrSkip(outsideDir, outsideLink, "dir");
|
||||
if (!createdInternalLink || !createdOutsideLink) {
|
||||
return;
|
||||
}
|
||||
|
||||
const internalResolved = resolveSafeRealPath(safeRoot, internalLink);
|
||||
const outsideResolved = resolveSafeRealPath(safeRoot, outsideLink);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import errno
|
||||
import os
|
||||
import unittest
|
||||
|
||||
|
||||
def is_symlink_privilege_error(error: OSError) -> bool:
|
||||
winerror = getattr(error, "winerror", None)
|
||||
return (
|
||||
os.name == "nt"
|
||||
and (
|
||||
winerror == 1314
|
||||
or error.errno in {errno.EPERM, errno.EACCES}
|
||||
or "privilege" in str(error).lower()
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def symlink_or_skip(test_case: unittest.TestCase, target, link_path, target_is_directory=False) -> None:
|
||||
try:
|
||||
link_path.symlink_to(target, target_is_directory=target_is_directory)
|
||||
except OSError as error:
|
||||
if is_symlink_privilege_error(error):
|
||||
test_case.skipTest(f"Windows denied symlink creation for {link_path}")
|
||||
raise
|
||||
+3
-1
@@ -6,6 +6,8 @@ import unittest
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
from symlink_test_utils import symlink_or_skip
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
TOOLS_SCRIPTS_DIR = REPO_ROOT / "tools" / "scripts"
|
||||
@@ -175,7 +177,7 @@ description: Build and distribute Expo development clients locally or via TestFl
|
||||
"""
|
||||
target.write_text(original, encoding="utf-8")
|
||||
skill_path = skill_dir / "SKILL.md"
|
||||
skill_path.symlink_to(target)
|
||||
symlink_or_skip(self, target, skill_path)
|
||||
|
||||
changed, changes = cleanup_synthetic_skill_sections.cleanup_skill_file(repo_root, skill_path)
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ TOOLS_SCRIPTS_DIR = REPO_ROOT / "tools" / "scripts"
|
||||
if str(TOOLS_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(TOOLS_SCRIPTS_DIR))
|
||||
|
||||
from symlink_test_utils import symlink_or_skip
|
||||
|
||||
|
||||
def load_module(relative_path: str, module_name: str):
|
||||
module_path = REPO_ROOT / relative_path
|
||||
@@ -155,7 +157,7 @@ description: "External file."
|
||||
"""
|
||||
target.write_text(original, encoding="utf-8")
|
||||
skill_path = skill_dir / "SKILL.md"
|
||||
skill_path.symlink_to(target)
|
||||
symlink_or_skip(self, target, skill_path)
|
||||
|
||||
changed, changes = fix_missing_skill_metadata.update_skill_file(skill_path)
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ TOOLS_SCRIPTS_DIR = REPO_ROOT / "tools" / "scripts"
|
||||
if str(TOOLS_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(TOOLS_SCRIPTS_DIR))
|
||||
|
||||
from symlink_test_utils import symlink_or_skip
|
||||
|
||||
|
||||
def load_module(relative_path: str, module_name: str):
|
||||
module_path = REPO_ROOT / relative_path
|
||||
@@ -144,7 +146,7 @@ description: Demo description.
|
||||
"""
|
||||
target.write_text(original, encoding="utf-8")
|
||||
skill_path = skill_dir / "SKILL.md"
|
||||
skill_path.symlink_to(target)
|
||||
symlink_or_skip(self, target, skill_path)
|
||||
|
||||
changed, changes = fix_missing_skill_sections.update_skill_file(skill_path, add_missing=True)
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ TOOLS_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(TOOLS_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(TOOLS_SCRIPTS_DIR))
|
||||
|
||||
from symlink_test_utils import symlink_or_skip
|
||||
|
||||
import fix_skills_metadata
|
||||
|
||||
|
||||
@@ -22,7 +24,7 @@ class FixSkillsMetadataSecurityTests(unittest.TestCase):
|
||||
|
||||
target = outside_dir / "SKILL.md"
|
||||
target.write_text("---\nname: outside\n---\nbody\n", encoding="utf-8")
|
||||
(skill_dir / "SKILL.md").symlink_to(target)
|
||||
symlink_or_skip(self, target, skill_dir / "SKILL.md")
|
||||
|
||||
fix_skills_metadata.fix_skills(root)
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ TOOLS_SCRIPTS_DIR = REPO_ROOT / "tools" / "scripts"
|
||||
if str(TOOLS_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(TOOLS_SCRIPTS_DIR))
|
||||
|
||||
from symlink_test_utils import symlink_or_skip
|
||||
|
||||
|
||||
def load_module(relative_path: str, module_name: str):
|
||||
module_path = REPO_ROOT / relative_path
|
||||
@@ -127,7 +129,7 @@ This paragraph should never be written back through a symlink.
|
||||
"""
|
||||
target.write_text(original, encoding="utf-8")
|
||||
skill_path = skill_dir / "SKILL.md"
|
||||
skill_path.symlink_to(target)
|
||||
symlink_or_skip(self, target, skill_path)
|
||||
|
||||
changed, new_description = fix_truncated_descriptions.update_skill_file(skill_path)
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ TOOLS_SCRIPTS_DIR = REPO_ROOT / "tools" / "scripts"
|
||||
if str(TOOLS_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(TOOLS_SCRIPTS_DIR))
|
||||
|
||||
from symlink_test_utils import symlink_or_skip
|
||||
|
||||
|
||||
def load_module(relative_path: str, module_name: str):
|
||||
module_path = REPO_ROOT / relative_path
|
||||
@@ -128,7 +130,7 @@ class FrontmatterParsingSecurityTests(unittest.TestCase):
|
||||
(safe_skill / "SKILL.md").write_text("---\nname: safe-skill\ndescription: safe\n---\n", encoding="utf-8")
|
||||
target = outside_dir / "SKILL.md"
|
||||
target.write_text("---\nname: outside\ndescription: outside\n---\n", encoding="utf-8")
|
||||
(linked_skill / "SKILL.md").symlink_to(target)
|
||||
symlink_or_skip(self, target, linked_skill / "SKILL.md")
|
||||
|
||||
skills = generate_index.generate_index(str(skills_dir), str(output_file))
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import unittest
|
||||
REPO_ROOT = pathlib.Path(__file__).resolve().parents[3]
|
||||
sys.path.insert(0, str(REPO_ROOT / "tools" / "scripts"))
|
||||
|
||||
from symlink_test_utils import symlink_or_skip
|
||||
|
||||
|
||||
def load_module(module_path: str, module_name: str):
|
||||
spec = importlib.util.spec_from_file_location(module_name, REPO_ROOT / module_path)
|
||||
@@ -40,7 +42,7 @@ class GenerateIndexSecurityTests(unittest.TestCase):
|
||||
(safe_skill_dir / "SKILL.md").write_text("---\nname: Safe Skill\n---\nbody\n", encoding="utf-8")
|
||||
target = outside_dir / "secret.txt"
|
||||
target.write_text("outside data", encoding="utf-8")
|
||||
(linked_skill_dir / "SKILL.md").symlink_to(target)
|
||||
symlink_or_skip(self, target, linked_skill_dir / "SKILL.md")
|
||||
|
||||
skills = generate_index.generate_index(str(skills_dir), str(output_file))
|
||||
|
||||
|
||||
+9
-7
@@ -8,6 +8,8 @@ TOOLS_SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(TOOLS_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(TOOLS_SCRIPTS_DIR))
|
||||
|
||||
from symlink_test_utils import symlink_or_skip
|
||||
|
||||
import sync_microsoft_skills as sms
|
||||
|
||||
|
||||
@@ -25,12 +27,12 @@ class SyncMicrosoftSkillsSecurityTests(unittest.TestCase):
|
||||
safe_skill = root / ".github" / "skills" / "safe-skill"
|
||||
safe_skill.mkdir(parents=True)
|
||||
(safe_skill / "SKILL.md").write_text("---\nname: safe-skill\n---\n", encoding="utf-8")
|
||||
(skills_dir / "safe-skill").symlink_to(safe_skill, target_is_directory=True)
|
||||
symlink_or_skip(self, safe_skill, skills_dir / "safe-skill", target_is_directory=True)
|
||||
|
||||
outside = Path(tempfile.mkdtemp())
|
||||
try:
|
||||
(outside / "SKILL.md").write_text("---\nname: leaked\n---\n", encoding="utf-8")
|
||||
(skills_dir / "escape").symlink_to(outside, target_is_directory=True)
|
||||
symlink_or_skip(self, outside, skills_dir / "escape", target_is_directory=True)
|
||||
|
||||
entries = sms.find_skills_in_directory(root)
|
||||
relative_paths = {str(entry["relative_path"]) for entry in entries}
|
||||
@@ -58,7 +60,7 @@ class SyncMicrosoftSkillsSecurityTests(unittest.TestCase):
|
||||
try:
|
||||
target = outside / "SKILL.md"
|
||||
target.write_text("---\nname: escaped\n---\n", encoding="utf-8")
|
||||
(linked_skill / "SKILL.md").symlink_to(target)
|
||||
symlink_or_skip(self, target, linked_skill / "SKILL.md")
|
||||
|
||||
entries = sms.find_skills_in_directory(root)
|
||||
relative_paths = {str(entry["relative_path"]) for entry in entries}
|
||||
@@ -83,7 +85,7 @@ class SyncMicrosoftSkillsSecurityTests(unittest.TestCase):
|
||||
escaped = outside / "escaped-skill"
|
||||
escaped.mkdir()
|
||||
(escaped / "SKILL.md").write_text("---\nname: escaped\n---\n", encoding="utf-8")
|
||||
(github_skills / "escape").symlink_to(escaped, target_is_directory=True)
|
||||
symlink_or_skip(self, escaped, github_skills / "escape", target_is_directory=True)
|
||||
|
||||
entries = sms.find_github_skills(root, set())
|
||||
relative_paths = {str(entry["relative_path"]) for entry in entries}
|
||||
@@ -112,7 +114,7 @@ class SyncMicrosoftSkillsSecurityTests(unittest.TestCase):
|
||||
try:
|
||||
target = outside / "SKILL.md"
|
||||
target.write_text("---\nname: escaped\n---\n", encoding="utf-8")
|
||||
(linked_skill / "SKILL.md").symlink_to(target)
|
||||
symlink_or_skip(self, target, linked_skill / "SKILL.md")
|
||||
|
||||
entries = sms.find_github_skills(root, set())
|
||||
relative_paths = {str(entry["relative_path"]) for entry in entries}
|
||||
@@ -139,7 +141,7 @@ class SyncMicrosoftSkillsSecurityTests(unittest.TestCase):
|
||||
try:
|
||||
target = outside / "SKILL.md"
|
||||
target.write_text("---\nname: escaped\n---\n", encoding="utf-8")
|
||||
(linked_plugin / "SKILL.md").symlink_to(target)
|
||||
symlink_or_skip(self, target, linked_plugin / "SKILL.md")
|
||||
|
||||
entries = sms.find_plugin_skills(root, set())
|
||||
relative_paths = {str(entry["relative_path"]) for entry in entries}
|
||||
@@ -158,7 +160,7 @@ class SyncMicrosoftSkillsSecurityTests(unittest.TestCase):
|
||||
|
||||
outside = root / "outside-license.txt"
|
||||
outside.write_text("secret license payload", encoding="utf-8")
|
||||
(source / "LICENSE").symlink_to(outside)
|
||||
symlink_or_skip(self, outside, source / "LICENSE")
|
||||
|
||||
previous_docs_dir = sms.DOCS_DIR
|
||||
sms.DOCS_DIR = docs
|
||||
|
||||
@@ -10,6 +10,8 @@ TOOLS_SCRIPTS_DIR = REPO_ROOT / "tools" / "scripts"
|
||||
if str(TOOLS_SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(TOOLS_SCRIPTS_DIR))
|
||||
|
||||
from symlink_test_utils import symlink_or_skip
|
||||
|
||||
|
||||
def load_module(relative_path: str, module_name: str):
|
||||
module_path = REPO_ROOT / relative_path
|
||||
@@ -165,7 +167,7 @@ If you want a faster answer than "browse all 1,273+ skills", start with a tool-s
|
||||
outside = root / "outside.md"
|
||||
outside.write_text("original", encoding="utf-8")
|
||||
linked = root / "README.md"
|
||||
linked.symlink_to(outside)
|
||||
symlink_or_skip(self, outside, linked)
|
||||
|
||||
changed = sync_repo_metadata.update_text_file(
|
||||
linked,
|
||||
|
||||
@@ -7,6 +7,8 @@ import types
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from symlink_test_utils import symlink_or_skip
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
MODULE_PATH = REPO_ROOT / "skills" / "videodb" / "scripts" / "ws_listener.py"
|
||||
@@ -47,7 +49,7 @@ class WsListenerSecurityTests(unittest.TestCase):
|
||||
module.OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
outside = state_home / "outside.txt"
|
||||
outside.write_text("secret", encoding="utf-8")
|
||||
module.PID_FILE.symlink_to(outside)
|
||||
symlink_or_skip(self, outside, module.PID_FILE)
|
||||
|
||||
with self.assertRaises(OSError):
|
||||
module.write_pid()
|
||||
@@ -73,7 +75,7 @@ class WsListenerSecurityTests(unittest.TestCase):
|
||||
module.OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
outside = state_home / "outside.jsonl"
|
||||
outside.write_text("secret\n", encoding="utf-8")
|
||||
module.EVENTS_FILE.symlink_to(outside)
|
||||
symlink_or_skip(self, outside, module.EVENTS_FILE)
|
||||
|
||||
with self.assertRaises(OSError):
|
||||
module.append_event({"channel": "demo"})
|
||||
|
||||
Reference in New Issue
Block a user