@http-forge/core 0.3.3 → 0.4.1
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/README.md +2 -1
- package/dist/di/service-container.d.ts +1 -1
- package/dist/di/service-identifiers.d.ts +1 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.js +573 -277
- package/dist/index.mjs +573 -277
- package/dist/infrastructure/config/config.interface.d.ts +32 -0
- package/dist/infrastructure/environment/environment-config-service.d.ts +29 -17
- package/dist/infrastructure/environment/environment-file-loader.d.ts +5 -0
- package/dist/infrastructure/execution/request-executor.d.ts +2 -4
- package/dist/infrastructure/execution/request-preparer.d.ts +3 -1
- package/dist/infrastructure/script/interfaces.d.ts +1 -2
- package/dist/infrastructure/script/script-executor.d.ts +10 -1
- package/dist/infrastructure/script/script-factories.d.ts +25 -0
- package/dist/infrastructure/secrets/aws-secret-resolver.d.ts +18 -0
- package/dist/infrastructure/secrets/azure-keyvault-resolver.d.ts +20 -0
- package/dist/infrastructure/secrets/doppler-resolver.d.ts +22 -0
- package/dist/infrastructure/secrets/gcp-secret-resolver.d.ts +21 -0
- package/dist/infrastructure/secrets/hashicorp-vault-resolver.d.ts +25 -0
- package/dist/infrastructure/secrets/onepassword-resolver.d.ts +26 -0
- package/dist/infrastructure/secrets/secret-resolver-registry.d.ts +43 -0
- package/dist/infrastructure/test-suite/html-report-generator.d.ts +24 -1
- package/dist/infrastructure/test-suite/result-storage-service.d.ts +1 -1
- package/dist/infrastructure/test-suite/result-storage.d.ts +45 -3
- package/dist/types/environment-config.d.ts +16 -7
- package/dist/types/secret-resolver.d.ts +106 -0
- package/dist/types/types.d.ts +6 -0
- package/package.json +13 -1
|
@@ -110,6 +110,36 @@ export interface ProxyConfig {
|
|
|
110
110
|
/** List of hosts to bypass proxy */
|
|
111
111
|
bypass?: string[];
|
|
112
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Cloud secret provider configuration (used in SecretsConfig.providers)
|
|
115
|
+
*/
|
|
116
|
+
export interface SecretProviderEntry {
|
|
117
|
+
/** Provider type */
|
|
118
|
+
provider: 'aws' | 'azure' | 'gcp' | 'vault' | '1password' | 'doppler';
|
|
119
|
+
/** AWS region (aws only) */
|
|
120
|
+
region?: string;
|
|
121
|
+
/** Azure Key Vault URL (azure only) */
|
|
122
|
+
vaultUrl?: string;
|
|
123
|
+
/** GCP project ID (gcp only) */
|
|
124
|
+
projectId?: string;
|
|
125
|
+
/** Vault server address (vault only) */
|
|
126
|
+
address?: string;
|
|
127
|
+
/** Vault mount path (vault only, default "secret") */
|
|
128
|
+
mountPath?: string;
|
|
129
|
+
/** Vault namespace (vault only, Enterprise/HCP) */
|
|
130
|
+
namespace?: string;
|
|
131
|
+
/** 1Password vault name (1password only) */
|
|
132
|
+
vault?: string;
|
|
133
|
+
/** Doppler service token (doppler only; falls back to DOPPLER_TOKEN env var) */
|
|
134
|
+
serviceToken?: string;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Top-level secrets block in http-forge.config.json
|
|
138
|
+
* Configures named cloud secret providers for {{secret:alias/path}} tokens.
|
|
139
|
+
*/
|
|
140
|
+
export interface SecretsConfig {
|
|
141
|
+
providers: Record<string, SecretProviderEntry>;
|
|
142
|
+
}
|
|
113
143
|
/**
|
|
114
144
|
* Main HTTP Forge configuration (http-forge.config.json)
|
|
115
145
|
*/
|
|
@@ -132,6 +162,8 @@ export interface HttpForgeConfig {
|
|
|
132
162
|
mcp?: McpConfig;
|
|
133
163
|
/** Proxy configuration (optional) */
|
|
134
164
|
proxy?: ProxyConfig | null;
|
|
165
|
+
/** Cloud secret provider configuration (optional) */
|
|
166
|
+
secrets?: SecretsConfig;
|
|
135
167
|
}
|
|
136
168
|
/**
|
|
137
169
|
* Configuration service interface
|
|
@@ -5,13 +5,14 @@
|
|
|
5
5
|
* VS Code's workspaceState/globalState.
|
|
6
6
|
*/
|
|
7
7
|
import type { IEnvironmentConfigService, ImportedEnvironment, LocalConfig, ResolvedEnvironment, SharedConfig } from '../../types/environment-config';
|
|
8
|
-
import { IFileWatcherFactory, IKeyValueStore } from '../../types/platform';
|
|
8
|
+
import { IFileWatcherFactory, IKeyValueStore, ISecretStore } from '../../types/platform';
|
|
9
9
|
import { IConfigService } from '../config';
|
|
10
10
|
export declare class EnvironmentConfigService implements IEnvironmentConfigService {
|
|
11
11
|
private workspaceFolder;
|
|
12
12
|
private workspaceStore;
|
|
13
13
|
private configService;
|
|
14
14
|
private fileWatcherFactory?;
|
|
15
|
+
private secretStore?;
|
|
15
16
|
private environmentsPath;
|
|
16
17
|
private sharedConfigPath;
|
|
17
18
|
private localConfigPath;
|
|
@@ -27,12 +28,14 @@ export declare class EnvironmentConfigService implements IEnvironmentConfigServi
|
|
|
27
28
|
*/
|
|
28
29
|
private localGlobalValues;
|
|
29
30
|
private localEnvironmentValues;
|
|
31
|
+
/** In-memory cache of secret values fetched from SecretStorage — keyed by envName */
|
|
32
|
+
private secretValuesCache;
|
|
30
33
|
/**
|
|
31
34
|
* Callback invoked when environment files change on disk.
|
|
32
35
|
* Set by the extension host to refresh tree views and panels.
|
|
33
36
|
*/
|
|
34
37
|
onEnvironmentsChanged?: () => void;
|
|
35
|
-
constructor(workspaceFolder: string, workspaceStore: IKeyValueStore, configService: IConfigService, fileWatcherFactory?: IFileWatcherFactory | undefined);
|
|
38
|
+
constructor(workspaceFolder: string, workspaceStore: IKeyValueStore, configService: IConfigService, fileWatcherFactory?: IFileWatcherFactory | undefined, secretStore?: ISecretStore | undefined);
|
|
36
39
|
private setupFileWatcher;
|
|
37
40
|
dispose(): void;
|
|
38
41
|
getWorkspaceFolder(): string;
|
|
@@ -53,9 +56,9 @@ export declare class EnvironmentConfigService implements IEnvironmentConfigServi
|
|
|
53
56
|
* Persist current environment overrides to workspace state (fire-and-forget).
|
|
54
57
|
*/
|
|
55
58
|
private persistEnvironmentOverrides;
|
|
56
|
-
setEnvironmentVariable(key: string, value: unknown): void;
|
|
57
|
-
deleteEnvironmentVariable(key: string): void;
|
|
58
|
-
clearEnvironmentVariables(): void;
|
|
59
|
+
setEnvironmentVariable(key: string, value: unknown, envName?: string): void;
|
|
60
|
+
deleteEnvironmentVariable(key: string, envName?: string): void;
|
|
61
|
+
clearEnvironmentVariables(envName?: string): void;
|
|
59
62
|
/**
|
|
60
63
|
* Reset all runtime environment overrides for the current environment.
|
|
61
64
|
* Equivalent to Postman's "Reset All" — reverts Current Values to Initial Values.
|
|
@@ -70,19 +73,28 @@ export declare class EnvironmentConfigService implements IEnvironmentConfigServi
|
|
|
70
73
|
getGlobalVariableLocals(): Record<string, string>;
|
|
71
74
|
deleteGlobalVariable(key: string): void;
|
|
72
75
|
clearGlobalVariables(): void;
|
|
73
|
-
/** @deprecated Use setEnvironmentVariable instead */
|
|
74
|
-
setSessionVariable(key: string, value: unknown): Promise<void>;
|
|
75
|
-
/** @deprecated Use getEnvironmentVariableLocal instead */
|
|
76
|
-
getSessionVariable(key: string): string | undefined;
|
|
77
|
-
/** @deprecated Use getEnvironmentVariableLocals instead */
|
|
78
|
-
getSessionVariables(): Record<string, string>;
|
|
79
|
-
/** @deprecated Use deleteEnvironmentVariable instead */
|
|
80
|
-
deleteSessionVariable(key: string): Promise<void>;
|
|
81
|
-
/** @deprecated Use clearEnvironmentVariables instead */
|
|
82
|
-
clearSessionVariables(): Promise<void>;
|
|
83
|
-
/** @deprecated Use getEnvironmentVariableLocal instead */
|
|
84
|
-
hasSessionVariable(key: string): boolean;
|
|
85
76
|
getResolvedEnvironment(envName?: string): ResolvedEnvironment | null;
|
|
77
|
+
/**
|
|
78
|
+
* Retrieve a secret variable value from SecretStorage.
|
|
79
|
+
* Returns undefined when no SecretStorage is available (e.g. CLI context).
|
|
80
|
+
*/
|
|
81
|
+
getSecretVariable(envName: string, key: string): Promise<string | undefined>;
|
|
82
|
+
/**
|
|
83
|
+
* Store a secret variable value in SecretStorage.
|
|
84
|
+
* No-op when no SecretStorage is available (e.g. CLI context).
|
|
85
|
+
*/
|
|
86
|
+
setSecretVariable(envName: string, key: string, value: string): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Delete a secret variable from SecretStorage.
|
|
89
|
+
* No-op when no SecretStorage is available (e.g. CLI context).
|
|
90
|
+
*/
|
|
91
|
+
deleteSecretVariable(envName: string, key: string): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* Pre-load all secret values for an environment into the in-memory cache.
|
|
94
|
+
* Call this when switching environments or on extension activation so that
|
|
95
|
+
* the synchronous getResolvedEnvironment() always has secret values available.
|
|
96
|
+
*/
|
|
97
|
+
loadSecretVariables(envName?: string): Promise<void>;
|
|
86
98
|
resolveVariables(input: string, envName?: string): string;
|
|
87
99
|
exportEnvironmentsToFolder(outDir: string, mergeGlobals?: boolean): void;
|
|
88
100
|
resolveVariablesWithExtra(input: string, extraVariables: Record<string, string>, envName?: string): string;
|
|
@@ -28,6 +28,11 @@ export interface EnvironmentEntry {
|
|
|
28
28
|
description?: string;
|
|
29
29
|
requiresConfirmation?: boolean;
|
|
30
30
|
variables: Record<string, string>;
|
|
31
|
+
/**
|
|
32
|
+
* Names of variables whose values are stored in SecretStorage, not in the JSON file.
|
|
33
|
+
* These names are persisted in the JSON; the values are never written to disk.
|
|
34
|
+
*/
|
|
35
|
+
secretVariables?: string[];
|
|
31
36
|
}
|
|
32
37
|
/**
|
|
33
38
|
* Determine whether a filename is a system/meta file (not an environment file).
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* Single Responsibility: Orchestrate the complete request execution flow
|
|
5
5
|
* Facade Pattern: Provides simplified interface to complex subsystem
|
|
6
6
|
*/
|
|
7
|
+
import { IHttpClient } from '../../types/platform';
|
|
8
|
+
import { HttpRequest, HttpResponse, RequestOverrides, ScriptResult, UnifiedCollection, UnifiedRequest } from '../../types/types';
|
|
7
9
|
import { IForgeEnv } from '../environment/forge-env';
|
|
8
10
|
import { IRequestPreprocessor } from '../http/request-preprocessor';
|
|
9
11
|
import { IScriptExecutor } from '../script/interfaces';
|
|
10
|
-
import { IHttpClient } from '../../types/platform';
|
|
11
|
-
import { HttpRequest, HttpResponse, RequestOverrides, ScriptResult, UnifiedCollection, UnifiedRequest } from '../../types/types';
|
|
12
12
|
/**
|
|
13
13
|
* Options for request execution
|
|
14
14
|
*/
|
|
@@ -25,8 +25,6 @@ export interface ExecuteOptions {
|
|
|
25
25
|
additionalVariables?: Record<string, string>;
|
|
26
26
|
/** Timeout override */
|
|
27
27
|
timeout?: number;
|
|
28
|
-
/** Callback when scripts modify session variables */
|
|
29
|
-
onSessionChange?: (action: 'set' | 'unset' | 'clear', key?: string, value?: string) => void;
|
|
30
28
|
/** Callback when scripts modify environment variables */
|
|
31
29
|
onEnvironmentChange?: (action: 'set' | 'unset' | 'clear', key?: string, value?: string) => void;
|
|
32
30
|
}
|
|
@@ -15,6 +15,7 @@ import { ExecutionRequest, PreparedRequest } from '../../types/types';
|
|
|
15
15
|
import { IOAuth2TokenManager } from '../auth/interfaces';
|
|
16
16
|
import { IHttpRequestService } from '../http/interfaces';
|
|
17
17
|
import { IRequestPreprocessor } from '../http/request-preprocessor';
|
|
18
|
+
import { SecretResolverRegistry } from '../secrets/secret-resolver-registry';
|
|
18
19
|
import { IRequestPreparer } from './request-preparer-interfaces';
|
|
19
20
|
/**
|
|
20
21
|
* RequestPreparer implementation
|
|
@@ -28,7 +29,8 @@ export declare class RequestPreparer implements IRequestPreparer {
|
|
|
28
29
|
private readonly preprocessor;
|
|
29
30
|
private readonly tokenManager?;
|
|
30
31
|
private readonly appInfo?;
|
|
31
|
-
|
|
32
|
+
private readonly secretRegistry?;
|
|
33
|
+
constructor(envConfigService: IEnvironmentConfigService, httpService: IHttpRequestService, preprocessor: IRequestPreprocessor, tokenManager?: IOAuth2TokenManager | undefined, appInfo?: IApplicationInfo | undefined, secretRegistry?: SecretResolverRegistry | undefined);
|
|
32
34
|
prepareRequest(input: ExecutionRequest, environment: string, resolvedEnv: ResolvedEnvironment, extraVariables?: Record<string, string>): Promise<PreparedRequest>;
|
|
33
35
|
private applyOAuth2;
|
|
34
36
|
private applyApiKey;
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* Dependency Inversion: Define abstractions for request execution components
|
|
8
8
|
* Interface Segregation: Each interface has a focused purpose
|
|
9
9
|
*/
|
|
10
|
-
import { Cookie } from '../cookie/interfaces';
|
|
11
10
|
import { PreparedRequest, RequestAuth, RequestBody, RequestScripts, RequestSettings, ScriptInfo, TestAssertion } from '../../types/types';
|
|
11
|
+
import { Cookie } from '../cookie/interfaces';
|
|
12
12
|
export type { Cookie, ScriptInfo };
|
|
13
13
|
/**
|
|
14
14
|
* Cookie Jar Interface
|
|
@@ -69,7 +69,6 @@ export interface CommonScriptContext {
|
|
|
69
69
|
iteration?: number;
|
|
70
70
|
iterationCount?: number;
|
|
71
71
|
iterationData?: Record<string, any>;
|
|
72
|
-
onSessionChange?: (action: 'set' | 'unset' | 'clear', key?: string, value?: string) => void;
|
|
73
72
|
onEnvironmentChange?: (action: 'set' | 'unset' | 'clear', key?: string, value?: string) => void;
|
|
74
73
|
}
|
|
75
74
|
/**
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* It configures the VM sandbox and delegates session management to RequestScriptSession.
|
|
10
10
|
*/
|
|
11
11
|
import { IHttpRequestService } from '../http/interfaces';
|
|
12
|
+
import { SecretResolverRegistry } from '../secrets/secret-resolver-registry';
|
|
12
13
|
import { IRequestScriptSession, IScriptExecutor, PreRequestScriptContext } from './interfaces';
|
|
13
14
|
/**
|
|
14
15
|
* Script Executor Implementation
|
|
@@ -20,8 +21,9 @@ import { IRequestScriptSession, IScriptExecutor, PreRequestScriptContext } from
|
|
|
20
21
|
*/
|
|
21
22
|
export declare class ScriptExecutor implements IScriptExecutor {
|
|
22
23
|
private readonly httpService?;
|
|
24
|
+
private readonly secretRegistry?;
|
|
23
25
|
private readonly moduleLoader;
|
|
24
|
-
constructor(httpService?: IHttpRequestService | undefined, modulePaths?: string[]);
|
|
26
|
+
constructor(httpService?: IHttpRequestService | undefined, modulePaths?: string[], secretRegistry?: SecretResolverRegistry | undefined);
|
|
25
27
|
/**
|
|
26
28
|
* Create a request execution session
|
|
27
29
|
* Factory method implementing IScriptExecutor
|
|
@@ -60,6 +62,13 @@ export declare class ScriptExecutor implements IScriptExecutor {
|
|
|
60
62
|
* Create environment variable scope with change callbacks
|
|
61
63
|
*/
|
|
62
64
|
private createEnvironmentScope;
|
|
65
|
+
/**
|
|
66
|
+
* Create the Postman-compatible pm.vault namespace.
|
|
67
|
+
* Reads are backed by HTTP Forge's secret provider system using the same
|
|
68
|
+
* {{secret:provider/path}} resolution. Writes are not supported (read-only),
|
|
69
|
+
* and resolved values are never persisted to console/report output here.
|
|
70
|
+
*/
|
|
71
|
+
private createVault;
|
|
63
72
|
/**
|
|
64
73
|
* Create sendRequest function using httpService
|
|
65
74
|
*/
|
|
@@ -5,6 +5,15 @@
|
|
|
5
5
|
* Open/Closed: New factory methods can be added without modifying existing ones
|
|
6
6
|
*/
|
|
7
7
|
import { ResponseContext } from './interfaces';
|
|
8
|
+
/**
|
|
9
|
+
* Minimal, dependency-free JSON Schema validator.
|
|
10
|
+
*
|
|
11
|
+
* Supports the common subset used in API tests (draft-04 style):
|
|
12
|
+
* `type`, `properties`, `required`, `items`, `enum`, `additionalProperties`
|
|
13
|
+
* (boolean), `minimum`/`maximum`, `minLength`/`maxLength`, and `pattern`.
|
|
14
|
+
* Returns a list of human-readable error strings (empty when valid).
|
|
15
|
+
*/
|
|
16
|
+
export declare function validateJsonSchema(data: any, schema: any, path?: string): string[];
|
|
8
17
|
/**
|
|
9
18
|
* Response object interface for script context
|
|
10
19
|
*/
|
|
@@ -36,6 +45,7 @@ export interface ResponseAssertions {
|
|
|
36
45
|
header(headerName: string, expectedValue?: string): void;
|
|
37
46
|
body(expectedBody?: string): void;
|
|
38
47
|
jsonBody(expectedJson?: any): void;
|
|
48
|
+
jsonSchema(schema: any): void;
|
|
39
49
|
};
|
|
40
50
|
be: {
|
|
41
51
|
readonly ok: any;
|
|
@@ -62,12 +72,27 @@ export interface ExpectChain {
|
|
|
62
72
|
be: ExpectChain;
|
|
63
73
|
have: ExpectChain;
|
|
64
74
|
deep: ExpectChain;
|
|
75
|
+
and: ExpectChain;
|
|
76
|
+
that: ExpectChain;
|
|
77
|
+
which: ExpectChain;
|
|
78
|
+
is: ExpectChain;
|
|
79
|
+
been: ExpectChain;
|
|
80
|
+
has: ExpectChain;
|
|
81
|
+
with: ExpectChain;
|
|
82
|
+
at: ExpectChain;
|
|
83
|
+
of: ExpectChain;
|
|
84
|
+
same: ExpectChain;
|
|
85
|
+
but: ExpectChain;
|
|
86
|
+
does: ExpectChain;
|
|
87
|
+
still: ExpectChain;
|
|
88
|
+
also: ExpectChain;
|
|
65
89
|
equal(expected: any): ExpectChain;
|
|
66
90
|
eql(expected: any): ExpectChain;
|
|
67
91
|
property(name: string, value?: any): ExpectChain;
|
|
68
92
|
ok: ExpectChain;
|
|
69
93
|
exist: ExpectChain;
|
|
70
94
|
include(value: any): ExpectChain;
|
|
95
|
+
contain(value: any): ExpectChain;
|
|
71
96
|
oneOf(values: any[]): ExpectChain;
|
|
72
97
|
match(pattern: RegExp): ExpectChain;
|
|
73
98
|
above(num: number): ExpectChain;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Secrets Manager resolver
|
|
3
|
+
*
|
|
4
|
+
* Uses the AWS SDK v3 credential chain — no credentials are stored in HTTP Forge config.
|
|
5
|
+
* Order: env vars → ~/.aws/credentials → IAM instance role → ECS task role
|
|
6
|
+
*
|
|
7
|
+
* Token syntax: {{secret:aws/<secretId>}}
|
|
8
|
+
* e.g. {{secret:aws/myapp/prod/db-password}}
|
|
9
|
+
* {{secret:aws/myapp/prod/api-key#field}} (JSON secret field)
|
|
10
|
+
*/
|
|
11
|
+
import type { AwsSecretsConfig, ISecretResolver } from '../../types/secret-resolver';
|
|
12
|
+
export declare class AwsSecretResolver implements ISecretResolver {
|
|
13
|
+
readonly providerName = "aws";
|
|
14
|
+
private readonly region;
|
|
15
|
+
private readonly moduleRequire;
|
|
16
|
+
constructor(config: AwsSecretsConfig, moduleRequire?: (name: string) => any);
|
|
17
|
+
resolve(path: string): Promise<string | undefined>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure Key Vault resolver
|
|
3
|
+
*
|
|
4
|
+
* Uses DefaultAzureCredential — no credentials stored in HTTP Forge config.
|
|
5
|
+
* Order: env vars (AZURE_*) → managed identity → Azure CLI login → VS Code login
|
|
6
|
+
*
|
|
7
|
+
* Token syntax: {{secret:azure/<secretName>}}
|
|
8
|
+
* e.g. {{secret:azure/my-api-key}}
|
|
9
|
+
* {{secret:azure/my-api-key/1.0}} (specific version)
|
|
10
|
+
*
|
|
11
|
+
* Config requires vaultUrl, e.g. "https://myvault.vault.azure.net"
|
|
12
|
+
*/
|
|
13
|
+
import type { AzureKeyVaultConfig, ISecretResolver } from '../../types/secret-resolver';
|
|
14
|
+
export declare class AzureKeyVaultResolver implements ISecretResolver {
|
|
15
|
+
readonly providerName = "azure";
|
|
16
|
+
private readonly vaultUrl;
|
|
17
|
+
private readonly moduleRequire;
|
|
18
|
+
constructor(config: AzureKeyVaultConfig, moduleRequire?: (name: string) => any);
|
|
19
|
+
resolve(path: string): Promise<string | undefined>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doppler secret resolver
|
|
3
|
+
*
|
|
4
|
+
* Uses the Doppler REST API — no SDK required, just a service token.
|
|
5
|
+
* Credentials: DOPPLER_TOKEN env var (or serviceToken in config for per-project override)
|
|
6
|
+
*
|
|
7
|
+
* Token syntax: {{secret:doppler/<secretName>}}
|
|
8
|
+
* e.g. {{secret:doppler/API_KEY}}
|
|
9
|
+
* {{secret:doppler/DATABASE_URL}}
|
|
10
|
+
*
|
|
11
|
+
* The Doppler project/config are baked into the service token itself —
|
|
12
|
+
* no project or config fields needed in http-forge.config.json.
|
|
13
|
+
*
|
|
14
|
+
* Prerequisites: none (uses Node.js built-in https)
|
|
15
|
+
*/
|
|
16
|
+
import type { DopplerConfig, ISecretResolver } from '../../types/secret-resolver';
|
|
17
|
+
export declare class DopplerResolver implements ISecretResolver {
|
|
18
|
+
readonly providerName = "doppler";
|
|
19
|
+
private readonly token;
|
|
20
|
+
constructor(config: DopplerConfig);
|
|
21
|
+
resolve(path: string): Promise<string | undefined>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Cloud Secret Manager resolver
|
|
3
|
+
*
|
|
4
|
+
* Uses Application Default Credentials — no credentials stored in HTTP Forge config.
|
|
5
|
+
* Order: GOOGLE_APPLICATION_CREDENTIALS env var → gcloud CLI login → Workload Identity (GKE)
|
|
6
|
+
* → Metadata server (Cloud Run, Compute Engine)
|
|
7
|
+
*
|
|
8
|
+
* Token syntax: {{secret:gcp/<secretName>}}
|
|
9
|
+
* {{secret:gcp/<secretName>/versions/<version>}} (specific version, default: latest)
|
|
10
|
+
*
|
|
11
|
+
* Config: { "provider": "gcp", "projectId": "my-project" }
|
|
12
|
+
* projectId falls back to GOOGLE_CLOUD_PROJECT / GCLOUD_PROJECT env vars.
|
|
13
|
+
*/
|
|
14
|
+
import type { GcpSecretsConfig, ISecretResolver } from '../../types/secret-resolver';
|
|
15
|
+
export declare class GcpSecretResolver implements ISecretResolver {
|
|
16
|
+
readonly providerName = "gcp";
|
|
17
|
+
private readonly projectId;
|
|
18
|
+
private readonly moduleRequire;
|
|
19
|
+
constructor(config: GcpSecretsConfig, moduleRequire?: (name: string) => any);
|
|
20
|
+
resolve(path: string): Promise<string | undefined>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HashiCorp Vault resolver
|
|
3
|
+
*
|
|
4
|
+
* Credentials are NEVER stored in HTTP Forge config.
|
|
5
|
+
* Authentication uses:
|
|
6
|
+
* VAULT_TOKEN env var (token auth)
|
|
7
|
+
* VAULT_ADDR env var (server address, overrides config)
|
|
8
|
+
* VAULT_NAMESPACE env var (Enterprise/HCP namespace, overridden by config.namespace)
|
|
9
|
+
*
|
|
10
|
+
* Token syntax: {{secret:vault/<mountPath>/<secretPath>#<field>}}
|
|
11
|
+
* e.g. {{secret:vault/secret/myapp/prod#db_password}}
|
|
12
|
+
* {{secret:vault/kv/myapp/config#api_key}}
|
|
13
|
+
*
|
|
14
|
+
* The path format after the provider prefix: <mount>/<path>#<field>
|
|
15
|
+
* If no field is specified and the secret has a single key "value", that is returned.
|
|
16
|
+
*/
|
|
17
|
+
import type { HashiCorpVaultConfig, ISecretResolver } from '../../types/secret-resolver';
|
|
18
|
+
export declare class HashiCorpVaultResolver implements ISecretResolver {
|
|
19
|
+
readonly providerName = "vault";
|
|
20
|
+
private readonly address;
|
|
21
|
+
private readonly mountPath;
|
|
22
|
+
private readonly namespace;
|
|
23
|
+
constructor(config: HashiCorpVaultConfig);
|
|
24
|
+
resolve(path: string): Promise<string | undefined>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 1Password Connect / Service Account resolver
|
|
3
|
+
*
|
|
4
|
+
* Credentials are NEVER stored in HTTP Forge config.
|
|
5
|
+
* Authentication uses:
|
|
6
|
+
* OP_SERVICE_ACCOUNT_TOKEN env var (1Password Service Account — recommended for CI)
|
|
7
|
+
* OP_CONNECT_TOKEN + OP_CONNECT_HOST env vars (1Password Connect Server)
|
|
8
|
+
*
|
|
9
|
+
* Token syntax: {{secret:1password/<vault>/<item>/<field>}}
|
|
10
|
+
* e.g. {{secret:1password/MyVault/MyApp/api_key}}
|
|
11
|
+
* {{secret:1password/Shared/prod-db/password}}
|
|
12
|
+
*
|
|
13
|
+
* If `vault` is specified in the provider config, the token path may omit it:
|
|
14
|
+
* {{secret:1password/<item>/<field>}}
|
|
15
|
+
*
|
|
16
|
+
* Uses the 1Password CLI (`op`) via child_process if SDK is unavailable.
|
|
17
|
+
*/
|
|
18
|
+
import type { ISecretResolver, OnePasswordConfig } from '../../types/secret-resolver';
|
|
19
|
+
export declare class OnePasswordResolver implements ISecretResolver {
|
|
20
|
+
readonly providerName = "1password";
|
|
21
|
+
private readonly defaultVault;
|
|
22
|
+
constructor(config: OnePasswordConfig);
|
|
23
|
+
resolve(path: string): Promise<string | undefined>;
|
|
24
|
+
private tryResolveSdk;
|
|
25
|
+
private resolveViaCli;
|
|
26
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret Resolver Registry — Phase 3
|
|
3
|
+
*
|
|
4
|
+
* Builds and caches ISecretResolver instances from config, and provides
|
|
5
|
+
* async pre-resolution of {{secret:provider/path}} tokens in template strings.
|
|
6
|
+
*
|
|
7
|
+
* Design:
|
|
8
|
+
* - Registry is created once at startup from IConfigService
|
|
9
|
+
* - resolveSecretTokens() is called BEFORE variable interpolation per-request
|
|
10
|
+
* - Resolved values are injected as extraVariables so the sync VariableResolver
|
|
11
|
+
* picks them up transparently
|
|
12
|
+
* - Results are cached within a single request lifetime to avoid redundant API calls
|
|
13
|
+
*/
|
|
14
|
+
import type { IConfigService } from '../config/config.interface';
|
|
15
|
+
export declare class SecretResolverRegistry {
|
|
16
|
+
private readonly resolvers;
|
|
17
|
+
/**
|
|
18
|
+
* Require function rooted at the user's project (via config `scripts.modulePaths`),
|
|
19
|
+
* so optional cloud SDKs resolve from the same place users install custom script
|
|
20
|
+
* modules — not from the extension's own bundle.
|
|
21
|
+
*/
|
|
22
|
+
private readonly moduleRequire;
|
|
23
|
+
constructor(configService?: IConfigService);
|
|
24
|
+
/**
|
|
25
|
+
* Scan a string (or recursively, any object) for {{secret:alias/path}} tokens
|
|
26
|
+
* and resolve them all in parallel.
|
|
27
|
+
*
|
|
28
|
+
* Returns a flat map of "secret:alias/path" → plaintext value
|
|
29
|
+
* suitable for injection as extraVariables into VariableResolver.
|
|
30
|
+
*/
|
|
31
|
+
resolveSecretTokens(input: any, cache?: Map<string, string>): Promise<Record<string, string>>;
|
|
32
|
+
/** Whether any providers are configured */
|
|
33
|
+
get hasProviders(): boolean;
|
|
34
|
+
private collectTokens;
|
|
35
|
+
private createResolver;
|
|
36
|
+
/**
|
|
37
|
+
* Build a `require` function rooted at the user's project, so optional cloud SDKs
|
|
38
|
+
* resolve from the same `node_modules` where users install custom script modules
|
|
39
|
+
* (via config `scripts.modulePaths`). Falls back to the default `require` so the
|
|
40
|
+
* CLI (which lists SDKs in optionalDependencies) still works without modulePaths.
|
|
41
|
+
*/
|
|
42
|
+
private buildModuleRequire;
|
|
43
|
+
}
|
|
@@ -5,6 +5,13 @@
|
|
|
5
5
|
* generates a self-contained single-file HTML report (no external dependencies).
|
|
6
6
|
*
|
|
7
7
|
* Output: {basePath}/{suiteId}/{runId}/report.html
|
|
8
|
+
*
|
|
9
|
+
* Each request entry expands to show:
|
|
10
|
+
* - Full request URL, method, headers, body
|
|
11
|
+
* - Response status, headers, body (pretty-printed)
|
|
12
|
+
* - All test assertions (pass/fail + messages)
|
|
13
|
+
* - Console output (if any)
|
|
14
|
+
* - Error message (if any)
|
|
8
15
|
*/
|
|
9
16
|
export declare class HtmlReportGenerator {
|
|
10
17
|
private readonly basePath;
|
|
@@ -15,6 +22,22 @@ export declare class HtmlReportGenerator {
|
|
|
15
22
|
*/
|
|
16
23
|
generate(suiteId: string, runId: string): Promise<string>;
|
|
17
24
|
private loadAllSummaries;
|
|
18
|
-
|
|
25
|
+
/** Load every result file for every request (pass + fail). */
|
|
26
|
+
private loadAllDetails;
|
|
27
|
+
/**
|
|
28
|
+
* Group summaries by iteration, then by (collection + folder path),
|
|
29
|
+
* preserving execution order within each tier.
|
|
30
|
+
*/
|
|
31
|
+
private groupByIterCollectionFolder;
|
|
32
|
+
/**
|
|
33
|
+
* Build a combined group header label like:
|
|
34
|
+
* "01 - MyCollection: Auth/Login"
|
|
35
|
+
* Collection or folder parts are omitted when empty; falls back to "(root)".
|
|
36
|
+
*/
|
|
37
|
+
private groupLabel;
|
|
38
|
+
/** Render the detail accordions grouped by iteration → (collection + folder). */
|
|
39
|
+
private renderGroupedDetails;
|
|
40
|
+
/** Render the timeline table rows grouped by iteration → (collection + folder). */
|
|
41
|
+
private renderGroupedTimeline;
|
|
19
42
|
private buildHtml;
|
|
20
43
|
}
|
|
@@ -45,7 +45,7 @@ export declare class ResultStorageService implements IResultStorageService {
|
|
|
45
45
|
* Finalize run
|
|
46
46
|
* @returns path to the generated HTML report, or null if generation failed
|
|
47
47
|
*/
|
|
48
|
-
finalizeRun(status?: 'completed' | 'aborted' | 'error'): Promise<string | null>;
|
|
48
|
+
finalizeRun(status?: 'completed' | 'aborted' | 'error', generateHtmlReport?: boolean): Promise<string | null>;
|
|
49
49
|
getCurrentStats(): {
|
|
50
50
|
stats: RunStats;
|
|
51
51
|
requestStats: Record<string, RequestStats>;
|
|
@@ -39,6 +39,10 @@ export interface ResultSummary {
|
|
|
39
39
|
r: string;
|
|
40
40
|
/** Error message if failed (e) - null if passed */
|
|
41
41
|
e: string | null;
|
|
42
|
+
/** Folder path (fp) - slash-separated; omitted/empty for root-level requests */
|
|
43
|
+
fp?: string;
|
|
44
|
+
/** Collection name (cn) - omitted/empty when unknown */
|
|
45
|
+
cn?: string;
|
|
42
46
|
}
|
|
43
47
|
/**
|
|
44
48
|
* Build result filename from summary components
|
|
@@ -169,6 +173,10 @@ export interface FullResultDetails {
|
|
|
169
173
|
method: string;
|
|
170
174
|
/** Full URL */
|
|
171
175
|
url: string;
|
|
176
|
+
/** Folder path within the collection (slash-separated; empty for root) */
|
|
177
|
+
folderPath?: string;
|
|
178
|
+
/** Name of the collection this request belongs to */
|
|
179
|
+
collectionName?: string;
|
|
172
180
|
/** HTTP status code */
|
|
173
181
|
status: number;
|
|
174
182
|
/** HTTP status text */
|
|
@@ -181,13 +189,27 @@ export interface FullResultDetails {
|
|
|
181
189
|
timestamp: number;
|
|
182
190
|
/** Request details */
|
|
183
191
|
request: {
|
|
192
|
+
method: string;
|
|
193
|
+
url: string;
|
|
184
194
|
headers: Record<string, string>;
|
|
185
|
-
|
|
195
|
+
query: Record<string, string>;
|
|
196
|
+
params: Record<string, string>;
|
|
197
|
+
body: {
|
|
198
|
+
type: string;
|
|
199
|
+
format?: string;
|
|
200
|
+
content: any;
|
|
201
|
+
};
|
|
186
202
|
};
|
|
187
203
|
/** Response details */
|
|
188
204
|
response: {
|
|
189
205
|
headers: Record<string, string | string[]>;
|
|
190
206
|
body: any;
|
|
207
|
+
time?: number;
|
|
208
|
+
size?: number;
|
|
209
|
+
cookies?: Array<{
|
|
210
|
+
name?: string;
|
|
211
|
+
value?: string;
|
|
212
|
+
}>;
|
|
191
213
|
};
|
|
192
214
|
/** Test assertions */
|
|
193
215
|
assertions: Array<{
|
|
@@ -197,6 +219,23 @@ export interface FullResultDetails {
|
|
|
197
219
|
}>;
|
|
198
220
|
/** Error message */
|
|
199
221
|
error: string | null;
|
|
222
|
+
/** Console output produced while running the request */
|
|
223
|
+
consoleOutput?: string[];
|
|
224
|
+
/** Variables modified by pre/post scripts */
|
|
225
|
+
modifiedVariables?: Record<string, string>;
|
|
226
|
+
/** Environment variables modified by scripts */
|
|
227
|
+
modifiedEnvironmentVariables?: Record<string, string>;
|
|
228
|
+
/** Collection variables modified by scripts */
|
|
229
|
+
modifiedCollectionVariables?: Record<string, string>;
|
|
230
|
+
/** Session variables modified by scripts */
|
|
231
|
+
modifiedSessionVariables?: Record<string, string>;
|
|
232
|
+
/** pm.execution.setNextRequest() value */
|
|
233
|
+
nextRequest?: string | null;
|
|
234
|
+
/** pm.visualizer.set() payload */
|
|
235
|
+
visualizerData?: {
|
|
236
|
+
template: string;
|
|
237
|
+
data?: any;
|
|
238
|
+
};
|
|
200
239
|
}
|
|
201
240
|
/**
|
|
202
241
|
* Index page containing summaries
|
|
@@ -248,9 +287,12 @@ export interface IResultStorageService {
|
|
|
248
287
|
saveResult(iteration: number, result: ExecutionResult): Promise<ResultSummary>;
|
|
249
288
|
/**
|
|
250
289
|
* Finalize run
|
|
251
|
-
* @
|
|
290
|
+
* @param status final run status
|
|
291
|
+
* @param generateHtmlReport when false, the run is persisted (manifest + results)
|
|
292
|
+
* but the HTML report is not generated; returns null in that case
|
|
293
|
+
* @returns path to the generated HTML report, or null if not generated / generation failed
|
|
252
294
|
*/
|
|
253
|
-
finalizeRun(status: 'completed' | 'aborted' | 'error'): Promise<string | null>;
|
|
295
|
+
finalizeRun(status: 'completed' | 'aborted' | 'error', generateHtmlReport?: boolean): Promise<string | null>;
|
|
254
296
|
/**
|
|
255
297
|
* Get current run stats
|
|
256
298
|
*/
|
|
@@ -11,6 +11,11 @@ export interface EnvironmentConfig {
|
|
|
11
11
|
description?: string;
|
|
12
12
|
requiresConfirmation?: boolean;
|
|
13
13
|
variables?: Record<string, string>;
|
|
14
|
+
/**
|
|
15
|
+
* Names of variables whose values are stored in SecretStorage rather than the JSON file.
|
|
16
|
+
* The JSON file stores the variable name only; the value is fetched at resolution time.
|
|
17
|
+
*/
|
|
18
|
+
secretVariables?: string[];
|
|
14
19
|
}
|
|
15
20
|
/**
|
|
16
21
|
* Shared configuration file structure
|
|
@@ -95,18 +100,14 @@ export interface IVariableResolver {
|
|
|
95
100
|
* Variable management operations (for scripts)
|
|
96
101
|
*/
|
|
97
102
|
export interface IVariableManager {
|
|
98
|
-
setEnvironmentVariable(key: string, value: unknown): void;
|
|
99
|
-
deleteEnvironmentVariable(key: string): void;
|
|
100
|
-
clearEnvironmentVariables(): void;
|
|
103
|
+
setEnvironmentVariable(key: string, value: unknown, envName?: string): void;
|
|
104
|
+
deleteEnvironmentVariable(key: string, envName?: string): void;
|
|
105
|
+
clearEnvironmentVariables(envName?: string): void;
|
|
101
106
|
getEnvironmentVariableLocals(): Record<string, string>;
|
|
102
107
|
setGlobalVariable(key: string, value: unknown): void;
|
|
103
108
|
getGlobalVariable(key: string): string | undefined;
|
|
104
109
|
deleteGlobalVariable(key: string): void;
|
|
105
110
|
clearGlobalVariables(): void;
|
|
106
|
-
setSessionVariable(key: string, value: unknown): void;
|
|
107
|
-
deleteSessionVariable(key: string): Promise<void>;
|
|
108
|
-
clearSessionVariables(): Promise<void>;
|
|
109
|
-
getSessionVariables(): Record<string, string>;
|
|
110
111
|
getGlobalVariables(): Record<string, string>;
|
|
111
112
|
}
|
|
112
113
|
/**
|
|
@@ -115,6 +116,14 @@ export interface IVariableManager {
|
|
|
115
116
|
export interface IEnvironmentConfigService extends IEnvironmentConfigReader, IEnvironmentConfigWriter, IEnvironmentSelector, IVariableResolver, IVariableManager {
|
|
116
117
|
loadConfigs(): void;
|
|
117
118
|
exportEnvironmentsToFolder(outDir: string, mergeGlobals?: boolean): void;
|
|
119
|
+
/** Read a single secret variable from SecretStorage. */
|
|
120
|
+
getSecretVariable(envName: string, key: string): Promise<string | undefined>;
|
|
121
|
+
/** Store a secret variable value in SecretStorage. */
|
|
122
|
+
setSecretVariable(envName: string, key: string, value: string): Promise<void>;
|
|
123
|
+
/** Delete a secret variable from SecretStorage. */
|
|
124
|
+
deleteSecretVariable(envName: string, key: string): Promise<void>;
|
|
125
|
+
/** Load all secrets for an environment (or current) into cache. */
|
|
126
|
+
loadSecretVariables(envName?: string): Promise<void>;
|
|
118
127
|
}
|
|
119
128
|
/**
|
|
120
129
|
* Interface for storing and retrieving environment variables
|