Restrict auto-apply to trusted review comments so spoofed issue comments cannot write optimized SKILL.md content into pull request branches. Reject activation symlinks that escape the source root and add regression coverage for both security checks.
77 lines
2.5 KiB
JavaScript
77 lines
2.5 KiB
JavaScript
const assert = require("assert");
|
|
const fs = require("fs");
|
|
const os = require("os");
|
|
const path = require("path");
|
|
const { spawnSync } = require("child_process");
|
|
|
|
const repoRoot = path.resolve(__dirname, "../..", "..");
|
|
const scriptPath = path.join(repoRoot, "scripts", "activate-skills.sh");
|
|
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), "activate-skills-shell-"));
|
|
const baseDir = path.join(root, "antigravity");
|
|
const repoSkills = path.join(root, "repo-skills");
|
|
const outsideDir = path.join(root, "outside-skill-root");
|
|
|
|
function makeSkill(skillId) {
|
|
const skillDir = path.join(repoSkills, skillId);
|
|
fs.mkdirSync(skillDir, { recursive: true });
|
|
fs.writeFileSync(
|
|
path.join(skillDir, "SKILL.md"),
|
|
`---\nname: ${skillId}\ndescription: test skill\ncategory: testing\nrisk: safe\nsource: community\ndate_added: "2026-03-22"\n---\n`,
|
|
"utf8",
|
|
);
|
|
}
|
|
|
|
try {
|
|
makeSkill("brainstorming");
|
|
makeSkill("systematic-debugging");
|
|
makeSkill("custom-skill");
|
|
fs.mkdirSync(outsideDir, { recursive: true });
|
|
fs.writeFileSync(path.join(outsideDir, "secret.txt"), "outside", "utf8");
|
|
fs.symlinkSync(outsideDir, path.join(repoSkills, "escape-link"), "dir");
|
|
|
|
const result = spawnSync(
|
|
"bash",
|
|
[scriptPath, "--clear", "brainstorming", "custom-skill"],
|
|
{
|
|
cwd: repoRoot,
|
|
env: {
|
|
...process.env,
|
|
AG_BASE_DIR: baseDir,
|
|
AG_REPO_SKILLS_DIR: repoSkills,
|
|
AG_PYTHON_BIN: "python3",
|
|
},
|
|
encoding: "utf8",
|
|
},
|
|
);
|
|
|
|
assert.strictEqual(result.status, 0, result.stderr || result.stdout);
|
|
assert.ok(
|
|
fs.existsSync(path.join(baseDir, "skills", "brainstorming", "SKILL.md")),
|
|
"brainstorming should be activated into the live skills directory",
|
|
);
|
|
assert.ok(
|
|
fs.existsSync(path.join(baseDir, "skills", "custom-skill", "SKILL.md")),
|
|
"literal safe skill ids should be activated from the library",
|
|
);
|
|
assert.ok(
|
|
fs.existsSync(path.join(baseDir, "skills_library", "brainstorming", "SKILL.md")),
|
|
"repo skills should be synced into the backing library",
|
|
);
|
|
assert.ok(
|
|
!fs.existsSync(path.join(baseDir, "skills_library", "escape-link")),
|
|
"repo sync must not copy symlinked skills that point outside the source root",
|
|
);
|
|
assert.ok(
|
|
!fs.existsSync(path.join(baseDir, "skills", "escape-link")),
|
|
"unsafe symlinked skills must never become active",
|
|
);
|
|
assert.match(
|
|
result.stdout,
|
|
/Done! Antigravity skills are now activated\./,
|
|
"script should report successful activation",
|
|
);
|
|
} finally {
|
|
fs.rmSync(root, { recursive: true, force: true });
|
|
}
|