/** * The fenced profile — the evaluation mode where this process runs inside a * container started with `--network none`. * * The invariant the profile exists to hold: **code that sees log data and * code that has network access never coexist.** Everything in this process * reads the customer's logs, so this process gets no network. The two steps * that genuinely need the internet happen outside the fence, in front of the * user, before any log data is in scope: * * 1. minting the 14-day licence, with one visible `curl` the user runs; * 2. exporting the log sample, with the user's own `aws` / `curl` and the * user's own credentials, driven by a script this server emits and the * user reads (see `lib/siem/export-plan`). * * An egress allowlist was considered and rejected as the headline guarantee. * An allowlist constrains HOSTS, but tenancy is chosen by the credential * inside TLS: code carrying an attacker's own Datadog or AWS key can write * the user's logs to the attacker's tenant through an ALLOWED host, and a * presigned S3 PUT needs no credential at all. `--network none` is a kernel * fact the user can check; an allowlist is a promise about our own code. * * What this module does, mechanically, is make the profile FAIL rather than * FETCH. In the fenced profile the server never mints a licence: a missing or * expired `TENX_LICENSE_KEY` produces the pre-mint instructions, not a * network call that would hang for the connect timeout and then fail anyway. * Failing with instructions is the honest behaviour; a fetch that cannot * succeed is theatre. * * Detection is by environment variable, set on the `docker run` line the * documentation prints: * * - `TENX_AIRGAPPED=true` — the engine's own airgap switch. The engine * child this server spawns reads the same variable, so one declaration * covers both layers, and a host that sets it has already declared it * has no path to log10x. * - `LOG10X_FENCED=1` — explicit alias for callers who want the MCP-side * profile without touching the engine's variable. * * There is no runtime toggle: the profile is read from the environment at * each call site, so a test can set it and clear it, but nothing inside a * running server can turn the fence off. */ /** True when this process is running under the fenced evaluation profile. */ export declare function isFenced(env?: NodeJS.ProcessEnv): boolean; /** Which switch put us here, for boot banners and doctor output. */ export declare function fencedSignal(env?: NodeJS.ProcessEnv): string | null; /** * What to tell the user when the fenced profile needs a licence and has none. * * Front-loaded on purpose. This text travels as a `hint` on a chassis error * envelope, and that field is capped at 300 characters — an explanation that * builds to the command ends up truncated one line before the command, which * is the same as saying nothing. The state, the `curl`, and the variable to * put the result in all land inside the first 300 characters; the reassurance * about offline verification comes after, where losing it costs nothing. */ export declare function fencedPreMintInstructions(reason?: 'missing' | 'expired'): string; /** * Thrown by any code path that would have reached the network while fenced. * * Callers convert this into a `config_missing`-class refusal carrying * `fencedPreMintInstructions()`; nothing retries it, because there is nothing * a retry could reach. */ export declare class FencedEgressRefusedError extends Error { readonly operation: string; constructor(operation: string, detail?: string); } /** Refuse an operation that would have reached the network, when fenced. */ export declare function assertNotFenced(operation: string, detail?: string): void; /** * The image tag the documented run line uses. Local-only for now: there is no * publish pipeline, and `--pull=never` in the run line keeps a fenced start on * the image the user built and inspected rather than one fetched at boot. */ export declare const FENCED_IMAGE_REF = "log10x/poc:local"; /** * The one-line proof, and the exact output it must print. * * Kept here rather than only in the docs so a fenced run can hand back its own * verification at the moment of relevance. A test pins this string against * `docs/fenced-poc.md`: a proof that has drifted from the documented proof is * worse than no proof, because the reader checks it, sees a mismatch, and has * no way to tell which half is wrong. */ export declare const FENCED_INSPECT_COMMAND: string; export declare const FENCED_INSPECT_EXPECTED: string; /** * The check that settles it. `docker inspect` reads a configuration; this * reads the world. Nothing about the result depends on a network, so nothing * about the result can have left over one. */ export declare const FENCED_WIFI_SENTENCE = "Turn Wi-Fi off and the analysis still completes."; export interface FencedVerification { inspect_command: string; inspect_expected: string; wifi_check: string; markdown: string; } /** The verification block a fenced run appends to its own output. */ export declare function fencedVerification(): FencedVerification; export interface FencedOfferArgs { /** What the POC read, for the first half of the disclosure. */ read: string; /** Args to pre-fill on `log10x_emit_sample_plan`, so the agent need not remember the submit call. */ planArgs: Record; } export interface FencedOffer { disclosure: string; action: { tool: string; args: Record; reason: string; role: 'alternative'; }; markdown: string; } /** * The disclosure a POC that had network ends with, plus the action carrying * the alternative. * * `role: 'alternative'` and not `'recommended-next'`. The POC just finished; * telling an agent the recommended next step is to export a second sample * would send it off to redo work nobody asked for. `alternative` is the * envelope's own word for "one of several paths the user might pick" — which * is exactly what this is, and exactly what an offer means. * * One sentence of disclosure and one of alternative. No security lecture: a * user who wants the reasoning can read the docs, and a user who does not * should not have to scroll past it to reach their cost numbers. */ export declare function fencedOffer(opts: FencedOfferArgs): FencedOffer;