Repository: Redocly/redocly-cli
Pull request #1003 (2023-01-26 10:28:32)

fix: fix destination name validation
## What/Why/How?

Fix problem with symbols in organization id for the `push` command.
Disallow `@` in destination name;

## Reference
https://github.com/Redocly/redocly-cli/pull/890
## Testing

## Screenshots (optional)

## Check yourself

- [x] Code is linted
- [ ] Tested with redoc/reference-docs/workflows
- [x] All new/updated code is covered with tests

## Security

- [x] Security impact of change has been considered
- [x] Code follows company security practices and guidelines


github-actions[bot]: <!-- jest coverage report action for options with hash 3339ae53a38c44382c0fb4491bdb282d -->

## Coverage report 



| <div title="Status of coverage:&#10; 🟢 - ok&#10; 🟡 - slightly more than threshold&#10; 🔴 - under the threshold">St.<sup>:grey_question:</sup></div> | Category   | Percentage | Covered / Total |
| :----------------------------------------------------------------------------------------------------------------------------------------------------: | :--------- | :--------- | :-------------: |
|                                                                           🟡                                                                           | Statements | 73.79%     |    3432/4651    |
|                                                                           🟡                                                                           | Branches   | 65.28%     |    1952/2990    |
|                                                                           🟡                                                                           | Functions  | 66.06%     |     578/875     |
|                                                                           🟡                                                                           | Lines      | 73.81%     |    3191/4323    |


## Test suite run success
561 tests passing in 85 suites.

<p align="right">Report generated by <a href="https://github.com/ArtiomTr/jest-coverage-report-action">🧪jest coverage report action</a> from 3409f055d557ed381013f218a930f200971457cd</p>


Patch:
diff --git a/packages/cli/src/commands/push.ts b/packages/cli/src/commands/push.ts
index fdd9520c..6c8973a1 100644
--- a/packages/cli/src/commands/push.ts
+++ b/packages/cli/src/commands/push.ts
@@ -302,7 +302,7 @@ function hashFiles(filePaths: { filePath: string }[]) {
 }
 
 function validateDestination(destination: string) {
-  const regexp = /^(@(?<organizationId>\w+)\/)?(?<name>.*)@(?<version>[\w\.\-\_]+)$/;
+  const regexp = /^(@(?<organizationId>[\w\-\s]+)\/)?(?<name>[^@]*)@(?<version>[\w\.\-]+)$/;
 
   return destination?.match(regexp)?.groups;
 }


Test patch:
diff --git a/packages/cli/src/__tests__/commands/push.test.ts b/packages/cli/src/__tests__/commands/push.test.ts
index 4b802d93..aceb3458 100644
--- a/packages/cli/src/__tests__/commands/push.test.ts
+++ b/packages/cli/src/__tests__/commands/push.test.ts
@@ -202,6 +202,37 @@ describe('getDestinationProps', () => {
       version: 'v1',
     });
   });
+  it('should return organizationId from destination string', () => {
+    expect(getDestinationProps('@test-org/main@main-v1', undefined)).toEqual({
+      organizationId: 'test-org',
+      name: 'main',
+      version: 'main-v1',
+    });
+  });
+
+  it('should return organizationId, version and empty name from destination string', () => {
+    expect(getDestinationProps('@test_org/@main_v1', undefined)).toEqual({
+      organizationId: 'test_org',
+      name: '',
+      version: 'main_v1',
+    });
+  });
+
+  it('should validate organizationId with space and version with dot', () => {
+    expect(getDestinationProps('@test org/simple_name@main.v1', undefined)).toEqual({
+      organizationId: 'test org',
+      name: 'simple_name',
+      version: 'main.v1',
+    });
+  });
+
+  it('should not work with "@" in destination name', () => {
+    expect(getDestinationProps('@test org/simple@name@main.v1', undefined)).toEqual({
+      organizationId: undefined,
+      name: undefined,
+      version: undefined,
+    });
+  });
 });
 
 describe('getApiRoot', () => {