import * as monacoType from 'monaco-editor/esm/vs/editor/editor.api'; import React from 'react'; type SecretConfidence = 'high' | 'medium' | 'low'; type SecretRewrite = 'literal' | 'template-interpolation' | 'none'; interface SecretRange { start: number; end: number; } interface SecretFinding { id: string; type: string; label: string; confidence: SecretConfidence; secret: string; range: SecretRange; line: number; column: number; literal?: SecretRange; rewrite?: SecretRewrite; } interface DetectionResult { type: string; label: string; confidence: SecretConfidence; secret: string; } /** * Converts a character offset into a 1-based {line, column}. */ declare function offsetToPosition(text: string, offset: number): { line: number; column: number; }; /** Shannon entropy in bits per character — high for random tokens. */ declare function shannonEntropy(value: string): number; /** * Code-first scanner: flags likely hardcoded secrets in a script. * * String-literal aware (AST-based) rather than raw-text, so reported ranges line * up with what the user sees and a rewrite can edit the original text. * * For plain-text outside a literal, use `scanText`. * * Orchestration only; the detectors live in `./detection`. */ /** * A code scanner with its own memo. Prefer this to the shared {@link scanCode} * when more than one surface scans independently — see `memoizeLatest`. */ declare function createCodeScanner(): (script: string) => SecretFinding[]; /** Shared code scanner, for a host with a single scanning surface. */ declare const scanCode: (script: string) => SecretFinding[]; /** * A text scanner with its own memo. Prefer this to the shared {@link scanText} * when more than one surface scans independently — see `memoizeLatest`. */ declare function createTextScanner(): (text: string) => SecretFinding[]; /** Shared text scanner, for a host with a single scanning surface. */ declare const scanText: (text: string) => SecretFinding[]; /** * Memoizes the latest input only — a scanner sees an evolving document, so anything older is not relevant. */ declare function memoizeLatest(compute: (input: string) => T[]): (input: string) => T[]; /** * How long to wait after the last edit before re-scanning. A scan runs every * detector over the whole document (and, for code scans, re-parses it), so * running it on every keystroke blocks typing. Debouncing coalesces a burst of * edits into one scan. */ declare const DEFAULT_DEBOUNCE_MS = 1500; interface ApplyResult { text: string; addedImport: boolean; needsAsync: boolean; applied: boolean; } /** * Turns a finding into a reference to a managed secret * * Implement this to target something other than k6; pass it to * `useSecretScanner` (or call it directly). {@link k6SecretRewriter} is the * default. */ interface SecretRewriter { apply(text: string, finding: SecretFinding, secretName: string): ApplyResult; reference(secretName: string, binding?: string): string; } /** * The k6 {@link SecretRewriter}: rewrites a detected hardcoded secret into a * reference to the managed Secrets store, matching the syntax documented in the * in-product Secrets guide: * * import secrets from 'k6/secrets' * const value = await secrets.get('my-secret') * * This is the only k6-specific piece of the library. Everything else — the * detectors, the finding shape, the hooks, the panel — is runtime-agnostic. */ declare function buildSecretReference(secretName: string, binding?: string): string; declare function applySecretReference(script: string, finding: SecretFinding, secretName: string): ApplyResult; declare const k6SecretRewriter: SecretRewriter; /** * Suggests a Secrets-store-compatible name for a finding. Secret names must be * lowercase and may only contain letters, numbers, dashes and periods (see * `secretSchema`), so we derive the suggestion from the detector type and * de-duplicate against existing names. */ declare function suggestSecretName(finding: Pick, existingNames?: string[]): string; declare function maskSecret(secret: string): string; /** * Stable signature for remembering an "ignore" choice across edits and reloads. * Hashing (FNV-1a) keeps the plaintext out of local storage, and deriving it * from content rather than position keeps it stable when the secret moves — * unlike the finding `id`. */ declare function getFindingSignature(finding: Pick): string; type MonacoNamespace = typeof monacoType; type IStandaloneCodeEditor = monacoType.editor.IStandaloneCodeEditor; /** Marker `code` identifying the scanner's diagnostics for the quick fix. */ declare const SECRET_MARKER_CODE = "hardcoded-secret"; interface InstallSecretScannerOptions { languages?: string[]; enabled?: boolean; markerMessage?: (finding: SecretFinding) => string; quickFix?: { title?: string; run: (finding: SecretFinding) => void; }; scan?: (code: string) => SecretFinding[]; debounceMs?: number; } interface SecretScannerInstallation { refresh(): void; dispose(): void; } /** * Gutter markers for detected secrets plus an optional "Move to Secrets Manager" * quick fix. */ declare function installSecretScanner(monaco: MonacoNamespace, editor: IStandaloneCodeEditor, options?: InstallSecretScannerOptions): SecretScannerInstallation; interface UseSecretScannerParams { text: string; scan?: (text: string) => SecretFinding[]; rewriter?: SecretRewriter; onChange?: (text: string) => void; enabled?: boolean; ignoreStorageKey?: string; debounceMs?: number; } interface SecretReference { finding: SecretFinding; secretName: string; reference: string; } interface SecretMigration { finding: SecretFinding | null; request: (finding: SecretFinding) => void; cancel: () => void; apply: (finding: SecretFinding, secretName: string) => void; } /** The fallback flow for a secret that couldn't be inserted automatically. */ interface SecretReferenceFallback { pending: SecretReference | null; dismiss: () => void; } interface SecretScanner { /** Detected secrets, minus the ones the user ignored. */ findings: SecretFinding[]; ignore: (finding: SecretFinding) => void; migration: SecretMigration; reference: SecretReferenceFallback; } /** * Headless secret scanner over any string — a code editor's contents, a * textarea, a prompt field. Owns detection, debouncing, ignore state and the * rewrite. */ declare function useSecretScanner(params: UseSecretScannerParams): SecretScanner; interface UseMonacoSecretScannerParams extends UseSecretScannerParams { /** Monaco namespace + editor, injected from the host's editor mount. */ monaco?: MonacoNamespace; editor?: IStandaloneCodeEditor; /** Whether the "Move to secret" quick fix is offered. Default true. */ canMigrate?: boolean; /** Languages to register the quick fix for. Default: ts + js. */ languages?: string[]; } /** * Monaco adapter over {@link useSecretScanner}: adds gutter markers and a * "Move to Secrets Manager" quick fix on top of the headless scanner. * * The Monaco pieces are optional — until `monaco` and `editor` are both * provided, this behaves exactly like `useSecretScanner`, so a host can mount it * before its editor is ready. */ declare function useMonacoSecretScanner(params: UseMonacoSecretScannerParams): SecretScanner; type IgnorableFinding = Pick; /** * Remembers which detected secrets the user chose to ignore, persisted in * localStorage under `storageKey` (namespace it per document). Tracked by a * content-derived signature, never the plaintext. */ declare function useIgnoredSecrets(storageKey?: string): { isIgnored: (finding: IgnorableFinding) => boolean; ignore: (finding: IgnorableFinding) => void; }; interface SecretFindingSummary { id: string; label: string; confidence: SecretConfidence; secret: string; line?: number; } interface SecretFindingsPanelProps { findings: T[]; onMove?: (finding: T) => void; onIgnore?: (finding: T) => void; hidden?: boolean; showLine?: boolean; description?: NonNullable; moveLabel?: React.ReactNode; ignoreLabel?: React.ReactNode; } interface SecretScannerPanelProps extends Omit, 'findings' | 'onMove' | 'onIgnore'> { scanner: SecretScanner; readOnly?: boolean; } /** * Presentational: takes findings and renders them. Accepts any finding shape * carrying the fields in `SecretFindingSummary`, so a host can pass its own. * For a panel driven by `useSecretScanner`, use `SecretScannerPanel`. */ declare function SecretFindingsPanel({ findings, onMove, onIgnore, hidden, showLine, description, moveLabel, ignoreLabel, }: SecretFindingsPanelProps): React.JSX.Element | null; /** * "Move to secret" calls `scanner.migration.request(finding)`, which sets * `scanner.migration.finding`; render your own create-secret modal off that, and * call `scanner.migration.apply` once the secret exists. */ declare function SecretScannerPanel({ scanner, readOnly, ...rest }: SecretScannerPanelProps): React.JSX.Element; interface SecretReferenceModalProps { reference: SecretReference | null; onDismiss: () => void; snippet?: string; title?: string; description?: NonNullable; } /** * Shown after a secret is created for a finding that couldn't be rewritten in * place. Purely presentational — render it off `scanner.reference.pending`. */ declare function SecretReferenceModal({ reference, onDismiss, snippet, title, description, }: SecretReferenceModalProps): React.JSX.Element | null; export { DEFAULT_DEBOUNCE_MS, SECRET_MARKER_CODE, SecretFindingsPanel, SecretReferenceModal, SecretScannerPanel, applySecretReference, buildSecretReference, createCodeScanner, createTextScanner, getFindingSignature, installSecretScanner, k6SecretRewriter, maskSecret, memoizeLatest, offsetToPosition, scanCode, scanText, shannonEntropy, suggestSecretName, useIgnoredSecrets, useMonacoSecretScanner, useSecretScanner }; export type { ApplyResult, DetectionResult, IStandaloneCodeEditor, InstallSecretScannerOptions, MonacoNamespace, SecretConfidence, SecretFinding, SecretFindingSummary, SecretMigration, SecretRange, SecretReference, SecretReferenceFallback, SecretRewrite, SecretRewriter, SecretScanner, SecretScannerInstallation, UseMonacoSecretScannerParams, UseSecretScannerParams };