@redocly/cli 1.33.1 → 1.34.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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @redocly/cli
2
2
 
3
+ ## 1.34.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Improved OpenTelemetry data serialization.
8
+ - Updated @redocly/respect-core to v1.34.1.
9
+
10
+ ## 1.34.0
11
+
12
+ ### Minor Changes
13
+
14
+ - Added global execution timeout timer to `respect` command execution to prevent infinite test runs. You can configure this timer using the `RESPECT_TIMEOUT` environment variable (defaults to 1 hour).
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated @redocly/respect-core to v1.34.0.
19
+
3
20
  ## 1.33.1
4
21
 
5
22
  ### Patch Changes
package/README.md CHANGED
@@ -16,7 +16,7 @@ Supports OpenAPI 3.1, 3.0 and OpenAPI 2.0 (legacy Swagger), AsyncAPI 3.0 and 2.6
16
16
  ### Node
17
17
 
18
18
  ```sh
19
- npx @redocly/cli lint path-to-root-file.yaml
19
+ npx @redocly/cli@latest lint path-to-root-file.yaml
20
20
  ```
21
21
 
22
22
  Alternatively, install it globally with `npm`:
@@ -441,40 +441,51 @@ describe('cleanArgs', () => {
441
441
  afterEach(() => {
442
442
  jest.clearAllMocks();
443
443
  });
444
- it('should remove potentially sensitive data from args', () => {
445
- const testArgs = {
444
+ it('should remove potentially sensitive data from parsed args', () => {
445
+ const parsedArgs = {
446
446
  config: './fixtures/redocly.yaml',
447
447
  apis: ['main@v1', 'fixtures/openapi.yaml', 'http://some.url/openapi.yaml'],
448
448
  format: 'codeframe',
449
+ input: 'some-input',
450
+ 'client-cert': 'some-client-cert',
451
+ 'client-key': 'some-client-key',
452
+ 'ca-cert': 'some-ca-cert',
449
453
  };
450
- expect((0, miscellaneous_1.cleanArgs)(testArgs)).toEqual({
454
+ const rawArgs = [
455
+ 'redocly',
456
+ 'bundle',
457
+ 'main@v1',
458
+ 'fixtures/openapi.yaml',
459
+ 'http://some.url/openapi.yaml',
460
+ '--config=fixtures/redocly.yaml',
461
+ '--format=codeframe',
462
+ '--input=some-input',
463
+ '--client-cert=some-client-cert',
464
+ '--client-key=some-client-key',
465
+ '--ca-cert=some-ca-cert',
466
+ ];
467
+ const result = (0, miscellaneous_1.cleanArgs)(parsedArgs, rawArgs);
468
+ expect(result.arguments).toEqual(JSON.stringify({
451
469
  config: 'file-yaml',
452
470
  apis: ['api-name@api-version', 'file-yaml', 'http://url'],
453
471
  format: 'codeframe',
454
- });
472
+ input: '***',
473
+ 'client-cert': '***',
474
+ 'client-key': '***',
475
+ 'ca-cert': '***',
476
+ }));
455
477
  });
456
478
  it('should remove potentially sensitive data from a push destination', () => {
457
- const testArgs = {
479
+ const parsedArgs = {
458
480
  destination: '@org/name@version',
459
481
  };
460
- expect((0, miscellaneous_1.cleanArgs)(testArgs)).toEqual({
482
+ const rawArgs = ['redocly', 'push', '--destination=@org/name@version'];
483
+ const result = (0, miscellaneous_1.cleanArgs)(parsedArgs, rawArgs);
484
+ expect(result.arguments).toEqual(JSON.stringify({
461
485
  destination: '@organization/api-name@api-version',
462
- });
486
+ }));
463
487
  });
464
- });
465
- describe('cleanRawInput', () => {
466
- beforeEach(() => {
467
- // @ts-ignore
468
- openapi_core_1.isAbsoluteUrl = jest.requireActual('@redocly/openapi-core').isAbsoluteUrl;
469
- // @ts-ignore
470
- fs_1.existsSync = (value) => jest.requireActual('fs').existsSync(path.resolve(__dirname, value));
471
- // @ts-ignore
472
- fs_1.statSync = (value) => jest.requireActual('fs').statSync(path.resolve(__dirname, value));
473
- });
474
- afterEach(() => {
475
- jest.clearAllMocks();
476
- });
477
- it('should remove potentially sensitive data from raw CLI input', () => {
488
+ it('should remove potentially sensitive data from raw CLI input', () => {
478
489
  const rawInput = [
479
490
  'redocly',
480
491
  'bundle',
@@ -484,8 +495,41 @@ describe('cleanRawInput', () => {
484
495
  '--config=fixtures/redocly.yaml',
485
496
  '--output',
486
497
  'fixtures',
498
+ '--client-cert',
499
+ 'fixtures/client-cert.pem',
500
+ '--client-key',
501
+ 'fixtures/client-key.pem',
502
+ '--ca-cert',
503
+ 'fixtures/ca-cert.pem',
504
+ '--organization',
505
+ 'my-org',
506
+ '--input',
507
+ 'timeout=10000',
508
+ '--input',
509
+ '{"apiKey":"some=111=1111"}',
487
510
  ];
488
- expect((0, miscellaneous_1.cleanRawInput)(rawInput)).toEqual('redocly bundle api-name@api-version file-yaml http://url --config=file-yaml --output folder');
511
+ const parsedArgs = {
512
+ apis: ['./fixtures/openapi.yaml', 'http://some.url/openapi.yaml'],
513
+ input: ['timeout=10000', '{"apiKey":"some=111=1111"}'],
514
+ organization: 'my-org',
515
+ 'client-cert': 'fixtures/client-cert.pem',
516
+ 'client-key': 'fixtures/client-key.pem',
517
+ 'ca-cert': 'fixtures/ca-cert.pem',
518
+ config: 'fixtures/redocly.yaml',
519
+ output: 'fixtures',
520
+ };
521
+ const result = (0, miscellaneous_1.cleanArgs)(parsedArgs, rawInput);
522
+ expect(result.raw_input).toEqual('redocly bundle api-name@api-version file-yaml http://url --config=file-yaml --output folder --client-cert *** --client-key *** --ca-cert *** --organization *** --input *** --input ***');
523
+ expect(result.arguments).toEqual(JSON.stringify({
524
+ apis: ['file-yaml', 'http://url'],
525
+ input: '***',
526
+ organization: '***',
527
+ 'client-cert': '***',
528
+ 'client-key': '***',
529
+ 'ca-cert': '***',
530
+ config: 'file-yaml',
531
+ output: 'folder',
532
+ }));
489
533
  });
490
534
  it('should preserve safe data from raw CLI input', () => {
491
535
  const rawInput = [
@@ -498,18 +542,31 @@ describe('cleanRawInput', () => {
498
542
  '--skip-rule',
499
543
  'operation-4xx-response',
500
544
  ];
501
- expect((0, miscellaneous_1.cleanRawInput)(rawInput)).toEqual('redocly lint file-json --format stylish --extends=minimal --skip-rule operation-4xx-response');
545
+ const parsedArgs = {
546
+ apis: ['./fixtures/openapi.json'],
547
+ format: 'stylish',
548
+ extends: 'minimal',
549
+ 'skip-rule': ['operation-4xx-response'],
550
+ };
551
+ const result = (0, miscellaneous_1.cleanArgs)(parsedArgs, rawInput);
552
+ expect(result.raw_input).toEqual('redocly lint file-json --format stylish --extends=minimal --skip-rule operation-4xx-response');
553
+ expect(result.arguments).toEqual(JSON.stringify({
554
+ apis: ['file-json'],
555
+ format: 'stylish',
556
+ extends: 'minimal',
557
+ 'skip-rule': ['operation-4xx-response'],
558
+ }));
502
559
  });
503
- describe('validateFileExtension', () => {
504
- it('should return current file extension', () => {
505
- expect((0, miscellaneous_1.getAndValidateFileExtension)('test.json')).toEqual('json');
506
- });
507
- it('should return yaml and print warning if file extension does not supported', () => {
508
- const stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
509
- colorette_1.yellow.mockImplementation((text) => text);
510
- expect((0, miscellaneous_1.getAndValidateFileExtension)('test.xml')).toEqual('yaml');
511
- expect(stderrMock).toHaveBeenCalledWith(`Unsupported file extension: xml. Using yaml.\n`);
512
- });
560
+ });
561
+ describe('validateFileExtension', () => {
562
+ it('should return current file extension', () => {
563
+ expect((0, miscellaneous_1.getAndValidateFileExtension)('test.json')).toEqual('json');
564
+ });
565
+ it('should return yaml and print warning if file extension does not supported', () => {
566
+ const stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
567
+ colorette_1.yellow.mockImplementation((text) => text);
568
+ expect((0, miscellaneous_1.getAndValidateFileExtension)('test.xml')).toEqual('yaml');
569
+ expect(stderrMock).toHaveBeenCalledWith(`Unsupported file extension: xml. Using yaml.\n`);
513
570
  });
514
571
  });
515
572
  describe('writeToFileByExtension', () => {
@@ -75,8 +75,10 @@ export type Analytics = {
75
75
  spec_keyword?: string;
76
76
  spec_full_version?: string;
77
77
  };
78
- export declare function cleanArgs(args: CommandOptions): Record<string, unknown>;
79
- export declare function cleanRawInput(argv: string[]): string;
78
+ export declare function cleanArgs(parsedArgs: CommandOptions, rawArgv: string[]): {
79
+ arguments: string;
80
+ raw_input: string;
81
+ };
80
82
  export declare function checkForDeprecatedOptions<T>(argv: T, deprecatedOptions: Array<keyof T>): void;
81
83
  export declare function notifyAboutIncompatibleConfigOptions(themeOpenapiOptions: Record<string, unknown> | undefined): void;
82
84
  export declare function formatPath(path: string): string;
@@ -28,7 +28,6 @@ exports.checkIfRulesetExist = checkIfRulesetExist;
28
28
  exports.cleanColors = cleanColors;
29
29
  exports.sendTelemetry = sendTelemetry;
30
30
  exports.cleanArgs = cleanArgs;
31
- exports.cleanRawInput = cleanRawInput;
32
31
  exports.checkForDeprecatedOptions = checkForDeprecatedOptions;
33
32
  exports.notifyAboutIncompatibleConfigOptions = notifyAboutIncompatibleConfigOptions;
34
33
  exports.formatPath = formatPath;
@@ -458,7 +457,7 @@ async function sendTelemetry(argv, exit_code, has_config, spec_version, spec_key
458
457
  event_time,
459
458
  logged_in: logged_in ? 'yes' : 'no',
460
459
  command: `${command}`,
461
- arguments: JSON.stringify(cleanArgs(args)),
460
+ ...cleanArgs(args, process.argv.slice(2)),
462
461
  node_version: process.version,
463
462
  npm_version: (0, child_process_1.execSync)('npm -v').toString().replace('\n', ''),
464
463
  os_platform: os.platform(),
@@ -466,7 +465,6 @@ async function sendTelemetry(argv, exit_code, has_config, spec_version, spec_key
466
465
  exit_code,
467
466
  environment: process.env.REDOCLY_ENVIRONMENT,
468
467
  environment_ci: process.env.CI,
469
- raw_input: cleanRawInput(process.argv.slice(2)),
470
468
  has_config: has_config ? 'yes' : 'no',
471
469
  spec_version,
472
470
  spec_keyword,
@@ -504,27 +502,41 @@ function cleanString(value) {
504
502
  }
505
503
  return value;
506
504
  }
507
- function cleanArgs(args) {
508
- const keysToClean = ['organization', 'o'];
509
- const result = {};
510
- for (const [key, value] of Object.entries(args)) {
511
- if (keysToClean.includes(key)) {
512
- result[key] = '***';
505
+ function replaceArgs(commandInput, targets, replacement) {
506
+ const targetValues = Array.isArray(targets) ? targets : [targets];
507
+ for (const target of targetValues) {
508
+ commandInput = commandInput.replaceAll(target, replacement);
509
+ }
510
+ return commandInput;
511
+ }
512
+ function cleanArgs(parsedArgs, rawArgv) {
513
+ const KEYS_TO_CLEAN = ['organization', 'o', 'input', 'i', 'client-cert', 'client-key', 'ca-cert'];
514
+ let commandInput = rawArgv.join(' ');
515
+ const commandArguments = {};
516
+ for (const [key, value] of Object.entries(parsedArgs)) {
517
+ if (KEYS_TO_CLEAN.includes(key)) {
518
+ commandArguments[key] = '***';
519
+ commandInput = replaceArgs(commandInput, value, '***');
513
520
  }
514
521
  else if (typeof value === 'string') {
515
- result[key] = cleanString(value);
522
+ const cleanedValue = cleanString(value);
523
+ commandArguments[key] = cleanedValue;
524
+ commandInput = replaceArgs(commandInput, value, cleanedValue);
516
525
  }
517
526
  else if (Array.isArray(value)) {
518
- result[key] = value.map(cleanString);
527
+ commandArguments[key] = value.map(cleanString);
528
+ for (const replacedValue of value) {
529
+ const newValue = cleanString(replacedValue);
530
+ if (commandInput.includes(replacedValue)) {
531
+ commandInput = commandInput.replaceAll(replacedValue, newValue);
532
+ }
533
+ }
519
534
  }
520
535
  else {
521
- result[key] = value;
536
+ commandArguments[key] = value;
522
537
  }
523
538
  }
524
- return result;
525
- }
526
- function cleanRawInput(argv) {
527
- return argv.map((entry) => entry.split('=').map(cleanString).join('=')).join(' ');
539
+ return { arguments: JSON.stringify(commandArguments), raw_input: commandInput };
528
540
  }
529
541
  function checkForDeprecatedOptions(argv, deprecatedOptions) {
530
542
  for (const option of deprecatedOptions) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/cli",
3
- "version": "1.33.1",
3
+ "version": "1.34.1",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -38,8 +38,8 @@
38
38
  ],
39
39
  "dependencies": {
40
40
  "@redocly/config": "^0.22.0",
41
- "@redocly/openapi-core": "1.33.1",
42
- "@redocly/respect-core": "1.33.1",
41
+ "@redocly/openapi-core": "1.34.1",
42
+ "@redocly/respect-core": "1.34.1",
43
43
  "abort-controller": "^3.0.0",
44
44
  "chokidar": "^3.5.1",
45
45
  "colorette": "^1.2.0",
@@ -11,7 +11,6 @@ import {
11
11
  cleanColors,
12
12
  HandledError,
13
13
  cleanArgs,
14
- cleanRawInput,
15
14
  getAndValidateFileExtension,
16
15
  writeToFileByExtension,
17
16
  } from '../utils/miscellaneous';
@@ -28,7 +27,6 @@ import { blue, red, yellow } from 'colorette';
28
27
  import { existsSync, statSync } from 'fs';
29
28
  import * as path from 'path';
30
29
  import * as process from 'process';
31
- import { ConfigApis } from '../types';
32
30
 
33
31
  jest.mock('os');
34
32
  jest.mock('colorette');
@@ -540,41 +538,56 @@ describe('cleanArgs', () => {
540
538
  afterEach(() => {
541
539
  jest.clearAllMocks();
542
540
  });
543
- it('should remove potentially sensitive data from args', () => {
544
- const testArgs = {
541
+ it('should remove potentially sensitive data from parsed args', () => {
542
+ const parsedArgs = {
545
543
  config: './fixtures/redocly.yaml',
546
544
  apis: ['main@v1', 'fixtures/openapi.yaml', 'http://some.url/openapi.yaml'],
547
545
  format: 'codeframe',
546
+ input: 'some-input',
547
+ 'client-cert': 'some-client-cert',
548
+ 'client-key': 'some-client-key',
549
+ 'ca-cert': 'some-ca-cert',
548
550
  };
549
- expect(cleanArgs(testArgs)).toEqual({
550
- config: 'file-yaml',
551
- apis: ['api-name@api-version', 'file-yaml', 'http://url'],
552
- format: 'codeframe',
553
- });
551
+ const rawArgs = [
552
+ 'redocly',
553
+ 'bundle',
554
+ 'main@v1',
555
+ 'fixtures/openapi.yaml',
556
+ 'http://some.url/openapi.yaml',
557
+ '--config=fixtures/redocly.yaml',
558
+ '--format=codeframe',
559
+ '--input=some-input',
560
+ '--client-cert=some-client-cert',
561
+ '--client-key=some-client-key',
562
+ '--ca-cert=some-ca-cert',
563
+ ];
564
+ const result = cleanArgs(parsedArgs, rawArgs);
565
+ expect(result.arguments).toEqual(
566
+ JSON.stringify({
567
+ config: 'file-yaml',
568
+ apis: ['api-name@api-version', 'file-yaml', 'http://url'],
569
+ format: 'codeframe',
570
+ input: '***',
571
+ 'client-cert': '***',
572
+ 'client-key': '***',
573
+ 'ca-cert': '***',
574
+ })
575
+ );
554
576
  });
555
577
  it('should remove potentially sensitive data from a push destination', () => {
556
- const testArgs = {
578
+ const parsedArgs = {
557
579
  destination: '@org/name@version',
558
580
  };
559
- expect(cleanArgs(testArgs)).toEqual({
560
- destination: '@organization/api-name@api-version',
561
- });
581
+ const rawArgs = ['redocly', 'push', '--destination=@org/name@version'];
582
+ const result = cleanArgs(parsedArgs, rawArgs);
583
+ expect(result.arguments).toEqual(
584
+ JSON.stringify({
585
+ destination: '@organization/api-name@api-version',
586
+ })
587
+ );
562
588
  });
563
- });
564
589
 
565
- describe('cleanRawInput', () => {
566
- beforeEach(() => {
567
- // @ts-ignore
568
- isAbsoluteUrl = jest.requireActual('@redocly/openapi-core').isAbsoluteUrl;
569
- // @ts-ignore
570
- existsSync = (value) => jest.requireActual('fs').existsSync(path.resolve(__dirname, value));
571
- // @ts-ignore
572
- statSync = (value) => jest.requireActual('fs').statSync(path.resolve(__dirname, value));
573
- });
574
- afterEach(() => {
575
- jest.clearAllMocks();
576
- });
577
- it('should remove potentially sensitive data from raw CLI input', () => {
590
+ it('should remove potentially sensitive data from raw CLI input', () => {
578
591
  const rawInput = [
579
592
  'redocly',
580
593
  'bundle',
@@ -584,11 +597,47 @@ describe('cleanRawInput', () => {
584
597
  '--config=fixtures/redocly.yaml',
585
598
  '--output',
586
599
  'fixtures',
600
+ '--client-cert',
601
+ 'fixtures/client-cert.pem',
602
+ '--client-key',
603
+ 'fixtures/client-key.pem',
604
+ '--ca-cert',
605
+ 'fixtures/ca-cert.pem',
606
+ '--organization',
607
+ 'my-org',
608
+ '--input',
609
+ 'timeout=10000',
610
+ '--input',
611
+ '{"apiKey":"some=111=1111"}',
587
612
  ];
588
- expect(cleanRawInput(rawInput)).toEqual(
589
- 'redocly bundle api-name@api-version file-yaml http://url --config=file-yaml --output folder'
613
+ const parsedArgs = {
614
+ apis: ['./fixtures/openapi.yaml', 'http://some.url/openapi.yaml'],
615
+ input: ['timeout=10000', '{"apiKey":"some=111=1111"}'],
616
+ organization: 'my-org',
617
+ 'client-cert': 'fixtures/client-cert.pem',
618
+ 'client-key': 'fixtures/client-key.pem',
619
+ 'ca-cert': 'fixtures/ca-cert.pem',
620
+ config: 'fixtures/redocly.yaml',
621
+ output: 'fixtures',
622
+ };
623
+ const result = cleanArgs(parsedArgs, rawInput);
624
+ expect(result.raw_input).toEqual(
625
+ 'redocly bundle api-name@api-version file-yaml http://url --config=file-yaml --output folder --client-cert *** --client-key *** --ca-cert *** --organization *** --input *** --input ***'
626
+ );
627
+ expect(result.arguments).toEqual(
628
+ JSON.stringify({
629
+ apis: ['file-yaml', 'http://url'],
630
+ input: '***',
631
+ organization: '***',
632
+ 'client-cert': '***',
633
+ 'client-key': '***',
634
+ 'ca-cert': '***',
635
+ config: 'file-yaml',
636
+ output: 'folder',
637
+ })
590
638
  );
591
639
  });
640
+
592
641
  it('should preserve safe data from raw CLI input', () => {
593
642
  const rawInput = [
594
643
  'redocly',
@@ -600,23 +649,40 @@ describe('cleanRawInput', () => {
600
649
  '--skip-rule',
601
650
  'operation-4xx-response',
602
651
  ];
603
- expect(cleanRawInput(rawInput)).toEqual(
652
+ const parsedArgs = {
653
+ apis: ['./fixtures/openapi.json'],
654
+ format: 'stylish',
655
+ extends: 'minimal',
656
+ 'skip-rule': ['operation-4xx-response'],
657
+ };
658
+ const result = cleanArgs(parsedArgs, rawInput);
659
+
660
+ expect(result.raw_input).toEqual(
604
661
  'redocly lint file-json --format stylish --extends=minimal --skip-rule operation-4xx-response'
605
662
  );
663
+
664
+ expect(result.arguments).toEqual(
665
+ JSON.stringify({
666
+ apis: ['file-json'],
667
+ format: 'stylish',
668
+ extends: 'minimal',
669
+ 'skip-rule': ['operation-4xx-response'],
670
+ })
671
+ );
606
672
  });
673
+ });
607
674
 
608
- describe('validateFileExtension', () => {
609
- it('should return current file extension', () => {
610
- expect(getAndValidateFileExtension('test.json')).toEqual('json');
611
- });
675
+ describe('validateFileExtension', () => {
676
+ it('should return current file extension', () => {
677
+ expect(getAndValidateFileExtension('test.json')).toEqual('json');
678
+ });
612
679
 
613
- it('should return yaml and print warning if file extension does not supported', () => {
614
- const stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
615
- (yellow as jest.Mock<any, any>).mockImplementation((text: string) => text);
680
+ it('should return yaml and print warning if file extension does not supported', () => {
681
+ const stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
682
+ (yellow as jest.Mock<any, any>).mockImplementation((text: string) => text);
616
683
 
617
- expect(getAndValidateFileExtension('test.xml')).toEqual('yaml');
618
- expect(stderrMock).toHaveBeenCalledWith(`Unsupported file extension: xml. Using yaml.\n`);
619
- });
684
+ expect(getAndValidateFileExtension('test.xml')).toEqual('yaml');
685
+ expect(stderrMock).toHaveBeenCalledWith(`Unsupported file extension: xml. Using yaml.\n`);
620
686
  });
621
687
  });
622
688
 
@@ -575,7 +575,7 @@ export async function sendTelemetry(
575
575
  event_time,
576
576
  logged_in: logged_in ? 'yes' : 'no',
577
577
  command: `${command}`,
578
- arguments: JSON.stringify(cleanArgs(args)),
578
+ ...cleanArgs(args, process.argv.slice(2)),
579
579
  node_version: process.version,
580
580
  npm_version: execSync('npm -v').toString().replace('\n', ''),
581
581
  os_platform: os.platform(),
@@ -583,7 +583,6 @@ export async function sendTelemetry(
583
583
  exit_code,
584
584
  environment: process.env.REDOCLY_ENVIRONMENT,
585
585
  environment_ci: process.env.CI,
586
- raw_input: cleanRawInput(process.argv.slice(2)),
587
586
  has_config: has_config ? 'yes' : 'no',
588
587
  spec_version,
589
588
  spec_keyword,
@@ -627,7 +626,7 @@ function isDirectory(value: string) {
627
626
  return fs.existsSync(value) && fs.statSync(value).isDirectory();
628
627
  }
629
628
 
630
- function cleanString(value?: string): string | undefined {
629
+ function cleanString(value: string): string {
631
630
  if (!value) {
632
631
  return value;
633
632
  }
@@ -646,26 +645,44 @@ function cleanString(value?: string): string | undefined {
646
645
  return value;
647
646
  }
648
647
 
649
- export function cleanArgs(args: CommandOptions) {
650
- const keysToClean = ['organization', 'o'];
648
+ function replaceArgs(
649
+ commandInput: string,
650
+ targets: string | string[],
651
+ replacement: string
652
+ ): string {
653
+ const targetValues = Array.isArray(targets) ? targets : [targets];
654
+ for (const target of targetValues) {
655
+ commandInput = commandInput.replaceAll(target, replacement);
656
+ }
657
+ return commandInput;
658
+ }
651
659
 
652
- const result: Record<string, unknown> = {};
653
- for (const [key, value] of Object.entries(args)) {
654
- if (keysToClean.includes(key)) {
655
- result[key] = '***';
660
+ export function cleanArgs(parsedArgs: CommandOptions, rawArgv: string[]) {
661
+ const KEYS_TO_CLEAN = ['organization', 'o', 'input', 'i', 'client-cert', 'client-key', 'ca-cert'];
662
+ let commandInput = rawArgv.join(' ');
663
+ const commandArguments: Record<string, string | string[]> = {};
664
+ for (const [key, value] of Object.entries(parsedArgs)) {
665
+ if (KEYS_TO_CLEAN.includes(key)) {
666
+ commandArguments[key] = '***';
667
+ commandInput = replaceArgs(commandInput, value, '***');
656
668
  } else if (typeof value === 'string') {
657
- result[key] = cleanString(value);
669
+ const cleanedValue = cleanString(value);
670
+ commandArguments[key] = cleanedValue;
671
+ commandInput = replaceArgs(commandInput, value, cleanedValue);
658
672
  } else if (Array.isArray(value)) {
659
- result[key] = value.map(cleanString);
673
+ commandArguments[key] = value.map(cleanString);
674
+ for (const replacedValue of value) {
675
+ const newValue = cleanString(replacedValue);
676
+ if (commandInput.includes(replacedValue)) {
677
+ commandInput = commandInput.replaceAll(replacedValue, newValue);
678
+ }
679
+ }
660
680
  } else {
661
- result[key] = value;
681
+ commandArguments[key] = value;
662
682
  }
663
683
  }
664
- return result;
665
- }
666
684
 
667
- export function cleanRawInput(argv: string[]) {
668
- return argv.map((entry) => entry.split('=').map(cleanString).join('=')).join(' ');
685
+ return { arguments: JSON.stringify(commandArguments), raw_input: commandInput };
669
686
  }
670
687
 
671
688
  export function checkForDeprecatedOptions<T>(argv: T, deprecatedOptions: Array<keyof T>) {