📦 deps(thirdparty): update snapshots
This commit is contained in:
@@ -16,15 +16,34 @@ function currentUid() {
|
||||
return typeof process.getuid === "function" ? process.getuid() : null;
|
||||
}
|
||||
|
||||
function runWindowsAcl(script, filePath) {
|
||||
const result = spawnSync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script, filePath], {
|
||||
function windowsAclDiagnostic(value) {
|
||||
if (typeof value !== "string") return null;
|
||||
const normalized = value.replace(/[\u0000-\u001f\u007f]+/g, " ").replace(/\s+/g, " ").trim();
|
||||
return normalized ? normalized.slice(0, 512) : null;
|
||||
}
|
||||
|
||||
function runWindowsAcl(script, filePath, options = {}) {
|
||||
const runner = options.runner || spawnSync;
|
||||
const result = runner("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script], {
|
||||
encoding: "utf8",
|
||||
windowsHide: true,
|
||||
timeout: 15000,
|
||||
maxBuffer: 64 * 1024,
|
||||
env: {
|
||||
...process.env,
|
||||
AAS_WINDOWS_ACL_PATH: filePath,
|
||||
...(options.environment || {}),
|
||||
},
|
||||
});
|
||||
if (result.status !== 0 || result.error) {
|
||||
throw hostConfigError("AAS_ADAPTER_WINDOWS_ACL_FAILED", "filesystem", { status: result.status ?? null });
|
||||
const details = {
|
||||
status: result.status ?? null,
|
||||
phase: options.phase || "windowsAcl",
|
||||
path: filePath,
|
||||
};
|
||||
const diagnostic = windowsAclDiagnostic(result.stderr) || windowsAclDiagnostic(result.error?.message);
|
||||
if (diagnostic) details.diagnostic = diagnostic;
|
||||
throw hostConfigError("AAS_ADAPTER_WINDOWS_ACL_FAILED", "filesystem", details);
|
||||
}
|
||||
return result.stdout.trim();
|
||||
}
|
||||
@@ -32,17 +51,18 @@ function runWindowsAcl(script, filePath) {
|
||||
function windowsAclSnapshot(filePath) {
|
||||
const script = [
|
||||
"$ErrorActionPreference='Stop'",
|
||||
"$p=$args[0]",
|
||||
"$p=$env:AAS_WINDOWS_ACL_PATH",
|
||||
"function ConvertTo-SidValue($value){try{return ([Security.Principal.SecurityIdentifier]$value).Value}catch{};try{return ([Security.Principal.NTAccount]$value).Translate([Security.Principal.SecurityIdentifier]).Value}catch{return [string]$value}}",
|
||||
"$me=[Security.Principal.WindowsIdentity]::GetCurrent().User.Value",
|
||||
"$a=Get-Acl -LiteralPath $p",
|
||||
"$owner=(New-Object Security.Principal.NTAccount($a.Owner)).Translate([Security.Principal.SecurityIdentifier]).Value",
|
||||
"$rules=@($a.Access | ForEach-Object { $_.IdentityReference.Translate([Security.Principal.SecurityIdentifier]).Value + '|' + $_.AccessControlType + '|' + $_.IsInherited })",
|
||||
"$owner=ConvertTo-SidValue $a.Owner",
|
||||
"$rules=@($a.Access | ForEach-Object { (ConvertTo-SidValue $_.IdentityReference.Value) + '|' + $_.AccessControlType + '|' + $_.IsInherited })",
|
||||
"@{current=$me;owner=$owner;protected=$a.AreAccessRulesProtected;rules=$rules}|ConvertTo-Json -Compress",
|
||||
].join(";");
|
||||
let snapshot;
|
||||
try { snapshot = JSON.parse(runWindowsAcl(script, filePath)); } catch (cause) {
|
||||
try { snapshot = JSON.parse(runWindowsAcl(script, filePath, { phase: "inspectAcl" })); } catch (cause) {
|
||||
if (cause && cause.code) throw cause;
|
||||
throw hostConfigError("AAS_ADAPTER_WINDOWS_ACL_FAILED", "filesystem");
|
||||
throw hostConfigError("AAS_ADAPTER_WINDOWS_ACL_FAILED", "filesystem", { phase: "parseAcl", path: filePath });
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
@@ -67,7 +87,7 @@ function hardenWindowsPrivatePath(filePath, directory = false) {
|
||||
if (process.platform !== "win32") return;
|
||||
const script = [
|
||||
"$ErrorActionPreference='Stop'",
|
||||
"$p=$args[0]",
|
||||
"$p=$env:AAS_WINDOWS_ACL_PATH",
|
||||
"$sid=[Security.Principal.WindowsIdentity]::GetCurrent().User",
|
||||
"$acl=Get-Acl -LiteralPath $p",
|
||||
"$acl.SetAccessRuleProtection($true,$false)",
|
||||
@@ -78,17 +98,17 @@ function hardenWindowsPrivatePath(filePath, directory = false) {
|
||||
"$acl.SetAccessRule($rule)",
|
||||
"Set-Acl -LiteralPath $p -AclObject $acl",
|
||||
].join(";");
|
||||
runWindowsAcl(script, filePath);
|
||||
runWindowsAcl(script, filePath, { phase: "hardenAcl" });
|
||||
assertWindowsPrivatePath(filePath);
|
||||
}
|
||||
|
||||
function copyWindowsAcl(sourcePath, destinationPath) {
|
||||
if (process.platform !== "win32") return;
|
||||
const script = "$ErrorActionPreference='Stop';$source=$args[0];$destination=$args[1];$acl=Get-Acl -LiteralPath $source;Set-Acl -LiteralPath $destination -AclObject $acl";
|
||||
const result = spawnSync("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", script, sourcePath, destinationPath], {
|
||||
encoding: "utf8", windowsHide: true, timeout: 15000, maxBuffer: 64 * 1024,
|
||||
const script = "$ErrorActionPreference='Stop';$source=$env:AAS_WINDOWS_ACL_SOURCE_PATH;$destination=$env:AAS_WINDOWS_ACL_PATH;$acl=Get-Acl -LiteralPath $source;Set-Acl -LiteralPath $destination -AclObject $acl";
|
||||
runWindowsAcl(script, destinationPath, {
|
||||
phase: "copyAcl",
|
||||
environment: { AAS_WINDOWS_ACL_SOURCE_PATH: sourcePath },
|
||||
});
|
||||
if (result.status !== 0 || result.error) throw hostConfigError("AAS_ADAPTER_WINDOWS_ACL_FAILED", "filesystem", { status: result.status ?? null });
|
||||
assertWindowsOwned(destinationPath);
|
||||
}
|
||||
|
||||
@@ -202,6 +222,7 @@ module.exports = {
|
||||
fsyncDirectory,
|
||||
hardenWindowsPrivatePath,
|
||||
inspectRegularFile,
|
||||
runWindowsAcl,
|
||||
sameIdentity,
|
||||
writeExclusiveSynced,
|
||||
};
|
||||
|
||||
@@ -208,12 +208,7 @@ async function ensureRealDirectory(directoryPath, created, cacheRoot) {
|
||||
if (error.code !== "ENOENT") throw error;
|
||||
const parent = path.dirname(resolved);
|
||||
if (resolved === boundary) {
|
||||
const parentStat = await fsp.lstat(parent);
|
||||
if (!parentStat.isDirectory() || parentStat.isSymbolicLink()
|
||||
|| ownershipUnsafe(parentStat)
|
||||
|| (process.platform !== "win32" && (parentStat.mode & 0o022) !== 0)) {
|
||||
throw cacheError("AAS_RUNTIME_DIRECTORY_UNSAFE", "runtime cache parent is not a real directory");
|
||||
}
|
||||
await assertSafeCacheAncestorChain(parent);
|
||||
} else {
|
||||
await ensureRealDirectory(parent, created, boundary);
|
||||
}
|
||||
@@ -230,6 +225,42 @@ async function ensureRealDirectory(directoryPath, created, cacheRoot) {
|
||||
}
|
||||
}
|
||||
|
||||
async function assertSafeCacheAncestorChain(directoryPath) {
|
||||
const logical = path.resolve(directoryPath);
|
||||
let logicalCursor = path.parse(logical).root;
|
||||
for (const component of path.relative(logicalCursor, logical).split(path.sep).filter(Boolean)) {
|
||||
logicalCursor = path.join(logicalCursor, component);
|
||||
const stat = await fsp.lstat(logicalCursor);
|
||||
if (stat.isSymbolicLink()) {
|
||||
const stableSystemAlias = process.platform !== "win32"
|
||||
&& stat.uid === 0
|
||||
&& (stat.mode & 0o022) === 0;
|
||||
if (!stableSystemAlias) {
|
||||
throw cacheError("AAS_RUNTIME_DIRECTORY_UNSAFE", "runtime cache ancestor contains an untrusted symlink");
|
||||
}
|
||||
}
|
||||
}
|
||||
let current = await fsp.realpath(logical);
|
||||
let childStat = null;
|
||||
while (true) {
|
||||
const stat = await fsp.lstat(current);
|
||||
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
||||
throw cacheError("AAS_RUNTIME_DIRECTORY_UNSAFE", "runtime cache ancestor is not a real directory");
|
||||
}
|
||||
if (process.platform !== "win32" && (stat.mode & 0o022) !== 0) {
|
||||
const sticky = (stat.mode & 0o1000) !== 0;
|
||||
const childOwnedByCurrentUser = childStat !== null && !ownershipUnsafe(childStat);
|
||||
if (!sticky || !childOwnedByCurrentUser) {
|
||||
throw cacheError("AAS_RUNTIME_DIRECTORY_UNSAFE", "runtime cache ancestor is replaceable by another user");
|
||||
}
|
||||
}
|
||||
const parent = path.dirname(current);
|
||||
if (parent === current) return;
|
||||
childStat = stat;
|
||||
current = parent;
|
||||
}
|
||||
}
|
||||
|
||||
async function fsyncDirectory(directoryPath) {
|
||||
await fsyncDirectoryAsync(directoryPath);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
const { AGENT_SELECTION_CONTRACT, McpServer, TOOL_DEFINITIONS, TOOL_NAMES } = require("./server");
|
||||
const { AGENT_SELECTION_CONTRACT, MAX_SESSION_MANIFESTS, McpServer, TOOL_DEFINITIONS, TOOL_NAMES } = require("./server");
|
||||
const { runStdio } = require("./stdio");
|
||||
const { MAX_JSON_DEPTH, MAX_LINE_BYTES, StrictJsonError, parseStrictJsonLine } = require("./strict-json");
|
||||
|
||||
@@ -8,6 +8,7 @@ module.exports = {
|
||||
AGENT_SELECTION_CONTRACT,
|
||||
MAX_JSON_DEPTH,
|
||||
MAX_LINE_BYTES,
|
||||
MAX_SESSION_MANIFESTS,
|
||||
McpServer,
|
||||
StrictJsonError,
|
||||
TOOL_DEFINITIONS,
|
||||
|
||||
@@ -23,6 +23,7 @@ const TRACED_TOOL_NAMES = new Set([
|
||||
"inspect_stack",
|
||||
]);
|
||||
const MAX_TRACE_CALLS = 512;
|
||||
const MAX_SESSION_MANIFESTS = 128;
|
||||
const DIMENSION_IDS = Object.freeze([
|
||||
"architecture-runtime",
|
||||
"languages-frameworks",
|
||||
@@ -583,8 +584,7 @@ class McpServer {
|
||||
this.traceAttempts = new Map();
|
||||
this.traceLastFailure = new Map();
|
||||
this.traceOverflow = false;
|
||||
this.composedManifests = new Map();
|
||||
this.inspectedManifestDigests = new Set();
|
||||
this.manifestSessions = new Map();
|
||||
this.monotonicNow = options.monotonicNow || (() => process.hrtime.bigint());
|
||||
}
|
||||
|
||||
@@ -760,10 +760,11 @@ class McpServer {
|
||||
} else if (name === "export_selection_evidence") {
|
||||
assertExactKeys(args, ["manifestDigest", "project", "dimensions", "capabilities"]);
|
||||
if (this.traceOverflow) inputError("AAS_EVIDENCE_TRACE_LIMIT_EXCEEDED");
|
||||
const manifest = this.composedManifests.get(args.manifestDigest);
|
||||
if (!manifest || !this.inspectedManifestDigests.has(args.manifestDigest)) {
|
||||
const manifestSession = this.manifestSessions.get(args.manifestDigest);
|
||||
if (!manifestSession?.inspected) {
|
||||
inputError("AAS_EVIDENCE_MANIFEST_SESSION_MISSING");
|
||||
}
|
||||
const { manifest } = manifestSession;
|
||||
const evidence = core.createSelectionEvidence({
|
||||
catalog: this.catalog,
|
||||
manifest,
|
||||
@@ -802,13 +803,21 @@ class McpServer {
|
||||
};
|
||||
}
|
||||
if (name === "compose_stack" && payload.ok === true) {
|
||||
this.composedManifests.set(
|
||||
payload.manifestDigest,
|
||||
JSON.parse(core.canonicalJson(payload.manifest)),
|
||||
);
|
||||
this.manifestSessions.delete(payload.manifestDigest);
|
||||
this.manifestSessions.set(payload.manifestDigest, {
|
||||
manifest: JSON.parse(core.canonicalJson(payload.manifest)),
|
||||
inspected: false,
|
||||
});
|
||||
while (this.manifestSessions.size > MAX_SESSION_MANIFESTS) {
|
||||
this.manifestSessions.delete(this.manifestSessions.keys().next().value);
|
||||
}
|
||||
}
|
||||
if (name === "inspect_stack" && payload.ok === true && payload.status === "valid") {
|
||||
this.inspectedManifestDigests.add(payload.manifestDigest);
|
||||
const session = this.manifestSessions.get(payload.manifestDigest);
|
||||
if (session) {
|
||||
this.manifestSessions.delete(payload.manifestDigest);
|
||||
this.manifestSessions.set(payload.manifestDigest, { ...session, inspected: true });
|
||||
}
|
||||
}
|
||||
if (!Object.hasOwn(payload, "catalogDigest")) payload.catalogDigest = this.catalog.digest;
|
||||
this.recordTrace(name, args, payload, startedAt);
|
||||
@@ -850,6 +859,7 @@ class McpServer {
|
||||
|
||||
module.exports = {
|
||||
AGENT_SELECTION_CONTRACT,
|
||||
MAX_SESSION_MANIFESTS,
|
||||
McpServer,
|
||||
TOOL_DEFINITIONS,
|
||||
TOOL_NAMES,
|
||||
|
||||
@@ -32,11 +32,7 @@ function searchSkills(catalog, input = {}) {
|
||||
}
|
||||
const queryTokens = sortedUnique(tokenize(query));
|
||||
const normalizedQuery = query.trim().toLowerCase();
|
||||
const exactMatch = normalizedQuery
|
||||
? catalog.skills.find((skill) => skill.id === normalizedQuery)
|
||||
: null;
|
||||
const candidates = exactMatch ? [exactMatch] : catalog.skills;
|
||||
const matches = candidates.map((skill) => {
|
||||
const matches = catalog.skills.map((skill) => {
|
||||
const document = new Set(skill.searchTokens || []);
|
||||
const matchedTokens = queryTokens.filter((token) => document.has(token));
|
||||
const matchesQuery = !normalizedQuery
|
||||
|
||||
@@ -165,9 +165,12 @@ function materializeLayout(inspected, options) {
|
||||
logicalId: path.relative(inspected.root, directory).split(path.sep).join("/"),
|
||||
});
|
||||
}
|
||||
fsyncDirectory(parent);
|
||||
(options.fsyncDirectory || fsyncDirectory)(parent);
|
||||
} catch (cause) {
|
||||
try { fs.rmSync(stage, { recursive: true, force: true }); } catch {}
|
||||
if (fs.existsSync(stage)) {
|
||||
fs.rmSync(stage, { recursive: true, force: true });
|
||||
(options.fsyncDirectory || fsyncDirectory)(parent);
|
||||
}
|
||||
throw transactionError("AAS_TRANSACTION_LAYOUT_CREATE_FAILED", "filesystem", {}, cause);
|
||||
}
|
||||
const stat = assertRegularDirectory(directory);
|
||||
@@ -184,6 +187,7 @@ function materializeLayout(inspected, options) {
|
||||
|
||||
function cleanupMaterializedLayout(inspected, directories, options) {
|
||||
const { markerName, markerToken } = ownershipMarker(options);
|
||||
const syncDirectory = options.fsyncDirectory || fsyncDirectory;
|
||||
for (const directory of [...directories].reverse()) {
|
||||
if (!isContained(inspected.root, directory)) continue;
|
||||
const parent = path.dirname(directory);
|
||||
@@ -196,14 +200,16 @@ function cleanupMaterializedLayout(inspected, directories, options) {
|
||||
if (fs.existsSync(stage)) {
|
||||
const stageStat = fs.lstatSync(stage);
|
||||
if (!stageStat.isSymbolicLink() && stageStat.isDirectory() && stageStat.dev === inspected.device) {
|
||||
let removable = false;
|
||||
try {
|
||||
assertOwned(stageStat);
|
||||
if (markerOwned(stage, markerName, markerToken)
|
||||
&& !fs.readdirSync(stage).some((name) => name !== markerName)) {
|
||||
fs.rmSync(stage, { recursive: true });
|
||||
fsyncDirectory(parent);
|
||||
}
|
||||
} catch {}
|
||||
removable = markerOwned(stage, markerName, markerToken)
|
||||
&& !fs.readdirSync(stage).some((name) => name !== markerName);
|
||||
} catch { removable = false; }
|
||||
if (removable) {
|
||||
fs.rmSync(stage, { recursive: true });
|
||||
syncDirectory(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
// A prior cleanup may have published the exact token-bound tombstone and
|
||||
@@ -216,7 +222,7 @@ function cleanupMaterializedLayout(inspected, directories, options) {
|
||||
if (!markerOwned(tombstone, markerName, markerToken)) continue;
|
||||
if (fs.readdirSync(tombstone).some((name) => name !== markerName)) continue;
|
||||
fs.rmSync(tombstone, { recursive: true });
|
||||
fsyncDirectory(parent);
|
||||
syncDirectory(parent);
|
||||
continue;
|
||||
}
|
||||
if (!fs.existsSync(directory)) continue;
|
||||
@@ -231,9 +237,9 @@ function cleanupMaterializedLayout(inspected, directories, options) {
|
||||
logicalId: path.relative(inspected.root, directory).split(path.sep).join("/"),
|
||||
});
|
||||
}
|
||||
fsyncDirectory(parent);
|
||||
syncDirectory(parent);
|
||||
fs.rmSync(tombstone, { recursive: true });
|
||||
fsyncDirectory(parent);
|
||||
syncDirectory(parent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user