import type { DeviceProfile } from './registry.js';
/** Path to the CLI-managed known_hosts store (created lazily, mode 0600). */
export declare function managedKnownHostsPath(): string;
/** Ensure the parent directory of the managed store exists (mode 0700). */
export declare function ensureManagedKnownHostsDir(file?: string): void;
/** Read the managed store, or '' when it does not exist yet. */
export declare function readManagedKnownHosts(file?: string): string;
/**
 * True if `host` has at least one pinned key line in `content`. Pure (content
 * in) so the match logic is unit-testable without touching disk. Matching is
 * case-insensitive on the hostname, as OpenSSH does.
 */
export declare function isHostPinnedIn(content: string, host: string): boolean;
/** True if `host` is pinned in the managed store on disk. */
export declare function isHostPinned(host: string, file?: string): boolean;
/**
 * True if a DEVICE's host key is pinned — checked against the SAME host string
 * the ssh connection dials (`hostNameFor(device)`: the Tailscale dnsName/IP that
 * `sshTargetFor` resolves), falling back to the bare device name.
 *
 * A device discovered over the tailnet is pinned under its FQDN
 * (`yosemite-m6.tail….ts.net`), so a caller that checks the bare `device.name`
 * misses the pin and wrongly treats a reachable, pinned peer as unpinned —
 * silently excluding it from usage/auth fan-out while ssh to it would have
 * succeeded (PHNX-3505). Accepting the bare name too keeps a device pinned only
 * under its short name working. `isPinned` is injectable for tests; it defaults
 * to the managed on-disk store.
 */
export declare function isDevicePinned(device: DeviceProfile, isPinned?: (host: string) => boolean): boolean;
/**
 * The host-key-checking ssh options for a connection.
 *
 * Always points `UserKnownHostsFile` at the managed store so learned and pinned
 * keys live in exactly one CLI-owned file. `StrictHostKeyChecking` is `yes` once
 * the host is pinned (a key swap is refused) and `accept-new` before that
 * (genuine first enrollment learns the key into the managed store, which pins it
 * for every subsequent connect). Pure given `pinned`, so the policy is testable.
 */
export declare function hostKeyCheckingOpts(pinned: boolean, file?: string): string[];
/**
 * The key lines in `scanned` (ssh-keyscan output) not already present in
 * `existing`. Comments and blank lines are dropped; whitespace is normalized so
 * a re-scan of an already-pinned key is a no-op. Pure, so the idempotent-append
 * contract is unit-testable without spawning ssh-keyscan.
 */
export declare function newKnownHostsLines(existing: string, scanned: string): string[];
export interface PinResult {
    /** True if the host is pinned in the managed store after this call. */
    pinned: boolean;
    /** How many new key lines were appended. */
    added: number;
}
/**
 * Merge `ssh-keyscan` output for `host` into the managed store at `file`,
 * idempotently, and report whether `host` is pinned afterward. Split out from
 * {@link pinHostKey} so the store-write half — the part that decides a scanned
 * key now counts as pinned — is unit-testable with real keyscan text and no
 * network (the spawn stays in `pinHostKey`).
 */
export declare function recordScannedKeys(host: string, scanned: string, file?: string): PinResult;
/**
 * `ssh-keyscan` a host at a trusted moment and append any new key lines to the
 * managed store, idempotently. This is the explicit pin path; the implicit one
 * is a normal `accept-new` connection whose learned key lands in the same store.
 * Returns whether the host is pinned afterward.
 *
 * Host-name-agnostic: it scans whatever address it is handed, so it also pins a
 * host `agents ssh` can't reach — notably a bare `~/.ssh/config` `Host` alias,
 * which is not a registered device. The `--copy-creds` gate (commands/exec.ts)
 * calls this for exactly that case so the credential copy is usable for
 * ssh-config-alias hosts (RUSH-1767).
 */
export declare function pinHostKey(host: string, opts?: {
    file?: string;
    timeoutMs?: number;
    port?: number;
}): PinResult;
