mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-10-26 10:45:22 +00:00
feat: vendor permission system source
This commit is contained in:
@@ -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,
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user