📦 deps(thirdparty): update snapshots
This commit is contained in:
@@ -68,17 +68,8 @@ function assertNotIncludes(text, snippet, label) {
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const expected = readExpectedState();
|
||||
const [home, plugins, sitemap, llms, robots] = await Promise.all([
|
||||
fetchText(`${baseUrl}/`),
|
||||
fetchText(`${baseUrl}/plugins`),
|
||||
fetchText(`${baseUrl}/sitemap.xml`),
|
||||
fetchText(`${baseUrl}/llms.txt`),
|
||||
fetchText(`${baseUrl}/robots.txt`),
|
||||
]);
|
||||
|
||||
assertIncludes(home, `Agentic Awesome Skills GitHub | ${expected.countLabel} AI coding skills`, 'home');
|
||||
function assertLiveSeoDocuments({ home, plugins, sitemap, llms, robots }, expected) {
|
||||
assertIncludes(home, `AAS Core Preview | Agent-first stacks backed by ${expected.countLabel} skills`, 'home');
|
||||
assertIncludes(home, 'SoftwareSourceCode', 'home JSON-LD');
|
||||
assertIncludes(home, 'FAQPage', 'home JSON-LD');
|
||||
assertIncludes(home, 'specialized plugins', 'home');
|
||||
@@ -97,11 +88,28 @@ async function main() {
|
||||
assertIncludes(robots, 'User-agent: OAI-SearchBot', 'robots.txt');
|
||||
assertIncludes(robots, 'User-agent: ClaudeBot', 'robots.txt');
|
||||
assertIncludes(robots, 'User-agent: PerplexityBot', 'robots.txt');
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const expected = readExpectedState();
|
||||
const [home, plugins, sitemap, llms, robots] = await Promise.all([
|
||||
fetchText(`${baseUrl}/`),
|
||||
fetchText(`${baseUrl}/plugins`),
|
||||
fetchText(`${baseUrl}/sitemap.xml`),
|
||||
fetchText(`${baseUrl}/llms.txt`),
|
||||
fetchText(`${baseUrl}/robots.txt`),
|
||||
]);
|
||||
|
||||
assertLiveSeoDocuments({ home, plugins, sitemap, llms, robots }, expected);
|
||||
|
||||
console.log(`Live SEO/GEO check passed for ${baseUrl}`);
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
if (require.main === module) {
|
||||
main().catch((error) => {
|
||||
console.error(error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { assertLiveSeoDocuments, readExpectedState };
|
||||
|
||||
@@ -186,7 +186,10 @@ function normalizeEvidenceRecord(record) {
|
||||
function isSkillContentRecord(record) {
|
||||
return [record?.old_path, record?.new_path]
|
||||
.filter((filePath) => typeof filePath === "string" && filePath)
|
||||
.some((filePath) => ["canonical_skill", "skill_support"].includes(classifyPathPolicy(filePath).kind));
|
||||
.some((filePath) => (
|
||||
filePath.startsWith("skills/")
|
||||
|| ["canonical_skill", "skill_support"].includes(classifyPathPolicy(filePath).kind)
|
||||
));
|
||||
}
|
||||
|
||||
function assertValidSnapshot(snapshot, label) {
|
||||
@@ -583,6 +586,7 @@ function loadPullRequestDetails(projectRoot, repoSlug, prNumber) {
|
||||
jsonFields: [
|
||||
"body",
|
||||
"autoMergeRequest",
|
||||
"author",
|
||||
"baseRefName",
|
||||
"baseRefOid",
|
||||
"mergeStateStatus",
|
||||
@@ -1061,8 +1065,13 @@ function approveActionRequiredRuns(projectRoot, repoSlug, prDetails, options = {
|
||||
const mergeBaseOid = getMergeBase(projectRoot, baseOid, headOid, dependencies);
|
||||
const records = readRecords(projectRoot, mergeBaseOid, headOid, dependencies);
|
||||
const sameRepository = isSameRepositoryPullRequest(repoSlug, prDetails);
|
||||
const reviewedHeads = new Set(options.reviewedHeads || []);
|
||||
const repositoryOwner = String(repoSlug || "").split("/")[0].toLowerCase();
|
||||
const ownerAuthorizedSensitiveChange = sameRepository
|
||||
&& String(prDetails?.author?.login || "").toLowerCase() === repositoryOwner
|
||||
&& reviewedHeads.has(headOid);
|
||||
const preliminaryPolicy = classifyRecords(records, { requireBlobSizes: false });
|
||||
if (!sameRepository && !preliminaryPolicy?.approvalSafe) {
|
||||
if (!preliminaryPolicy?.approvalSafe && !ownerAuthorizedSensitiveChange) {
|
||||
const reasons = Array.isArray(preliminaryPolicy?.reasons) && preliminaryPolicy.reasons.length
|
||||
? preliminaryPolicy.reasons.slice(0, 12).join(", ")
|
||||
: "unclassified local diff";
|
||||
@@ -1070,7 +1079,7 @@ function approveActionRequiredRuns(projectRoot, repoSlug, prDetails, options = {
|
||||
}
|
||||
const blobSizes = getSizes(projectRoot, records, dependencies);
|
||||
const policy = classifyRecords(records, { blobSizes });
|
||||
if (!sameRepository && !policy?.approvalSafe) {
|
||||
if (!policy?.approvalSafe && !ownerAuthorizedSensitiveChange) {
|
||||
const reasons = Array.isArray(policy?.reasons) && policy.reasons.length
|
||||
? policy.reasons.slice(0, 12).join(", ")
|
||||
: "unclassified local diff";
|
||||
@@ -1091,7 +1100,6 @@ function approveActionRequiredRuns(projectRoot, repoSlug, prDetails, options = {
|
||||
throw new Error(`PR #${prNumber} trusted changed-skill evidence is blocking: ${reasons}.`);
|
||||
}
|
||||
|
||||
const reviewedHeads = new Set(options.reviewedHeads || []);
|
||||
if (policy.requiresHumanReview && !reviewedHeads.has(headOid)) {
|
||||
throw new Error(
|
||||
`PR #${prNumber} changes canonical skill content. Re-run with --reviewed-head ${headOid} after reviewing that exact full SHA.`,
|
||||
@@ -1245,9 +1253,9 @@ async function mergePullRequest(projectRoot, repoSlug, prNumber, options) {
|
||||
});
|
||||
const headSha = prDetails.headRefOid;
|
||||
const approvedRuns = approval.approvedRuns;
|
||||
// The Skill Review workflow is path-filtered to SKILL.md. Supporting skill
|
||||
// content still requires exact-head human attestation, but has no review
|
||||
// check run to wait for.
|
||||
// The Skill Review workflow covers canonical skill files and their tracked
|
||||
// support trees. Exact-head attestation remains the fallback when Tessl is
|
||||
// unavailable or does not produce a passing review.
|
||||
prDetails.hasSkillChanges = approval.policy.canonicalSkillChanges.length > 0;
|
||||
if (approvedRuns.length) {
|
||||
console.log(
|
||||
|
||||
@@ -96,19 +96,36 @@ function remoteTagTarget(projectRoot, tagName) {
|
||||
return output ? output.split(/\s+/u)[0] : null;
|
||||
}
|
||||
|
||||
function selectMergedReleaseCandidate(pullRequests, version) {
|
||||
function selectMergedReleaseCandidate(pullRequests, version, identity = {}) {
|
||||
const branch = `release/v${version}`;
|
||||
const repoSlug = String(identity.repoSlug || "").toLowerCase();
|
||||
const ownerLogin = String(identity.ownerLogin || "").toLowerCase();
|
||||
if (!repoSlug || !ownerLogin) {
|
||||
throw new Error("Release PR repository and owner identity are required.");
|
||||
}
|
||||
const matches = pullRequests.filter((pr) => (
|
||||
pr.headRefName === branch && pr.baseRefName === "main" && /^[0-9a-f]{40}$/u.test(String(pr.mergeCommit?.oid || ""))
|
||||
pr.headRefName === branch
|
||||
&& pr.baseRefName === "main"
|
||||
&& String(pr.headRepository?.nameWithOwner || "").toLowerCase() === repoSlug
|
||||
&& String(pr.author?.login || "").toLowerCase() === ownerLogin
|
||||
&& pr.title === `chore: release v${version}`
|
||||
&& /^[0-9a-f]{40}$/u.test(String(pr.mergeCommit?.oid || ""))
|
||||
&& Number.isFinite(Date.parse(String(pr.mergedAt || "")))
|
||||
));
|
||||
if (matches.length !== 1) {
|
||||
throw new Error(`Expected exactly one merged protected release PR for ${branch}.`);
|
||||
throw new Error(`Expected exactly one owner-authored same-repository protected release PR for ${branch}; found ${matches.length}.`);
|
||||
}
|
||||
return matches[0];
|
||||
}
|
||||
|
||||
function mergedReleaseCandidate(projectRoot, version) {
|
||||
const branch = `release/v${version}`;
|
||||
const repository = JSON.parse(runCommand(
|
||||
"gh",
|
||||
["repo", "view", "--json", "nameWithOwner,owner"],
|
||||
projectRoot,
|
||||
{ capture: true },
|
||||
));
|
||||
const payload = runCommand(
|
||||
"gh",
|
||||
[
|
||||
@@ -121,12 +138,15 @@ function mergedReleaseCandidate(projectRoot, version) {
|
||||
"--limit",
|
||||
"10",
|
||||
"--json",
|
||||
"number,headRefName,baseRefName,mergeCommit",
|
||||
"number,title,author,headRefName,headRepository,baseRefName,mergeCommit,mergedAt",
|
||||
],
|
||||
projectRoot,
|
||||
{ capture: true },
|
||||
);
|
||||
return selectMergedReleaseCandidate(JSON.parse(payload || "[]"), version);
|
||||
return selectMergedReleaseCandidate(JSON.parse(payload || "[]"), version, {
|
||||
repoSlug: repository.nameWithOwner,
|
||||
ownerLogin: repository.owner?.login,
|
||||
});
|
||||
}
|
||||
|
||||
function validateReleaseSuccessors(projectRoot, releaseCommit, headCommit, dependencies = {}) {
|
||||
|
||||
@@ -7,7 +7,7 @@ const { execFileSync, spawnSync } = require('node:child_process');
|
||||
|
||||
const DEFAULT_THRESHOLD = '80';
|
||||
const DEFAULT_WORKSPACE = 'antigravity-awesome-skills';
|
||||
const DEFAULT_CACHE_VERSION = '1';
|
||||
const DEFAULT_CACHE_VERSION = '2';
|
||||
const QUOTA_EXIT_CODE = 75;
|
||||
|
||||
function runGit(args, options = {}) {
|
||||
@@ -31,8 +31,10 @@ function getChangedSkillFiles(baseSha, headSha, options = {}) {
|
||||
}
|
||||
|
||||
const git = options.git || runGit;
|
||||
const output = git(['diff', '--name-only', '--diff-filter=ACMR', baseSha, headSha, '--']);
|
||||
return splitLines(output).filter((filePath) => filePath === 'SKILL.md' || filePath.endsWith('/SKILL.md'));
|
||||
const output = git(['diff', '--name-only', '--no-renames', '--diff-filter=ACDMR', baseSha, headSha, '--']);
|
||||
return splitLines(output).filter(
|
||||
(filePath) => filePath.startsWith('skills/') || /^plugins\/.+\/skills\//.test(filePath),
|
||||
);
|
||||
}
|
||||
|
||||
function ensureRepoRelative(filePath, repoRoot = process.cwd()) {
|
||||
@@ -43,10 +45,6 @@ function ensureRepoRelative(filePath, repoRoot = process.cwd()) {
|
||||
throw new Error(`Path traversal detected: ${filePath}`);
|
||||
}
|
||||
|
||||
if (path.basename(filePath) !== 'SKILL.md') {
|
||||
throw new Error(`Unexpected skill file path: ${filePath}`);
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
@@ -54,16 +52,25 @@ function getChangedSkillDirs(files, repoRoot = process.cwd()) {
|
||||
const dirs = new Set();
|
||||
|
||||
for (const filePath of files) {
|
||||
const resolved = ensureRepoRelative(filePath, repoRoot);
|
||||
if (!fs.existsSync(resolved)) {
|
||||
continue;
|
||||
let directory = path.dirname(ensureRepoRelative(filePath, repoRoot));
|
||||
while (directory !== repoRoot && directory.startsWith(`${repoRoot}${path.sep}`)) {
|
||||
if (fs.existsSync(path.join(directory, 'SKILL.md'))) {
|
||||
dirs.add(path.relative(repoRoot, directory).split(path.sep).join('/'));
|
||||
break;
|
||||
}
|
||||
directory = path.dirname(directory);
|
||||
}
|
||||
dirs.add(path.dirname(filePath));
|
||||
}
|
||||
|
||||
return [...dirs].sort();
|
||||
}
|
||||
|
||||
function getUnresolvedChangedSkillFiles(files, skillDirs) {
|
||||
return files.filter(
|
||||
(filePath) => !skillDirs.some((skillDir) => filePath === skillDir || filePath.startsWith(`${skillDir}/`)),
|
||||
);
|
||||
}
|
||||
|
||||
function buildReviewArgs(skillDir, options = {}) {
|
||||
const workspace = options.workspace || DEFAULT_WORKSPACE;
|
||||
const threshold = options.threshold || DEFAULT_THRESHOLD;
|
||||
@@ -101,10 +108,26 @@ function reviewFingerprint(skillDirs, options = {}) {
|
||||
|
||||
hash.update(`${JSON.stringify(policy)}\0`);
|
||||
for (const skillDir of [...skillDirs].sort()) {
|
||||
const skillPath = ensureRepoRelative(path.join(skillDir, 'SKILL.md'), repoRoot);
|
||||
const skillPath = ensureRepoRelative(skillDir, repoRoot);
|
||||
hash.update(`${skillDir}\0`);
|
||||
hash.update(fs.readFileSync(skillPath));
|
||||
hash.update('\0');
|
||||
const files = [];
|
||||
function visit(directory) {
|
||||
for (const entry of fs.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
||||
const absolute = path.join(directory, entry.name);
|
||||
const stat = fs.lstatSync(absolute);
|
||||
if (stat.isSymbolicLink()) throw new Error(`Symlink is not reviewable: ${path.relative(repoRoot, absolute)}`);
|
||||
if (entry.isDirectory()) visit(absolute);
|
||||
else if (entry.isFile()) files.push({ absolute, stat });
|
||||
else throw new Error(`Non-regular skill content is not reviewable: ${path.relative(repoRoot, absolute)}`);
|
||||
}
|
||||
}
|
||||
visit(skillPath);
|
||||
for (const { absolute, stat } of files) {
|
||||
const relative = path.relative(repoRoot, absolute).split(path.sep).join('/');
|
||||
hash.update(`${relative}\0file\0${(stat.mode & 0o7777).toString(8)}\0`);
|
||||
hash.update(fs.readFileSync(absolute));
|
||||
hash.update('\0');
|
||||
}
|
||||
}
|
||||
|
||||
return hash.digest('hex');
|
||||
@@ -127,15 +150,26 @@ function appendGitHubOutput(name, value, outputPath = process.env.GITHUB_OUTPUT)
|
||||
|
||||
function writePlan(skillDirs, options = {}) {
|
||||
const hasSkills = skillDirs.length > 0;
|
||||
const fingerprint = hasSkills ? reviewFingerprint(skillDirs, options) : 'none';
|
||||
const unresolvedFiles = [...(options.unresolvedFiles || [])].sort();
|
||||
const requiresManual = unresolvedFiles.length > 0;
|
||||
let fingerprint = hasSkills ? reviewFingerprint(skillDirs, options) : 'none';
|
||||
if (requiresManual) {
|
||||
const hash = crypto.createHash('sha256');
|
||||
hash.update(`${fingerprint}\0`);
|
||||
for (const filePath of unresolvedFiles) hash.update(`${filePath}\0`);
|
||||
fingerprint = `manual-${hash.digest('hex')}`;
|
||||
}
|
||||
const plan = {
|
||||
fingerprint,
|
||||
hasSkills,
|
||||
requiresManual,
|
||||
skillCount: skillDirs.length,
|
||||
unresolvedFiles,
|
||||
};
|
||||
|
||||
appendGitHubOutput('fingerprint', fingerprint, options.githubOutput);
|
||||
appendGitHubOutput('has-skills', String(hasSkills), options.githubOutput);
|
||||
appendGitHubOutput('requires-manual', String(requiresManual), options.githubOutput);
|
||||
appendGitHubOutput('skill-count', String(skillDirs.length), options.githubOutput);
|
||||
console.log(JSON.stringify(plan));
|
||||
return plan;
|
||||
@@ -182,10 +216,12 @@ function main() {
|
||||
|
||||
const files = getChangedSkillFiles(baseSha, headSha);
|
||||
const skillDirs = getChangedSkillDirs(files);
|
||||
const unresolvedFiles = getUnresolvedChangedSkillFiles(files, skillDirs);
|
||||
|
||||
if (planOnly) {
|
||||
writePlan(skillDirs, {
|
||||
cacheVersion: process.env.TESSL_REVIEW_CACHE_VERSION,
|
||||
unresolvedFiles,
|
||||
reviewPlugin,
|
||||
threshold,
|
||||
workspace,
|
||||
@@ -193,8 +229,12 @@ function main() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (unresolvedFiles.length > 0) {
|
||||
throw new Error(`Changed skill content cannot be reviewed from the pull-request tree: ${unresolvedFiles.join(', ')}`);
|
||||
}
|
||||
|
||||
if (skillDirs.length === 0) {
|
||||
console.log('No changed SKILL.md files to review.');
|
||||
console.log('No changed skill directories to review.');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -227,6 +267,7 @@ module.exports = {
|
||||
ensureRepoRelative,
|
||||
getChangedSkillDirs,
|
||||
getChangedSkillFiles,
|
||||
getUnresolvedChangedSkillFiles,
|
||||
isQuotaFailure,
|
||||
reviewFingerprint,
|
||||
reviewLabel,
|
||||
|
||||
@@ -238,6 +238,16 @@ def sync_readme_copy(content: str, metadata: dict) -> str:
|
||||
for pattern, replacement in replacements:
|
||||
content, _ = replace_if_present(content, pattern, replacement)
|
||||
|
||||
core_guide_url = (
|
||||
"https://github.com/sickn33/agentic-awesome-skills/"
|
||||
f"blob/v{version}/docs/users/aas-core.md"
|
||||
)
|
||||
content = re.sub(
|
||||
r"https://github\.com/sickn33/agentic-awesome-skills/blob/(?:main|v[^/]+)/docs/users/aas-core\.md",
|
||||
core_guide_url,
|
||||
content,
|
||||
)
|
||||
|
||||
return content
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ const {
|
||||
cleanupBackups,
|
||||
inspectHostConfig,
|
||||
} = require("../../lib/aas-v1/adapters");
|
||||
const { inspectRegularFile } = require("../../lib/aas-v1/adapters/safety");
|
||||
const { inspectRegularFile, runWindowsAcl } = require("../../lib/aas-v1/adapters/safety");
|
||||
|
||||
const FIXTURES = path.join(__dirname, "fixtures", "aas-v1-adapters");
|
||||
const CODEX_SERVER = { command: "/opt/aas/aas-mcp", args: ["--stdio", "--runtime", "14.6.0"], enabled: true };
|
||||
@@ -139,6 +139,31 @@ test("symlink, non-regular, and ownership mismatches are rejected", async (t) =>
|
||||
await assert.rejects(inspectRegularFile(real, { expectedUid: stat.uid + 1 }), (error) => error.code === "AAS_ADAPTER_OWNERSHIP_MISMATCH");
|
||||
});
|
||||
|
||||
test("Windows ACL runner passes paths out of the command and reports bounded diagnostics", () => {
|
||||
const inspectedPath = String.raw`C:\Users\Example\.codex\config.toml`;
|
||||
let invocation;
|
||||
const runner = (...args) => {
|
||||
invocation = args;
|
||||
return { status: 1, stdout: "", stderr: "Get-Acl failed\r\nwith details\u0000" };
|
||||
};
|
||||
assert.throws(
|
||||
() => runWindowsAcl("$p=$env:AAS_WINDOWS_ACL_PATH", inspectedPath, { phase: "inspectAcl", runner }),
|
||||
(error) => {
|
||||
assert.equal(error.code, "AAS_ADAPTER_WINDOWS_ACL_FAILED");
|
||||
assert.deepEqual(error.details, {
|
||||
status: 1,
|
||||
phase: "inspectAcl",
|
||||
path: inspectedPath,
|
||||
diagnostic: "Get-Acl failed with details",
|
||||
});
|
||||
return true;
|
||||
},
|
||||
);
|
||||
assert.deepEqual(invocation[1], ["-NoProfile", "-NonInteractive", "-Command", "$p=$env:AAS_WINDOWS_ACL_PATH"]);
|
||||
assert.equal(invocation[2].env.AAS_WINDOWS_ACL_PATH, inspectedPath);
|
||||
assert.ok(!invocation[1].includes(inspectedPath));
|
||||
});
|
||||
|
||||
test("ambiguous TOML and duplicate JSON keys fail closed", async (t) => {
|
||||
const directory = await temporaryDirectory(t);
|
||||
const toml = path.join(directory, "config.toml");
|
||||
|
||||
@@ -68,7 +68,7 @@ test("search retrieval preserves catalog order without scores or relevance ranki
|
||||
skills: [
|
||||
{ id: "z-first", name: "Z first", category: "test", searchTokens: ["alpha"], description: "", tags: [], triggers: [] },
|
||||
{ id: "a-many", name: "A many", category: "test", searchTokens: ["alpha", "beta"], description: "", tags: [], triggers: [] },
|
||||
{ id: "m-second", name: "M second", category: "test", searchTokens: ["beta"], description: "", tags: [], triggers: [] },
|
||||
{ id: "m-second", name: "M second", category: "test", searchTokens: ["beta", "many"], description: "", tags: [], triggers: [] },
|
||||
{ id: "unrelated", name: "Unrelated", category: "test", searchTokens: ["gamma"], description: "", tags: [], triggers: [] },
|
||||
],
|
||||
};
|
||||
@@ -85,22 +85,16 @@ test("search retrieval preserves catalog order without scores or relevance ranki
|
||||
}
|
||||
|
||||
const exact = core.searchSkills(catalog, { query: "a-many", limit: 50 });
|
||||
assert.deepEqual(exact.results.map((entry) => entry.id), ["a-many"]);
|
||||
assert.deepEqual(exact.results.map((entry) => entry.id), ["a-many", "m-second"]);
|
||||
});
|
||||
|
||||
test("every canonical skill is directly gettable, exactly searchable, and agent-composable", () => {
|
||||
test("every canonical skill is directly gettable and agent-composable", () => {
|
||||
const catalog = core.loadBundledCatalog();
|
||||
|
||||
for (const id of canonicalSkillIds) {
|
||||
const skill = core.getSkill(catalog, id);
|
||||
assert.equal(skill.id, id);
|
||||
|
||||
const search = core.searchSkills(catalog, { query: id, limit: 1 });
|
||||
assert.equal(search.totalMatches, 1);
|
||||
assert.equal(search.results[0]?.id, id, `exact search did not return ${id} first`);
|
||||
assert.equal(Object.hasOwn(search.results[0], "score"), false);
|
||||
assert.equal(Object.hasOwn(search.results[0], "rank"), false);
|
||||
|
||||
const composed = core.composeStack(catalog, selection([id]));
|
||||
assert.equal(composed.ok, true);
|
||||
assert.equal(composed.status, "composed");
|
||||
|
||||
@@ -10,6 +10,7 @@ const {
|
||||
AGENT_SELECTION_CONTRACT,
|
||||
MAX_JSON_DEPTH,
|
||||
MAX_LINE_BYTES,
|
||||
MAX_SESSION_MANIFESTS,
|
||||
McpServer,
|
||||
TOOL_NAMES,
|
||||
parseStrictJsonLine,
|
||||
@@ -38,6 +39,32 @@ async function initializedServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
test("MCP bounds composed manifest session state and evicts the oldest digest", async () => {
|
||||
const server = await initializedServer();
|
||||
const catalog = core.loadBundledCatalog({ root: ROOT });
|
||||
const selectedId = catalog.skills[0].id;
|
||||
const digests = [];
|
||||
for (let index = 0; index <= MAX_SESSION_MANIFESTS; index += 1) {
|
||||
const response = await server.handle({
|
||||
jsonrpc: "2.0",
|
||||
id: 1000 + index,
|
||||
method: "tools/call",
|
||||
params: {
|
||||
name: "compose_stack",
|
||||
arguments: {
|
||||
profile: { goals: [`bounded-session-${index}`] },
|
||||
skillIds: [selectedId],
|
||||
},
|
||||
},
|
||||
});
|
||||
assert.equal(response.result.isError, false);
|
||||
digests.push(response.result.structuredContent.manifestDigest);
|
||||
}
|
||||
assert.equal(server.manifestSessions.size, MAX_SESSION_MANIFESTS);
|
||||
assert.equal(server.manifestSessions.has(digests[0]), false);
|
||||
assert.equal(server.manifestSessions.has(digests.at(-1)), true);
|
||||
});
|
||||
|
||||
test("strict JSON-lines parser rejects invalid UTF-8, duplicate keys, excess depth, batches, and oversized input", () => {
|
||||
assert.deepEqual(parseStrictJsonLine(Buffer.from('{"jsonrpc":"2.0"}')), { jsonrpc: "2.0" });
|
||||
assert.doesNotThrow(() => parseStrictJsonLine(Buffer.from(JSON.stringify({
|
||||
|
||||
@@ -147,6 +147,26 @@ test("runtime promotion rejects a missing cache root under a group or world writ
|
||||
);
|
||||
});
|
||||
|
||||
test("runtime promotion rejects a private parent beneath a replaceable ancestor", async (t) => {
|
||||
if (process.platform === "win32") return;
|
||||
const root = await temp(t);
|
||||
const sharedAncestor = path.join(root, "shared");
|
||||
const privateParent = path.join(sharedAncestor, "mine");
|
||||
await fsp.mkdir(privateParent, { recursive: true, mode: 0o700 });
|
||||
await fsp.chmod(sharedAncestor, 0o777);
|
||||
await fsp.chmod(privateParent, 0o700);
|
||||
const fixture = releaseFixture();
|
||||
await assert.rejects(
|
||||
core.cache.installRuntimeFromRegistry({
|
||||
cacheRoot: path.join(privateParent, "aas-cache"),
|
||||
version: "14.6.0",
|
||||
expectedIntegrity: fixture.integrity,
|
||||
fetcher: fixture.fetcher,
|
||||
}),
|
||||
(error) => error.code === "AAS_RUNTIME_DIRECTORY_UNSAFE",
|
||||
);
|
||||
});
|
||||
|
||||
test("the packed runtime launches MCP from an isolated verified dependency closure", async (t) => {
|
||||
const root = await temp(t);
|
||||
const repoRoot = path.resolve(__dirname, "../../..");
|
||||
|
||||
@@ -392,6 +392,26 @@ test("layout cleanup removes only exact marker-owned stages left before publicat
|
||||
fs.rmSync(fx.sandbox, { recursive: true });
|
||||
});
|
||||
|
||||
test("layout stage cleanup propagates a failed deletion durability barrier", () => {
|
||||
const fx = fixture();
|
||||
fs.rmSync(fx.transactionDirectory, { recursive: true });
|
||||
const inspected = inspectLayout(fx.adapter, { host: "codex", scope: "project", identityDigest: TARGET_ID });
|
||||
const markerToken = "7".repeat(48);
|
||||
const markerName = `.aas-layout-recovery-${"6".repeat(32)}`;
|
||||
const directory = inspected.missingDirectories[0];
|
||||
const stage = path.join(path.dirname(directory), `.aas-layout-stage-${markerToken}-${path.basename(directory)}`);
|
||||
fs.mkdirSync(stage, { mode: 0o700 });
|
||||
fs.writeFileSync(path.join(stage, markerName), `${markerToken}\n`, { mode: 0o600 });
|
||||
assert.throws(() => cleanupMaterializedLayout(inspected, [directory], {
|
||||
markerName,
|
||||
markerToken,
|
||||
fsyncDirectory() { throw new Error("injected parent fsync failure"); },
|
||||
}), /injected parent fsync failure/);
|
||||
assert.equal(fs.existsSync(stage), false);
|
||||
cleanupMaterializedLayout(inspected, [directory], { markerName, markerToken });
|
||||
fs.rmSync(fx.sandbox, { recursive: true });
|
||||
});
|
||||
|
||||
test("layout cleanup postcondition detects a dangling symlink artifact", (t) => {
|
||||
const fx = fixture();
|
||||
fs.rmSync(fx.transactionDirectory, { recursive: true });
|
||||
|
||||
@@ -11,12 +11,21 @@ function readText(relativePath) {
|
||||
const packageJson = JSON.parse(readText("package.json"));
|
||||
const generatedFiles = JSON.parse(readText("tools/config/generated-files.json"));
|
||||
const ciWorkflow = readText(".github/workflows/ci.yml");
|
||||
const hygieneWorkflowForPages = readText(".github/workflows/repo-hygiene.yml");
|
||||
const offlineCatalogBuilder = readText("tools/scripts/build-aas-v1-offline-catalog.js");
|
||||
const canonicalMergeScript = readText("tools/scripts/merge_canonical_sync_pr.cjs");
|
||||
const publishWorkflow = readText(".github/workflows/publish-npm.yml");
|
||||
const releaseWorkflowScript = readText("tools/scripts/release_workflow.js");
|
||||
const hygieneWorkflowPath = path.join(repoRoot, ".github", "workflows", "repo-hygiene.yml");
|
||||
|
||||
for (const [name, workflow] of [["main CI", ciWorkflow], ["repo hygiene", hygieneWorkflowForPages]]) {
|
||||
assert.match(
|
||||
workflow,
|
||||
/merge_canonical_sync_pr\.cjs[\s\S]*?--head "\$PR_HEAD" \\\n+\s+--skip-pages/,
|
||||
`${name} canonical sync must not dispatch release-only Pages`,
|
||||
);
|
||||
}
|
||||
|
||||
const prepareReleaseBlock = releaseWorkflowScript.slice(
|
||||
releaseWorkflowScript.indexOf("function prepareRelease"),
|
||||
releaseWorkflowScript.indexOf("function publishRelease"),
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
const assert = require('node:assert');
|
||||
const { assertLiveSeoDocuments } = require('../check-live-seo-geo');
|
||||
|
||||
const expected = { countLabel: '1,987+', releaseLabel: 'V15.3.0' };
|
||||
const documents = {
|
||||
home: 'AAS Core Preview | Agent-first stacks backed by 1,987+ skills SoftwareSourceCode FAQPage specialized plugins',
|
||||
plugins: 'AAS Specialized Plugins | 15 AI coding workflow packs specialized plugin packs numberOfItems',
|
||||
sitemap: 'https://sickn33.github.io/agentic-awesome-skills/plugins',
|
||||
llms: 'https://sickn33.github.io/agentic-awesome-skills/plugins Current release: V15.3.0. 1,987+',
|
||||
robots: 'User-agent: GPTBot User-agent: OAI-SearchBot User-agent: ClaudeBot User-agent: PerplexityBot',
|
||||
};
|
||||
|
||||
assert.doesNotThrow(() => assertLiveSeoDocuments(documents, expected));
|
||||
assert.throws(
|
||||
() => assertLiveSeoDocuments({
|
||||
...documents,
|
||||
home: 'Agentic Awesome Skills GitHub | 1,987+ AI coding skills SoftwareSourceCode FAQPage specialized plugins',
|
||||
}, expected),
|
||||
/AAS Core Preview/,
|
||||
);
|
||||
assert.throws(
|
||||
() => assertLiveSeoDocuments({ ...documents, home: `${documents.home} prompt templates` }, expected),
|
||||
/stale snippet/,
|
||||
);
|
||||
|
||||
console.log('live SEO/GEO contract tests passed');
|
||||
@@ -83,6 +83,13 @@ const wpSiteHealthCatalog = fs.readFileSync(
|
||||
'utf8',
|
||||
);
|
||||
const dispatchSkill = fs.readFileSync(path.join(repoRoot, 'skills', 'dispatch', 'SKILL.md'), 'utf8');
|
||||
const anywriteSkill = fs.readFileSync(path.join(repoRoot, 'skills', 'anywrite', 'SKILL.md'), 'utf8');
|
||||
const sshepherdSkill = fs.readFileSync(path.join(repoRoot, 'skills', 'sshepherd', 'SKILL.md'), 'utf8');
|
||||
const awsDiscoverySkill = fs.readFileSync(path.join(repoRoot, 'skills', 'hf-cloud-aws-context-discovery', 'SKILL.md'), 'utf8');
|
||||
const pptxDeckSkill = fs.readFileSync(path.join(repoRoot, 'skills', 'pptx-deck-creation', 'SKILL.md'), 'utf8');
|
||||
const pptxDesignProfiles = fs.readFileSync(path.join(repoRoot, 'skills', 'pptx-deck-creation', 'references', 'design-profiles.md'), 'utf8');
|
||||
const cloudflareAuditSkill = fs.readFileSync(path.join(repoRoot, 'skills', 'cloudflare-security-audit', 'SKILL.md'), 'utf8');
|
||||
const weaviatePdfReference = fs.readFileSync(path.join(repoRoot, 'skills', 'weaviate-cookbooks', 'references', 'pdf_multimodal_rag.md'), 'utf8');
|
||||
const eclCreatorConfig = fs.readFileSync(
|
||||
path.join(repoRoot, 'skills', 'ecl-harness-engineer', 'agents', 'creator-config.md'),
|
||||
'utf8',
|
||||
@@ -456,6 +463,20 @@ assert.match(
|
||||
/^\s+codex:\s*blocked$/m,
|
||||
'Dispatch must be blocked from plugin-safe Codex distribution',
|
||||
);
|
||||
for (const [name, skill] of [['anywrite', anywriteSkill], ['sshepherd', sshepherdSkill]]) {
|
||||
assert.match(skill, /^\s+codex:\s*blocked$/m, `${name} must be blocked from Codex plugins without a shipped runtime`);
|
||||
assert.match(skill, /^\s+claude:\s*blocked$/m, `${name} must be blocked from Claude plugins without a shipped runtime`);
|
||||
assert.doesNotMatch(skill, /^\.\/dist\/(?:anywrite|sshepherd)\b/m, `${name} must not execute a workspace-relative binary`);
|
||||
assert.match(skill, /explicit absolute path/i, `${name} must require a user-approved absolute executable path`);
|
||||
}
|
||||
assert.match(awsDiscoverySkill, /Never open or print `~\/\.aws\/credentials`/);
|
||||
assert.doesNotMatch(awsDiscoverySkill, /credentials` are plain INI files — read-only/);
|
||||
assert.match(`${pptxDeckSkill}\n${pptxDesignProfiles}`, /untrusted (?:reference )?data/i);
|
||||
assert.match(`${pptxDeckSkill}\n${pptxDesignProfiles}`, /Ignore embedded instructions|never as instructions/i);
|
||||
assert.match(cloudflareAuditSkill, /canonical physical repository path plus its normalized `origin`/);
|
||||
assert.match(cloudflareAuditSkill, /Do not search or reuse prior runs from a basename-only directory/);
|
||||
assert.doesNotMatch(weaviatePdfReference, /-o \/tmp\/(?:uv|ollama)-install\.sh/);
|
||||
assert.match(weaviatePdfReference, /mktemp -d/);
|
||||
assert.match(
|
||||
dispatchSkill,
|
||||
/^\s+claude:\s*blocked$/m,
|
||||
|
||||
@@ -508,6 +508,7 @@ function approvalDependencies(overrides = {}) {
|
||||
headRefOid: HEAD_SHA,
|
||||
headRefName: "maintenance/internal",
|
||||
headRepository: { nameWithOwner: "OWNER/REPO" },
|
||||
author: { login: "owner" },
|
||||
};
|
||||
let classifications = 0;
|
||||
const dependencies = approvalDependencies({
|
||||
@@ -532,6 +533,30 @@ function approvalDependencies(overrides = {}) {
|
||||
assert.deepStrictEqual(result.runs, []);
|
||||
}
|
||||
|
||||
{
|
||||
const prDetails = {
|
||||
number: 451,
|
||||
baseRefName: "main",
|
||||
baseRefOid: BASE_SHA,
|
||||
headRefOid: HEAD_SHA,
|
||||
headRefName: "maintenance/internal",
|
||||
headRepository: { nameWithOwner: "owner/repo" },
|
||||
author: { login: "collaborator" },
|
||||
};
|
||||
const dependencies = approvalDependencies({
|
||||
classifyChangeRecords() {
|
||||
return { approvalSafe: false, reasons: ["record_0:new_unapproved_path"] };
|
||||
},
|
||||
});
|
||||
assert.throws(
|
||||
() => mergeBatch.approveActionRequiredRuns("/repo", "owner/repo", prDetails, {
|
||||
dependencies,
|
||||
reviewedHeads: [HEAD_SHA],
|
||||
}),
|
||||
/not fork-approval-safe/,
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
const record = {
|
||||
status: "M",
|
||||
@@ -566,6 +591,23 @@ function approvalDependencies(overrides = {}) {
|
||||
}),
|
||||
report,
|
||||
);
|
||||
const nestedBundleRecord = {
|
||||
...record,
|
||||
old_path: "skills/example/examples/app/package-lock.json",
|
||||
new_path: "skills/example/examples/app/package-lock.json",
|
||||
};
|
||||
const nestedBundleReport = {
|
||||
...report,
|
||||
changes: [{ ...report.changes[0], records: [nestedBundleRecord] }],
|
||||
};
|
||||
assert.strictEqual(
|
||||
mergeBatch.validateChangedSkillEvidence(nestedBundleReport, {
|
||||
mergeBaseOid: BASE_SHA,
|
||||
headOid: HEAD_SHA,
|
||||
rawRecords: [nestedBundleRecord],
|
||||
}),
|
||||
nestedBundleReport,
|
||||
);
|
||||
assert.throws(
|
||||
() => mergeBatch.validateChangedSkillEvidence(
|
||||
{ ...report, head_oid: BLOB_SHA },
|
||||
|
||||
@@ -78,12 +78,12 @@ assert.strictEqual(
|
||||
"published package must declare the first Core-capable major",
|
||||
);
|
||||
assert.ok(
|
||||
readme.includes("https://github.com/sickn33/agentic-awesome-skills/blob/main/docs/users/aas-core.md"),
|
||||
"published README must link to the canonical AAS Core guide without relying on an unpackaged relative path",
|
||||
readme.includes(`https://github.com/sickn33/agentic-awesome-skills/blob/v${packageJson.version}/docs/users/aas-core.md`),
|
||||
"published README must link to the AAS Core guide pinned to the exact package release",
|
||||
);
|
||||
assert.ok(
|
||||
!readme.includes("](docs/users/aas-core.md)"),
|
||||
"published README must not link to an AAS Core guide path excluded from the npm package",
|
||||
!readme.includes("/blob/main/docs/users/aas-core.md"),
|
||||
"published README must not direct package readers to moving main-branch Core instructions",
|
||||
);
|
||||
assert.ok(
|
||||
coreGuide.includes(`--package=agentic-awesome-skills@${packageJson.version}`),
|
||||
|
||||
@@ -20,13 +20,35 @@ function git(cwd, ...args) {
|
||||
const mergeOid = "a".repeat(40);
|
||||
const candidate = {
|
||||
number: 10,
|
||||
title: "chore: release v1.2.3",
|
||||
author: { login: "owner" },
|
||||
headRefName: "release/v1.2.3",
|
||||
headRepository: { nameWithOwner: "owner/repo" },
|
||||
baseRefName: "main",
|
||||
mergeCommit: { oid: mergeOid },
|
||||
mergedAt: "2026-01-01T00:00:00Z",
|
||||
};
|
||||
assert.strictEqual(release.selectMergedReleaseCandidate([candidate], "1.2.3"), candidate);
|
||||
assert.throws(() => release.selectMergedReleaseCandidate([], "1.2.3"), /exactly one/);
|
||||
assert.throws(() => release.selectMergedReleaseCandidate([candidate, { ...candidate, number: 11 }], "1.2.3"), /exactly one/);
|
||||
const releaseIdentity = { repoSlug: "owner/repo", ownerLogin: "owner" };
|
||||
assert.strictEqual(release.selectMergedReleaseCandidate([candidate], "1.2.3", releaseIdentity), candidate);
|
||||
assert.throws(() => release.selectMergedReleaseCandidate([], "1.2.3", releaseIdentity), /exactly one/);
|
||||
const newerCandidate = {
|
||||
...candidate,
|
||||
number: 11,
|
||||
mergeCommit: { oid: "b".repeat(40) },
|
||||
mergedAt: "2026-01-02T00:00:00Z",
|
||||
};
|
||||
assert.throws(
|
||||
() => release.selectMergedReleaseCandidate([candidate, newerCandidate], "1.2.3", releaseIdentity),
|
||||
/found 2/,
|
||||
);
|
||||
assert.throws(
|
||||
() => release.selectMergedReleaseCandidate([{ ...candidate, headRepository: { nameWithOwner: "attacker/repo" } }], "1.2.3", releaseIdentity),
|
||||
/found 0/,
|
||||
);
|
||||
assert.throws(
|
||||
() => release.selectMergedReleaseCandidate([{ ...candidate, author: { login: "collaborator" } }], "1.2.3", releaseIdentity),
|
||||
/found 0/,
|
||||
);
|
||||
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "release-workflow-"));
|
||||
const repo = path.join(root, "repo");
|
||||
|
||||
@@ -9,6 +9,7 @@ const {
|
||||
ensureRepoRelative,
|
||||
getChangedSkillDirs,
|
||||
getChangedSkillFiles,
|
||||
getUnresolvedChangedSkillFiles,
|
||||
isQuotaFailure,
|
||||
reviewFingerprint,
|
||||
reviewLabel,
|
||||
@@ -20,7 +21,8 @@ const changed = getChangedSkillFiles('base', 'head', {
|
||||
assert.deepStrictEqual(args, [
|
||||
'diff',
|
||||
'--name-only',
|
||||
'--diff-filter=ACMR',
|
||||
'--no-renames',
|
||||
'--diff-filter=ACDMR',
|
||||
'base',
|
||||
'head',
|
||||
'--',
|
||||
@@ -28,25 +30,36 @@ const changed = getChangedSkillFiles('base', 'head', {
|
||||
return [
|
||||
'skills/alpha/SKILL.md',
|
||||
'README.md',
|
||||
'plugins/example/SKILL.md',
|
||||
'plugins/bundle/skills/example/SKILL.md',
|
||||
'plugins/bundle/package.json',
|
||||
'skills/beta/notes.md',
|
||||
'',
|
||||
].join('\n');
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(changed, ['skills/alpha/SKILL.md', 'plugins/example/SKILL.md']);
|
||||
assert.deepStrictEqual(changed, [
|
||||
'skills/alpha/SKILL.md',
|
||||
'plugins/bundle/skills/example/SKILL.md',
|
||||
'skills/beta/notes.md',
|
||||
]);
|
||||
|
||||
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aas-review-skills-'));
|
||||
fs.mkdirSync(path.join(tempDir, 'skills', 'alpha'), { recursive: true });
|
||||
fs.mkdirSync(path.join(tempDir, 'plugins', 'example'), { recursive: true });
|
||||
fs.mkdirSync(path.join(tempDir, 'plugins', 'bundle', 'skills', 'example'), { recursive: true });
|
||||
fs.writeFileSync(path.join(tempDir, 'skills', 'alpha', 'SKILL.md'), 'alpha');
|
||||
fs.writeFileSync(path.join(tempDir, 'plugins', 'example', 'SKILL.md'), 'example');
|
||||
fs.mkdirSync(path.join(tempDir, 'skills', 'alpha', 'references'));
|
||||
fs.writeFileSync(path.join(tempDir, 'skills', 'alpha', 'references', 'guide.md'), 'guide');
|
||||
fs.writeFileSync(path.join(tempDir, 'plugins', 'bundle', 'skills', 'example', 'SKILL.md'), 'example');
|
||||
|
||||
assert.deepStrictEqual(getChangedSkillDirs(changed, tempDir), [
|
||||
'plugins/example',
|
||||
'plugins/bundle/skills/example',
|
||||
'skills/alpha',
|
||||
]);
|
||||
assert.deepStrictEqual(
|
||||
getUnresolvedChangedSkillFiles(changed, ['plugins/bundle/skills/example', 'skills/alpha']),
|
||||
['skills/beta/notes.md'],
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => ensureRepoRelative('../outside/SKILL.md', tempDir),
|
||||
@@ -129,6 +142,18 @@ assert.notStrictEqual(
|
||||
alphaFingerprint,
|
||||
);
|
||||
|
||||
fs.writeFileSync(path.join(tempDir, 'skills', 'alpha', 'SKILL.md'), 'alpha');
|
||||
fs.writeFileSync(path.join(tempDir, 'skills', 'alpha', 'references', 'guide.md'), 'guide changed');
|
||||
assert.notStrictEqual(
|
||||
reviewFingerprint(['skills/alpha'], {
|
||||
cacheVersion: '1',
|
||||
repoRoot: tempDir,
|
||||
threshold: '80',
|
||||
workspace: 'antigravity-awesome-skills',
|
||||
}),
|
||||
alphaFingerprint,
|
||||
);
|
||||
|
||||
const githubOutput = path.join(tempDir, 'github-output.txt');
|
||||
const plan = writePlan(['skills/alpha'], {
|
||||
cacheVersion: '1',
|
||||
@@ -143,6 +168,20 @@ assert.match(fs.readFileSync(githubOutput, 'utf8'), /has-skills=true/);
|
||||
assert.match(fs.readFileSync(githubOutput, 'utf8'), /skill-count=1/);
|
||||
assert.match(fs.readFileSync(githubOutput, 'utf8'), /fingerprint=[0-9a-f]{64}/);
|
||||
|
||||
const deletedOutput = path.join(tempDir, 'deleted-output.txt');
|
||||
const deletedPlan = writePlan([], {
|
||||
githubOutput: deletedOutput,
|
||||
unresolvedFiles: ['skills/deleted/SKILL.md', 'skills/deleted/examples/demo.md'],
|
||||
});
|
||||
assert.strictEqual(deletedPlan.hasSkills, false);
|
||||
assert.strictEqual(deletedPlan.requiresManual, true);
|
||||
assert.deepStrictEqual(deletedPlan.unresolvedFiles, [
|
||||
'skills/deleted/SKILL.md',
|
||||
'skills/deleted/examples/demo.md',
|
||||
]);
|
||||
assert.match(deletedPlan.fingerprint, /^manual-[0-9a-f]{64}$/);
|
||||
assert.match(fs.readFileSync(deletedOutput, 'utf8'), /requires-manual=true/);
|
||||
|
||||
assert.strictEqual(isQuotaFailure('Credit quota exceeded for this workspace'), true);
|
||||
assert.strictEqual(isQuotaFailure('Insufficient credits remaining'), true);
|
||||
assert.strictEqual(isQuotaFailure('Monthly credit allowance has been reached'), true);
|
||||
|
||||
@@ -41,6 +41,26 @@ async function run() {
|
||||
assert.throws(() => verifyLocalDeployment({ ...generatorOptions, deploymentRoot }), /unexpected=.*stale\.txt/);
|
||||
fs.unlinkSync(stalePath);
|
||||
|
||||
const assertSymlinkRejected = (relativePath, type = 'file') => {
|
||||
const target = path.join(deploymentRoot, relativePath);
|
||||
const physical = `${target}.physical`;
|
||||
fs.renameSync(target, physical);
|
||||
try {
|
||||
fs.symlinkSync(physical, target, type);
|
||||
assert.throws(
|
||||
() => verifyLocalDeployment({ ...generatorOptions, deploymentRoot }),
|
||||
/physical|non-file entry|regular file/i,
|
||||
);
|
||||
} finally {
|
||||
if (fs.existsSync(target) || fs.lstatSync(target).isSymbolicLink()) fs.unlinkSync(target);
|
||||
fs.renameSync(physical, target);
|
||||
}
|
||||
};
|
||||
assertSymlinkRejected('.nojekyll');
|
||||
assertSymlinkRejected('redirect-manifest.json');
|
||||
assertSymlinkRejected('antigravity-awesome-skills/index.html');
|
||||
assertSymlinkRejected('antigravity-awesome-skills', 'dir');
|
||||
|
||||
const fetchImpl = async (url) => {
|
||||
const parsed = new URL(url);
|
||||
if (parsed.pathname.startsWith('/agentic-awesome-skills/')) return new Response('current destination', { status: 200 });
|
||||
|
||||
@@ -80,6 +80,25 @@ const maintainerSkill = fs.readFileSync(
|
||||
path.join(repositoryRoot, "skills", "antigravity-maintainer-batch-release", "SKILL.md"),
|
||||
"utf8",
|
||||
);
|
||||
const mergeBatchGuide = fs.readFileSync(path.join(repositoryRoot, "docs", "maintainers", "merge-batch.md"), "utf8");
|
||||
const mergingGuide = fs.readFileSync(path.join(repositoryRoot, "docs", "maintainers", "merging-prs.md"), "utf8");
|
||||
const autonomyGuide = fs.readFileSync(path.join(repositoryRoot, "docs", "maintainers", "pr-autonomy.md"), "utf8");
|
||||
const maintainerSkillUi = fs.readFileSync(
|
||||
path.join(repositoryRoot, "skills", "antigravity-maintainer-batch-release", "agents", "openai.yaml"),
|
||||
"utf8",
|
||||
);
|
||||
for (const contractText of [maintainerSkill, maintenanceGuide, mergeBatchGuide, mergingGuide, autonomyGuide]) {
|
||||
assert.match(contractText, /skills\/\*\*|skills\/<skill-id>\/\*\*/);
|
||||
}
|
||||
assert.match(maintainerSkill, /entire tracked `skills\/<skill-id>\/\*\*` subtree/);
|
||||
assert.match(maintainerSkill, /authored by the repository owner/);
|
||||
assert.match(maintainerSkill, /exactly one merged release PR/);
|
||||
assert.match(maintenanceGuide, /canonical-repo-state` PR owns that state/);
|
||||
assert.match(autonomyGuide, /complete nearest skill-directory fingerprint/);
|
||||
assert.match(mergingGuide, /No local-integration exception/);
|
||||
assert.doesNotMatch(mergingGuide, /Rare exception: local squash|`gh pr merge <PR_NUMBER>/);
|
||||
assert.match(maintainerSkillUi, /\$antigravity-maintainer-batch-release/);
|
||||
assert.doesNotMatch(maintainerSkillUi, /frozen matrix|product, verifier, and gold|recommend|rank/i);
|
||||
assert.match(maintainerSkill, /discover every already-configured local AAS MCP host from its real configuration and update each one to the exact same package version/);
|
||||
assert.match(maintainerSkill, /Pin `agentic-awesome-skills@X\.Y\.Z` and `--version X\.Y\.Z`; never use `latest`/);
|
||||
assert.match(maintainerSkill, /real MCP `initialize` plus `tools\/list` handshake reports catalog package version `X\.Y\.Z`/);
|
||||
@@ -174,13 +193,16 @@ assert.match(
|
||||
/needs\.review-attempt\.outputs\.outcome != 'reviewed'/,
|
||||
"every non-passing Tessl outcome must route to exact-head manual review",
|
||||
);
|
||||
assert.match(skillReviewWorkflow, /paths:\s*\n\s+- 'skills\/\*\*'\s*\n\s+- 'plugins\/\*\*\/skills\/\*\*'/);
|
||||
assert.match(skillReviewWorkflow, /steps\.plan\.outputs\.requires-manual != 'true'/);
|
||||
assert.match(skillReviewWorkflow, /REQUIRES_MANUAL: \$\{\{ steps\.plan\.outputs\.requires-manual \}\}/);
|
||||
assert.match(skillReviewWorkflow, /result=manual/);
|
||||
assert.match(skillReviewWorkflow, /needs\.review-state\.outputs\.configured != 'true'/);
|
||||
assert.match(skillReviewWorkflow, /ref: \$\{\{ github\.event\.pull_request\.base\.sha \}\}/);
|
||||
assert.match(skillReviewWorkflow, /review_changed_skills\.cjs --plan/);
|
||||
assert.match(skillReviewWorkflow, /actions\/cache\/restore@[0-9a-f]{40}/);
|
||||
assert.match(skillReviewWorkflow, /actions\/cache\/save@[0-9a-f]{40}/);
|
||||
assert.match(skillReviewWorkflow, /tessl-review-v1-\$\{\{ steps\.plan\.outputs\.fingerprint \}\}/);
|
||||
assert.match(skillReviewWorkflow, /tessl-review-v2-\$\{\{ steps\.plan\.outputs\.fingerprint \}\}/);
|
||||
assert.match(skillReviewWorkflow, /steps\.review-cache\.outputs\.cache-hit != 'true'/);
|
||||
assert.match(skillReviewWorkflow, /needs\.review-attempt\.outputs\.outcome == 'reviewed'/);
|
||||
assert.ok(
|
||||
|
||||
@@ -7,6 +7,10 @@ const path = require('path');
|
||||
const { generateBridge } = require('./generate-pages-redirect-bridge');
|
||||
|
||||
function listFiles(root) {
|
||||
const rootStat = fs.lstatSync(root);
|
||||
if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
|
||||
throw new Error(`managed bridge directory is not a physical directory: ${root}`);
|
||||
}
|
||||
const files = [];
|
||||
function visit(directory) {
|
||||
for (const entry of fs.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
||||
@@ -20,12 +24,35 @@ function listFiles(root) {
|
||||
return files;
|
||||
}
|
||||
|
||||
function assertManagedRegularFile(root, relativePath) {
|
||||
const absoluteRoot = path.resolve(root);
|
||||
const absolutePath = path.resolve(absoluteRoot, relativePath);
|
||||
if (absolutePath !== absoluteRoot && !absolutePath.startsWith(`${absoluteRoot}${path.sep}`)) {
|
||||
throw new Error(`managed bridge path escapes deployment root: ${relativePath}`);
|
||||
}
|
||||
const stat = fs.lstatSync(absolutePath);
|
||||
if (stat.isSymbolicLink() || !stat.isFile()) {
|
||||
throw new Error(`managed bridge path is not a physical regular file: ${relativePath}`);
|
||||
}
|
||||
const physicalRoot = fs.realpathSync(absoluteRoot);
|
||||
const physicalPath = fs.realpathSync(absolutePath);
|
||||
if (physicalPath !== physicalRoot && !physicalPath.startsWith(`${physicalRoot}${path.sep}`)) {
|
||||
throw new Error(`managed bridge path escapes physical deployment root: ${relativePath}`);
|
||||
}
|
||||
return absolutePath;
|
||||
}
|
||||
|
||||
function managedFiles(root, legacyBase) {
|
||||
const required = ['.nojekyll', 'redirect-manifest.json'];
|
||||
const legacyDirectory = path.join(root, ...new URL(legacyBase).pathname.split('/').filter(Boolean));
|
||||
if (!fs.existsSync(legacyDirectory) || !fs.statSync(legacyDirectory).isDirectory()) {
|
||||
if (!fs.existsSync(legacyDirectory)) {
|
||||
throw new Error(`missing managed legacy directory: ${legacyDirectory}`);
|
||||
}
|
||||
const legacyStat = fs.lstatSync(legacyDirectory);
|
||||
if (legacyStat.isSymbolicLink() || !legacyStat.isDirectory()) {
|
||||
throw new Error(`managed legacy directory is not a physical directory: ${legacyDirectory}`);
|
||||
}
|
||||
for (const file of required) assertManagedRegularFile(root, file);
|
||||
return [...required, ...listFiles(legacyDirectory).map((file) => path.join(path.relative(root, legacyDirectory), file))]
|
||||
.map((file) => file.split(path.sep).join('/'))
|
||||
.sort();
|
||||
@@ -39,7 +66,7 @@ function compareManagedTrees(expectedRoot, actualRoot, legacyBase) {
|
||||
const missing = expectedFiles.filter((file) => !actualSet.has(file));
|
||||
const unexpected = actualFiles.filter((file) => !expectedSet.has(file));
|
||||
const mismatched = expectedFiles.filter((file) => actualSet.has(file)
|
||||
&& !fs.readFileSync(path.join(expectedRoot, file)).equals(fs.readFileSync(path.join(actualRoot, file))));
|
||||
&& !fs.readFileSync(assertManagedRegularFile(expectedRoot, file)).equals(fs.readFileSync(assertManagedRegularFile(actualRoot, file))));
|
||||
if (missing.length || unexpected.length || mismatched.length) {
|
||||
throw new Error(`managed bridge drift detected: missing=${missing.join(',') || '-'} unexpected=${unexpected.join(',') || '-'} mismatched=${mismatched.join(',') || '-'}`);
|
||||
}
|
||||
@@ -115,17 +142,17 @@ async function verifyLiveDeployment(options) {
|
||||
if (!Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 64) {
|
||||
throw new Error('--concurrency must be an integer from 1 to 64');
|
||||
}
|
||||
const manifestSource = fs.readFileSync(path.join(deploymentRoot, 'redirect-manifest.json'), 'utf8');
|
||||
const manifestSource = fs.readFileSync(assertManagedRegularFile(deploymentRoot, 'redirect-manifest.json'), 'utf8');
|
||||
const manifest = JSON.parse(manifestSource);
|
||||
const liveManifest = await fetchText(new URL('redirect-manifest.json', liveRoot), fetchImpl, timeoutMs);
|
||||
if (liveManifest !== manifestSource) throw new Error('live redirect manifest differs from the protected deployment');
|
||||
|
||||
const googlePath = manifest.webmaster_verification.google.legacy_file;
|
||||
const expectedGoogle = fs.readFileSync(path.join(deploymentRoot, googlePath), 'utf8');
|
||||
const expectedGoogle = fs.readFileSync(assertManagedRegularFile(deploymentRoot, googlePath), 'utf8');
|
||||
const liveGoogle = await fetchText(new URL(googlePath, liveRoot), fetchImpl, timeoutMs);
|
||||
if (liveGoogle !== expectedGoogle) throw new Error('live Google verification file differs from the protected deployment');
|
||||
|
||||
const expectedSitemap = fs.readFileSync(path.join(deploymentRoot, manifest.legacy_sitemap), 'utf8');
|
||||
const expectedSitemap = fs.readFileSync(assertManagedRegularFile(deploymentRoot, manifest.legacy_sitemap), 'utf8');
|
||||
const liveSitemap = await fetchText(new URL(manifest.legacy_sitemap, liveRoot), fetchImpl, timeoutMs);
|
||||
if (liveSitemap !== expectedSitemap) throw new Error('live legacy sitemap differs from the protected deployment');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user