qa360 2.1.1 → 2.1.3
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/commands/history.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* CLI interface for Evidence Vault querying and management
|
|
4
4
|
*/
|
|
5
5
|
import { Command } from 'commander';
|
|
6
|
-
import { existsSync, createWriteStream, readFileSync } from 'fs';
|
|
6
|
+
import { existsSync, createWriteStream, readFileSync, statSync, readdirSync, unlinkSync } from 'fs';
|
|
7
7
|
import { join } from 'path';
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
import AdmZip from 'adm-zip';
|
|
@@ -434,7 +434,7 @@ export class QA360History {
|
|
|
434
434
|
console.log(chalk.gray(' ✓ verification data'));
|
|
435
435
|
// 6. Write ZIP file
|
|
436
436
|
zip.writeZip(options.bundle);
|
|
437
|
-
const stats =
|
|
437
|
+
const stats = statSync(options.bundle);
|
|
438
438
|
const sizeKB = (stats.size / 1024).toFixed(2);
|
|
439
439
|
console.log(chalk.green(`\n✅ Bundle exported successfully!`));
|
|
440
440
|
console.log(chalk.gray(`📦 ${options.bundle} (${sizeKB} KB)`));
|
|
@@ -479,8 +479,6 @@ export class QA360History {
|
|
|
479
479
|
let orphanedCount = 0;
|
|
480
480
|
let orphanedSize = 0;
|
|
481
481
|
if (existsSync(casDir)) {
|
|
482
|
-
const { readdirSync, statSync, unlinkSync } = require('fs');
|
|
483
|
-
const { join } = require('path');
|
|
484
482
|
// Scan CAS directory
|
|
485
483
|
const scanCAS = (dir) => {
|
|
486
484
|
const entries = readdirSync(dir);
|
package/dist/commands/init.js
CHANGED
|
@@ -57,7 +57,7 @@ export const GATE_DESCRIPTIONS = {
|
|
|
57
57
|
'api-smoke': {
|
|
58
58
|
short: 'API smoke tests (REST/GraphQL health checks)',
|
|
59
59
|
beginner: 'Tests if your API is alive and responds correctly. Like checking if the server is up.',
|
|
60
|
-
example: 'Checks if GET /api/health returns 200 OK',
|
|
60
|
+
example: 'Checks if GET /api/health or GET /status/200 returns 200 OK',
|
|
61
61
|
icon: '🔌',
|
|
62
62
|
adapter: 'playwright-api',
|
|
63
63
|
},
|
|
@@ -155,8 +155,9 @@ function generateV2Pack(name, gates, apiTarget, webTarget) {
|
|
|
155
155
|
case 'api-smoke':
|
|
156
156
|
pack.gates['api-health'] = createGate('playwright-api', apiBaseUrl, {
|
|
157
157
|
smoke: [
|
|
158
|
-
'GET /
|
|
159
|
-
'GET /
|
|
158
|
+
'GET /status/200 -> 200',
|
|
159
|
+
'GET /get -> 200',
|
|
160
|
+
'GET /uuid -> 200',
|
|
160
161
|
],
|
|
161
162
|
});
|
|
162
163
|
break;
|
|
@@ -8,7 +8,10 @@ export declare class QA360Secrets {
|
|
|
8
8
|
/**
|
|
9
9
|
* Add a secret
|
|
10
10
|
*/
|
|
11
|
-
add(secretName?: string
|
|
11
|
+
add(secretName?: string, options?: {
|
|
12
|
+
value?: string;
|
|
13
|
+
nonInteractive?: boolean;
|
|
14
|
+
}): Promise<{
|
|
12
15
|
success: boolean;
|
|
13
16
|
exitCode: number;
|
|
14
17
|
}>;
|
|
@@ -43,7 +46,10 @@ export declare class QA360Secrets {
|
|
|
43
46
|
exitCode: number;
|
|
44
47
|
}>;
|
|
45
48
|
}
|
|
46
|
-
export declare function secretsAddCommand(secretName?: string
|
|
49
|
+
export declare function secretsAddCommand(secretName?: string, options?: {
|
|
50
|
+
value?: string;
|
|
51
|
+
nonInteractive?: boolean;
|
|
52
|
+
}): Promise<void>;
|
|
47
53
|
export declare function secretsListCommand(): Promise<void>;
|
|
48
54
|
export declare function secretsRemoveCommand(secretName?: string): Promise<void>;
|
|
49
55
|
export declare function secretsDoctorCommand(): Promise<void>;
|
package/dist/commands/secrets.js
CHANGED
|
@@ -14,12 +14,17 @@ export class QA360Secrets {
|
|
|
14
14
|
/**
|
|
15
15
|
* Add a secret
|
|
16
16
|
*/
|
|
17
|
-
async add(secretName) {
|
|
17
|
+
async add(secretName, options = {}) {
|
|
18
18
|
try {
|
|
19
19
|
let name = secretName;
|
|
20
20
|
let value;
|
|
21
|
-
// Interactive mode if no name provided
|
|
21
|
+
// Interactive mode if no name provided (and not non-interactive)
|
|
22
22
|
if (!name) {
|
|
23
|
+
if (options.nonInteractive) {
|
|
24
|
+
console.log(chalk.red('❌ Nom du secret requis en mode non-interactif'));
|
|
25
|
+
console.log(chalk.yellow('💡 Usage: qa360 secrets add <NOM> --value <VALUE> --non-interactive'));
|
|
26
|
+
return { success: false, exitCode: 1 };
|
|
27
|
+
}
|
|
23
28
|
const nameAnswer = await inquirer.prompt([{
|
|
24
29
|
type: 'input',
|
|
25
30
|
name: 'secretName',
|
|
@@ -39,22 +44,29 @@ export class QA360Secrets {
|
|
|
39
44
|
console.log(chalk.yellow('💡 Format requis: MAJUSCULES_AVEC_UNDERSCORES (ex: API_TOKEN)'));
|
|
40
45
|
return { success: false, exitCode: 1 };
|
|
41
46
|
}
|
|
42
|
-
// Get secret value
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
// Get secret value
|
|
48
|
+
if (options.value) {
|
|
49
|
+
// Non-interactive mode: value provided via option
|
|
50
|
+
value = options.value;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
// Interactive mode: prompt for value
|
|
54
|
+
const valueAnswer = await inquirer.prompt([{
|
|
55
|
+
type: 'password',
|
|
56
|
+
name: 'secretValue',
|
|
57
|
+
message: `Valeur pour ${name}:`,
|
|
58
|
+
mask: '*',
|
|
59
|
+
validate: (input) => {
|
|
60
|
+
if (!input.trim()) {
|
|
61
|
+
return 'La valeur ne peut pas être vide';
|
|
62
|
+
}
|
|
63
|
+
return true;
|
|
51
64
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (!SecretsCrypto.looksLikeSecret(value)) {
|
|
65
|
+
}]);
|
|
66
|
+
value = valueAnswer.secretValue;
|
|
67
|
+
}
|
|
68
|
+
// Check if it looks like a secret (skip in non-interactive mode)
|
|
69
|
+
if (!options.nonInteractive && !SecretsCrypto.looksLikeSecret(value)) {
|
|
58
70
|
const confirmAnswer = await inquirer.prompt([{
|
|
59
71
|
type: 'confirm',
|
|
60
72
|
name: 'confirm',
|
|
@@ -250,9 +262,9 @@ export class QA360Secrets {
|
|
|
250
262
|
}
|
|
251
263
|
}
|
|
252
264
|
// Command handlers
|
|
253
|
-
export async function secretsAddCommand(secretName) {
|
|
265
|
+
export async function secretsAddCommand(secretName, options) {
|
|
254
266
|
const secrets = new QA360Secrets();
|
|
255
|
-
const result = await secrets.add(secretName);
|
|
267
|
+
const result = await secrets.add(secretName, options);
|
|
256
268
|
process.exit(result.exitCode);
|
|
257
269
|
}
|
|
258
270
|
export async function secretsListCommand() {
|
|
@@ -245,6 +245,10 @@ export class PlaywrightNativeApiAdapter {
|
|
|
245
245
|
* Format: "GET /path -> 200" or "POST /api/users -> 201"
|
|
246
246
|
*/
|
|
247
247
|
parseTestSpec(spec, baseUrl) {
|
|
248
|
+
// Validate baseUrl first
|
|
249
|
+
if (!baseUrl || typeof baseUrl !== 'string') {
|
|
250
|
+
throw new Error('baseUrl is required in gate configuration. Add "baseUrl: https://your-api.com" to the config section.');
|
|
251
|
+
}
|
|
248
252
|
const match = spec.match(/^(\w+)\s+(.+?)\s*->\s*(\d+)$/);
|
|
249
253
|
if (!match) {
|
|
250
254
|
throw new Error(`Invalid test spec format: ${spec}. Expected: "METHOD /path -> STATUS"`);
|
|
@@ -347,14 +351,14 @@ export class PlaywrightNativeApiAdapter {
|
|
|
347
351
|
static validateConfig(target) {
|
|
348
352
|
const errors = [];
|
|
349
353
|
if (!target.baseUrl) {
|
|
350
|
-
errors.push('
|
|
354
|
+
errors.push('baseUrl is required in gate config. Add: "baseUrl: https://your-api.com"');
|
|
351
355
|
}
|
|
352
356
|
else {
|
|
353
357
|
try {
|
|
354
358
|
new URL(target.baseUrl);
|
|
355
359
|
}
|
|
356
360
|
catch {
|
|
357
|
-
errors.push(
|
|
361
|
+
errors.push(`baseUrl "${target.baseUrl}" is not a valid URL. Expected format: https://api.example.com`);
|
|
358
362
|
}
|
|
359
363
|
}
|
|
360
364
|
if (target.smoke) {
|
package/dist/index.js
CHANGED
|
@@ -172,8 +172,10 @@ const secretsCommand = program
|
|
|
172
172
|
secretsCommand
|
|
173
173
|
.command('add [name]')
|
|
174
174
|
.description('Add or update a secret')
|
|
175
|
-
.
|
|
176
|
-
|
|
175
|
+
.option('-v, --value <value>', 'Secret value (for non-interactive mode)')
|
|
176
|
+
.option('-n, --non-interactive', 'Disable all prompts and confirmations')
|
|
177
|
+
.action(async (name, options) => {
|
|
178
|
+
await secretsAddCommand(name, options);
|
|
177
179
|
});
|
|
178
180
|
secretsCommand
|
|
179
181
|
.command('list')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qa360",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "QA360 Proof CLI - Quality as Cryptographic Proof",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
"ollama": "^0.5.1",
|
|
46
46
|
"ora": "^5.4.1",
|
|
47
47
|
"playwright": "^1.57.0",
|
|
48
|
-
|
|
49
48
|
"sqlite3": "^5.1.6",
|
|
50
49
|
"tweetnacl": "^1.0.3"
|
|
51
50
|
},
|