feat: vendor permission system source

This commit is contained in:
云服务部-叶林立
2026-08-19 14:35:19 +08:00
parent 198584daf8
commit 410c50a3e5
809 changed files with 157793 additions and 139 deletions
@@ -0,0 +1,118 @@
import { getToolInputPath } from "#src/access-intent/tool-input-path";
import type { PathNormalizer } from "#src/path-normalizer";
import type { ScopedPermissionResolver } from "#src/permission-resolver";
import { buildExternalDirectoryAskPayload } from "#src/presentation/path-ask-payload";
import { SessionApproval } from "#src/session-approval";
import { deriveApprovalPattern } from "#src/session-rules";
import type { ToolAccessExtractorLookup } from "#src/tool-access-extractor-registry";
import type { GateResult } from "./descriptor";
import { resolveExternalDirectoryPolicy } from "./external-directory-policy";
import { accessFactsFromPath } from "./helpers";
import type { ToolCallContext } from "./types";
/**
* Build a pure descriptor for the external-directory permission gate.
*
* Returns `null` when the gate does not apply (no CWD, tool is not
* path-bearing, or path is inside the working directory).
* Returns a `GateBypass` for Pi infrastructure reads.
* Returns a `GateDescriptor` for external paths needing a permission check.
*/
export function describeExternalDirectoryGate(
tcc: ToolCallContext,
infraDirs: string[],
resolver: ScopedPermissionResolver,
normalizer: PathNormalizer,
extractors?: ToolAccessExtractorLookup,
): GateResult {
const externalDirectoryPath = getToolInputPath(
tcc.toolName,
tcc.input,
extractors,
);
if (!externalDirectoryPath) return null;
if (!normalizer.isOutsideWorkingDirectory(externalDirectoryPath)) {
return null;
}
// The boundary decision (above) and the infrastructure-read containment
// check (below) use the canonical, symlink-resolved path; pattern matching
// uses the typed and resolved aliases (#418).
const accessPath = normalizer.forPath(externalDirectoryPath);
// ── Pi infrastructure read bypass ──────────────────────────────────────
if (normalizer.isInfrastructureRead(tcc.toolName, accessPath, infraDirs)) {
return {
action: "allow",
// Containment allowed this, not a rule the operator wrote.
decidedBy: { kind: "infrastructure_read" },
log: {
event: "permission_request.infrastructure_auto_allowed",
details: {
source: "tool_call",
toolCallId: tcc.toolCallId,
toolName: tcc.toolName,
agentName: tcc.agentName,
path: externalDirectoryPath,
},
},
decision: {
surface: tcc.toolName,
value: externalDirectoryPath,
result: "allow",
resolution: "infrastructure_auto_allowed",
origin: null,
agentName: tcc.agentName ?? null,
matchedPattern: null,
},
};
}
// ── Build descriptor for permission check ───────────────────────────────
const resolvedAlias = accessPath.resolvedAlias();
// The runner consumes this preCheck and skips its own resolve.
const preCheck = resolveExternalDirectoryPolicy(
accessPath,
resolver,
tcc.agentName ?? undefined,
);
const pattern = deriveApprovalPattern(accessPath.value());
const payload = buildExternalDirectoryAskPayload({
toolName: tcc.toolName,
pathValue: externalDirectoryPath,
resolvedPath: resolvedAlias,
cwd: tcc.cwd,
agentName: tcc.agentName,
matchedPattern: preCheck.matchedPattern,
});
return {
surface: "external_directory",
input: {},
preCheck,
payload,
sessionApproval: SessionApproval.single("external_directory", pattern),
promptDetails: {
source: "tool_call",
agentName: tcc.agentName,
toolCallId: tcc.toolCallId,
toolName: tcc.toolName,
path: externalDirectoryPath,
accessIntent: accessFactsFromPath("external_directory", accessPath),
},
logContext: {
source: "tool_call",
toolCallId: tcc.toolCallId,
toolName: tcc.toolName,
agentName: tcc.agentName,
path: externalDirectoryPath,
},
decision: {
surface: "external_directory",
value: externalDirectoryPath,
},
};
}