@testrigor/testrigor-cli 0.0.44-beta → 0.0.45-beta
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/test-suite/run.d.ts +2 -0
- package/dist/commands/test-suite/run.js +93 -2
- package/dist/types.d.ts +51 -0
- package/dist/util/certificate-uploader.d.ts +2 -0
- package/dist/util/certificate-uploader.js +32 -0
- package/dist/util/type-guards.d.ts +4 -0
- package/dist/util/type-guards.js +15 -0
- package/dist/util/variable-file-uploader.d.ts +1 -0
- package/dist/util/variable-file-uploader.js +43 -0
- package/dist/util/variables-path-parser.d.ts +2 -0
- package/dist/util/variables-path-parser.js +126 -0
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
|
@@ -38,6 +38,8 @@ export default class Run extends CommandBase<typeof Run> {
|
|
|
38
38
|
run(): Promise<void>;
|
|
39
39
|
private fetchStatus;
|
|
40
40
|
private getStatusApiEndpoint;
|
|
41
|
+
private uploadVariableFiles;
|
|
42
|
+
private uploadClientCertificates;
|
|
41
43
|
private callRetest;
|
|
42
44
|
private fetchSuiteType;
|
|
43
45
|
private isMobileSuiteType;
|
|
@@ -11,6 +11,9 @@ const chrome_extension_1 = require("../../flags/chrome-extension");
|
|
|
11
11
|
const parser_1 = require("../../util/parser");
|
|
12
12
|
const request_builder_1 = require("../../util/request-builder");
|
|
13
13
|
const tunnel_1 = require("../../util/tunnel");
|
|
14
|
+
const certificate_uploader_1 = require("../../util/certificate-uploader");
|
|
15
|
+
const variable_file_uploader_1 = require("../../util/variable-file-uploader");
|
|
16
|
+
const variables_path_parser_1 = require("../../util/variables-path-parser");
|
|
14
17
|
const appium_1 = require("../../util/appium");
|
|
15
18
|
const utils_1 = require("../../util/utils");
|
|
16
19
|
const sleep = async (milliseconds) => {
|
|
@@ -118,10 +121,23 @@ class Run extends command_base_1.CommandBase {
|
|
|
118
121
|
if (variablesPath) {
|
|
119
122
|
try {
|
|
120
123
|
const file = await Fs.content(variablesPath);
|
|
121
|
-
|
|
124
|
+
const parsed = JSON.parse(file.toString());
|
|
125
|
+
const { textValues, fileInputs, certInputs } = (0, variables_path_parser_1.parseVariablesJson)(parsed);
|
|
126
|
+
context.configuration.storedValues = textValues;
|
|
127
|
+
if (fileInputs.length > 0) {
|
|
128
|
+
context.storedValueFileInputs = fileInputs;
|
|
129
|
+
}
|
|
130
|
+
if (certInputs.length > 0) {
|
|
131
|
+
context.storedValueCertInputs = certInputs;
|
|
132
|
+
}
|
|
122
133
|
}
|
|
123
134
|
catch (e) {
|
|
124
|
-
|
|
135
|
+
if (e instanceof SyntaxError) {
|
|
136
|
+
core_1.ux.error("--variables-path must be a valid JSON path");
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
core_1.ux.error(e instanceof Error ? e.message : String(e));
|
|
140
|
+
}
|
|
125
141
|
}
|
|
126
142
|
}
|
|
127
143
|
if (testCasesPath) {
|
|
@@ -293,6 +309,18 @@ class Run extends command_base_1.CommandBase {
|
|
|
293
309
|
},
|
|
294
310
|
exitOnError: false,
|
|
295
311
|
},
|
|
312
|
+
{
|
|
313
|
+
title: "Uploading variable files",
|
|
314
|
+
enabled: () => !!context.storedValueFileInputs?.length,
|
|
315
|
+
task: (ctx) => this.uploadVariableFiles(ctx, testSuiteId, token),
|
|
316
|
+
exitOnError: false,
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
title: "Uploading client certificates",
|
|
320
|
+
enabled: () => !!context.storedValueCertInputs?.length,
|
|
321
|
+
task: (ctx, task) => this.uploadClientCertificates(ctx, testSuiteId, token, task),
|
|
322
|
+
exitOnError: false,
|
|
323
|
+
},
|
|
296
324
|
{
|
|
297
325
|
enabled: () => !flags["file-path"] && !flags["chrome-extension"],
|
|
298
326
|
task: async (ctx) => {
|
|
@@ -564,6 +592,69 @@ class Run extends command_base_1.CommandBase {
|
|
|
564
592
|
const queryString = queryParams.toString();
|
|
565
593
|
return queryString ? `${apiEndpoint}?${queryString}` : apiEndpoint;
|
|
566
594
|
}
|
|
595
|
+
async uploadVariableFiles(ctx, testSuiteId, token) {
|
|
596
|
+
const controller = new AbortController();
|
|
597
|
+
const timeoutId = setTimeout(() => controller.abort(), utils_1.UPLOAD_TIMEOUT_MS);
|
|
598
|
+
try {
|
|
599
|
+
ctx.configuration.storedValues = ctx.configuration.storedValues || {};
|
|
600
|
+
const uploads = await Promise.all(ctx.storedValueFileInputs.map(async (input) => ({
|
|
601
|
+
name: input.name,
|
|
602
|
+
url: await (0, variable_file_uploader_1.uploadVariableFile)(this.TESTRIGOR_API2_URL, testSuiteId, token, input.file),
|
|
603
|
+
})));
|
|
604
|
+
for (const { name, url } of uploads) {
|
|
605
|
+
ctx.configuration.storedValues[name] = url;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
catch (error) {
|
|
609
|
+
if (error.name === "AbortError") {
|
|
610
|
+
throw new Error("Variable files upload timed out. Please check your network connection.");
|
|
611
|
+
}
|
|
612
|
+
throw error;
|
|
613
|
+
}
|
|
614
|
+
finally {
|
|
615
|
+
clearTimeout(timeoutId);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
async uploadClientCertificates(ctx, testSuiteId, token, task) {
|
|
619
|
+
const controller = new AbortController();
|
|
620
|
+
const timeoutId = setTimeout(() => controller.abort(), utils_1.UPLOAD_TIMEOUT_MS);
|
|
621
|
+
try {
|
|
622
|
+
ctx.configuration.clientCertificateOverrides =
|
|
623
|
+
ctx.configuration.clientCertificateOverrides || {};
|
|
624
|
+
const uploads = await Promise.all(ctx.storedValueCertInputs.map(async (input) => {
|
|
625
|
+
const uploaded = await (0, certificate_uploader_1.uploadClientCertificate)(this.TESTRIGOR_API2_URL, testSuiteId, token, input.file, input.password);
|
|
626
|
+
return {
|
|
627
|
+
name: input.name,
|
|
628
|
+
certificateId: uploaded.certificateId,
|
|
629
|
+
info: uploaded.info,
|
|
630
|
+
};
|
|
631
|
+
}));
|
|
632
|
+
for (const { name, certificateId } of uploads) {
|
|
633
|
+
ctx.configuration.clientCertificateOverrides[name] = certificateId;
|
|
634
|
+
}
|
|
635
|
+
const summary = uploads
|
|
636
|
+
.map(({ name, info }) => {
|
|
637
|
+
const subject = info?.subject?.commonName || info?.subject?.distinguishedName;
|
|
638
|
+
const notAfter = info?.notAfter
|
|
639
|
+
? ` (expires ${info.notAfter.slice(0, 10)})`
|
|
640
|
+
: "";
|
|
641
|
+
return subject ? `${name}: ${subject}${notAfter}` : name;
|
|
642
|
+
})
|
|
643
|
+
.join("; ");
|
|
644
|
+
if (summary) {
|
|
645
|
+
task.title = `Uploaded client certificate(s): ${summary}`;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
catch (error) {
|
|
649
|
+
if (error.name === "AbortError") {
|
|
650
|
+
throw new Error("Client certificates upload timed out. Please check your network connection.");
|
|
651
|
+
}
|
|
652
|
+
throw error;
|
|
653
|
+
}
|
|
654
|
+
finally {
|
|
655
|
+
clearTimeout(timeoutId);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
567
658
|
async callRetest(testSuiteId, configuration, token) {
|
|
568
659
|
return (0, node_fetch_commonjs_1.default)(`${this.TESTRIGOR_API_URL}/apps/${testSuiteId}/retest`, {
|
|
569
660
|
method: "POST",
|
package/dist/types.d.ts
CHANGED
|
@@ -65,3 +65,54 @@ export type ChromeExtensionOverrideItem = {
|
|
|
65
65
|
export type ChromeExtensionOverridesRequest = {
|
|
66
66
|
chromeExtensions: ChromeExtensionOverrideItem[];
|
|
67
67
|
};
|
|
68
|
+
export type StoredValueFileInput = {
|
|
69
|
+
name: string;
|
|
70
|
+
file: string;
|
|
71
|
+
};
|
|
72
|
+
export type StoredValueCertInput = {
|
|
73
|
+
name: string;
|
|
74
|
+
file: string;
|
|
75
|
+
password: string;
|
|
76
|
+
};
|
|
77
|
+
export type ParsedVariables = {
|
|
78
|
+
textValues: Record<string, string>;
|
|
79
|
+
fileInputs: StoredValueFileInput[];
|
|
80
|
+
certInputs: StoredValueCertInput[];
|
|
81
|
+
};
|
|
82
|
+
export type ClientCertificateDistinguishedName = {
|
|
83
|
+
distinguishedName?: string;
|
|
84
|
+
commonName?: string;
|
|
85
|
+
};
|
|
86
|
+
export type ClientCertificateInfo = {
|
|
87
|
+
serialNumber?: string;
|
|
88
|
+
notBefore?: string;
|
|
89
|
+
notAfter?: string;
|
|
90
|
+
issuer?: ClientCertificateDistinguishedName;
|
|
91
|
+
subject?: ClientCertificateDistinguishedName;
|
|
92
|
+
};
|
|
93
|
+
export type CertificateUploadDataApi2Response = {
|
|
94
|
+
certificateId: string;
|
|
95
|
+
info?: ClientCertificateInfo;
|
|
96
|
+
};
|
|
97
|
+
export type UploadedClientCertificate = {
|
|
98
|
+
certificateId: string;
|
|
99
|
+
info?: ClientCertificateInfo;
|
|
100
|
+
};
|
|
101
|
+
export type CertificateUploadApi2Response = Api2Wrapper & {
|
|
102
|
+
data: CertificateUploadDataApi2Response;
|
|
103
|
+
};
|
|
104
|
+
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
105
|
+
[key: string]: JsonValue;
|
|
106
|
+
};
|
|
107
|
+
export type JsonObject = {
|
|
108
|
+
[key: string]: JsonValue;
|
|
109
|
+
};
|
|
110
|
+
export type FileVariableObject = {
|
|
111
|
+
type: "FILE";
|
|
112
|
+
value: string;
|
|
113
|
+
};
|
|
114
|
+
export type CertVariableObject = {
|
|
115
|
+
type: "CLIENT_CERTIFICATE";
|
|
116
|
+
value: string;
|
|
117
|
+
password: string;
|
|
118
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.uploadClientCertificate = void 0;
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const node_fetch_commonjs_1 = require("node-fetch-commonjs");
|
|
7
|
+
const type_guards_1 = require("./type-guards");
|
|
8
|
+
async function uploadClientCertificate(api2BaseUrl, testSuiteId, token, localFilePath, password) {
|
|
9
|
+
const fileName = path.basename(localFilePath);
|
|
10
|
+
const certBase64 = fs.readFileSync(localFilePath).toString("base64");
|
|
11
|
+
const response = await (0, node_fetch_commonjs_1.default)(`${api2BaseUrl}/apps/${testSuiteId}/test_data/global_variables/client_certificate`, {
|
|
12
|
+
method: "POST",
|
|
13
|
+
body: JSON.stringify({ fileName, certBase64, password }),
|
|
14
|
+
headers: {
|
|
15
|
+
"Content-Type": "application/json",
|
|
16
|
+
Accept: "application/json",
|
|
17
|
+
"auth-token": token,
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
const responseJson = await response.json();
|
|
21
|
+
if (!(0, type_guards_1.isCertificateUploadApi2Response)(responseJson)) {
|
|
22
|
+
throw new Error(`Unexpected response shape from client certificate upload endpoint for '${fileName}'`);
|
|
23
|
+
}
|
|
24
|
+
if (!response.ok || responseJson.status !== 200 || !responseJson.data) {
|
|
25
|
+
throw new Error(`Failed to upload client certificate '${fileName}': ${responseJson.message}`);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
certificateId: responseJson.data.certificateId,
|
|
29
|
+
info: responseJson.data.info,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
exports.uploadClientCertificate = uploadClientCertificate;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { CertificateUploadApi2Response, SignedUrlApi2Response } from "../types";
|
|
2
|
+
export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
3
|
+
export declare function isSignedUrlApi2Response(value: unknown): value is SignedUrlApi2Response;
|
|
4
|
+
export declare function isCertificateUploadApi2Response(value: unknown): value is CertificateUploadApi2Response;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isCertificateUploadApi2Response = exports.isSignedUrlApi2Response = exports.isPlainObject = void 0;
|
|
4
|
+
function isPlainObject(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
exports.isPlainObject = isPlainObject;
|
|
8
|
+
function isSignedUrlApi2Response(value) {
|
|
9
|
+
return isPlainObject(value) && "status" in value;
|
|
10
|
+
}
|
|
11
|
+
exports.isSignedUrlApi2Response = isSignedUrlApi2Response;
|
|
12
|
+
function isCertificateUploadApi2Response(value) {
|
|
13
|
+
return isPlainObject(value) && "status" in value;
|
|
14
|
+
}
|
|
15
|
+
exports.isCertificateUploadApi2Response = isCertificateUploadApi2Response;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function uploadVariableFile(api2BaseUrl: string, testSuiteId: string, token: string, localFilePath: string): Promise<string>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.uploadVariableFile = void 0;
|
|
4
|
+
const Fs = require("@supercharge/fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const node_fetch_commonjs_1 = require("node-fetch-commonjs");
|
|
7
|
+
const utils_1 = require("./utils");
|
|
8
|
+
const type_guards_1 = require("./type-guards");
|
|
9
|
+
async function uploadVariableFile(api2BaseUrl, testSuiteId, token, localFilePath) {
|
|
10
|
+
const fileName = path.basename(localFilePath);
|
|
11
|
+
const fileSize = Fs.statSync(localFilePath).size;
|
|
12
|
+
const presignedResp = await (0, node_fetch_commonjs_1.default)(`${api2BaseUrl}/apps/${testSuiteId}/test_data/global_variables/file/pre_signed_url`, {
|
|
13
|
+
method: "POST",
|
|
14
|
+
body: JSON.stringify({ fileName }),
|
|
15
|
+
headers: {
|
|
16
|
+
"Content-Type": "application/json",
|
|
17
|
+
Accept: "application/json",
|
|
18
|
+
"auth-token": token,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
const presignedJson = await presignedResp.json();
|
|
22
|
+
if (!(0, type_guards_1.isSignedUrlApi2Response)(presignedJson)) {
|
|
23
|
+
throw new Error(`Unexpected response shape from presigned URL endpoint for '${fileName}'`);
|
|
24
|
+
}
|
|
25
|
+
if (!presignedResp.ok ||
|
|
26
|
+
presignedJson.status !== 200 ||
|
|
27
|
+
!presignedJson.data) {
|
|
28
|
+
throw new Error(`Failed to request presigned URL for variable file '${fileName}': ${presignedJson.message}`);
|
|
29
|
+
}
|
|
30
|
+
const fileStream = Fs.createReadStream(localFilePath);
|
|
31
|
+
const putResp = await (0, node_fetch_commonjs_1.default)(presignedJson.data.url, {
|
|
32
|
+
method: "PUT",
|
|
33
|
+
body: fileStream,
|
|
34
|
+
headers: {
|
|
35
|
+
"Content-length": `${fileSize}`,
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
if (!putResp.ok) {
|
|
39
|
+
throw new Error(`Failed to upload variable file '${fileName}' to S3: ${putResp.statusText}`);
|
|
40
|
+
}
|
|
41
|
+
return (0, utils_1.extractUrlWithoutQueryParams)(presignedJson.data.url);
|
|
42
|
+
}
|
|
43
|
+
exports.uploadVariableFile = uploadVariableFile;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseVariablesJson = void 0;
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const type_guards_1 = require("./type-guards");
|
|
7
|
+
const MAX_FILE_SIZE_BYTES = 100 * 1024 * 1024;
|
|
8
|
+
const MAX_COMBINED_SIZE_BYTES = 100 * 1024 * 1024;
|
|
9
|
+
const MAX_SIZE_LABEL = "100 MB";
|
|
10
|
+
const MAX_CERT_FILE_SIZE_BYTES = 20 * 1024; // 20 KB
|
|
11
|
+
const MAX_CERT_PASSWORD_LENGTH = 100;
|
|
12
|
+
const MAX_CERT_FILENAME_LENGTH = 100;
|
|
13
|
+
const ERROR_ROOT_NOT_OBJECT = "--variables-path must contain a JSON object at the top level";
|
|
14
|
+
const ERROR_COMBINED_SIZE_EXCEEDED = `Variable files combined size exceeds the maximum allowed (${MAX_SIZE_LABEL})`;
|
|
15
|
+
function isUrl(value) {
|
|
16
|
+
return /^https?:\/\//i.test(value);
|
|
17
|
+
}
|
|
18
|
+
function isFileVariableObject(value) {
|
|
19
|
+
return ((0, type_guards_1.isPlainObject)(value) &&
|
|
20
|
+
value.type === "FILE" &&
|
|
21
|
+
typeof value.value === "string");
|
|
22
|
+
}
|
|
23
|
+
function isCertVariableObject(value) {
|
|
24
|
+
return ((0, type_guards_1.isPlainObject)(value) &&
|
|
25
|
+
value.type === "CLIENT_CERTIFICATE" &&
|
|
26
|
+
typeof value.value === "string" &&
|
|
27
|
+
typeof value.password === "string");
|
|
28
|
+
}
|
|
29
|
+
function readLocalFileSize(key, filePath) {
|
|
30
|
+
if (!fs.existsSync(filePath)) {
|
|
31
|
+
throw new Error(`Variable "${key}": file not found at path "${filePath}"`);
|
|
32
|
+
}
|
|
33
|
+
const size = fs.statSync(filePath).size;
|
|
34
|
+
if (size > MAX_FILE_SIZE_BYTES) {
|
|
35
|
+
throw new Error(`Variable "${key}": file size exceeds the maximum allowed (${MAX_SIZE_LABEL})`);
|
|
36
|
+
}
|
|
37
|
+
return size;
|
|
38
|
+
}
|
|
39
|
+
function validateLocalCertFile(key, value) {
|
|
40
|
+
if (isUrl(value)) {
|
|
41
|
+
throw new Error(`Variable "${key}": CLIENT_CERTIFICATE does not support URL values; provide a local .pfx file path`);
|
|
42
|
+
}
|
|
43
|
+
if (!fs.existsSync(value)) {
|
|
44
|
+
throw new Error(`Variable "${key}": file not found at path "${value}"`);
|
|
45
|
+
}
|
|
46
|
+
if (!/\.pfx$/i.test(path.basename(value))) {
|
|
47
|
+
throw new Error(`Variable "${key}": CLIENT_CERTIFICATE requires a .pfx file`);
|
|
48
|
+
}
|
|
49
|
+
if (path.basename(value).length > MAX_CERT_FILENAME_LENGTH) {
|
|
50
|
+
throw new Error(`Variable "${key}": filename is too long (max ${MAX_CERT_FILENAME_LENGTH} chars)`);
|
|
51
|
+
}
|
|
52
|
+
if (fs.statSync(value).size > MAX_CERT_FILE_SIZE_BYTES) {
|
|
53
|
+
throw new Error(`Variable "${key}": certificate file exceeds the maximum allowed (20 KB)`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function parseVariablesJson(parsed) {
|
|
57
|
+
if (!(0, type_guards_1.isPlainObject)(parsed)) {
|
|
58
|
+
throw new Error(ERROR_ROOT_NOT_OBJECT);
|
|
59
|
+
}
|
|
60
|
+
const textValues = {};
|
|
61
|
+
const fileInputs = [];
|
|
62
|
+
const certInputs = [];
|
|
63
|
+
let combinedSize = 0;
|
|
64
|
+
for (const [key, raw] of Object.entries(parsed)) {
|
|
65
|
+
if (typeof raw === "string") {
|
|
66
|
+
textValues[key] = raw;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (!(0, type_guards_1.isPlainObject)(raw)) {
|
|
70
|
+
throw new Error(`Variable "${key}": expected a string or { type: "FILE", value: "..." }`);
|
|
71
|
+
}
|
|
72
|
+
if (raw.type === "FILE" && raw.password !== undefined) {
|
|
73
|
+
throw new Error(`Variable "${key}": "password" field is only valid for CLIENT_CERTIFICATE. Did you mean type:"CLIENT_CERTIFICATE"?`);
|
|
74
|
+
}
|
|
75
|
+
if (raw.type === "FILE") {
|
|
76
|
+
if (!isFileVariableObject(raw)) {
|
|
77
|
+
throw new Error(`Variable "${key}": missing or empty "value" for type:FILE`);
|
|
78
|
+
}
|
|
79
|
+
const value = raw.value.trim();
|
|
80
|
+
if (value.length === 0) {
|
|
81
|
+
throw new Error(`Variable "${key}": missing or empty "value" for type:FILE`);
|
|
82
|
+
}
|
|
83
|
+
if (isUrl(value)) {
|
|
84
|
+
textValues[key] = value;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
combinedSize += readLocalFileSize(key, value);
|
|
88
|
+
if (combinedSize > MAX_COMBINED_SIZE_BYTES) {
|
|
89
|
+
throw new Error(ERROR_COMBINED_SIZE_EXCEEDED);
|
|
90
|
+
}
|
|
91
|
+
fileInputs.push({ name: key, file: value });
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (raw.type === "CLIENT_CERTIFICATE") {
|
|
95
|
+
if (!isCertVariableObject(raw)) {
|
|
96
|
+
if (typeof raw.value !== "string" || raw.value.trim().length === 0) {
|
|
97
|
+
throw new Error(`Variable "${key}": missing or empty "value" for type:CLIENT_CERTIFICATE`);
|
|
98
|
+
}
|
|
99
|
+
throw new Error(`Variable "${key}": missing or empty "password" for type:CLIENT_CERTIFICATE`);
|
|
100
|
+
}
|
|
101
|
+
const value = raw.value.trim();
|
|
102
|
+
if (value.length === 0) {
|
|
103
|
+
throw new Error(`Variable "${key}": missing or empty "value" for type:CLIENT_CERTIFICATE`);
|
|
104
|
+
}
|
|
105
|
+
if (raw.password.length === 0) {
|
|
106
|
+
throw new Error(`Variable "${key}": missing or empty "password" for type:CLIENT_CERTIFICATE`);
|
|
107
|
+
}
|
|
108
|
+
if (raw.password.length > MAX_CERT_PASSWORD_LENGTH) {
|
|
109
|
+
throw new Error(`Variable "${key}": "password" exceeds the maximum length of ${MAX_CERT_PASSWORD_LENGTH} characters`);
|
|
110
|
+
}
|
|
111
|
+
validateLocalCertFile(key, value);
|
|
112
|
+
certInputs.push({
|
|
113
|
+
name: key,
|
|
114
|
+
file: value,
|
|
115
|
+
password: raw.password,
|
|
116
|
+
});
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (typeof raw.type === "string" && raw.type.toUpperCase() === "FILE") {
|
|
120
|
+
throw new Error(`Variable "${key}": unsupported type "${String(raw.type)}". Only "FILE" (uppercase) and "CLIENT_CERTIFICATE" are supported.`);
|
|
121
|
+
}
|
|
122
|
+
throw new Error(`Variable "${key}": unsupported type "${String(raw.type)}". Only "FILE" and "CLIENT_CERTIFICATE" are supported.`);
|
|
123
|
+
}
|
|
124
|
+
return { textValues, fileInputs, certInputs };
|
|
125
|
+
}
|
|
126
|
+
exports.parseVariablesJson = parseVariablesJson;
|
package/oclif.manifest.json
CHANGED