@provartesting/provardx-cli 1.5.0-beta.3 → 1.5.0-beta.4
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 +101 -1
- package/lib/commands/provar/auth/clear.d.ts +7 -0
- package/lib/commands/provar/auth/clear.js +36 -0
- package/lib/commands/provar/auth/clear.js.map +1 -0
- package/lib/commands/provar/auth/login.d.ts +10 -0
- package/lib/commands/provar/auth/login.js +88 -0
- package/lib/commands/provar/auth/login.js.map +1 -0
- package/lib/commands/provar/auth/rotate.d.ts +7 -0
- package/lib/commands/provar/auth/rotate.js +42 -0
- package/lib/commands/provar/auth/rotate.js.map +1 -0
- package/lib/commands/provar/auth/status.d.ts +7 -0
- package/lib/commands/provar/auth/status.js +89 -0
- package/lib/commands/provar/auth/status.js.map +1 -0
- package/lib/mcp/tools/testCaseValidate.d.ts +4 -0
- package/lib/mcp/tools/testCaseValidate.js +98 -17
- package/lib/mcp/tools/testCaseValidate.js.map +1 -1
- package/lib/services/auth/credentials.d.ts +18 -0
- package/lib/services/auth/credentials.js +71 -0
- package/lib/services/auth/credentials.js.map +1 -0
- package/lib/services/auth/loginFlow.d.ts +61 -0
- package/lib/services/auth/loginFlow.js +183 -0
- package/lib/services/auth/loginFlow.js.map +1 -0
- package/lib/services/qualityHub/client.d.ts +131 -0
- package/lib/services/qualityHub/client.js +196 -0
- package/lib/services/qualityHub/client.js.map +1 -0
- package/messages/sf.provar.auth.clear.md +13 -0
- package/messages/sf.provar.auth.login.md +31 -0
- package/messages/sf.provar.auth.rotate.md +23 -0
- package/messages/sf.provar.auth.status.md +13 -0
- package/oclif.manifest.json +327 -114
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
[](https://npmjs.org/package/@provartesting/provardx-cli)
|
|
4
4
|
[](https://npmjs.org/package/@provartesting/provardx-cli)
|
|
5
5
|
[](https://github.com/ProvarTesting/provardx-cli/blob/main/LICENSE.md)
|
|
6
|
+
[](https://aqqlrlhga7.execute-api.us-east-1.amazonaws.com/dev/auth/request-access)
|
|
6
7
|
|
|
7
8
|
# What is the ProvarDX CLI?
|
|
8
9
|
|
|
@@ -30,7 +31,9 @@ $ sf plugins uninstall @provartesting/provardx-cli
|
|
|
30
31
|
|
|
31
32
|
# MCP Server (AI-Assisted Quality)
|
|
32
33
|
|
|
33
|
-
The Provar DX CLI includes a built-in **Model Context Protocol (MCP) server** that connects AI assistants (Claude Desktop, Claude Code, Cursor) directly to your Provar project. Once connected, an AI agent can inspect your project structure, generate Page Objects and test cases, validate every level of the test hierarchy with quality scores
|
|
34
|
+
The Provar DX CLI includes a built-in **Model Context Protocol (MCP) server** that connects AI assistants (Claude Desktop, Claude Code, Cursor) directly to your Provar project. Once connected, an AI agent can inspect your project structure, generate Page Objects and test cases, validate every level of the test hierarchy with quality scores, and work with NitroX (Hybrid Model) component page objects for LWC, Screen Flow, Industry Components, Experience Cloud, and HTML5.
|
|
35
|
+
|
|
36
|
+
Validation runs in two modes: **local only** (structural rules, no key required) or **Quality Hub API** (170+ rules, quality scoring — requires a `pv_k_` API key). Run `sf provar auth login` to authenticate and unlock full validation. Don't have an account? **[Request access](https://aqqlrlhga7.execute-api.us-east-1.amazonaws.com/dev/auth/request-access)**.
|
|
34
37
|
|
|
35
38
|
```sh
|
|
36
39
|
sf provar mcp start --allowed-paths /path/to/your/provar/project
|
|
@@ -57,6 +60,10 @@ When `NODE_ENV=test` the validation step is skipped entirely. This is intended o
|
|
|
57
60
|
|
|
58
61
|
# Commands
|
|
59
62
|
|
|
63
|
+
- [`sf provar auth login`](#sf-provar-auth-login)
|
|
64
|
+
- [`sf provar auth rotate`](#sf-provar-auth-rotate)
|
|
65
|
+
- [`sf provar auth status`](#sf-provar-auth-status)
|
|
66
|
+
- [`sf provar auth clear`](#sf-provar-auth-clear)
|
|
60
67
|
- [`sf provar mcp start`](#sf-provar-mcp-start)
|
|
61
68
|
- [`sf provar config get`](#sf-provar-config-get)
|
|
62
69
|
- [`sf provar config set`](#sf-provar-config-set)
|
|
@@ -84,6 +91,99 @@ When `NODE_ENV=test` the validation step is skipped entirely. This is intended o
|
|
|
84
91
|
- [`sf provar manager test run report`](#sf-provar-manager-test-run-report) _(deprecated — use `sf provar quality-hub test run report`)_
|
|
85
92
|
- [`sf provar manager test run abort`](#sf-provar-manager-test-run-abort) _(deprecated — use `sf provar quality-hub test run abort`)_
|
|
86
93
|
|
|
94
|
+
## `sf provar auth login`
|
|
95
|
+
|
|
96
|
+
Log in to Provar Quality Hub and store your API key.
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
USAGE
|
|
100
|
+
$ sf provar auth login [--url <value>]
|
|
101
|
+
|
|
102
|
+
FLAGS
|
|
103
|
+
--url=<value> Override the Quality Hub API base URL (for non-production environments).
|
|
104
|
+
|
|
105
|
+
DESCRIPTION
|
|
106
|
+
Opens a browser to the Provar login page. After you authenticate, your API key is
|
|
107
|
+
stored at ~/.provar/credentials.json and used automatically by the Provar MCP tools
|
|
108
|
+
and CI/CD integrations. The key is valid for approximately 90 days.
|
|
109
|
+
|
|
110
|
+
For CI/CD pipelines (GitHub Actions, Jenkins, etc.) where a browser cannot open:
|
|
111
|
+
run sf provar auth login once on your local machine, copy the api_key value from
|
|
112
|
+
~/.provar/credentials.json, and store it as the PROVAR_API_KEY environment variable
|
|
113
|
+
or secret in your pipeline. Rotate the secret every ~90 days when the key expires.
|
|
114
|
+
|
|
115
|
+
Don't have an account? Request access at:
|
|
116
|
+
https://aqqlrlhga7.execute-api.us-east-1.amazonaws.com/dev/auth/request-access
|
|
117
|
+
|
|
118
|
+
EXAMPLES
|
|
119
|
+
Log in interactively:
|
|
120
|
+
|
|
121
|
+
$ sf provar auth login
|
|
122
|
+
|
|
123
|
+
Log in against a staging environment:
|
|
124
|
+
|
|
125
|
+
$ sf provar auth login --url https://dev.api.example.com
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## `sf provar auth rotate`
|
|
129
|
+
|
|
130
|
+
Rotate your stored API key without re-authenticating via browser.
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
USAGE
|
|
134
|
+
$ sf provar auth rotate
|
|
135
|
+
|
|
136
|
+
DESCRIPTION
|
|
137
|
+
Exchanges your current pv_k_ key for a new one atomically. The old key is
|
|
138
|
+
invalidated immediately. The new key is written to ~/.provar/credentials.json.
|
|
139
|
+
|
|
140
|
+
Use this to rotate your key on a regular schedule (~every 90 days) without
|
|
141
|
+
going through the browser login flow. If your current key is already expired,
|
|
142
|
+
run sf provar auth login instead.
|
|
143
|
+
|
|
144
|
+
EXAMPLES
|
|
145
|
+
Rotate the stored API key:
|
|
146
|
+
|
|
147
|
+
$ sf provar auth rotate
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## `sf provar auth status`
|
|
151
|
+
|
|
152
|
+
Show the current API key configuration and validate it against Quality Hub.
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
USAGE
|
|
156
|
+
$ sf provar auth status
|
|
157
|
+
|
|
158
|
+
DESCRIPTION
|
|
159
|
+
Reports whether an API key is configured, where it came from (environment variable
|
|
160
|
+
or credentials file), and performs a live check against the Quality Hub API to
|
|
161
|
+
confirm the key is still valid.
|
|
162
|
+
|
|
163
|
+
EXAMPLES
|
|
164
|
+
Check auth status:
|
|
165
|
+
|
|
166
|
+
$ sf provar auth status
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## `sf provar auth clear`
|
|
170
|
+
|
|
171
|
+
Remove the stored API key.
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
USAGE
|
|
175
|
+
$ sf provar auth clear
|
|
176
|
+
|
|
177
|
+
DESCRIPTION
|
|
178
|
+
Deletes ~/.provar/credentials.json and revokes the key server-side. After clearing,
|
|
179
|
+
the MCP tools fall back to local validation mode. Has no effect if no key is stored.
|
|
180
|
+
|
|
181
|
+
EXAMPLES
|
|
182
|
+
Remove the stored key:
|
|
183
|
+
|
|
184
|
+
$ sf provar auth clear
|
|
185
|
+
```
|
|
186
|
+
|
|
87
187
|
## `sf provar mcp start`
|
|
88
188
|
|
|
89
189
|
Start a local MCP server for Provar tools over stdio transport.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024 Provar Limited.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.md file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
import { SfCommand } from '@salesforce/sf-plugins-core';
|
|
8
|
+
import { Messages } from '@provartesting/provardx-plugins-utils';
|
|
9
|
+
import { clearCredentials, readStoredCredentials } from '../../../services/auth/credentials.js';
|
|
10
|
+
import { qualityHubClient, getQualityHubBaseUrl } from '../../../services/qualityHub/client.js';
|
|
11
|
+
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
|
|
12
|
+
const messages = Messages.loadMessages('@provartesting/provardx-cli', 'sf.provar.auth.clear');
|
|
13
|
+
export default class SfProvarAuthClear extends SfCommand {
|
|
14
|
+
static summary = messages.getMessage('summary');
|
|
15
|
+
static description = messages.getMessage('description');
|
|
16
|
+
static examples = messages.getMessages('examples');
|
|
17
|
+
async run() {
|
|
18
|
+
const stored = readStoredCredentials();
|
|
19
|
+
if (stored) {
|
|
20
|
+
const baseUrl = getQualityHubBaseUrl();
|
|
21
|
+
try {
|
|
22
|
+
await qualityHubClient.revokeKey(stored.api_key, baseUrl);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
this.log(' Note: could not reach Quality Hub to revoke key server-side (offline?).');
|
|
26
|
+
this.log(' The local credentials have been removed — the key may still be valid until it expires.');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
clearCredentials();
|
|
30
|
+
this.log('API key cleared.');
|
|
31
|
+
this.log(' Next validation will use local rules only (structural checks, no quality scoring).');
|
|
32
|
+
this.log(' To reconfigure: sf provar auth login');
|
|
33
|
+
this.log(' For CI/CD: set the PROVAR_API_KEY environment variable.');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=clear.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clear.js","sourceRoot":"","sources":["../../../../src/commands/provar/auth/clear.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAEhG,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,6BAA6B,EAAE,sBAAsB,CAAC,CAAC;AAE9F,MAAM,CAAC,OAAO,OAAO,iBAAkB,SAAQ,SAAe;IACrD,MAAM,CAAU,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACzD,MAAM,CAAU,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACjE,MAAM,CAAU,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAE5D,KAAK,CAAC,GAAG;QACd,MAAM,MAAM,GAAG,qBAAqB,EAAE,CAAC;QACvC,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,OAAO,GAAG,oBAAoB,EAAE,CAAC;YACvC,IAAI,CAAC;gBACH,MAAM,gBAAgB,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC5D,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAC;gBACtF,IAAI,CAAC,GAAG,CAAC,0FAA0F,CAAC,CAAC;YACvG,CAAC;QACH,CAAC;QAED,gBAAgB,EAAE,CAAC;QACnB,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,sFAAsF,CAAC,CAAC;QACjG,IAAI,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;QACnD,IAAI,CAAC,GAAG,CAAC,gEAAgE,CAAC,CAAC;IAC7E,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SfCommand } from '@salesforce/sf-plugins-core';
|
|
2
|
+
export default class SfProvarAuthLogin extends SfCommand<void> {
|
|
3
|
+
static readonly summary: string;
|
|
4
|
+
static readonly description: string;
|
|
5
|
+
static readonly examples: string[];
|
|
6
|
+
static readonly flags: {
|
|
7
|
+
url: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024 Provar Limited.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.md file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
/* eslint-disable camelcase */
|
|
8
|
+
import { Flags, SfCommand } from '@salesforce/sf-plugins-core';
|
|
9
|
+
import { Messages } from '@provartesting/provardx-plugins-utils';
|
|
10
|
+
import { writeCredentials } from '../../../services/auth/credentials.js';
|
|
11
|
+
import { loginFlowClient } from '../../../services/auth/loginFlow.js';
|
|
12
|
+
import { qualityHubClient, getQualityHubBaseUrl, QualityHubAuthError, REQUEST_ACCESS_URL, } from '../../../services/qualityHub/client.js';
|
|
13
|
+
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
|
|
14
|
+
const messages = Messages.loadMessages('@provartesting/provardx-cli', 'sf.provar.auth.login');
|
|
15
|
+
// Production values bundled from Phase 2 handoff (2026-04-11).
|
|
16
|
+
// Override via PROVAR_COGNITO_DOMAIN / PROVAR_COGNITO_CLIENT_ID for non-prod environments.
|
|
17
|
+
const DEFAULT_COGNITO_DOMAIN = 'us-east-1xpfwzwmop.auth.us-east-1.amazoncognito.com';
|
|
18
|
+
const DEFAULT_CLIENT_ID = '29cs1a784r4cervmth8ugbkkri';
|
|
19
|
+
export default class SfProvarAuthLogin extends SfCommand {
|
|
20
|
+
static summary = messages.getMessage('summary');
|
|
21
|
+
static description = messages.getMessage('description');
|
|
22
|
+
static examples = messages.getMessages('examples');
|
|
23
|
+
static flags = {
|
|
24
|
+
url: Flags.string({
|
|
25
|
+
summary: messages.getMessage('flags.url.summary'),
|
|
26
|
+
required: false,
|
|
27
|
+
}),
|
|
28
|
+
};
|
|
29
|
+
async run() {
|
|
30
|
+
const { flags } = await this.parse(SfProvarAuthLogin);
|
|
31
|
+
const cognitoDomain = process.env.PROVAR_COGNITO_DOMAIN ?? DEFAULT_COGNITO_DOMAIN;
|
|
32
|
+
const clientId = process.env.PROVAR_COGNITO_CLIENT_ID ?? DEFAULT_CLIENT_ID;
|
|
33
|
+
const baseUrl = flags.url ?? getQualityHubBaseUrl();
|
|
34
|
+
// ── Step 1: Generate PKCE pair, nonce, and state ───────────────────────
|
|
35
|
+
const { verifier, challenge } = loginFlowClient.generatePkce();
|
|
36
|
+
const nonce = loginFlowClient.generateNonce();
|
|
37
|
+
const state = loginFlowClient.generateState();
|
|
38
|
+
// ── Step 2: Find an available registered callback port ──────────────────
|
|
39
|
+
const port = await loginFlowClient.findAvailablePort();
|
|
40
|
+
const redirectUri = `http://localhost:${port}/callback`;
|
|
41
|
+
// ── Step 3: Build the Cognito authorize URL ────────────────────────────
|
|
42
|
+
const authorizeUrl = new URL(`https://${cognitoDomain}/oauth2/authorize`);
|
|
43
|
+
authorizeUrl.searchParams.set('response_type', 'code');
|
|
44
|
+
authorizeUrl.searchParams.set('client_id', clientId);
|
|
45
|
+
authorizeUrl.searchParams.set('redirect_uri', redirectUri);
|
|
46
|
+
authorizeUrl.searchParams.set('code_challenge', challenge);
|
|
47
|
+
authorizeUrl.searchParams.set('code_challenge_method', 'S256');
|
|
48
|
+
authorizeUrl.searchParams.set('scope', 'openid email aws.cognito.signin.user.admin');
|
|
49
|
+
authorizeUrl.searchParams.set('state', state);
|
|
50
|
+
authorizeUrl.searchParams.set('nonce', nonce);
|
|
51
|
+
// ── Step 4: Open browser and wait for callback ──────────────────────────
|
|
52
|
+
this.log('Opening browser for login...');
|
|
53
|
+
this.log(` If the browser did not open, visit:\n ${authorizeUrl.toString()}`);
|
|
54
|
+
loginFlowClient.openBrowser(authorizeUrl.toString());
|
|
55
|
+
this.log('\nWaiting for authentication... (Ctrl-C to cancel)');
|
|
56
|
+
const authCode = await loginFlowClient.listenForCallback(port, state);
|
|
57
|
+
// ── Step 5: Exchange code for Cognito tokens ────────────────────────────
|
|
58
|
+
const tokens = await loginFlowClient.exchangeCodeForTokens({
|
|
59
|
+
code: authCode,
|
|
60
|
+
redirectUri,
|
|
61
|
+
clientId,
|
|
62
|
+
verifier,
|
|
63
|
+
tokenEndpoint: `https://${cognitoDomain}/oauth2/token`,
|
|
64
|
+
});
|
|
65
|
+
// ── Step 6: Exchange Cognito access token for pv_k_ key ─────────────────
|
|
66
|
+
// Cognito tokens are held in memory only — discarded after this call.
|
|
67
|
+
let keyData;
|
|
68
|
+
try {
|
|
69
|
+
keyData = await qualityHubClient.exchangeTokenForKey(tokens.access_token, baseUrl);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
if (err instanceof QualityHubAuthError) {
|
|
73
|
+
this.error(`No Provar MCP account found for this login.\nRequest access at: ${REQUEST_ACCESS_URL}`, { exit: 1 });
|
|
74
|
+
}
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
77
|
+
// ── Step 7: Persist the pv_k_ key ──────────────────────────────────────
|
|
78
|
+
writeCredentials(keyData.api_key, keyData.prefix, 'cognito', {
|
|
79
|
+
username: keyData.username,
|
|
80
|
+
tier: keyData.tier,
|
|
81
|
+
expires_at: keyData.expires_at,
|
|
82
|
+
});
|
|
83
|
+
this.log(`\nAuthenticated as ${keyData.username} (${keyData.tier} tier)`);
|
|
84
|
+
this.log(`API key stored (prefix: ${keyData.prefix}). Valid until ${keyData.expires_at}.`);
|
|
85
|
+
this.log(" Run 'sf provar auth status' to check at any time.");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../../../src/commands/provar/auth/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024 Provar Limited.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.md file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
/* eslint-disable camelcase */
|
|
8
|
+
import { SfCommand } from '@salesforce/sf-plugins-core';
|
|
9
|
+
import { Messages } from '@provartesting/provardx-plugins-utils';
|
|
10
|
+
import { readStoredCredentials, writeCredentials } from '../../../services/auth/credentials.js';
|
|
11
|
+
import { qualityHubClient, getQualityHubBaseUrl, QualityHubAuthError } from '../../../services/qualityHub/client.js';
|
|
12
|
+
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
|
|
13
|
+
const messages = Messages.loadMessages('@provartesting/provardx-cli', 'sf.provar.auth.rotate');
|
|
14
|
+
export default class SfProvarAuthRotate extends SfCommand {
|
|
15
|
+
static summary = messages.getMessage('summary');
|
|
16
|
+
static description = messages.getMessage('description');
|
|
17
|
+
static examples = messages.getMessages('examples');
|
|
18
|
+
async run() {
|
|
19
|
+
const stored = readStoredCredentials();
|
|
20
|
+
if (!stored) {
|
|
21
|
+
this.error('No API key stored. Run `sf provar auth login` first.', { exit: 1 });
|
|
22
|
+
}
|
|
23
|
+
const baseUrl = getQualityHubBaseUrl();
|
|
24
|
+
try {
|
|
25
|
+
const keyData = await qualityHubClient.rotateKey(stored.api_key, baseUrl);
|
|
26
|
+
writeCredentials(keyData.api_key, keyData.prefix, 'cognito', {
|
|
27
|
+
username: keyData.username,
|
|
28
|
+
tier: keyData.tier,
|
|
29
|
+
expires_at: keyData.expires_at,
|
|
30
|
+
});
|
|
31
|
+
this.log(`API key rotated (new prefix: ${keyData.prefix}). Valid until ${keyData.expires_at}.`);
|
|
32
|
+
this.log(" Run 'sf provar auth status' to verify.");
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
if (err instanceof QualityHubAuthError) {
|
|
36
|
+
this.error('Current key is invalid or expired — rotation requires a valid key.\nRun `sf provar auth login` to authenticate via browser and get a fresh key.', { exit: 1 });
|
|
37
|
+
}
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=rotate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotate.js","sourceRoot":"","sources":["../../../../src/commands/provar/auth/rotate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,8BAA8B;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAErH,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,6BAA6B,EAAE,uBAAuB,CAAC,CAAC;AAE/F,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,SAAe;IACtD,MAAM,CAAU,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACzD,MAAM,CAAU,WAAW,GAAG,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IACjE,MAAM,CAAU,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAE5D,KAAK,CAAC,GAAG;QACd,MAAM,MAAM,GAAG,qBAAqB,EAAE,CAAC;QAEvC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,KAAK,CAAC,sDAAsD,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QAClF,CAAC;QAED,MAAM,OAAO,GAAG,oBAAoB,EAAE,CAAC;QAEvC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC1E,gBAAgB,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE;gBAC3D,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,UAAU,EAAE,OAAO,CAAC,UAAU;aAC/B,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,gCAAgC,OAAO,CAAC,MAAM,kBAAkB,OAAO,CAAC,UAAU,GAAG,CAAC,CAAC;YAChG,IAAI,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,GAAG,YAAY,mBAAmB,EAAE,CAAC;gBACvC,IAAI,CAAC,KAAK,CACR,iJAAiJ,EACjJ,EAAE,IAAI,EAAE,CAAC,EAAE,CACZ,CAAC;YACJ,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2024 Provar Limited.
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* Licensed under the BSD 3-Clause license.
|
|
5
|
+
* For full license text, see LICENSE.md file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
6
|
+
*/
|
|
7
|
+
/* eslint-disable camelcase */
|
|
8
|
+
import { SfCommand } from '@salesforce/sf-plugins-core';
|
|
9
|
+
import { Messages } from '@provartesting/provardx-plugins-utils';
|
|
10
|
+
import { readStoredCredentials } from '../../../services/auth/credentials.js';
|
|
11
|
+
import { qualityHubClient, getQualityHubBaseUrl, REQUEST_ACCESS_URL } from '../../../services/qualityHub/client.js';
|
|
12
|
+
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
|
|
13
|
+
const messages = Messages.loadMessages('@provartesting/provardx-cli', 'sf.provar.auth.status');
|
|
14
|
+
export default class SfProvarAuthStatus extends SfCommand {
|
|
15
|
+
static summary = messages.getMessage('summary');
|
|
16
|
+
static description = messages.getMessage('description');
|
|
17
|
+
static examples = messages.getMessages('examples');
|
|
18
|
+
async run() {
|
|
19
|
+
const envKey = process.env.PROVAR_API_KEY?.trim();
|
|
20
|
+
if (envKey) {
|
|
21
|
+
if (!envKey.startsWith('pv_k_')) {
|
|
22
|
+
this.log('Warning: PROVAR_API_KEY is set but invalid (does not start with "pv_k_").');
|
|
23
|
+
this.log(` Value: "${envKey.substring(0, 10)}..." — ignored for API calls.`);
|
|
24
|
+
this.log(' Fix: update PROVAR_API_KEY to a valid pv_k_ key from https://success.provartesting.com');
|
|
25
|
+
this.log('');
|
|
26
|
+
// Fall through to check stored credentials (matches resolveApiKey behaviour)
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
this.log('API key configured');
|
|
30
|
+
this.log(' Source: environment variable (PROVAR_API_KEY)');
|
|
31
|
+
this.log(` Prefix: ${envKey.substring(0, 12)}`);
|
|
32
|
+
this.log('');
|
|
33
|
+
this.log(' Validation mode: Quality Hub API');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const stored = readStoredCredentials();
|
|
38
|
+
if (stored) {
|
|
39
|
+
// Best-effort live check — silent fallback to cached values if offline or unconfigured.
|
|
40
|
+
// Does not run for env var keys (CI environments may not have outbound access).
|
|
41
|
+
let liveValid;
|
|
42
|
+
try {
|
|
43
|
+
const live = await qualityHubClient.fetchKeyStatus(stored.api_key, getQualityHubBaseUrl());
|
|
44
|
+
liveValid = live.valid;
|
|
45
|
+
if (live.username)
|
|
46
|
+
stored.username = live.username;
|
|
47
|
+
if (live.tier)
|
|
48
|
+
stored.tier = live.tier;
|
|
49
|
+
if (live.expires_at)
|
|
50
|
+
stored.expires_at = live.expires_at;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Offline or API not yet configured — use locally cached values
|
|
54
|
+
}
|
|
55
|
+
if (liveValid === false) {
|
|
56
|
+
this.log('API key expired or revoked.');
|
|
57
|
+
this.log(' Source: ~/.provar/credentials.json');
|
|
58
|
+
this.log(` Prefix: ${stored.prefix}`);
|
|
59
|
+
this.log('');
|
|
60
|
+
this.log(' Run: sf provar auth login to refresh your key.');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
this.log('API key configured');
|
|
64
|
+
this.log(' Source: ~/.provar/credentials.json');
|
|
65
|
+
this.log(` Prefix: ${stored.prefix}`);
|
|
66
|
+
this.log(` Set at: ${stored.set_at}`);
|
|
67
|
+
if (stored.username)
|
|
68
|
+
this.log(` Account: ${stored.username}`);
|
|
69
|
+
if (stored.tier)
|
|
70
|
+
this.log(` Tier: ${stored.tier}`);
|
|
71
|
+
if (stored.expires_at)
|
|
72
|
+
this.log(` Expires: ${stored.expires_at}`);
|
|
73
|
+
this.log('');
|
|
74
|
+
this.log(' Validation mode: Quality Hub API');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
this.log('No API key configured.');
|
|
78
|
+
this.log('');
|
|
79
|
+
this.log('To enable Quality Hub validation (170 rules):');
|
|
80
|
+
this.log(' Run: sf provar auth login');
|
|
81
|
+
this.log('');
|
|
82
|
+
this.log('For CI/CD: set the PROVAR_API_KEY environment variable.');
|
|
83
|
+
this.log('');
|
|
84
|
+
this.log(`No account? Request access at: ${REQUEST_ACCESS_URL}`);
|
|
85
|
+
this.log('');
|
|
86
|
+
this.log('Validation mode: local only (structural rules, no quality scoring)');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../../src/commands/provar/auth/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,10 @@ export interface TestCaseValidationResult {
|
|
|
15
15
|
/** Violations from the Best Practices Engine (same rules as the Quality Hub API). */
|
|
16
16
|
best_practices_violations?: Array<import('./bestPracticesEngine.js').BPViolation>;
|
|
17
17
|
best_practices_rules_evaluated?: number;
|
|
18
|
+
/** Which ruleset produced this result. Always present. */
|
|
19
|
+
validation_source: 'quality_hub' | 'local' | 'local_fallback';
|
|
20
|
+
/** Set when falling back to local — explains why and what to do. */
|
|
21
|
+
validation_warning?: string;
|
|
18
22
|
}
|
|
19
23
|
/** Pure function — exported for unit testing */
|
|
20
24
|
export declare function validateTestCase(xmlContent: string, testName?: string): TestCaseValidationResult;
|