#!/usr/bin/env node /** * `motebit-verify` CLI — the canonical motebit artifact verifier. * * Verifies identity files, execution receipts, credentials, and * presentations against their embedded signatures. When a credential * carries a `hardware_attestation` claim for `device_check` / `tpm` / * `android_keystore` / `webauthn`, the bundled platform adapters * verify the chain, extension, package binding, and identity binding * end-to-end. * * ``` * motebit-verify # auto-detect, print human * motebit-verify --json # structured output * motebit-verify --expect credential * motebit-verify --clock-skew 30 * * # Platform-specific overrides (all optional; defaults match * # motebit's canonical identifiers). * motebit-verify \ * --bundle-id com.example.app \ * --android-attestation-application-id ./app-id.bin \ * --rp-id example.com * ``` * * Exit codes: * 0 artifact verified (including any hardware-attestation channel) * 1 artifact detected but signature / hardware-channel invalid * 2 usage / I/O error * * Network-free by design. Every adapter pins its own trust anchor * (Apple App Attest Root CA, FIDO roots, TPM vendor roots, Google * Hardware Attestation roots). * * Three-package lineage — mirrors how tools like `git` / `libgit2` or * `cargo` / `tokio` separate the verb-tool from the library layer: * * @motebit/verify — this CLI (Apache-2.0, bundles all 4 adapters) * @motebit/verifier — Apache-2.0 library (file I/O, human formatting) * @motebit/crypto — Apache-2.0 primitives (verify, sign, suite dispatch) */ import type { ArtifactType, ContentArtifactManifest } from "@motebit/crypto"; import type { ContentArtifactType } from "@motebit/protocol"; interface ParsedArgs { readonly mode: "verify" | "verify-content-artifact" | "verify-approval-decision" | "help" | "version"; readonly file?: string; readonly json: boolean; readonly expectedType?: ArtifactType; readonly clockSkewSeconds?: number; readonly strictHashBinding?: boolean; readonly bundleId?: string; readonly androidAttestationApplicationIdPath?: string; readonly rpId?: string; /** Content-artifact mode: manifest input — either base64url header value or path to JSON file. */ readonly manifest?: string; /** Content-artifact + approval-decision modes: optional pinned producer/approver key (hex, 64 chars). */ readonly expectedProducerKey?: string; /** Content-artifact mode: optional expected artifact-type from the closed registry. */ readonly expectedArtifactType?: ContentArtifactType; /** Approval-decision mode: optional expected verdict to assert. */ readonly expectedVerdict?: "approved" | "denied"; readonly usageError?: string; } export declare function parseArgs(argv: readonly string[]): ParsedArgs; /** * Decode the `--manifest` argument. Tries the value as a filesystem * path first; if the file exists and parses as JSON, returns that. * Otherwise, treats it as a base64url-encoded canonical-JSON * representation (the form `services/relay/src/state-export.ts` emits * in the `X-Motebit-Content-Manifest` HTTP header). Returns the * parsed manifest object or a usage error. * * Auto-detect order matters: a base64url string could in principle be * a legal path on disk, but the path-first try is bounded (readFileSync * + JSON.parse) and falls through silently to header-decode. The * inverse — treating every input as header bytes — would accidentally * succeed on JSON files whose contents happen to base64-decode as * arbitrary bytes, returning malformed garbage. */ export declare function decodeManifestInput(value: string): { ok: true; manifest: ContentArtifactManifest; } | { ok: false; error: string; }; /** Failure-reason → human-readable phrase for the human-mode CLI output. */ export declare function describeContentArtifactReason(reason: string): string; /** Failure-reason → human phrase for approval-decision mode. */ export declare function describeApprovalDecisionReason(reason: string): string; /** * True when this module is the process entry point — only then does `main()` * run, so importing cli.ts to test the pure helpers never triggers it. * * The comparison is by REALPATH, deliberately. Every real way a user runs this * binary — npm's `.bin/motebit-verify`, a global install on `$PATH`, `npx * @motebit/verify` — passes the SYMLINK path as `process.argv[1]`, while * `import.meta.url` is the realpath of the target. The previous string compare * (`import.meta.url === \`file://${argv[1]}\``) never matched in those cases, so * `main()` never ran and the CLI silently no-op'd with exit 0 for every * installed invocation (it only worked when `node`-ing the realpath directly, * which no user does) — a violation of Rule 5 (never silent acceptance). * Resolving the symlink on both sides via `realpathSync` makes the bin work the * way it's installed. Exported so the bin-invocation regression test can assert * the symlink case without spawning. */ export declare function isMainModule(metaUrl: string, argv1: string | undefined): boolean; export {}; //# sourceMappingURL=cli.d.ts.map