@adobe/aio-cli-plugin-api-mesh 3.3.1-alpha → 3.4.0
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/oclif.manifest.json +1 -1
- package/package.json +4 -6
- package/src/commands/api-mesh/__tests__/create.test.js +0 -246
- package/src/commands/api-mesh/__tests__/run.test.js +0 -126
- package/src/commands/api-mesh/create.js +0 -16
- package/src/commands/api-mesh/run.js +0 -17
- package/src/commands/api-mesh/update.js +0 -16
- package/src/helpers.js +0 -21
- package/src/server.js +0 -7
- package/src/serverUtils.js +0 -21
- package/src/utils.js +0 -104
- package/src/commands/__fixtures__/sample_secrets_mesh.json +0 -18
- package/src/commands/__fixtures__/secrets_invalid.yaml +0 -3
- package/src/commands/__fixtures__/secrets_valid.yaml +0 -2
- package/src/commands/__fixtures__/secrets_with_batch_variables.yaml +0 -4
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"3.
|
|
1
|
+
{"version":"3.4.0","commands":{"PLUGINNAME":{"id":"PLUGINNAME","description":"Your description here","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":["$ aio PLUGINNAME:some_command"],"flags":{"someflag":{"name":"someflag","type":"option","char":"f","description":"this is some flag"}},"args":[]},"api-mesh:create":{"id":"api-mesh:create","description":"Create a mesh with the given config.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"json":{"name":"json","type":"boolean","description":"Output JSON","allowNo":false},"env":{"name":"env","type":"option","char":"e","description":"Path to env file","default":".env"}},"args":[{"name":"file"}]},"api-mesh:delete":{"id":"api-mesh:delete","description":"Delete the config of a given mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false}},"args":[]},"api-mesh:describe":{"id":"api-mesh:describe","description":"Get details of a mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[]},"api-mesh:get":{"id":"api-mesh:get","description":"Get the config of a given mesh","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"json":{"name":"json","type":"boolean","description":"Output JSON","allowNo":false}},"args":[{"name":"file"}]},"api-mesh:init":{"id":"api-mesh:init","description":"This command will create a workspace where you can organise your API mesh configuration and other files","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":[{"description":"API mesh workspace init","command":"aio api-mesh init commerce-mesh"},{"description":"API mesh workspace init with flags","command":"aio api-mesh init commerce-mesh --path ./mesh_projects/test_mesh --git y --packageManager yarn"}],"flags":{"path":{"name":"path","type":"option","char":"p","default":"."},"packageManager":{"name":"packageManager","type":"option","char":"m","options":["npm","yarn"]},"git":{"name":"git","type":"option","char":"g","options":["y","n"]}},"args":[{"name":"projectName","description":"Project name","required":true}]},"api-mesh:run":{"id":"api-mesh:run","description":"Run a local development server that builds and compiles a mesh locally","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":[],"flags":{"port":{"name":"port","type":"option","char":"p","description":"Port number for the local dev server"},"debug":{"name":"debug","type":"boolean","description":"Enable debugging mode","allowNo":false},"env":{"name":"env","type":"option","char":"e","description":"Path to env file","default":".env"},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"select":{"name":"select","type":"boolean","description":"Retrieve existing artifacts from the mesh","allowNo":false}},"args":[{"name":"file","description":"Mesh File"}]},"api-mesh:status":{"id":"api-mesh:status","description":"Get a mesh status with a given meshid.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[]},"api-mesh:update":{"id":"api-mesh:update","description":"Update a mesh with the given config.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false},"autoConfirmAction":{"name":"autoConfirmAction","type":"boolean","char":"c","description":"Auto confirm action prompt. CLI will not check for user approval before executing the action.","allowNo":false},"env":{"name":"env","type":"option","char":"e","description":"Path to env file","default":".env"}},"args":[{"name":"file"}]},"api-mesh:source:discover":{"id":"api-mesh:source:discover","description":"Return the list of avaliable sources","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"flags":{"confirm":{"name":"confirm","type":"boolean","char":"c","description":"Auto confirm install action prompt. CLI will not check ask user to install source.","allowNo":false}},"args":[]},"api-mesh:source:get":{"id":"api-mesh:source:get","description":"Command returns the content of a specific source.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":["$ aio api-mesh:source:get -s=<version>@<source_name>","$ aio api-mesh:source:get -s<source_name>","$ aio api-mesh:source:get -m"],"flags":{"confirm":{"name":"confirm","type":"boolean","char":"c","description":"Auto confirm print action prompt. CLI will not check ask user to print source.","allowNo":false},"source":{"name":"source","type":"option","char":"s","description":"Source name"},"multiple":{"name":"multiple","type":"boolean","char":"m","description":"Select multiple sources","allowNo":false}},"args":[]},"api-mesh:source:install":{"id":"api-mesh:source:install","description":"Command to install the source to your API mesh.","pluginName":"@adobe/aio-cli-plugin-api-mesh","pluginType":"core","aliases":[],"examples":["$ aio api-mesh:source:install <version>@<source_name>","$ aio api-mesh:source:install <source_name> -v <variable_name>=<variable_value>","$ aio api-mesh:source:install <source_name> -f <path_to_variables_file>"],"flags":{"source":{"name":"source","type":"option","char":"s","description":"Source name"},"confirm":{"name":"confirm","type":"boolean","char":"c","description":"Auto confirm override action prompt. CLI will not check ask user to override source.","allowNo":false},"variable":{"name":"variable","type":"option","char":"v","description":"Variables required for the source"},"variable-file":{"name":"variable-file","type":"option","char":"f","description":"Variables file path"},"ignoreCache":{"name":"ignoreCache","type":"boolean","char":"i","description":"Ignore cache and force manual org -> project -> workspace selection","allowNo":false}},"args":[{"name":"source"}]}}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/aio-cli-plugin-api-mesh",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "Adobe I/O CLI plugin to develop and manage API mesh sources",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"oclif-plugin"
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"version": "oclif-dev readme && git add README.md"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@adobe-apimesh/mesh-builder": "1.
|
|
40
|
+
"@adobe-apimesh/mesh-builder": "1.5.0",
|
|
41
41
|
"@adobe/aio-cli-lib-console": "^4.0.0",
|
|
42
42
|
"@adobe/aio-lib-core-config": "^3.0.0",
|
|
43
43
|
"@adobe/aio-lib-core-logging": "^2.0.0",
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
"@graphql-mesh/plugin-http-details-extensions": "0.1.21",
|
|
53
53
|
"@graphql-mesh/runtime": "0.46.21",
|
|
54
54
|
"@graphql-mesh/soap": "0.14.25",
|
|
55
|
-
"@graphql-mesh/store": "0.9.20",
|
|
56
55
|
"@graphql-mesh/transform-encapsulate": "0.4.21",
|
|
57
56
|
"@graphql-mesh/transform-federation": "0.11.14",
|
|
58
57
|
"@graphql-mesh/transform-filter-schema": "0.15.23",
|
|
@@ -65,6 +64,7 @@
|
|
|
65
64
|
"@graphql-mesh/transform-resolvers-composition": "0.13.20",
|
|
66
65
|
"@graphql-mesh/transform-type-merging": "0.5.20",
|
|
67
66
|
"@graphql-mesh/types": "0.91.12",
|
|
67
|
+
"@graphql-mesh/store": "0.9.20",
|
|
68
68
|
"@oclif/command": "^1.6.1",
|
|
69
69
|
"@oclif/config": "^1.15.1",
|
|
70
70
|
"@oclif/core": "^1.14.1",
|
|
@@ -74,7 +74,6 @@
|
|
|
74
74
|
"child_process": "^1.0.2",
|
|
75
75
|
"content-disposition": "^0.5.4",
|
|
76
76
|
"dotenv": "^16.0.3",
|
|
77
|
-
"envsub": "^4.1.0",
|
|
78
77
|
"eslint-plugin-promise": "^6.0.0",
|
|
79
78
|
"eslint-plugin-security": "^1.5.0",
|
|
80
79
|
"eslint-plugin-sonarjs": "^0.16.0",
|
|
@@ -93,8 +92,7 @@
|
|
|
93
92
|
"pupa": "^3.1.0",
|
|
94
93
|
"source-registry-storage-adapter": "github:devx-services/source-registry-storage-adapter#main",
|
|
95
94
|
"util": "^0.12.5",
|
|
96
|
-
"uuid": "^8.3.2"
|
|
97
|
-
"yaml": "^2.4.2"
|
|
95
|
+
"uuid": "^8.3.2"
|
|
98
96
|
},
|
|
99
97
|
"devDependencies": {
|
|
100
98
|
"@babel/eslint-parser": "^7.15.8",
|
|
@@ -47,38 +47,12 @@ const {
|
|
|
47
47
|
} = require('../../../lib/devConsole');
|
|
48
48
|
|
|
49
49
|
const selectedOrg = { id: '1234', code: 'CODE1234@AdobeOrg', name: 'ORG01', type: 'entp' };
|
|
50
|
-
|
|
51
|
-
const os = require('os');
|
|
52
|
-
|
|
53
50
|
const selectedProject = { id: '5678', title: 'Project01' };
|
|
54
51
|
const selectedWorkspace = { id: '123456789', title: 'Workspace01' };
|
|
55
52
|
|
|
56
|
-
jest.mock('@adobe/aio-cli-lib-console', () => ({
|
|
57
|
-
init: jest.fn().mockResolvedValue(mockConsoleCLIInstance),
|
|
58
|
-
cleanStdOut: jest.fn(),
|
|
59
|
-
}));
|
|
60
|
-
|
|
61
|
-
jest.mock('axios');
|
|
62
|
-
jest.mock('@adobe/aio-lib-ims');
|
|
63
|
-
jest.mock('@adobe/aio-lib-env');
|
|
64
|
-
jest.mock('@adobe/aio-cli-lib-console');
|
|
65
|
-
jest.mock('../../../helpers', () => ({
|
|
66
|
-
initSdk: jest.fn().mockResolvedValue({}),
|
|
67
|
-
initRequestId: jest.fn().mockResolvedValue({}),
|
|
68
|
-
promptConfirm: jest.fn().mockResolvedValue(true),
|
|
69
|
-
interpolateMesh: jest.fn().mockResolvedValue({}),
|
|
70
|
-
importFiles: jest.fn().mockResolvedValue(),
|
|
71
|
-
}));
|
|
72
|
-
jest.mock('../../../lib/devConsole');
|
|
73
|
-
jest.mock('chalk', () => ({
|
|
74
|
-
red: jest.fn(text => text), // Return the input text without any color formatting
|
|
75
|
-
bold: jest.fn(text => text),
|
|
76
|
-
}));
|
|
77
|
-
|
|
78
53
|
let logSpy = null;
|
|
79
54
|
let errorLogSpy = null;
|
|
80
55
|
let parseSpy = null;
|
|
81
|
-
let platformSpy = null;
|
|
82
56
|
|
|
83
57
|
const mockIgnoreCacheFlag = Promise.resolve(true);
|
|
84
58
|
const mockAutoApproveAction = Promise.resolve(false);
|
|
@@ -95,12 +69,6 @@ describe('create command tests', () => {
|
|
|
95
69
|
projectName: selectedProject.title,
|
|
96
70
|
});
|
|
97
71
|
|
|
98
|
-
global.requestId = 'dummy_request_id';
|
|
99
|
-
|
|
100
|
-
logSpy = jest.spyOn(CreateCommand.prototype, 'log');
|
|
101
|
-
errorLogSpy = jest.spyOn(CreateCommand.prototype, 'error');
|
|
102
|
-
platformSpy = jest.spyOn(os, 'platform');
|
|
103
|
-
|
|
104
72
|
createMesh.mockResolvedValue({
|
|
105
73
|
mesh: {
|
|
106
74
|
meshId: 'dummy_mesh_id',
|
|
@@ -141,10 +109,6 @@ describe('create command tests', () => {
|
|
|
141
109
|
});
|
|
142
110
|
});
|
|
143
111
|
|
|
144
|
-
afterEach(() => {
|
|
145
|
-
platformSpy.mockRestore();
|
|
146
|
-
});
|
|
147
|
-
|
|
148
112
|
test('must return proper object structure used by adobe/generator-app-api-mesh', async () => {
|
|
149
113
|
parseSpy.mockResolvedValueOnce({
|
|
150
114
|
args: { file: 'src/commands/__fixtures__/sample_mesh.json' },
|
|
@@ -207,15 +171,6 @@ describe('create command tests', () => {
|
|
|
207
171
|
"parse": [Function],
|
|
208
172
|
"type": "boolean",
|
|
209
173
|
},
|
|
210
|
-
"secrets": {
|
|
211
|
-
"char": "s",
|
|
212
|
-
"default": false,
|
|
213
|
-
"description": "Path to secrets file",
|
|
214
|
-
"input": [],
|
|
215
|
-
"multiple": false,
|
|
216
|
-
"parse": [Function],
|
|
217
|
-
"type": "option",
|
|
218
|
-
},
|
|
219
174
|
}
|
|
220
175
|
`);
|
|
221
176
|
expect(CreateCommand.aliases).toMatchInlineSnapshot(`[]`);
|
|
@@ -1876,205 +1831,4 @@ describe('create command tests', () => {
|
|
|
1876
1831
|
'https://graph.adobe.io/api/dummy_mesh_id/graphql?api_key=dummy_api_key',
|
|
1877
1832
|
);
|
|
1878
1833
|
});
|
|
1879
|
-
|
|
1880
|
-
test('should return error if mesh has placeholders and the provided secrets file is invalid', async () => {
|
|
1881
|
-
parseSpy.mockResolvedValueOnce({
|
|
1882
|
-
args: { file: 'src/commands/__fixtures__/sample_secrets_mesh.json' },
|
|
1883
|
-
flags: {
|
|
1884
|
-
ignoreCache: mockIgnoreCacheFlag,
|
|
1885
|
-
autoConfirmAction: Promise.resolve(true),
|
|
1886
|
-
secrets: 'src/commands/__fixtures__/secrets_invalid.yaml',
|
|
1887
|
-
},
|
|
1888
|
-
});
|
|
1889
|
-
|
|
1890
|
-
const runResult = CreateCommand.run();
|
|
1891
|
-
|
|
1892
|
-
await expect(runResult).rejects.toEqual(
|
|
1893
|
-
new Error('Unable to import secrets. Please check the file and try again.'),
|
|
1894
|
-
);
|
|
1895
|
-
|
|
1896
|
-
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
1897
|
-
[
|
|
1898
|
-
[
|
|
1899
|
-
"Unable to import secrets. Please check the file and try again.",
|
|
1900
|
-
],
|
|
1901
|
-
]
|
|
1902
|
-
`);
|
|
1903
|
-
});
|
|
1904
|
-
|
|
1905
|
-
test('should return error if mesh has placeholders and the provided secrets file is not yaml or yml', async () => {
|
|
1906
|
-
parseSpy.mockResolvedValueOnce({
|
|
1907
|
-
args: { file: 'src/commands/__fixtures__/sample_secrets_mesh.json' },
|
|
1908
|
-
flags: {
|
|
1909
|
-
ignoreCache: mockIgnoreCacheFlag,
|
|
1910
|
-
autoConfirmAction: Promise.resolve(true),
|
|
1911
|
-
secrets: 'src/commands/__fixtures__/.secrets_file.env',
|
|
1912
|
-
},
|
|
1913
|
-
});
|
|
1914
|
-
|
|
1915
|
-
const runResult = CreateCommand.run();
|
|
1916
|
-
|
|
1917
|
-
await expect(runResult).rejects.toEqual(
|
|
1918
|
-
new Error('Unable to import secrets. Please check the file and try again.'),
|
|
1919
|
-
);
|
|
1920
|
-
|
|
1921
|
-
expect(logSpy.mock.calls).toMatchInlineSnapshot(`
|
|
1922
|
-
[
|
|
1923
|
-
[
|
|
1924
|
-
"Invalid file format. Please provide a YAML file (.yaml or .yml).",
|
|
1925
|
-
],
|
|
1926
|
-
]
|
|
1927
|
-
`);
|
|
1928
|
-
|
|
1929
|
-
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
1930
|
-
[
|
|
1931
|
-
[
|
|
1932
|
-
"Unable to import secrets. Please check the file and try again.",
|
|
1933
|
-
],
|
|
1934
|
-
]
|
|
1935
|
-
`);
|
|
1936
|
-
});
|
|
1937
|
-
|
|
1938
|
-
test('should successfully create a mesh if provided secrets file is valid', async () => {
|
|
1939
|
-
parseSpy.mockResolvedValueOnce({
|
|
1940
|
-
args: { file: 'src/commands/__fixtures__/sample_secrets_mesh.json' },
|
|
1941
|
-
flags: {
|
|
1942
|
-
ignoreCache: mockIgnoreCacheFlag,
|
|
1943
|
-
autoConfirmAction: Promise.resolve(true),
|
|
1944
|
-
secrets: 'src/commands/__fixtures__/secrets_valid.yaml',
|
|
1945
|
-
},
|
|
1946
|
-
});
|
|
1947
|
-
|
|
1948
|
-
const runResult = await CreateCommand.run();
|
|
1949
|
-
expect(runResult).toMatchInlineSnapshot(`
|
|
1950
|
-
{
|
|
1951
|
-
"apiKey": "dummy_api_key",
|
|
1952
|
-
"mesh": {
|
|
1953
|
-
"meshConfig": {
|
|
1954
|
-
"sources": [
|
|
1955
|
-
{
|
|
1956
|
-
"handler": {
|
|
1957
|
-
"graphql": {
|
|
1958
|
-
"endpoint": "<gql_endpoint>",
|
|
1959
|
-
},
|
|
1960
|
-
},
|
|
1961
|
-
"name": "<api_name>",
|
|
1962
|
-
},
|
|
1963
|
-
],
|
|
1964
|
-
},
|
|
1965
|
-
"meshId": "dummy_mesh_id",
|
|
1966
|
-
},
|
|
1967
|
-
"sdkList": [
|
|
1968
|
-
"dummy_service",
|
|
1969
|
-
],
|
|
1970
|
-
}
|
|
1971
|
-
`);
|
|
1972
|
-
});
|
|
1973
|
-
|
|
1974
|
-
test('should return error if ran against windows platform with batch variables', async () => {
|
|
1975
|
-
platformSpy.mockReturnValue('win32');
|
|
1976
|
-
parseSpy.mockResolvedValueOnce({
|
|
1977
|
-
args: { file: 'src/commands/__fixtures__/sample_secrets_mesh.json' },
|
|
1978
|
-
flags: {
|
|
1979
|
-
ignoreCache: mockIgnoreCacheFlag,
|
|
1980
|
-
autoConfirmAction: Promise.resolve(true),
|
|
1981
|
-
secrets: 'src/commands/__fixtures__/secrets_with_batch_variables.yaml',
|
|
1982
|
-
},
|
|
1983
|
-
});
|
|
1984
|
-
|
|
1985
|
-
const runResult = CreateCommand.run();
|
|
1986
|
-
|
|
1987
|
-
await expect(runResult).rejects.toEqual(
|
|
1988
|
-
new Error('Unable to import secrets. Please check the file and try again.'),
|
|
1989
|
-
);
|
|
1990
|
-
|
|
1991
|
-
expect(logSpy.mock.calls).toMatchInlineSnapshot(`
|
|
1992
|
-
[
|
|
1993
|
-
[
|
|
1994
|
-
"Batch variables are not supported in YAML files on Windows.",
|
|
1995
|
-
],
|
|
1996
|
-
]
|
|
1997
|
-
`);
|
|
1998
|
-
expect(errorLogSpy.mock.calls).toMatchInlineSnapshot(`
|
|
1999
|
-
[
|
|
2000
|
-
[
|
|
2001
|
-
"Unable to import secrets. Please check the file and try again.",
|
|
2002
|
-
],
|
|
2003
|
-
]
|
|
2004
|
-
`);
|
|
2005
|
-
});
|
|
2006
|
-
|
|
2007
|
-
test('should pass if ran against linux platform with batch variables', async () => {
|
|
2008
|
-
platformSpy.mockReturnValue('linux');
|
|
2009
|
-
parseSpy.mockResolvedValueOnce({
|
|
2010
|
-
args: { file: 'src/commands/__fixtures__/sample_secrets_mesh.json' },
|
|
2011
|
-
flags: {
|
|
2012
|
-
ignoreCache: mockIgnoreCacheFlag,
|
|
2013
|
-
autoConfirmAction: Promise.resolve(true),
|
|
2014
|
-
secrets: 'src/commands/__fixtures__/secrets_with_batch_variables.yaml',
|
|
2015
|
-
},
|
|
2016
|
-
});
|
|
2017
|
-
|
|
2018
|
-
const runResult = await CreateCommand.run();
|
|
2019
|
-
expect(runResult).toMatchInlineSnapshot(`
|
|
2020
|
-
{
|
|
2021
|
-
"apiKey": "dummy_api_key",
|
|
2022
|
-
"mesh": {
|
|
2023
|
-
"meshConfig": {
|
|
2024
|
-
"sources": [
|
|
2025
|
-
{
|
|
2026
|
-
"handler": {
|
|
2027
|
-
"graphql": {
|
|
2028
|
-
"endpoint": "<gql_endpoint>",
|
|
2029
|
-
},
|
|
2030
|
-
},
|
|
2031
|
-
"name": "<api_name>",
|
|
2032
|
-
},
|
|
2033
|
-
],
|
|
2034
|
-
},
|
|
2035
|
-
"meshId": "dummy_mesh_id",
|
|
2036
|
-
},
|
|
2037
|
-
"sdkList": [
|
|
2038
|
-
"dummy_service",
|
|
2039
|
-
],
|
|
2040
|
-
}
|
|
2041
|
-
`);
|
|
2042
|
-
});
|
|
2043
|
-
|
|
2044
|
-
test('should pass if ran against darwin(macOS) platform with batch variables', async () => {
|
|
2045
|
-
platformSpy.mockReturnValue('darwin');
|
|
2046
|
-
parseSpy.mockResolvedValueOnce({
|
|
2047
|
-
args: { file: 'src/commands/__fixtures__/sample_secrets_mesh.json' },
|
|
2048
|
-
flags: {
|
|
2049
|
-
ignoreCache: mockIgnoreCacheFlag,
|
|
2050
|
-
autoConfirmAction: Promise.resolve(true),
|
|
2051
|
-
secrets: 'src/commands/__fixtures__/secrets_with_batch_variables.yaml',
|
|
2052
|
-
},
|
|
2053
|
-
});
|
|
2054
|
-
|
|
2055
|
-
const runResult = await CreateCommand.run();
|
|
2056
|
-
expect(runResult).toMatchInlineSnapshot(`
|
|
2057
|
-
{
|
|
2058
|
-
"apiKey": "dummy_api_key",
|
|
2059
|
-
"mesh": {
|
|
2060
|
-
"meshConfig": {
|
|
2061
|
-
"sources": [
|
|
2062
|
-
{
|
|
2063
|
-
"handler": {
|
|
2064
|
-
"graphql": {
|
|
2065
|
-
"endpoint": "<gql_endpoint>",
|
|
2066
|
-
},
|
|
2067
|
-
},
|
|
2068
|
-
"name": "<api_name>",
|
|
2069
|
-
},
|
|
2070
|
-
],
|
|
2071
|
-
},
|
|
2072
|
-
"meshId": "dummy_mesh_id",
|
|
2073
|
-
},
|
|
2074
|
-
"sdkList": [
|
|
2075
|
-
"dummy_service",
|
|
2076
|
-
],
|
|
2077
|
-
}
|
|
2078
|
-
`);
|
|
2079
|
-
});
|
|
2080
1834
|
});
|
|
@@ -18,7 +18,6 @@ const {
|
|
|
18
18
|
promptConfirm,
|
|
19
19
|
setUpTenantFiles,
|
|
20
20
|
initSdk,
|
|
21
|
-
writeSecretsFile,
|
|
22
21
|
} = require('../../../helpers');
|
|
23
22
|
const { getMeshId, getMeshArtifact } = require('../../../lib/devConsole');
|
|
24
23
|
require('@adobe-apimesh/mesh-builder');
|
|
@@ -36,16 +35,12 @@ jest.mock('../../../helpers', () => ({
|
|
|
36
35
|
importFiles: jest.fn().mockResolvedValue(),
|
|
37
36
|
promptConfirm: jest.fn().mockResolvedValue(true),
|
|
38
37
|
setUpTenantFiles: jest.fn().mockResolvedValue(),
|
|
39
|
-
writeSecretsFile: jest.fn().mockResolvedValue(),
|
|
40
38
|
}));
|
|
41
39
|
|
|
42
40
|
jest.mock('../../../lib/devConsole', () => ({
|
|
43
41
|
getMeshId: jest.fn().mockResolvedValue('mockMeshId'),
|
|
44
42
|
getMeshArtifact: jest.fn().mockResolvedValue(),
|
|
45
43
|
}));
|
|
46
|
-
jest.mock('chalk', () => ({
|
|
47
|
-
red: jest.fn(text => text), // Return the input text without any color formatting
|
|
48
|
-
}));
|
|
49
44
|
|
|
50
45
|
jest.mock('@adobe-apimesh/mesh-builder', () => {
|
|
51
46
|
return {
|
|
@@ -60,15 +55,12 @@ jest.mock('@adobe-apimesh/mesh-builder', () => {
|
|
|
60
55
|
let logSpy = null;
|
|
61
56
|
let errorLogSpy = null;
|
|
62
57
|
let parseSpy = null;
|
|
63
|
-
let platformSpy = null;
|
|
64
58
|
|
|
65
59
|
const originalEnv = {
|
|
66
60
|
API_MESH_TIER: 'NON-TI',
|
|
67
61
|
};
|
|
68
62
|
|
|
69
63
|
const defaultPort = 5000;
|
|
70
|
-
const os = require('os');
|
|
71
|
-
|
|
72
64
|
describe('run command tests', () => {
|
|
73
65
|
beforeEach(() => {
|
|
74
66
|
global.requestId = 'dummy_request_id';
|
|
@@ -76,14 +68,10 @@ describe('run command tests', () => {
|
|
|
76
68
|
logSpy = jest.spyOn(RunCommand.prototype, 'log');
|
|
77
69
|
errorLogSpy = jest.spyOn(RunCommand.prototype, 'error');
|
|
78
70
|
parseSpy = jest.spyOn(RunCommand.prototype, 'parse');
|
|
79
|
-
platformSpy = jest.spyOn(os, 'platform');
|
|
80
71
|
process.env = {
|
|
81
72
|
...originalEnv,
|
|
82
73
|
};
|
|
83
74
|
});
|
|
84
|
-
afterEach(() => {
|
|
85
|
-
platformSpy.mockRestore();
|
|
86
|
-
});
|
|
87
75
|
|
|
88
76
|
test('snapshot run command description', () => {
|
|
89
77
|
expect(RunCommand.description).toMatchInlineSnapshot(
|
|
@@ -133,15 +121,6 @@ describe('run command tests', () => {
|
|
|
133
121
|
"parse": [Function],
|
|
134
122
|
"type": "option",
|
|
135
123
|
},
|
|
136
|
-
"secrets": {
|
|
137
|
-
"char": "s",
|
|
138
|
-
"default": false,
|
|
139
|
-
"description": "Path to secrets file",
|
|
140
|
-
"input": [],
|
|
141
|
-
"multiple": false,
|
|
142
|
-
"parse": [Function],
|
|
143
|
-
"type": "option",
|
|
144
|
-
},
|
|
145
124
|
"select": {
|
|
146
125
|
"allowNo": false,
|
|
147
126
|
"default": false,
|
|
@@ -857,109 +836,4 @@ describe('run command tests', () => {
|
|
|
857
836
|
);
|
|
858
837
|
expect(setUpTenantFiles).toHaveBeenCalled();
|
|
859
838
|
});
|
|
860
|
-
|
|
861
|
-
test('should return error for run command if mesh has placeholders and the provided secrets file is invalid', async () => {
|
|
862
|
-
parseSpy.mockResolvedValueOnce({
|
|
863
|
-
args: { file: 'src/commands/__fixtures__/sample_secrets_mesh.json' },
|
|
864
|
-
flags: {
|
|
865
|
-
secrets: 'src/commands/__fixtures__/secrets_invalid.yaml',
|
|
866
|
-
},
|
|
867
|
-
});
|
|
868
|
-
|
|
869
|
-
const runResult = RunCommand.run();
|
|
870
|
-
|
|
871
|
-
await expect(runResult).rejects.toEqual(
|
|
872
|
-
new Error('Unable to import secrets. Please check the file and try again.'),
|
|
873
|
-
);
|
|
874
|
-
});
|
|
875
|
-
|
|
876
|
-
test('should return error for run command if mesh has placeholders and the provided secrets file is not yaml or yml', async () => {
|
|
877
|
-
parseSpy.mockResolvedValueOnce({
|
|
878
|
-
args: { file: 'src/commands/__fixtures__/sample_secrets_mesh.json' },
|
|
879
|
-
flags: {
|
|
880
|
-
secrets: 'src/commands/__fixtures__/.secrets_file.env',
|
|
881
|
-
},
|
|
882
|
-
});
|
|
883
|
-
|
|
884
|
-
const runResult = RunCommand.run();
|
|
885
|
-
|
|
886
|
-
await expect(runResult).rejects.toEqual(
|
|
887
|
-
new Error('Unable to import secrets. Please check the file and try again.'),
|
|
888
|
-
);
|
|
889
|
-
|
|
890
|
-
expect(logSpy.mock.calls).toMatchInlineSnapshot(`
|
|
891
|
-
[
|
|
892
|
-
[
|
|
893
|
-
"Invalid file format. Please provide a YAML file (.yaml or .yml).",
|
|
894
|
-
],
|
|
895
|
-
]
|
|
896
|
-
`);
|
|
897
|
-
});
|
|
898
|
-
|
|
899
|
-
test('should successfully run the mesh if provided secrets file is valid', async () => {
|
|
900
|
-
parseSpy.mockResolvedValueOnce({
|
|
901
|
-
args: { file: 'src/commands/__fixtures__/sample_secrets_mesh.json' },
|
|
902
|
-
flags: {
|
|
903
|
-
secrets: 'src/commands/__fixtures__/secrets_valid.yaml',
|
|
904
|
-
debug: false,
|
|
905
|
-
},
|
|
906
|
-
});
|
|
907
|
-
|
|
908
|
-
await RunCommand.run();
|
|
909
|
-
expect(writeSecretsFile).toHaveBeenCalled();
|
|
910
|
-
expect(startGraphqlServer).toHaveBeenCalledWith(expect.anything(), defaultPort, false);
|
|
911
|
-
});
|
|
912
|
-
|
|
913
|
-
test('should return error if ran with secrets against windows platform with batch variables', async () => {
|
|
914
|
-
platformSpy.mockReturnValue('win32');
|
|
915
|
-
parseSpy.mockResolvedValueOnce({
|
|
916
|
-
args: { file: 'src/commands/__fixtures__/sample_secrets_mesh.json' },
|
|
917
|
-
flags: {
|
|
918
|
-
secrets: 'src/commands/__fixtures__/secrets_with_batch_variables.yaml',
|
|
919
|
-
},
|
|
920
|
-
});
|
|
921
|
-
|
|
922
|
-
const runResult = RunCommand.run();
|
|
923
|
-
await expect(runResult).rejects.toEqual(
|
|
924
|
-
new Error('Unable to import secrets. Please check the file and try again.'),
|
|
925
|
-
);
|
|
926
|
-
|
|
927
|
-
expect(logSpy.mock.calls).toMatchInlineSnapshot(`
|
|
928
|
-
[
|
|
929
|
-
[
|
|
930
|
-
"Batch variables are not supported in YAML files on Windows.",
|
|
931
|
-
],
|
|
932
|
-
]
|
|
933
|
-
`);
|
|
934
|
-
});
|
|
935
|
-
|
|
936
|
-
test('should pass if ran with secrets against linux platform with batch variables', async () => {
|
|
937
|
-
platformSpy.mockReturnValue('linux');
|
|
938
|
-
parseSpy.mockResolvedValueOnce({
|
|
939
|
-
args: { file: 'src/commands/__fixtures__/sample_secrets_mesh.json' },
|
|
940
|
-
flags: {
|
|
941
|
-
secrets: 'src/commands/__fixtures__/secrets_with_batch_variables.yaml',
|
|
942
|
-
debug: false,
|
|
943
|
-
},
|
|
944
|
-
});
|
|
945
|
-
|
|
946
|
-
await RunCommand.run();
|
|
947
|
-
expect(writeSecretsFile).toHaveBeenCalled();
|
|
948
|
-
expect(startGraphqlServer).toHaveBeenCalledWith(expect.anything(), defaultPort, false);
|
|
949
|
-
});
|
|
950
|
-
|
|
951
|
-
test('should pass if ran with secrets against darwin(macOS) platform with batch variables', async () => {
|
|
952
|
-
platformSpy.mockReturnValue('darwin');
|
|
953
|
-
parseSpy.mockResolvedValueOnce({
|
|
954
|
-
args: { file: 'src/commands/__fixtures__/sample_secrets_mesh.json' },
|
|
955
|
-
flags: {
|
|
956
|
-
secrets: 'src/commands/__fixtures__/secrets_with_batch_variables.yaml',
|
|
957
|
-
debug: false,
|
|
958
|
-
},
|
|
959
|
-
});
|
|
960
|
-
|
|
961
|
-
await RunCommand.run();
|
|
962
|
-
expect(writeSecretsFile).toHaveBeenCalled();
|
|
963
|
-
expect(startGraphqlServer).toHaveBeenCalledWith(expect.anything(), defaultPort, false);
|
|
964
|
-
});
|
|
965
839
|
});
|
|
@@ -19,12 +19,9 @@ const {
|
|
|
19
19
|
jsonFlag,
|
|
20
20
|
getFilesInMeshConfig,
|
|
21
21
|
envFileFlag,
|
|
22
|
-
secretsFlag,
|
|
23
22
|
checkPlaceholders,
|
|
24
23
|
readFileContents,
|
|
25
24
|
validateAndInterpolateMesh,
|
|
26
|
-
interpolateSecrets,
|
|
27
|
-
validateSecretsFile,
|
|
28
25
|
} = require('../../utils');
|
|
29
26
|
const { createMesh, getTenantFeatures } = require('../../lib/devConsole');
|
|
30
27
|
const { buildEdgeMeshUrl, buildMeshUrl } = require('../../urlBuilder');
|
|
@@ -36,7 +33,6 @@ class CreateCommand extends Command {
|
|
|
36
33
|
autoConfirmAction: autoConfirmActionFlag,
|
|
37
34
|
json: jsonFlag,
|
|
38
35
|
env: envFileFlag,
|
|
39
|
-
secrets: secretsFlag,
|
|
40
36
|
};
|
|
41
37
|
|
|
42
38
|
static enableJsonFlag = true;
|
|
@@ -57,7 +53,6 @@ class CreateCommand extends Command {
|
|
|
57
53
|
const ignoreCache = await flags.ignoreCache;
|
|
58
54
|
const autoConfirmAction = await flags.autoConfirmAction;
|
|
59
55
|
const envFilePath = await flags.env;
|
|
60
|
-
const secretsFilePath = await flags.secrets;
|
|
61
56
|
const {
|
|
62
57
|
imsOrgId,
|
|
63
58
|
imsOrgCode,
|
|
@@ -108,17 +103,6 @@ class CreateCommand extends Command {
|
|
|
108
103
|
}
|
|
109
104
|
}
|
|
110
105
|
|
|
111
|
-
// if secrets is present, include that in data.secrets
|
|
112
|
-
if (secretsFilePath) {
|
|
113
|
-
try {
|
|
114
|
-
await validateSecretsFile(secretsFilePath);
|
|
115
|
-
data.secrets = await interpolateSecrets(secretsFilePath, this);
|
|
116
|
-
} catch (err) {
|
|
117
|
-
this.log(err.message);
|
|
118
|
-
this.error('Unable to import secrets. Please check the file and try again.');
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
106
|
let shouldContinue = true;
|
|
123
107
|
|
|
124
108
|
if (!autoConfirmAction) {
|
|
@@ -15,14 +15,11 @@ const {
|
|
|
15
15
|
debugFlag,
|
|
16
16
|
selectFlag,
|
|
17
17
|
envFileFlag,
|
|
18
|
-
secretsFlag,
|
|
19
18
|
autoConfirmActionFlag,
|
|
20
19
|
readFileContents,
|
|
21
20
|
validateAndInterpolateMesh,
|
|
22
21
|
checkPlaceholders,
|
|
23
22
|
getFilesInMeshConfig,
|
|
24
|
-
validateSecretsFile,
|
|
25
|
-
interpolateSecrets,
|
|
26
23
|
} = require('../../utils');
|
|
27
24
|
const meshBuilder = require('@adobe-apimesh/mesh-builder');
|
|
28
25
|
const fs = require('fs');
|
|
@@ -34,7 +31,6 @@ const {
|
|
|
34
31
|
startGraphqlServer,
|
|
35
32
|
importFiles,
|
|
36
33
|
setUpTenantFiles,
|
|
37
|
-
writeSecretsFile,
|
|
38
34
|
} = require('../../helpers');
|
|
39
35
|
const logger = require('../../classes/logger');
|
|
40
36
|
const { getMeshId, getMeshArtifact } = require('../../lib/devConsole');
|
|
@@ -59,7 +55,6 @@ class RunCommand extends Command {
|
|
|
59
55
|
env: envFileFlag,
|
|
60
56
|
autoConfirmAction: autoConfirmActionFlag,
|
|
61
57
|
select: selectFlag,
|
|
62
|
-
secrets: secretsFlag,
|
|
63
58
|
};
|
|
64
59
|
|
|
65
60
|
static enableJsonFlag = true;
|
|
@@ -72,7 +67,6 @@ class RunCommand extends Command {
|
|
|
72
67
|
logger.info(`RequestId: ${global.requestId}`);
|
|
73
68
|
|
|
74
69
|
const { args, flags } = await this.parse(RunCommand);
|
|
75
|
-
const secretsFilePath = await flags.secrets;
|
|
76
70
|
|
|
77
71
|
//Initialize the meshId based on
|
|
78
72
|
let meshId = null;
|
|
@@ -171,17 +165,6 @@ class RunCommand extends Command {
|
|
|
171
165
|
}
|
|
172
166
|
|
|
173
167
|
let portNo;
|
|
174
|
-
//secrets management
|
|
175
|
-
if (secretsFilePath) {
|
|
176
|
-
try {
|
|
177
|
-
await validateSecretsFile(secretsFilePath);
|
|
178
|
-
const stringifiedSecrets = await interpolateSecrets(secretsFilePath, this);
|
|
179
|
-
await writeSecretsFile(stringifiedSecrets, meshId);
|
|
180
|
-
} catch (error) {
|
|
181
|
-
this.log(error.message);
|
|
182
|
-
this.error('Unable to import secrets. Please check the file and try again.');
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
168
|
|
|
186
169
|
//To set the port number using the environment file
|
|
187
170
|
if (process.env.PORT !== undefined) {
|
|
@@ -17,13 +17,10 @@ const {
|
|
|
17
17
|
ignoreCacheFlag,
|
|
18
18
|
autoConfirmActionFlag,
|
|
19
19
|
envFileFlag,
|
|
20
|
-
secretsFlag,
|
|
21
20
|
checkPlaceholders,
|
|
22
21
|
readFileContents,
|
|
23
22
|
validateAndInterpolateMesh,
|
|
24
23
|
getFilesInMeshConfig,
|
|
25
|
-
interpolateSecrets,
|
|
26
|
-
validateSecretsFile,
|
|
27
24
|
} = require('../../utils');
|
|
28
25
|
const { getMeshId, updateMesh } = require('../../lib/devConsole');
|
|
29
26
|
|
|
@@ -33,7 +30,6 @@ class UpdateCommand extends Command {
|
|
|
33
30
|
ignoreCache: ignoreCacheFlag,
|
|
34
31
|
autoConfirmAction: autoConfirmActionFlag,
|
|
35
32
|
env: envFileFlag,
|
|
36
|
-
secrets: secretsFlag,
|
|
37
33
|
};
|
|
38
34
|
|
|
39
35
|
async run() {
|
|
@@ -52,7 +48,6 @@ class UpdateCommand extends Command {
|
|
|
52
48
|
const ignoreCache = await flags.ignoreCache;
|
|
53
49
|
const autoConfirmAction = await flags.autoConfirmAction;
|
|
54
50
|
const envFilePath = await flags.env;
|
|
55
|
-
const secretsFilePath = await flags.secrets;
|
|
56
51
|
|
|
57
52
|
const { imsOrgId, projectId, workspaceId, orgName, projectName, workspaceName } = await initSdk(
|
|
58
53
|
{
|
|
@@ -108,17 +103,6 @@ class UpdateCommand extends Command {
|
|
|
108
103
|
}
|
|
109
104
|
}
|
|
110
105
|
|
|
111
|
-
// if secrets is present, include that in data.secrets
|
|
112
|
-
if (secretsFilePath) {
|
|
113
|
-
try {
|
|
114
|
-
await validateSecretsFile(secretsFilePath);
|
|
115
|
-
data.secrets = await interpolateSecrets(secretsFilePath, this);
|
|
116
|
-
} catch (err) {
|
|
117
|
-
this.log(err.message);
|
|
118
|
-
this.error('Unable to import secrets. Please check the file and try again.');
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
106
|
if (meshId) {
|
|
123
107
|
let shouldContinue = true;
|
|
124
108
|
|
package/src/helpers.js
CHANGED
|
@@ -860,26 +860,6 @@ async function setUpTenantFiles(meshId) {
|
|
|
860
860
|
}
|
|
861
861
|
}
|
|
862
862
|
|
|
863
|
-
/**
|
|
864
|
-
* This function is to create secrets.yaml in mesh-artifacts for respective meshId. Used for local development run command
|
|
865
|
-
*
|
|
866
|
-
* @secretsData secretsData
|
|
867
|
-
* @meshId meshId
|
|
868
|
-
*/
|
|
869
|
-
async function writeSecretsFile(secretsData, meshId) {
|
|
870
|
-
if (!fs.existsSync(path.resolve(process.cwd(), 'mesh-artifact', meshId))) {
|
|
871
|
-
throw new Error(`Unexpected Error: issue creating secrets file.`);
|
|
872
|
-
}
|
|
873
|
-
try {
|
|
874
|
-
const secretsFileName = 'secrets.yaml';
|
|
875
|
-
const folderPath = path.join(process.cwd(), 'mesh-artifact', meshId);
|
|
876
|
-
const filePath = path.join(folderPath, secretsFileName);
|
|
877
|
-
fs.writeFileSync(filePath, secretsData);
|
|
878
|
-
} catch (error) {
|
|
879
|
-
throw new Error(error.message);
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
|
|
883
863
|
module.exports = {
|
|
884
864
|
objToString,
|
|
885
865
|
promptInput,
|
|
@@ -896,5 +876,4 @@ module.exports = {
|
|
|
896
876
|
updateFilesArray,
|
|
897
877
|
startGraphqlServer,
|
|
898
878
|
setUpTenantFiles,
|
|
899
|
-
writeSecretsFile,
|
|
900
879
|
};
|
package/src/server.js
CHANGED
|
@@ -13,7 +13,6 @@ const {
|
|
|
13
13
|
removeRequestHeaders,
|
|
14
14
|
prepSourceResponseHeaders,
|
|
15
15
|
processResponseHeaders,
|
|
16
|
-
readSecretsFile,
|
|
17
16
|
} = require('./serverUtils');
|
|
18
17
|
|
|
19
18
|
let yogaServer = null;
|
|
@@ -65,8 +64,6 @@ const getYogaServer = async () => {
|
|
|
65
64
|
const tenantMesh = await getBuiltMesh();
|
|
66
65
|
const corsOptions = getCORSOptions();
|
|
67
66
|
|
|
68
|
-
const secrets = readSecretsFile(meshId);
|
|
69
|
-
|
|
70
67
|
logger.info('Creating graphQL server');
|
|
71
68
|
|
|
72
69
|
meshConfig = readMeshConfig(meshId);
|
|
@@ -76,10 +73,6 @@ const getYogaServer = async () => {
|
|
|
76
73
|
graphqlEndpoint: `/graphql`,
|
|
77
74
|
graphiql: true,
|
|
78
75
|
cors: corsOptions,
|
|
79
|
-
context: initialContext => ({
|
|
80
|
-
...initialContext,
|
|
81
|
-
secrets,
|
|
82
|
-
}),
|
|
83
76
|
});
|
|
84
77
|
|
|
85
78
|
return yogaServer;
|
package/src/serverUtils.js
CHANGED
|
@@ -2,7 +2,6 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const LRUCache = require('lru-cache');
|
|
4
4
|
const logger = require('./classes/logger');
|
|
5
|
-
const YAML = require('yaml');
|
|
6
5
|
|
|
7
6
|
const headersCache = new LRUCache({
|
|
8
7
|
max: parseInt(process.env.CACHE_OPT_MAX || '500', 10),
|
|
@@ -316,29 +315,9 @@ function ccDirectivesToString(directives) {
|
|
|
316
315
|
return chStr.toString();
|
|
317
316
|
}
|
|
318
317
|
|
|
319
|
-
/**
|
|
320
|
-
* Returns secrets content from artifacts
|
|
321
|
-
* @param meshId
|
|
322
|
-
* @returns
|
|
323
|
-
*/
|
|
324
|
-
function readSecretsFile(meshId) {
|
|
325
|
-
let secrets = {};
|
|
326
|
-
try {
|
|
327
|
-
const filePath = path.resolve(process.cwd(), 'mesh-artifact', `${meshId}`, 'secrets.yaml');
|
|
328
|
-
if (fs.existsSync(filePath)) {
|
|
329
|
-
secrets = YAML.parse(fs.readFileSync(filePath, 'utf8'));
|
|
330
|
-
}
|
|
331
|
-
} catch (error) {
|
|
332
|
-
logger.error('Unexpected error: unable to locate secrets file in mesh artifacts.');
|
|
333
|
-
throw new Error(error.message);
|
|
334
|
-
}
|
|
335
|
-
return secrets;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
318
|
module.exports = {
|
|
339
319
|
readMeshConfig,
|
|
340
320
|
removeRequestHeaders,
|
|
341
321
|
prepSourceResponseHeaders,
|
|
342
322
|
processResponseHeaders,
|
|
343
|
-
readSecretsFile,
|
|
344
323
|
};
|
package/src/utils.js
CHANGED
|
@@ -5,10 +5,6 @@ const { Flags } = require('@oclif/core');
|
|
|
5
5
|
const { readFile } = require('fs/promises');
|
|
6
6
|
const { interpolateMesh } = require('./helpers');
|
|
7
7
|
const dotenv = require('dotenv');
|
|
8
|
-
const YAML = require('yaml');
|
|
9
|
-
const parseEnv = require('envsub/js/envsub-parser');
|
|
10
|
-
const os = require('os');
|
|
11
|
-
const chalk = require('chalk');
|
|
12
8
|
|
|
13
9
|
/**
|
|
14
10
|
* @returns returns the root directory of the project
|
|
@@ -45,12 +41,6 @@ const envFileFlag = Flags.string({
|
|
|
45
41
|
default: '.env',
|
|
46
42
|
});
|
|
47
43
|
|
|
48
|
-
const secretsFlag = Flags.string({
|
|
49
|
-
char: 's',
|
|
50
|
-
description: 'Path to secrets file',
|
|
51
|
-
default: false,
|
|
52
|
-
});
|
|
53
|
-
|
|
54
44
|
const portNoFlag = Flags.integer({
|
|
55
45
|
char: 'p',
|
|
56
46
|
description: 'Port number for the local dev server',
|
|
@@ -401,97 +391,6 @@ async function validateAndInterpolateMesh(inputMeshData, envFilePath, command) {
|
|
|
401
391
|
}
|
|
402
392
|
}
|
|
403
393
|
|
|
404
|
-
/**
|
|
405
|
-
* Validate secrets file
|
|
406
|
-
*
|
|
407
|
-
* @param secretsFile Validates that secrets file extension is in yaml
|
|
408
|
-
*/
|
|
409
|
-
async function validateSecretsFile(secretsFile) {
|
|
410
|
-
try {
|
|
411
|
-
const validExtensions = ['.yaml', '.yml'];
|
|
412
|
-
const fileExtension = secretsFile.split('.').pop().toLowerCase();
|
|
413
|
-
if (!validExtensions.includes('.' + fileExtension)) {
|
|
414
|
-
throw new Error(
|
|
415
|
-
chalk.red('Invalid file format. Please provide a YAML file (.yaml or .yml).'),
|
|
416
|
-
);
|
|
417
|
-
}
|
|
418
|
-
} catch (error) {
|
|
419
|
-
logger.error(error.message);
|
|
420
|
-
throw new Error(error.message);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Read the secrets file, checks validation and interpolate mesh
|
|
426
|
-
*
|
|
427
|
-
* @param secretsFilePath Secrets file path
|
|
428
|
-
* @param command
|
|
429
|
-
*/
|
|
430
|
-
async function interpolateSecrets(secretsFilePath, command) {
|
|
431
|
-
try {
|
|
432
|
-
const secretsContent = await readFileContents(secretsFilePath, command, 'secrets');
|
|
433
|
-
|
|
434
|
-
// Check if environment variables are used in the file content
|
|
435
|
-
if (os.platform() === 'win32' && /\$({)?[a-zA-Z_][a-zA-Z0-9_]*}?/.test(secretsContent)) {
|
|
436
|
-
throw new Error(chalk.red('Batch variables are not supported in YAML files on Windows.'));
|
|
437
|
-
}
|
|
438
|
-
const secrets = await parseSecrets(secretsContent);
|
|
439
|
-
return secrets;
|
|
440
|
-
} catch (err) {
|
|
441
|
-
logger.error(err.message);
|
|
442
|
-
throw new Error(err.message);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/**
|
|
447
|
-
* Parse secrets YAML content.
|
|
448
|
-
*
|
|
449
|
-
* @param secretsFilePath Secrets file path
|
|
450
|
-
*/
|
|
451
|
-
async function parseSecrets(secretsContent) {
|
|
452
|
-
try {
|
|
453
|
-
const envParserConfig = {
|
|
454
|
-
outputFile: null,
|
|
455
|
-
options: {
|
|
456
|
-
all: false,
|
|
457
|
-
diff: false,
|
|
458
|
-
protect: false,
|
|
459
|
-
syntax: 'dollar-both',
|
|
460
|
-
},
|
|
461
|
-
cli: false,
|
|
462
|
-
};
|
|
463
|
-
const compiledSecretsFileContent = parseEnv(secretsContent, envParserConfig);
|
|
464
|
-
const parsedSecrets = YAML.parse(compiledSecretsFileContent);
|
|
465
|
-
//check if secrets file is empty
|
|
466
|
-
if (!parsedSecrets) {
|
|
467
|
-
throw new Error(chalk.red('Invalid YAML file contents. Please verify and try again.'));
|
|
468
|
-
}
|
|
469
|
-
//check if parsedSecrets is string and not in k:v pair
|
|
470
|
-
if (typeof parsedSecrets === 'string') {
|
|
471
|
-
throw new Error(chalk.red('Please provide a valid YAML in key:value format.'));
|
|
472
|
-
}
|
|
473
|
-
const secretsYamlString = YAML.stringify(parsedSecrets);
|
|
474
|
-
return secretsYamlString; //TODO: here we will encrypt secrets and return.
|
|
475
|
-
} catch (err) {
|
|
476
|
-
throw new Error(chalk.red(getSecretsYamlParseError(err)));
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* This function returns user friendly errors that occurs while YAML.parse
|
|
482
|
-
*
|
|
483
|
-
* @param error errors from YAML.parse
|
|
484
|
-
*/
|
|
485
|
-
function getSecretsYamlParseError(error) {
|
|
486
|
-
if (error.code === 'BAD_INDENT') {
|
|
487
|
-
return 'Invalid YAML - Bad Indentation: ' + error.message;
|
|
488
|
-
} else if (error.code === 'DUPLICATE_KEY') {
|
|
489
|
-
return 'Invalid YAML - Found Duplicate Keys: ' + error.message;
|
|
490
|
-
} else {
|
|
491
|
-
return 'Unexpected Error: ' + error.message;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
394
|
module.exports = {
|
|
496
395
|
ignoreCacheFlag,
|
|
497
396
|
autoConfirmActionFlag,
|
|
@@ -506,7 +405,4 @@ module.exports = {
|
|
|
506
405
|
portNoFlag,
|
|
507
406
|
debugFlag,
|
|
508
407
|
selectFlag,
|
|
509
|
-
secretsFlag,
|
|
510
|
-
interpolateSecrets,
|
|
511
|
-
validateSecretsFile,
|
|
512
408
|
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"meshConfig": {
|
|
3
|
-
"sources": [
|
|
4
|
-
{
|
|
5
|
-
"name": "Commerce",
|
|
6
|
-
"handler": {
|
|
7
|
-
"graphql": {
|
|
8
|
-
"endpoint": "https://venia.magento.com/graphql",
|
|
9
|
-
"operationHeaders": {
|
|
10
|
-
"Authorization": "{context.secrets.Token}"
|
|
11
|
-
},
|
|
12
|
-
"useGETForQueries": true
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
]
|
|
17
|
-
}
|
|
18
|
-
}
|