import type { MountResolver } from '../runtime/resolver.ts'; import type { ScriptSource } from '../runtime/routing/types.ts'; import type { BridgeDispatchFn, EvalValue } from '../runtime/types.ts'; import type { Policy } from './base.ts'; import { SESSION_SCOPED, type SessionScoped } from './mixin.ts'; import { type Action, type Ask, type CommandContext, type Deny, type OpsContext, type PolicyHook, type SessionContext, type SessionScriptsQuery } from './types.ts'; /** The admission hooks a policy program may define, as the Policy interface spells them. */ export type ScriptHook = 'preCommand' | 'preOps' | 'preSession'; /** * The admission hooks a policy program may define, JavaScript spelling * to python spelling. The output doors (postOps, postExecute) stay * coded: they answer with a Limit over a live result. */ export declare const HOOKS: Readonly>; /** * What a profile's script is told about one command: the * `CommandContext` the coded hooks read, as plain data. * * The same facts on both hosts, JSON-shaped because the script runs * inside a sandboxed engine that a live object cannot cross into. * Paths are spelled as resolved virtual paths, so a script matches what * the command will actually touch, not what was typed; the raw words * are in `argv` for a script that wants them. */ export declare function scriptContext(profile: string, ctx: CommandContext, mounts: readonly string[]): Record; /** * What a profile's script is told about one VFS op: the `OpsContext` * the coded hooks read, as plain data. */ export declare function opsScriptContext(profile: string, ctx: OpsContext, mounts: readonly string[]): Record; /** * What a profile's script is told about one session-state write: the * `SessionContext` the coded hooks read, as plain data. */ export declare function sessionScriptContext(profile: string, ctx: SessionContext, mounts: readonly string[]): Record; /** * The policy answer a policy's hook returns. * * The vocabulary is the coded hook's own, spelled as data: null or * `'allow'` is no opinion (the command runs unless another rule refuses * it, and can never override one that does), `'deny'` / `{deny: reason}` * refuses, and at `preCommand` alone `'ask'` / `{ask: reason}` takes the * line to the approval door, since the op and session doors cannot wait * on a host (`VALIDITY`). The bare strings carry the document's default * reasons, the same ones a rule stating no reason gets. * * Throws a plain Error whose message is a clause about "script", for * the caller to prefix with whose policy it is. */ export declare function scriptAction(value: EvalValue, hook?: ScriptHook): Deny | Ask | null; /** * The workspace's file doors, for the engine a profile policy runs on. * * A policy judges a line before it runs, and some judgments are about * what a file holds rather than what it is called. The engine is * attached with these exactly as `Runtimes` attaches an agent's, so * the policy's `open()` reads the mounts through the same door an * agent's program would, and a read from a policy clears the op door * like any other. The bridge is built for one `issuer`, the policy's * own token: every op it dispatches carries the token to the op door * (`OpsContext.issuer`), which is how the policy's `preOps` tells its * own read from anyone else's. The workspace supplies them; a bare * ScriptPolicy (outside a workspace) has none, and its programs see no * file. */ export interface ScriptWiring { bridge: (issuer: symbol) => BridgeDispatchFn; resolver: MountResolver; } /** A hook's name in the program's own language: `preOps` in JavaScript, `pre_ops` in python. */ export declare function hookName(script: ScriptSource, hook: ScriptHook): string; /** * The call that runs one of a policy's hooks, in its language's own * spelling. * * A policy program defines the hooks it answers at, the way a coded * Policy defines only the hooks it cares about: `pre_command(ctx)` in * python, `preCommand(ctx)` in JavaScript, returning the verdict. The * program is evaluated whole, with this call appended as its last * expression, so the definitions run and the call's return is what the * evaluator hands back. */ export declare function hookCall(script: ScriptSource, hook: ScriptHook): string; /** * The expression that lists which hooks a policy program defines. * * Appended to the program once, before its first judgment, so a hook * the program leaves out is silence at that door rather than a call * that fails, and the op door in particular is never charged an * evaluation for a program that only judges commands. Spelled per * language and in the engines' common subset: monty has neither * `globals()` nor `callable()`, so python asks each name and catches * the NameError; JavaScript asks `typeof`, behind a `;` that ends * whatever statement the program left open, since a bracket on the * next line would otherwise index its last value. A name the program * binds is a hook it defines, whatever it bound. */ export declare function hookProbe(script: ScriptSource): string; /** * The hooks `hookProbe` found, as the Policy interface spells them. * Throws a plain Error, a clause about "script", when the value is not * a list of the probe's names. */ export declare function definedHooks(script: ScriptSource, value: EvalValue): ReadonlySet; /** * Each profile's policy, enforced at the admission gates. * * The scripted twin of `PermissionsPolicy`, registered right after it: * where that policy evaluates the document's declarative rules, this * one calls the profile's policy program with the same facts. A program * defines the hooks it answers at, the way a coded Policy defines only * the hooks it cares about: `preCommand` per command (`scriptContext`), * `preOps` per VFS op (`opsScriptContext`), `preSession` per env write * (`sessionScriptContext`). Which ones it defines is probed once per * program (`hookProbe`), so a hook it leaves out is silence at that * door and costs no evaluation, and a program defining none fails * closed at every door. It reads the session's policy through the * narrow `SessionScriptsQuery` by the session id the door put in the * context, so a session whose profile states no policy costs one lookup * and nothing else. * * The facts name the paths; the engine can open them. It is wired to * the workspace's files the way an agent's runtime is (`ScriptWiring`), * so a policy may read what an operand holds and answer for its * content, not only its name. A read from a policy clears the op door * like any other, except this policy's own `preOps`: the policy is the * one asking, and judging its own read would re-enter the evaluation * waiting on it. It knows its own read by `issuer`, a token only its * bridge stamps and that rides each op as an argument: a mark kept in * ambient context would be whatever op another task dispatched while * a read was in flight on a runtime with no task isolation. * * Every failure fails closed: a policy that threw, timed out, answered * with the wrong shape, defines no hook, or names an engine that cannot * be built refuses the command, op or write with a reason naming the * profile. Silence on failure would run exactly what the policy existed * to judge. * * Engines are built lazily on the first judgment that needs one, shared * per engine name, and closed by the workspace's own close. * Evaluations are serialized: the engines are workers, and two * concurrent evals on one would interleave. */ export declare class ScriptPolicy implements Policy, SessionScoped { readonly [SESSION_SCOPED]: true; private readonly sessions; private readonly mounts; private readonly wiring; private readonly engines; private readonly defined; private readonly issuer; private queue; constructor(sessions: SessionScriptsQuery, mounts: () => readonly string[], wiring?: ScriptWiring | null); preCommand(ctx: CommandContext): Promise; preOps(ctx: OpsContext): Promise; preSession(ctx: SessionContext): Promise; /** * Whether this session's policy speaks at `hook`: it has a program, * and the program defines the hook, or defines none and so refuses at * every door. A probe that fails answers true for the same reason: * the door will refuse. */ wantsFor(hook: PolicyHook, sessionId: string): Promise; /** Close every engine a script was evaluated on. */ close(): Promise; /** One hook of the session's policy, with the door's facts as `ctx`. */ private judge; /** * The hooks one profile's program defines, probed on its first * judgment and remembered by program text and language: the probe * asks in the program's own spelling, so one text read as two * languages is two programs. */ private hooksOf; /** The program whole, then `tail` as its last expression, on the profile's engine, serialized. */ private evaluate; } //# sourceMappingURL=script.d.ts.map