mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-10-26 10:45:22 +00:00
101 lines
3.7 KiB
TypeScript
101 lines
3.7 KiB
TypeScript
import type { AccessIntent } from "./access-intent/access-intent";
|
||
import { buildAccessIntentForSurface } from "./access-intent/input-normalizer";
|
||
import type { Authorizer } from "./authority/authorizer";
|
||
import type { AuthorizerRegistrar } from "./authority/authorizer-registry";
|
||
import { resolveBashAdvisoryCheck } from "./bash-advisory-check";
|
||
import type { PathNormalizer } from "./path-normalizer";
|
||
import type { PermissionsService } from "./service";
|
||
import type {
|
||
ToolAccessExtractor,
|
||
ToolAccessExtractorRegistrar,
|
||
} from "./tool-access-extractor-registry";
|
||
import type {
|
||
ToolInputFormatter,
|
||
ToolInputFormatterRegistrar,
|
||
} from "./tool-input-formatter-registry";
|
||
import type { PermissionCheckResult, PermissionState } from "./types";
|
||
|
||
/**
|
||
* Resolution surface the service needs: answer a gate-style {@link AccessIntent}
|
||
* (composing the session ruleset internally) and report a tool-level state.
|
||
* `PermissionResolver` satisfies it.
|
||
*/
|
||
interface ResolverForService {
|
||
resolve(intent: AccessIntent): PermissionCheckResult;
|
||
getToolPermission(toolName: string, agentName?: string): PermissionState;
|
||
}
|
||
|
||
/** Narrow session view: hands out the cwd-bound path normalizer. */
|
||
interface PathNormalizerProvider {
|
||
getPathNormalizer(): PathNormalizer;
|
||
}
|
||
|
||
/**
|
||
* In-process implementation of the cross-extension {@link PermissionsService}.
|
||
*
|
||
* Constructed once in the composition root and backed by the single shared
|
||
* `PermissionResolver` and `PermissionSession` that the gates also use — so
|
||
* service queries and gate-path decisions see the same state. Path-shaped
|
||
* surface queries route through the resolver as an `access-path` intent, so
|
||
* they match the lexical aliases ∪ canonical (symlink-resolved) set the gates
|
||
* do (#503); non-path surfaces stay on the `tool` intent.
|
||
*/
|
||
export class LocalPermissionsService implements PermissionsService {
|
||
constructor(
|
||
private readonly resolver: ResolverForService,
|
||
private readonly session: PathNormalizerProvider,
|
||
private readonly formatterRegistry: ToolInputFormatterRegistrar,
|
||
private readonly accessExtractorRegistry: ToolAccessExtractorRegistrar,
|
||
private readonly authorizerRegistry: AuthorizerRegistrar,
|
||
) {}
|
||
|
||
checkPermission(
|
||
surface: string,
|
||
value?: string,
|
||
agentName?: string,
|
||
): ReturnType<PermissionsService["checkPermission"]> {
|
||
// Bash decomposes at gate parity: a chained/nested command is split into
|
||
// its command-pattern units and resolved most-restrictive, matching what
|
||
// the enforcement gate enforces (#309). A cold parser falls back to the
|
||
// whole-string match inside resolveBashAdvisoryCheck.
|
||
if (surface === "bash") {
|
||
return resolveBashAdvisoryCheck(value ?? "", agentName, this.resolver);
|
||
}
|
||
const intent = buildAccessIntentForSurface(
|
||
surface,
|
||
value,
|
||
this.session.getPathNormalizer(),
|
||
agentName,
|
||
);
|
||
return this.resolver.resolve(intent);
|
||
}
|
||
|
||
getToolPermission(
|
||
toolName: string,
|
||
agentName?: string,
|
||
): ReturnType<PermissionsService["getToolPermission"]> {
|
||
return this.resolver.getToolPermission(toolName, agentName);
|
||
}
|
||
|
||
registerToolInputFormatter(
|
||
toolName: string,
|
||
formatter: ToolInputFormatter,
|
||
): ReturnType<PermissionsService["registerToolInputFormatter"]> {
|
||
return this.formatterRegistry.register(toolName, formatter);
|
||
}
|
||
|
||
registerToolAccessExtractor(
|
||
toolName: string,
|
||
extractor: ToolAccessExtractor,
|
||
): ReturnType<PermissionsService["registerToolAccessExtractor"]> {
|
||
return this.accessExtractorRegistry.register(toolName, extractor);
|
||
}
|
||
|
||
registerAuthorizer(
|
||
name: string,
|
||
authorize: Authorizer["authorize"],
|
||
): ReturnType<PermissionsService["registerAuthorizer"]> {
|
||
return this.authorizerRegistry.register(name, authorize);
|
||
}
|
||
}
|