import type { CommandRule, AdmissionRules, ProfileScript } from './types.ts'; import { ScriptSource } from '../runtime/routing/types.ts'; import type { HiddenPaths, HiddenVars, ShowEntry, ShownPaths } from '../types.ts'; import { type MountMode } from '../types.ts'; import type { HideReason } from './types.ts'; /** * `paths:` of a profile, or of one of its mount sections. `hide` entries * use the document's one grammar: an entry with `*`, `?` or `[` is a * pattern, anything else an exact path and its subtree * (`utils/hidden.classifyPaths`); every entry holds a token and is * absolute or a name pattern, wherever the block is written. A hide * entry may also be a group `{patterns: [...], reason: ...}`: the * patterns join the flat list like any other entry and the reason lands * in `reasons`, the operator-only side table (`HideReason`). * * `show` is the other half of the path axis: a mapping of path to mode * (`{"/repo/docs": "r"}`), or a plain list whose entries inherit the * mount's mode. Every entry is absolute, a subtree or an anchored * pattern, because a show anchors to a place and a name pattern names * none. An entry re-opens its subtree inside a hidden region when its * anchor is deeper than the hide's, and states the mode in force below * its anchor when it carries one; both on the one anchor-depth rule. */ export interface PathsBlock { readonly hide: readonly string[]; readonly show?: readonly ShowEntry[]; readonly reasons?: readonly HideReason[]; } /** `vars:` of a profile: names or globs over names the session reads as unset. */ export interface VarsBlock { readonly hide: readonly string[]; } /** * `commands:` at the top level of a profile. `allow` lists the command * patterns the profile installs; a name none of them starts with is not a * command for the session (127, absent from `type` / `which` / `man`), * a line no pattern covers is refused. Shell builtins are subjects like * everything else: a list stating only `cat` leaves no `echo` and no * `cd`. The agent's own functions are the one exemption, safe because * every line of a body passes the gate itself. `ask` rules are admitted * only with a host approval; `deny` rules refuse with a reason. A bare * string in either is one command pattern with the default reason. * `allow` null or absent (unstated) installs everything. */ export interface CommandsBlock { readonly allow?: readonly string[] | null; readonly ask?: readonly CommandRule[]; readonly deny?: readonly CommandRule[]; } /** * `commands:` of one mount section: `ask` and `deny` only. A mount rule * applies to a line that works inside the mount (its cwd or one of its * paths lies under the root); its `paths` are absolute, like every other * path in the document, and must name something under that root. There * is no `allow` here: what a session can see is a property of the * session, and an operand cannot make a command "not found". */ export interface MountCommandsBlock { readonly ask?: readonly CommandRule[]; readonly deny?: readonly CommandRule[]; } /** * One mount's entry in a profile: what this profile may do there. Every field * is optional, and an omitted mount is not a refusal: the mount is * reachable at the mode it declares in the workspace's `mounts:`, which * a profile can only weaken (`weakerMode`), never raise. A profile that must * not touch a mount hides it, so the mount reads as nonexistent rather * than as a permission error naming something the profile cannot see. * * `commands` here carries ask and deny only: an allow list installs a * command for the whole session, and visibility is answered before any * operand exists, so it cannot be per mount. Rules written here apply to * a line that works inside this mount, by cwd or by operand, which is * what a path-scoped rule cannot express (`cd /repo && git commit` names * no path). */ export interface ProfileMount { readonly mode?: MountMode | null; readonly commands?: MountCommandsBlock | null; readonly paths?: PathsBlock | null; } /** * One profile: the whole permission document a session runs under. * * A session is created from exactly one of these, and it is the only * place permissions are written. There is no workspace-wide block and * no mount-owned block above it, so reading this object is reading * everything the profile may do; what a profile does not say, it does not * restrict. Configuration, not enforcement: the resolver compiles it * onto the session's narrowing fields and the doors keep enforcing. * Deliberately not named a View, which per the view convention is a * door-scoped handle an agent holds, while a profile is what the * embedder uses to *define* one. Immutable by type, so two agents with * the same profile share one object and neither can bend the other's view. * * Two rules decide a line against it, and they are the whole law. A * rule naming no path is read by verb (deny before ask before allow), * wherever it is written. A rule carrying paths, and every hide, is * read by anchor depth: the deeper entry wins, ties break by verb. * * `mounts` is keyed by prefix; a bare mode string is sugar for the * section that carries only a mode. `parseProfileMounts` normalizes * every spelling and the resolver reads only the normalized form. */ export interface SessionProfile { readonly cwd?: string | null; readonly env?: Readonly> | null; readonly mounts?: ReadonlyMap | null; readonly paths?: PathsBlock | null; readonly vars?: VarsBlock | null; readonly commands?: CommandsBlock | null; /** * The profile's policy: a program defining the admission hooks it * answers at, the way a coded Policy defines only the hooks it cares * about: `preCommand(ctx)` per command, `preOps(ctx)` per VFS op, * `preSession(ctx)` per env write (`pre_command`, `pre_ops`, * `pre_session` in python). Each is handed the door's facts as `ctx` * and answers with `return`: null or 'allow' for no opinion, 'deny' / * {deny: reason}, and at the command gate 'ask' / {ask: reason}. A block * naming the program and the engine it runs on, the shape a `clis` * entry has. The document is optional beside it: a profile stating * only a policy hides nothing, and the policy is its whole admission * policy. */ readonly policy?: ProfilePolicySpec | null; } /** * A profile's policy as the document states it: the program, and the * engine that runs it. * * `script` is the path form the config door accepts and loads; code * passes the loaded ScriptSource, so a path still spelled as a string * when the workspace reads it means the config layer never saw it. * `runtime` is required: there is no default engine, because an engine * the operator never chose should not be the one their policy runs on. */ export interface ProfilePolicySpec { readonly script: ScriptSource | string; readonly runtime: string; } /** * The session fields a profile compiles to. `commands` is the profile's * admission rules, its own and its mount sections' in one list; * `script` is its policy program, which `ScriptPolicy` calls at the * admission gate. */ export interface CompiledProfile { readonly mountModes: ReadonlyMap | null; readonly hiddenPaths: HiddenPaths | null; readonly hiddenVars: HiddenVars | null; readonly env: Readonly> | null; readonly cwd: string | null; readonly commands: AdmissionRules | null; readonly script?: ProfileScript | null; /** Every show entry the profile states, its own and its mount sections'. */ readonly shownPaths?: ShownPaths | null; /** The operator's reasons for grouped hides, never rendered to the agent. */ readonly hideReasons?: readonly HideReason[]; /** The profile's name, null for a document passed without one; the session's group. */ readonly profile?: string | null; } /** Validate a `paths:` block. Every entry is absolute or a name pattern. */ export declare function parsePathsBlock(raw: unknown, where?: string): PathsBlock; export declare function parseVarsBlock(raw: unknown, where?: string): VarsBlock; export declare function parseCommandsBlock(raw: unknown, where?: string): CommandsBlock; /** Validate a mount section's `commands:` block (`ask` and `deny` only). */ export declare function parseMountCommandsBlock(raw: unknown, where?: string): MountCommandsBlock; /** Validate one `mounts.` section of a profile. */ export declare function parseProfileMount(raw: unknown, root: string, where: string): ProfileMount; /** * Normalize a profile's `mounts` mapping: prefix to its settings, with a * bare mode string as sugar for a section carrying only a mode. A bare * list used to mean "only these mounts" and now means nothing at all, * so it fails loudly rather than quietly dropping the confinement it * used to carry. */ export declare function parseProfileMounts(raw: unknown, where?: string): ReadonlyMap | null; /** Validate one profile (a `profiles.` block, or an inline document). */ /** * Validate a profile's `policy` block: the program and the engine that * runs it, both required. A block, not a path: with no default engine * a path alone would name a program nothing could run. */ export declare function parseProfilePolicy(raw: unknown, where: string): ProfilePolicySpec; /** Validate one profile (a `profiles.` block, or an inline document). */ export declare function parseSessionProfile(raw: unknown, where?: string): SessionProfile; //# sourceMappingURL=profile.d.ts.map