@vulcn/engine 0.5.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -124,12 +124,22 @@ interface PluginHooks {
124
124
  onRecordStep?: (step: Step, ctx: RecordContext) => Promise<Step>;
125
125
  /** Called when recording ends, can transform session */
126
126
  onRecordEnd?: (session: Session, ctx: RecordContext) => Promise<Session>;
127
+ /** Called once when a scan starts (before any session is executed) */
128
+ onScanStart?: (ctx: ScanContext) => Promise<void>;
129
+ /** Called once when a scan ends (after all sessions have executed) */
130
+ onScanEnd?: (result: RunResult, ctx: ScanContext) => Promise<RunResult>;
127
131
  /** Called when run starts */
128
132
  onRunStart?: (ctx: RunContext$1) => Promise<void>;
129
133
  /** Called before each payload is injected, can transform payload */
130
134
  onBeforePayload?: (payload: string, step: Step, ctx: RunContext$1) => Promise<string>;
131
135
  /** Called after payload injection, for detection */
132
136
  onAfterPayload?: (ctx: DetectContext) => Promise<Finding[]>;
137
+ /**
138
+ * Called before the browser/driver is closed.
139
+ * Plugins should await any pending async work here (e.g., flush
140
+ * in-flight response handlers that need browser access).
141
+ */
142
+ onBeforeClose?: (ctx: PluginContext) => Promise<void>;
133
143
  /** Called when run ends, can transform results */
134
144
  onRunEnd?: (result: RunResult, ctx: RunContext$1) => Promise<RunResult>;
135
145
  /** Called when JavaScript alert/confirm/prompt appears */
@@ -169,8 +179,14 @@ interface PluginContext {
169
179
  engine: EngineInfo;
170
180
  /** Shared payload registry - loaders add payloads here */
171
181
  payloads: RuntimePayload[];
172
- /** Shared findings collection - detectors add findings here */
182
+ /** Shared findings collection (read-only view, use addFinding to add) */
173
183
  findings: Finding[];
184
+ /**
185
+ * Add a finding through the proper callback chain.
186
+ * Plugins should use this instead of pushing to findings[] directly,
187
+ * so consumers (CLI, worker) get notified via onFinding callbacks.
188
+ */
189
+ addFinding: (finding: Finding) => void;
174
190
  /** Scoped logger */
175
191
  logger: PluginLogger;
176
192
  /** Fetch API for network requests */
@@ -194,6 +210,17 @@ interface RunContext$1 extends PluginContext {
194
210
  /** Whether running headless */
195
211
  headless: boolean;
196
212
  }
213
+ /**
214
+ * Context for scan-level hooks (wraps all sessions)
215
+ */
216
+ interface ScanContext extends PluginContext {
217
+ /** All sessions in this scan */
218
+ sessions: Session[];
219
+ /** Whether running headless */
220
+ headless: boolean;
221
+ /** Total sessions count */
222
+ sessionCount: number;
223
+ }
197
224
  /**
198
225
  * Context for detection hooks
199
226
  */
@@ -438,6 +465,8 @@ interface CrawlOptions {
438
465
  pageTimeout?: number;
439
466
  /** Only crawl pages under the same origin (default: true) */
440
467
  sameOrigin?: boolean;
468
+ /** Playwright storage state JSON for authenticated crawling */
469
+ storageState?: string;
441
470
  /** Callback when a page is crawled */
442
471
  onPageCrawled?: (url: string, formsFound: number) => void;
443
472
  }
@@ -451,6 +480,18 @@ interface RunOptions {
451
480
  onFinding?: (finding: Finding) => void;
452
481
  /** Callback for step completion */
453
482
  onStepComplete?: (stepId: string, payloadCount: number) => void;
483
+ /**
484
+ * Called by the driver runner after the page/environment is ready.
485
+ * The driver-manager uses this to fire plugin onRunStart hooks
486
+ * with the real page object (instead of null).
487
+ */
488
+ onPageReady?: (page: unknown) => Promise<void>;
489
+ /**
490
+ * Called by the driver runner before closing the browser/environment.
491
+ * The driver-manager uses this to fire plugin onBeforeClose hooks
492
+ * so plugins can flush pending async work.
493
+ */
494
+ onBeforeClose?: (page: unknown) => Promise<void>;
454
495
  /** Driver-specific options */
455
496
  [key: string]: unknown;
456
497
  }
@@ -627,8 +668,27 @@ declare class DriverManager {
627
668
  /**
628
669
  * Execute a session
629
670
  * Invokes plugin hooks (onRunStart, onRunEnd) around the driver runner.
671
+ * Plugin onRunStart is deferred until the driver signals the page is ready
672
+ * via the onPageReady callback, ensuring plugins get a real page object.
630
673
  */
631
674
  execute(session: Session, pluginManager: PluginManager, options?: RunOptions): Promise<RunResult>;
675
+ /**
676
+ * Execute multiple sessions with a shared browser (scan-level orchestration).
677
+ *
678
+ * This is the preferred entry point for running a full scan. It:
679
+ * 1. Launches ONE browser for the entire scan
680
+ * 2. Passes the browser to each session's runner via options.browser
681
+ * 3. Each session creates its own context (lightweight, isolated cookies)
682
+ * 4. Aggregates results across all sessions
683
+ * 5. Closes the browser once at the end
684
+ *
685
+ * This is 5-10x faster than calling execute() per session because
686
+ * launching a browser takes 2-3 seconds.
687
+ */
688
+ executeScan(sessions: Session[], pluginManager: PluginManager, options?: RunOptions): Promise<{
689
+ results: RunResult[];
690
+ aggregate: RunResult;
691
+ }>;
632
692
  /**
633
693
  * Validate driver structure
634
694
  */
@@ -643,4 +703,215 @@ declare class DriverManager {
643
703
  */
644
704
  declare const driverManager: DriverManager;
645
705
 
646
- export { type CrawlOptions, type CustomPayload, type CustomPayloadFile, DRIVER_API_VERSION, type DetectContext, type DriverLogger, DriverManager, type DriverSource, type EngineInfo, type Finding, type LoadedDriver, type LoadedPlugin as LoadedPluginInfo, PLUGIN_API_VERSION, type PayloadCategory, type PayloadSource, type PluginConfig, type PluginContext, type PluginHooks, type PluginLogger, PluginManager, type RunContext$1 as PluginRunContext, type PluginSource, type RecordContext, type RecordOptions, type RecorderDriver, type RecordingHandle, type RunContext, type RunOptions, type RunResult, type RunnerDriver, type RuntimePayload, type Session, type Step, type VulcnConfig, type VulcnDriver, type VulcnPlugin, driverManager, pluginManager };
706
+ /**
707
+ * Vulcn Auth Module
708
+ *
709
+ * Handles credential encryption/decryption and auth state management.
710
+ *
711
+ * Security:
712
+ * - AES-256-GCM encryption for credentials at rest
713
+ * - PBKDF2 key derivation from passphrase
714
+ * - Reads passphrase from VULCN_KEY env var (CI/CD) or interactive prompt
715
+ * - Auth state (cookies, localStorage) encrypted separately
716
+ */
717
+ /** Form-based login credentials */
718
+ interface FormCredentials {
719
+ type: "form";
720
+ username: string;
721
+ password: string;
722
+ /** Custom login URL (if different from target) */
723
+ loginUrl?: string;
724
+ /** Custom CSS selector for username field */
725
+ userSelector?: string;
726
+ /** Custom CSS selector for password field */
727
+ passSelector?: string;
728
+ }
729
+ /** Header-based authentication (API keys, Bearer tokens) */
730
+ interface HeaderCredentials {
731
+ type: "header";
732
+ headers: Record<string, string>;
733
+ }
734
+ /** All credential types */
735
+ type Credentials = FormCredentials | HeaderCredentials;
736
+ /** Auth configuration for a scan */
737
+ interface AuthConfig {
738
+ /** Auth strategy */
739
+ strategy: "storage-state" | "header";
740
+ /** Login page URL */
741
+ loginUrl?: string;
742
+ /** Text that appears when logged in (e.g., "Logout") */
743
+ loggedInIndicator?: string;
744
+ /** Text that appears when logged out (e.g., "Sign In") */
745
+ loggedOutIndicator?: string;
746
+ /** Session expiry detection rules */
747
+ sessionExpiry?: {
748
+ /** HTTP status codes that indicate session expired */
749
+ statusCodes?: number[];
750
+ /** URL pattern that indicates redirect to login */
751
+ redirectPattern?: string;
752
+ /** Page content that indicates session expired */
753
+ pageContent?: string;
754
+ };
755
+ }
756
+ /**
757
+ * Encrypt data with AES-256-GCM.
758
+ *
759
+ * @param data - Plaintext data to encrypt
760
+ * @param passphrase - Passphrase for key derivation
761
+ * @returns JSON string of EncryptedData
762
+ */
763
+ declare function encrypt(data: string, passphrase: string): string;
764
+ /**
765
+ * Decrypt data encrypted with encrypt().
766
+ *
767
+ * @param encrypted - JSON string from encrypt()
768
+ * @param passphrase - Passphrase used during encryption
769
+ * @returns Decrypted plaintext
770
+ * @throws Error if passphrase is wrong or data is tampered
771
+ */
772
+ declare function decrypt(encrypted: string, passphrase: string): string;
773
+ /**
774
+ * Encrypt credentials to a storable string.
775
+ */
776
+ declare function encryptCredentials(credentials: Credentials, passphrase: string): string;
777
+ /**
778
+ * Decrypt credentials from a stored string.
779
+ */
780
+ declare function decryptCredentials(encrypted: string, passphrase: string): Credentials;
781
+ /**
782
+ * Encrypt browser storage state (cookies, localStorage, etc.).
783
+ * The state is the JSON output from Playwright's context.storageState().
784
+ */
785
+ declare function encryptStorageState(storageState: string, passphrase: string): string;
786
+ /**
787
+ * Decrypt browser storage state.
788
+ */
789
+ declare function decryptStorageState(encrypted: string, passphrase: string): string;
790
+ /**
791
+ * Get passphrase from environment or throw.
792
+ *
793
+ * In CI/CD, set VULCN_KEY env var.
794
+ * In interactive mode, the CLI should prompt and pass the value here.
795
+ */
796
+ declare function getPassphrase(interactive?: string): string;
797
+
798
+ /**
799
+ * Vulcn Session Format v2
800
+ *
801
+ * Directory-based session format: `.vulcn/` or `<name>.vulcn/`
802
+ *
803
+ * Structure:
804
+ * manifest.yml - scan config, session list, auth config
805
+ * auth/config.yml - login strategy, indicators
806
+ * auth/state.enc - encrypted storageState (cookies/localStorage)
807
+ * sessions/*.yml - individual session files (one per form)
808
+ * requests/*.json - captured HTTP metadata (for Tier 1 fast scan)
809
+ */
810
+
811
+ /** Manifest file schema (manifest.yml) */
812
+ interface ScanManifest {
813
+ /** Format version */
814
+ version: "2";
815
+ /** Human-readable scan name */
816
+ name: string;
817
+ /** Target URL */
818
+ target: string;
819
+ /** When the scan was recorded */
820
+ recordedAt: string;
821
+ /** Driver name */
822
+ driver: string;
823
+ /** Driver configuration */
824
+ driverConfig: Record<string, unknown>;
825
+ /** Auth configuration (optional) */
826
+ auth?: {
827
+ strategy: string;
828
+ configFile?: string;
829
+ stateFile?: string;
830
+ loggedInIndicator?: string;
831
+ loggedOutIndicator?: string;
832
+ reAuthOn?: Array<Record<string, unknown>>;
833
+ };
834
+ /** Session file references */
835
+ sessions: SessionRef[];
836
+ /** Scan configuration */
837
+ scan?: {
838
+ tier?: "auto" | "http-only" | "browser-only";
839
+ parallel?: number;
840
+ timeout?: number;
841
+ };
842
+ }
843
+ /** Reference to a session file within the manifest */
844
+ interface SessionRef {
845
+ /** Relative path to session file */
846
+ file: string;
847
+ /** Whether this session has injectable inputs */
848
+ injectable?: boolean;
849
+ }
850
+ /** HTTP request metadata for Tier 1 fast scanning */
851
+ interface CapturedRequest {
852
+ /** Request method */
853
+ method: string;
854
+ /** Full URL */
855
+ url: string;
856
+ /** Request headers */
857
+ headers: Record<string, string>;
858
+ /** Form data (for POST) */
859
+ body?: string;
860
+ /** Content type */
861
+ contentType?: string;
862
+ /** Which form field is injectable */
863
+ injectableField?: string;
864
+ /** Session name this request belongs to */
865
+ sessionName: string;
866
+ }
867
+ /**
868
+ * Load a v2 session directory into Session[] ready for execution.
869
+ *
870
+ * @param dirPath - Path to the .vulcn/ directory
871
+ * @returns Array of sessions with manifest metadata attached
872
+ */
873
+ declare function loadSessionDir(dirPath: string): Promise<{
874
+ manifest: ScanManifest;
875
+ sessions: Session[];
876
+ authConfig?: AuthConfig;
877
+ }>;
878
+ /**
879
+ * Check if a path is a v2 session directory.
880
+ */
881
+ declare function isSessionDir(path: string): boolean;
882
+ /**
883
+ * Check if a path looks like a v2 session directory (by extension).
884
+ */
885
+ declare function looksLikeSessionDir(path: string): boolean;
886
+ /**
887
+ * Save sessions to a v2 session directory.
888
+ *
889
+ * Creates the directory structure:
890
+ * <dirPath>/
891
+ * ├── manifest.yml
892
+ * ├── sessions/
893
+ * │ ├── <session-name>.yml
894
+ * │ └── ...
895
+ * └── requests/ (if HTTP metadata provided)
896
+ * └── ...
897
+ */
898
+ declare function saveSessionDir(dirPath: string, options: {
899
+ name: string;
900
+ target: string;
901
+ driver: string;
902
+ driverConfig: Record<string, unknown>;
903
+ sessions: Session[];
904
+ authConfig?: AuthConfig;
905
+ encryptedState?: string;
906
+ requests?: CapturedRequest[];
907
+ }): Promise<void>;
908
+ /**
909
+ * Read encrypted auth state from a session directory.
910
+ */
911
+ declare function readAuthState(dirPath: string): Promise<string | null>;
912
+ /**
913
+ * Read captured HTTP requests from a session directory.
914
+ */
915
+ declare function readCapturedRequests(dirPath: string): Promise<CapturedRequest[]>;
916
+
917
+ export { type AuthConfig, type CapturedRequest, type CrawlOptions, type Credentials, type CustomPayload, type CustomPayloadFile, DRIVER_API_VERSION, type DetectContext, type DriverLogger, DriverManager, type DriverSource, type EngineInfo, type Finding, type FormCredentials, type HeaderCredentials, type LoadedDriver, type LoadedPlugin as LoadedPluginInfo, PLUGIN_API_VERSION, type PayloadCategory, type PayloadSource, type PluginConfig, type PluginContext, type PluginHooks, type PluginLogger, PluginManager, type RunContext$1 as PluginRunContext, type PluginSource, type RecordContext, type RecordOptions, type RecorderDriver, type RecordingHandle, type RunContext, type RunOptions, type RunResult, type RunnerDriver, type RuntimePayload, type ScanContext, type ScanManifest, type Session, type SessionRef, type Step, type VulcnConfig, type VulcnDriver, type VulcnPlugin, decrypt, decryptCredentials, decryptStorageState, driverManager, encrypt, encryptCredentials, encryptStorageState, getPassphrase, isSessionDir, loadSessionDir, looksLikeSessionDir, pluginManager, readAuthState, readCapturedRequests, saveSessionDir };
package/dist/index.d.ts CHANGED
@@ -124,12 +124,22 @@ interface PluginHooks {
124
124
  onRecordStep?: (step: Step, ctx: RecordContext) => Promise<Step>;
125
125
  /** Called when recording ends, can transform session */
126
126
  onRecordEnd?: (session: Session, ctx: RecordContext) => Promise<Session>;
127
+ /** Called once when a scan starts (before any session is executed) */
128
+ onScanStart?: (ctx: ScanContext) => Promise<void>;
129
+ /** Called once when a scan ends (after all sessions have executed) */
130
+ onScanEnd?: (result: RunResult, ctx: ScanContext) => Promise<RunResult>;
127
131
  /** Called when run starts */
128
132
  onRunStart?: (ctx: RunContext$1) => Promise<void>;
129
133
  /** Called before each payload is injected, can transform payload */
130
134
  onBeforePayload?: (payload: string, step: Step, ctx: RunContext$1) => Promise<string>;
131
135
  /** Called after payload injection, for detection */
132
136
  onAfterPayload?: (ctx: DetectContext) => Promise<Finding[]>;
137
+ /**
138
+ * Called before the browser/driver is closed.
139
+ * Plugins should await any pending async work here (e.g., flush
140
+ * in-flight response handlers that need browser access).
141
+ */
142
+ onBeforeClose?: (ctx: PluginContext) => Promise<void>;
133
143
  /** Called when run ends, can transform results */
134
144
  onRunEnd?: (result: RunResult, ctx: RunContext$1) => Promise<RunResult>;
135
145
  /** Called when JavaScript alert/confirm/prompt appears */
@@ -169,8 +179,14 @@ interface PluginContext {
169
179
  engine: EngineInfo;
170
180
  /** Shared payload registry - loaders add payloads here */
171
181
  payloads: RuntimePayload[];
172
- /** Shared findings collection - detectors add findings here */
182
+ /** Shared findings collection (read-only view, use addFinding to add) */
173
183
  findings: Finding[];
184
+ /**
185
+ * Add a finding through the proper callback chain.
186
+ * Plugins should use this instead of pushing to findings[] directly,
187
+ * so consumers (CLI, worker) get notified via onFinding callbacks.
188
+ */
189
+ addFinding: (finding: Finding) => void;
174
190
  /** Scoped logger */
175
191
  logger: PluginLogger;
176
192
  /** Fetch API for network requests */
@@ -194,6 +210,17 @@ interface RunContext$1 extends PluginContext {
194
210
  /** Whether running headless */
195
211
  headless: boolean;
196
212
  }
213
+ /**
214
+ * Context for scan-level hooks (wraps all sessions)
215
+ */
216
+ interface ScanContext extends PluginContext {
217
+ /** All sessions in this scan */
218
+ sessions: Session[];
219
+ /** Whether running headless */
220
+ headless: boolean;
221
+ /** Total sessions count */
222
+ sessionCount: number;
223
+ }
197
224
  /**
198
225
  * Context for detection hooks
199
226
  */
@@ -438,6 +465,8 @@ interface CrawlOptions {
438
465
  pageTimeout?: number;
439
466
  /** Only crawl pages under the same origin (default: true) */
440
467
  sameOrigin?: boolean;
468
+ /** Playwright storage state JSON for authenticated crawling */
469
+ storageState?: string;
441
470
  /** Callback when a page is crawled */
442
471
  onPageCrawled?: (url: string, formsFound: number) => void;
443
472
  }
@@ -451,6 +480,18 @@ interface RunOptions {
451
480
  onFinding?: (finding: Finding) => void;
452
481
  /** Callback for step completion */
453
482
  onStepComplete?: (stepId: string, payloadCount: number) => void;
483
+ /**
484
+ * Called by the driver runner after the page/environment is ready.
485
+ * The driver-manager uses this to fire plugin onRunStart hooks
486
+ * with the real page object (instead of null).
487
+ */
488
+ onPageReady?: (page: unknown) => Promise<void>;
489
+ /**
490
+ * Called by the driver runner before closing the browser/environment.
491
+ * The driver-manager uses this to fire plugin onBeforeClose hooks
492
+ * so plugins can flush pending async work.
493
+ */
494
+ onBeforeClose?: (page: unknown) => Promise<void>;
454
495
  /** Driver-specific options */
455
496
  [key: string]: unknown;
456
497
  }
@@ -627,8 +668,27 @@ declare class DriverManager {
627
668
  /**
628
669
  * Execute a session
629
670
  * Invokes plugin hooks (onRunStart, onRunEnd) around the driver runner.
671
+ * Plugin onRunStart is deferred until the driver signals the page is ready
672
+ * via the onPageReady callback, ensuring plugins get a real page object.
630
673
  */
631
674
  execute(session: Session, pluginManager: PluginManager, options?: RunOptions): Promise<RunResult>;
675
+ /**
676
+ * Execute multiple sessions with a shared browser (scan-level orchestration).
677
+ *
678
+ * This is the preferred entry point for running a full scan. It:
679
+ * 1. Launches ONE browser for the entire scan
680
+ * 2. Passes the browser to each session's runner via options.browser
681
+ * 3. Each session creates its own context (lightweight, isolated cookies)
682
+ * 4. Aggregates results across all sessions
683
+ * 5. Closes the browser once at the end
684
+ *
685
+ * This is 5-10x faster than calling execute() per session because
686
+ * launching a browser takes 2-3 seconds.
687
+ */
688
+ executeScan(sessions: Session[], pluginManager: PluginManager, options?: RunOptions): Promise<{
689
+ results: RunResult[];
690
+ aggregate: RunResult;
691
+ }>;
632
692
  /**
633
693
  * Validate driver structure
634
694
  */
@@ -643,4 +703,215 @@ declare class DriverManager {
643
703
  */
644
704
  declare const driverManager: DriverManager;
645
705
 
646
- export { type CrawlOptions, type CustomPayload, type CustomPayloadFile, DRIVER_API_VERSION, type DetectContext, type DriverLogger, DriverManager, type DriverSource, type EngineInfo, type Finding, type LoadedDriver, type LoadedPlugin as LoadedPluginInfo, PLUGIN_API_VERSION, type PayloadCategory, type PayloadSource, type PluginConfig, type PluginContext, type PluginHooks, type PluginLogger, PluginManager, type RunContext$1 as PluginRunContext, type PluginSource, type RecordContext, type RecordOptions, type RecorderDriver, type RecordingHandle, type RunContext, type RunOptions, type RunResult, type RunnerDriver, type RuntimePayload, type Session, type Step, type VulcnConfig, type VulcnDriver, type VulcnPlugin, driverManager, pluginManager };
706
+ /**
707
+ * Vulcn Auth Module
708
+ *
709
+ * Handles credential encryption/decryption and auth state management.
710
+ *
711
+ * Security:
712
+ * - AES-256-GCM encryption for credentials at rest
713
+ * - PBKDF2 key derivation from passphrase
714
+ * - Reads passphrase from VULCN_KEY env var (CI/CD) or interactive prompt
715
+ * - Auth state (cookies, localStorage) encrypted separately
716
+ */
717
+ /** Form-based login credentials */
718
+ interface FormCredentials {
719
+ type: "form";
720
+ username: string;
721
+ password: string;
722
+ /** Custom login URL (if different from target) */
723
+ loginUrl?: string;
724
+ /** Custom CSS selector for username field */
725
+ userSelector?: string;
726
+ /** Custom CSS selector for password field */
727
+ passSelector?: string;
728
+ }
729
+ /** Header-based authentication (API keys, Bearer tokens) */
730
+ interface HeaderCredentials {
731
+ type: "header";
732
+ headers: Record<string, string>;
733
+ }
734
+ /** All credential types */
735
+ type Credentials = FormCredentials | HeaderCredentials;
736
+ /** Auth configuration for a scan */
737
+ interface AuthConfig {
738
+ /** Auth strategy */
739
+ strategy: "storage-state" | "header";
740
+ /** Login page URL */
741
+ loginUrl?: string;
742
+ /** Text that appears when logged in (e.g., "Logout") */
743
+ loggedInIndicator?: string;
744
+ /** Text that appears when logged out (e.g., "Sign In") */
745
+ loggedOutIndicator?: string;
746
+ /** Session expiry detection rules */
747
+ sessionExpiry?: {
748
+ /** HTTP status codes that indicate session expired */
749
+ statusCodes?: number[];
750
+ /** URL pattern that indicates redirect to login */
751
+ redirectPattern?: string;
752
+ /** Page content that indicates session expired */
753
+ pageContent?: string;
754
+ };
755
+ }
756
+ /**
757
+ * Encrypt data with AES-256-GCM.
758
+ *
759
+ * @param data - Plaintext data to encrypt
760
+ * @param passphrase - Passphrase for key derivation
761
+ * @returns JSON string of EncryptedData
762
+ */
763
+ declare function encrypt(data: string, passphrase: string): string;
764
+ /**
765
+ * Decrypt data encrypted with encrypt().
766
+ *
767
+ * @param encrypted - JSON string from encrypt()
768
+ * @param passphrase - Passphrase used during encryption
769
+ * @returns Decrypted plaintext
770
+ * @throws Error if passphrase is wrong or data is tampered
771
+ */
772
+ declare function decrypt(encrypted: string, passphrase: string): string;
773
+ /**
774
+ * Encrypt credentials to a storable string.
775
+ */
776
+ declare function encryptCredentials(credentials: Credentials, passphrase: string): string;
777
+ /**
778
+ * Decrypt credentials from a stored string.
779
+ */
780
+ declare function decryptCredentials(encrypted: string, passphrase: string): Credentials;
781
+ /**
782
+ * Encrypt browser storage state (cookies, localStorage, etc.).
783
+ * The state is the JSON output from Playwright's context.storageState().
784
+ */
785
+ declare function encryptStorageState(storageState: string, passphrase: string): string;
786
+ /**
787
+ * Decrypt browser storage state.
788
+ */
789
+ declare function decryptStorageState(encrypted: string, passphrase: string): string;
790
+ /**
791
+ * Get passphrase from environment or throw.
792
+ *
793
+ * In CI/CD, set VULCN_KEY env var.
794
+ * In interactive mode, the CLI should prompt and pass the value here.
795
+ */
796
+ declare function getPassphrase(interactive?: string): string;
797
+
798
+ /**
799
+ * Vulcn Session Format v2
800
+ *
801
+ * Directory-based session format: `.vulcn/` or `<name>.vulcn/`
802
+ *
803
+ * Structure:
804
+ * manifest.yml - scan config, session list, auth config
805
+ * auth/config.yml - login strategy, indicators
806
+ * auth/state.enc - encrypted storageState (cookies/localStorage)
807
+ * sessions/*.yml - individual session files (one per form)
808
+ * requests/*.json - captured HTTP metadata (for Tier 1 fast scan)
809
+ */
810
+
811
+ /** Manifest file schema (manifest.yml) */
812
+ interface ScanManifest {
813
+ /** Format version */
814
+ version: "2";
815
+ /** Human-readable scan name */
816
+ name: string;
817
+ /** Target URL */
818
+ target: string;
819
+ /** When the scan was recorded */
820
+ recordedAt: string;
821
+ /** Driver name */
822
+ driver: string;
823
+ /** Driver configuration */
824
+ driverConfig: Record<string, unknown>;
825
+ /** Auth configuration (optional) */
826
+ auth?: {
827
+ strategy: string;
828
+ configFile?: string;
829
+ stateFile?: string;
830
+ loggedInIndicator?: string;
831
+ loggedOutIndicator?: string;
832
+ reAuthOn?: Array<Record<string, unknown>>;
833
+ };
834
+ /** Session file references */
835
+ sessions: SessionRef[];
836
+ /** Scan configuration */
837
+ scan?: {
838
+ tier?: "auto" | "http-only" | "browser-only";
839
+ parallel?: number;
840
+ timeout?: number;
841
+ };
842
+ }
843
+ /** Reference to a session file within the manifest */
844
+ interface SessionRef {
845
+ /** Relative path to session file */
846
+ file: string;
847
+ /** Whether this session has injectable inputs */
848
+ injectable?: boolean;
849
+ }
850
+ /** HTTP request metadata for Tier 1 fast scanning */
851
+ interface CapturedRequest {
852
+ /** Request method */
853
+ method: string;
854
+ /** Full URL */
855
+ url: string;
856
+ /** Request headers */
857
+ headers: Record<string, string>;
858
+ /** Form data (for POST) */
859
+ body?: string;
860
+ /** Content type */
861
+ contentType?: string;
862
+ /** Which form field is injectable */
863
+ injectableField?: string;
864
+ /** Session name this request belongs to */
865
+ sessionName: string;
866
+ }
867
+ /**
868
+ * Load a v2 session directory into Session[] ready for execution.
869
+ *
870
+ * @param dirPath - Path to the .vulcn/ directory
871
+ * @returns Array of sessions with manifest metadata attached
872
+ */
873
+ declare function loadSessionDir(dirPath: string): Promise<{
874
+ manifest: ScanManifest;
875
+ sessions: Session[];
876
+ authConfig?: AuthConfig;
877
+ }>;
878
+ /**
879
+ * Check if a path is a v2 session directory.
880
+ */
881
+ declare function isSessionDir(path: string): boolean;
882
+ /**
883
+ * Check if a path looks like a v2 session directory (by extension).
884
+ */
885
+ declare function looksLikeSessionDir(path: string): boolean;
886
+ /**
887
+ * Save sessions to a v2 session directory.
888
+ *
889
+ * Creates the directory structure:
890
+ * <dirPath>/
891
+ * ├── manifest.yml
892
+ * ├── sessions/
893
+ * │ ├── <session-name>.yml
894
+ * │ └── ...
895
+ * └── requests/ (if HTTP metadata provided)
896
+ * └── ...
897
+ */
898
+ declare function saveSessionDir(dirPath: string, options: {
899
+ name: string;
900
+ target: string;
901
+ driver: string;
902
+ driverConfig: Record<string, unknown>;
903
+ sessions: Session[];
904
+ authConfig?: AuthConfig;
905
+ encryptedState?: string;
906
+ requests?: CapturedRequest[];
907
+ }): Promise<void>;
908
+ /**
909
+ * Read encrypted auth state from a session directory.
910
+ */
911
+ declare function readAuthState(dirPath: string): Promise<string | null>;
912
+ /**
913
+ * Read captured HTTP requests from a session directory.
914
+ */
915
+ declare function readCapturedRequests(dirPath: string): Promise<CapturedRequest[]>;
916
+
917
+ export { type AuthConfig, type CapturedRequest, type CrawlOptions, type Credentials, type CustomPayload, type CustomPayloadFile, DRIVER_API_VERSION, type DetectContext, type DriverLogger, DriverManager, type DriverSource, type EngineInfo, type Finding, type FormCredentials, type HeaderCredentials, type LoadedDriver, type LoadedPlugin as LoadedPluginInfo, PLUGIN_API_VERSION, type PayloadCategory, type PayloadSource, type PluginConfig, type PluginContext, type PluginHooks, type PluginLogger, PluginManager, type RunContext$1 as PluginRunContext, type PluginSource, type RecordContext, type RecordOptions, type RecorderDriver, type RecordingHandle, type RunContext, type RunOptions, type RunResult, type RunnerDriver, type RuntimePayload, type ScanContext, type ScanManifest, type Session, type SessionRef, type Step, type VulcnConfig, type VulcnDriver, type VulcnPlugin, decrypt, decryptCredentials, decryptStorageState, driverManager, encrypt, encryptCredentials, encryptStorageState, getPassphrase, isSessionDir, loadSessionDir, looksLikeSessionDir, pluginManager, readAuthState, readCapturedRequests, saveSessionDir };