@credibledata/cred-cli 0.0.6

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.
Files changed (259) hide show
  1. package/.github/workflows/build.yml +23 -0
  2. package/.mocharc.json +10 -0
  3. package/.prettierignore +2 -0
  4. package/.prettierrc +4 -0
  5. package/README-DEV.md +40 -0
  6. package/README.md +11 -0
  7. package/bun.lock +1158 -0
  8. package/dist/client/api.js +7715 -0
  9. package/dist/client/api.js.map +1 -0
  10. package/dist/client/base.js +69 -0
  11. package/dist/client/base.js.map +1 -0
  12. package/dist/client/common.js +162 -0
  13. package/dist/client/common.js.map +1 -0
  14. package/dist/client/configuration.js +44 -0
  15. package/dist/client/configuration.js.map +1 -0
  16. package/dist/client/index.js +32 -0
  17. package/dist/client/index.js.map +1 -0
  18. package/dist/clientconfiguration.js +205 -0
  19. package/dist/clientconfiguration.js.map +1 -0
  20. package/dist/clientconfiguration.spec.js +381 -0
  21. package/dist/clientconfiguration.spec.js.map +1 -0
  22. package/dist/commands/add.js +66 -0
  23. package/dist/commands/add.js.map +1 -0
  24. package/dist/commands/connection/createconnections.js +89 -0
  25. package/dist/commands/connection/createconnections.js.map +1 -0
  26. package/dist/commands/connection/createconnections.spec.js +219 -0
  27. package/dist/commands/connection/createconnections.spec.js.map +1 -0
  28. package/dist/commands/connection/deleteconnection.js +52 -0
  29. package/dist/commands/connection/deleteconnection.js.map +1 -0
  30. package/dist/commands/connection/deleteconnection.spec.js +130 -0
  31. package/dist/commands/connection/deleteconnection.spec.js.map +1 -0
  32. package/dist/commands/connection/listconnections.js +50 -0
  33. package/dist/commands/connection/listconnections.js.map +1 -0
  34. package/dist/commands/connection/listconnections.spec.js +117 -0
  35. package/dist/commands/connection/listconnections.spec.js.map +1 -0
  36. package/dist/commands/get.js +28 -0
  37. package/dist/commands/get.js.map +1 -0
  38. package/dist/commands/group/addmember.js +75 -0
  39. package/dist/commands/group/addmember.js.map +1 -0
  40. package/dist/commands/group/addmember.spec.js +148 -0
  41. package/dist/commands/group/addmember.spec.js.map +1 -0
  42. package/dist/commands/group/creategroup.js +55 -0
  43. package/dist/commands/group/creategroup.js.map +1 -0
  44. package/dist/commands/group/creategroup.spec.js +122 -0
  45. package/dist/commands/group/creategroup.spec.js.map +1 -0
  46. package/dist/commands/group/deletegroup.js +48 -0
  47. package/dist/commands/group/deletegroup.js.map +1 -0
  48. package/dist/commands/group/deletegroup.spec.js +104 -0
  49. package/dist/commands/group/deletegroup.spec.js.map +1 -0
  50. package/dist/commands/group/getgroup.js +50 -0
  51. package/dist/commands/group/getgroup.js.map +1 -0
  52. package/dist/commands/group/getgroup.spec.js +111 -0
  53. package/dist/commands/group/getgroup.spec.js.map +1 -0
  54. package/dist/commands/group/listgroups.js +56 -0
  55. package/dist/commands/group/listgroups.js.map +1 -0
  56. package/dist/commands/group/listgroups.spec.js +118 -0
  57. package/dist/commands/group/listgroups.spec.js.map +1 -0
  58. package/dist/commands/group/removemember.js +69 -0
  59. package/dist/commands/group/removemember.js.map +1 -0
  60. package/dist/commands/group/removemember.spec.js +138 -0
  61. package/dist/commands/group/removemember.spec.js.map +1 -0
  62. package/dist/commands/groupaccesstoken/createToken.js +53 -0
  63. package/dist/commands/groupaccesstoken/createToken.js.map +1 -0
  64. package/dist/commands/groupaccesstoken/createToken.spec.js +127 -0
  65. package/dist/commands/groupaccesstoken/createToken.spec.js.map +1 -0
  66. package/dist/commands/groupaccesstoken/deleteToken.js +24 -0
  67. package/dist/commands/groupaccesstoken/deleteToken.js.map +1 -0
  68. package/dist/commands/groupaccesstoken/deleteToken.spec.js +103 -0
  69. package/dist/commands/groupaccesstoken/deleteToken.spec.js.map +1 -0
  70. package/dist/commands/groupaccesstoken/groupContainer.js +71 -0
  71. package/dist/commands/groupaccesstoken/groupContainer.js.map +1 -0
  72. package/dist/commands/groupaccesstoken/listTokens.js +25 -0
  73. package/dist/commands/groupaccesstoken/listTokens.js.map +1 -0
  74. package/dist/commands/groupaccesstoken/listTokens.spec.js +115 -0
  75. package/dist/commands/groupaccesstoken/listTokens.spec.js.map +1 -0
  76. package/dist/commands/list.js +75 -0
  77. package/dist/commands/list.js.map +1 -0
  78. package/dist/commands/misc/login.js +290 -0
  79. package/dist/commands/misc/login.js.map +1 -0
  80. package/dist/commands/misc/login.spec.js +243 -0
  81. package/dist/commands/misc/login.spec.js.map +1 -0
  82. package/dist/commands/misc/logout.js +11 -0
  83. package/dist/commands/misc/logout.js.map +1 -0
  84. package/dist/commands/misc/logout.spec.js +30 -0
  85. package/dist/commands/misc/logout.spec.js.map +1 -0
  86. package/dist/commands/misc/loopbackOAuth.js +110 -0
  87. package/dist/commands/misc/loopbackOAuth.js.map +1 -0
  88. package/dist/commands/misc/set-access-token.js +27 -0
  89. package/dist/commands/misc/set-access-token.js.map +1 -0
  90. package/dist/commands/misc/set-access-token.spec.js +65 -0
  91. package/dist/commands/misc/set-access-token.spec.js.map +1 -0
  92. package/dist/commands/package/deletepackage.js +54 -0
  93. package/dist/commands/package/deletepackage.js.map +1 -0
  94. package/dist/commands/package/deletepackage.spec.js +136 -0
  95. package/dist/commands/package/deletepackage.spec.js.map +1 -0
  96. package/dist/commands/package/listpackages.js +57 -0
  97. package/dist/commands/package/listpackages.js.map +1 -0
  98. package/dist/commands/package/listpackages.spec.js +129 -0
  99. package/dist/commands/package/listpackages.spec.js.map +1 -0
  100. package/dist/commands/package/publish.js +157 -0
  101. package/dist/commands/package/publish.js.map +1 -0
  102. package/dist/commands/package/publish.spec.js +511 -0
  103. package/dist/commands/package/publish.spec.js.map +1 -0
  104. package/dist/commands/package/updatepackage.js +75 -0
  105. package/dist/commands/package/updatepackage.js.map +1 -0
  106. package/dist/commands/package/updatepackage.spec.js +189 -0
  107. package/dist/commands/package/updatepackage.spec.js.map +1 -0
  108. package/dist/commands/project/createproject.js +75 -0
  109. package/dist/commands/project/createproject.js.map +1 -0
  110. package/dist/commands/project/createproject.spec.js +154 -0
  111. package/dist/commands/project/createproject.spec.js.map +1 -0
  112. package/dist/commands/project/deleteproject.js +49 -0
  113. package/dist/commands/project/deleteproject.js.map +1 -0
  114. package/dist/commands/project/deleteproject.spec.js +106 -0
  115. package/dist/commands/project/deleteproject.spec.js.map +1 -0
  116. package/dist/commands/project/getproject.js +44 -0
  117. package/dist/commands/project/getproject.js.map +1 -0
  118. package/dist/commands/project/getproject.spec.js +99 -0
  119. package/dist/commands/project/getproject.spec.js.map +1 -0
  120. package/dist/commands/project/listprojects.js +52 -0
  121. package/dist/commands/project/listprojects.js.map +1 -0
  122. package/dist/commands/project/listprojects.spec.js +111 -0
  123. package/dist/commands/project/listprojects.spec.js.map +1 -0
  124. package/dist/commands/project/setproject.js +26 -0
  125. package/dist/commands/project/setproject.js.map +1 -0
  126. package/dist/commands/project/setproject.spec.js +58 -0
  127. package/dist/commands/project/setproject.spec.js.map +1 -0
  128. package/dist/commands/project/updateproject.js +68 -0
  129. package/dist/commands/project/updateproject.js.map +1 -0
  130. package/dist/commands/project/updateproject.spec.js +129 -0
  131. package/dist/commands/project/updateproject.spec.js.map +1 -0
  132. package/dist/commands/rm.js +68 -0
  133. package/dist/commands/rm.js.map +1 -0
  134. package/dist/commands/set.js +17 -0
  135. package/dist/commands/set.js.map +1 -0
  136. package/dist/commands/update.js +42 -0
  137. package/dist/commands/update.js.map +1 -0
  138. package/dist/commands/version/archive-unarchive-version.js +79 -0
  139. package/dist/commands/version/archive-unarchive-version.js.map +1 -0
  140. package/dist/commands/version/archive-unarchive-version.spec.js +244 -0
  141. package/dist/commands/version/archive-unarchive-version.spec.js.map +1 -0
  142. package/dist/commands/version/listversions.js +46 -0
  143. package/dist/commands/version/listversions.js.map +1 -0
  144. package/dist/commands/version/listversions.spec.js +121 -0
  145. package/dist/commands/version/listversions.spec.js.map +1 -0
  146. package/dist/common/UserGroupId.js +112 -0
  147. package/dist/common/UserGroupId.js.map +1 -0
  148. package/dist/common/UserGroupId.spec.js +92 -0
  149. package/dist/common/UserGroupId.spec.js.map +1 -0
  150. package/dist/constants.js +90 -0
  151. package/dist/constants.js.map +1 -0
  152. package/dist/index.js +159 -0
  153. package/dist/index.js.map +1 -0
  154. package/dist/logger.js +77 -0
  155. package/dist/logger.js.map +1 -0
  156. package/dist/logger.spec.js +125 -0
  157. package/dist/logger.spec.js.map +1 -0
  158. package/dist/polyfills/file.polyfill.js +6 -0
  159. package/dist/polyfills/file.polyfill.js.map +1 -0
  160. package/dist/utils.js +110 -0
  161. package/dist/utils.js.map +1 -0
  162. package/dist/utils.spec.js +158 -0
  163. package/dist/utils.spec.js.map +1 -0
  164. package/dist/validator.js +53 -0
  165. package/dist/validator.js.map +1 -0
  166. package/dist/validator.spec.js +41 -0
  167. package/dist/validator.spec.js.map +1 -0
  168. package/docker/Dockerfile.ci +18 -0
  169. package/docker-compose.yml +18 -0
  170. package/eslint.config.mjs +45 -0
  171. package/generate-client.sh +27 -0
  172. package/mocha.setup.ts +4 -0
  173. package/openapitools.json +7 -0
  174. package/package.json +75 -0
  175. package/src/client/.openapi-generator/FILES +9 -0
  176. package/src/client/.openapi-generator/VERSION +1 -0
  177. package/src/client/.openapi-generator-ignore +23 -0
  178. package/src/client/api.ts +9729 -0
  179. package/src/client/base.ts +86 -0
  180. package/src/client/common.ts +150 -0
  181. package/src/client/configuration.ts +110 -0
  182. package/src/client/git_push.sh +57 -0
  183. package/src/client/index.ts +18 -0
  184. package/src/clientconfiguration.spec.ts +490 -0
  185. package/src/clientconfiguration.ts +263 -0
  186. package/src/commands/add.ts +125 -0
  187. package/src/commands/connection/createconnections.spec.ts +403 -0
  188. package/src/commands/connection/createconnections.ts +109 -0
  189. package/src/commands/connection/deleteconnection.spec.ts +189 -0
  190. package/src/commands/connection/deleteconnection.ts +57 -0
  191. package/src/commands/connection/listconnections.spec.ts +132 -0
  192. package/src/commands/connection/listconnections.ts +58 -0
  193. package/src/commands/get.ts +31 -0
  194. package/src/commands/group/addmember.spec.ts +257 -0
  195. package/src/commands/group/addmember.ts +85 -0
  196. package/src/commands/group/creategroup.spec.ts +146 -0
  197. package/src/commands/group/creategroup.ts +54 -0
  198. package/src/commands/group/deletegroup.spec.ts +120 -0
  199. package/src/commands/group/deletegroup.ts +45 -0
  200. package/src/commands/group/getgroup.spec.ts +129 -0
  201. package/src/commands/group/getgroup.ts +47 -0
  202. package/src/commands/group/listgroups.spec.ts +137 -0
  203. package/src/commands/group/listgroups.ts +45 -0
  204. package/src/commands/group/removemember.spec.ts +224 -0
  205. package/src/commands/group/removemember.ts +75 -0
  206. package/src/commands/groupaccesstoken/createToken.spec.ts +211 -0
  207. package/src/commands/groupaccesstoken/createToken.ts +72 -0
  208. package/src/commands/groupaccesstoken/deleteToken.spec.ts +147 -0
  209. package/src/commands/groupaccesstoken/deleteToken.ts +29 -0
  210. package/src/commands/groupaccesstoken/groupContainer.ts +83 -0
  211. package/src/commands/groupaccesstoken/listTokens.spec.ts +147 -0
  212. package/src/commands/groupaccesstoken/listTokens.ts +29 -0
  213. package/src/commands/list.ts +131 -0
  214. package/src/commands/misc/login.spec.ts +213 -0
  215. package/src/commands/misc/login.ts +325 -0
  216. package/src/commands/misc/logout.spec.ts +32 -0
  217. package/src/commands/misc/logout.ts +9 -0
  218. package/src/commands/misc/loopbackOAuth.ts +127 -0
  219. package/src/commands/misc/set-access-token.spec.ts +95 -0
  220. package/src/commands/misc/set-access-token.ts +32 -0
  221. package/src/commands/package/deletepackage.spec.ts +164 -0
  222. package/src/commands/package/deletepackage.ts +58 -0
  223. package/src/commands/package/listpackages.spec.ts +147 -0
  224. package/src/commands/package/listpackages.ts +67 -0
  225. package/src/commands/package/publish.spec.ts +597 -0
  226. package/src/commands/package/publish.ts +211 -0
  227. package/src/commands/package/updatepackage.spec.ts +319 -0
  228. package/src/commands/package/updatepackage.ts +95 -0
  229. package/src/commands/project/createproject.spec.ts +247 -0
  230. package/src/commands/project/createproject.ts +70 -0
  231. package/src/commands/project/deleteproject.spec.ts +123 -0
  232. package/src/commands/project/deleteproject.ts +48 -0
  233. package/src/commands/project/getproject.spec.ts +109 -0
  234. package/src/commands/project/getproject.ts +43 -0
  235. package/src/commands/project/listprojects.spec.ts +121 -0
  236. package/src/commands/project/listprojects.ts +62 -0
  237. package/src/commands/project/setproject.spec.ts +63 -0
  238. package/src/commands/project/setproject.ts +14 -0
  239. package/src/commands/project/updateproject.spec.ts +217 -0
  240. package/src/commands/project/updateproject.ts +82 -0
  241. package/src/commands/rm.ts +101 -0
  242. package/src/commands/set.ts +16 -0
  243. package/src/commands/update.ts +64 -0
  244. package/src/commands/version/archive-unarchive-version.spec.ts +456 -0
  245. package/src/commands/version/archive-unarchive-version.ts +111 -0
  246. package/src/commands/version/listversions.spec.ts +138 -0
  247. package/src/commands/version/listversions.ts +45 -0
  248. package/src/common/UserGroupId.spec.ts +117 -0
  249. package/src/common/UserGroupId.ts +137 -0
  250. package/src/constants.ts +116 -0
  251. package/src/index.ts +209 -0
  252. package/src/logger.spec.ts +158 -0
  253. package/src/logger.ts +86 -0
  254. package/src/polyfills/file.polyfill.ts +6 -0
  255. package/src/utils.spec.ts +135 -0
  256. package/src/utils.ts +115 -0
  257. package/src/validator.spec.ts +51 -0
  258. package/src/validator.ts +44 -0
  259. package/tsconfig.json +17 -0
@@ -0,0 +1,45 @@
1
+ import { GroupsApi } from "../../client/api";
2
+ import { Configuration } from "../../client/configuration";
3
+ import { ClientConfiguration } from "../../clientconfiguration";
4
+ import { logger } from "../../logger";
5
+ import { printOutError } from "../../utils";
6
+
7
+ const groupsApi = new GroupsApi(new Configuration());
8
+
9
+ export async function listGroups(controlPlane: string, debug: boolean) {
10
+ const clientConfig = new ClientConfiguration();
11
+
12
+ if (!clientConfig.doesConfigExists()) {
13
+ logger.error("Please, make sure that you are logged in");
14
+ return;
15
+ }
16
+
17
+ const organizationName = clientConfig.getOrganization();
18
+ if (!organizationName) {
19
+ logger.error("No organization set. Please login or set an organization.");
20
+ return;
21
+ }
22
+
23
+ logger.info(`Listing groups in organization ${organizationName}`);
24
+
25
+ try {
26
+ const response = await groupsApi.listGroups(organizationName, {
27
+ baseURL: controlPlane,
28
+ headers: {
29
+ Authorization: clientConfig.getAuthenticationHeader(),
30
+ },
31
+ });
32
+
33
+ const jsonString = JSON.stringify(response.data, null, 2);
34
+ console.log(jsonString);
35
+ logger.info("Groups listed successfully");
36
+ } catch (error) {
37
+ logger.error("Failed to list groups");
38
+ printOutError(error, debug);
39
+ process.exit(1);
40
+ }
41
+ }
42
+
43
+ export async function printOutGroups(controlPlane: string, debug: boolean) {
44
+ return listGroups(controlPlane, debug);
45
+ }
@@ -0,0 +1,224 @@
1
+ import { expect } from "chai";
2
+ import sinon from "sinon";
3
+ import { GroupsApi } from "../../client/api";
4
+ import { ClientConfiguration } from "../../clientconfiguration";
5
+ import { logger } from "../../logger";
6
+ import { removeMember } from "./removemember";
7
+
8
+ describe("remove-member", () => {
9
+ let sandbox: sinon.SinonSandbox;
10
+ let removeGroupMembersStub: sinon.SinonStub;
11
+ let loggerStub: sinon.SinonStubbedInstance<typeof logger>;
12
+ let processExitStub: sinon.SinonStub;
13
+
14
+ beforeEach(() => {
15
+ sandbox = sinon.createSandbox();
16
+ removeGroupMembersStub = sandbox.stub();
17
+ loggerStub = sandbox.stub(logger);
18
+ processExitStub = sandbox.stub(process, "exit");
19
+
20
+ sandbox
21
+ .stub(ClientConfiguration.prototype, "getOrganization")
22
+ .returns("test-org");
23
+ sandbox
24
+ .stub(ClientConfiguration.prototype, "doesConfigExists")
25
+ .returns(true);
26
+ sandbox
27
+ .stub(ClientConfiguration.prototype, "getAuthenticationHeader")
28
+ .returns("Bearer test-token");
29
+
30
+ sandbox
31
+ .stub(GroupsApi.prototype, "removeGroupMembers")
32
+ .callsFake(removeGroupMembersStub);
33
+ });
34
+
35
+ afterEach(() => {
36
+ sandbox.restore();
37
+ });
38
+
39
+ it("should remove user member successfully", async () => {
40
+ const mockResponse = {
41
+ data: {},
42
+ };
43
+ removeGroupMembersStub.resolves(mockResponse);
44
+
45
+ await removeMember(
46
+ "http://test-server",
47
+ "test-group",
48
+ "user",
49
+ "test-user",
50
+ false,
51
+ );
52
+
53
+ expect(removeGroupMembersStub.calledOnce).to.be.true;
54
+ expect(removeGroupMembersStub.firstCall.args[0]).to.equal("test-org");
55
+ expect(removeGroupMembersStub.firstCall.args[1]).to.equal("test-group");
56
+ expect(removeGroupMembersStub.firstCall.args[2]).to.deep.include({
57
+ members: [
58
+ {
59
+ userGroupId: "user:test-user",
60
+ },
61
+ ],
62
+ });
63
+ expect(
64
+ loggerStub.info.calledWith(
65
+ sinon.match(
66
+ "Successfully removed user test-user from group test-group",
67
+ ),
68
+ ),
69
+ ).to.be.true;
70
+ });
71
+
72
+ it("should remove group member successfully", async () => {
73
+ const mockResponse = {
74
+ data: {},
75
+ };
76
+ removeGroupMembersStub.resolves(mockResponse);
77
+
78
+ await removeMember(
79
+ "http://test-server",
80
+ "test-group",
81
+ "group",
82
+ "test-subgroup",
83
+ false,
84
+ );
85
+
86
+ expect(removeGroupMembersStub.firstCall.args[2]).to.deep.include({
87
+ members: [
88
+ {
89
+ userGroupId: "group:test-subgroup",
90
+ },
91
+ ],
92
+ });
93
+ expect(
94
+ loggerStub.info.calledWith(
95
+ sinon.match(
96
+ "Successfully removed group test-subgroup from group test-group",
97
+ ),
98
+ ),
99
+ ).to.be.true;
100
+ });
101
+
102
+ it("should handle case-insensitive member type", async () => {
103
+ const mockResponse = {
104
+ data: {},
105
+ };
106
+ removeGroupMembersStub.resolves(mockResponse);
107
+
108
+ await removeMember(
109
+ "http://test-server",
110
+ "test-group",
111
+ "USER",
112
+ "test-user",
113
+ false,
114
+ );
115
+
116
+ expect(
117
+ removeGroupMembersStub.firstCall.args[2].members[0].userGroupId,
118
+ ).to.equal("user:test-user");
119
+ });
120
+
121
+ it("should handle missing config", async () => {
122
+ sandbox.restore();
123
+ sandbox = sinon.createSandbox();
124
+ removeGroupMembersStub = sandbox.stub();
125
+ loggerStub = sandbox.stub(logger);
126
+ processExitStub = sandbox.stub(process, "exit");
127
+
128
+ sandbox
129
+ .stub(ClientConfiguration.prototype, "doesConfigExists")
130
+ .returns(false);
131
+ sandbox
132
+ .stub(GroupsApi.prototype, "removeGroupMembers")
133
+ .callsFake(removeGroupMembersStub);
134
+
135
+ await removeMember(
136
+ "http://test-server",
137
+ "test-group",
138
+ "user",
139
+ "test-user",
140
+ false,
141
+ );
142
+
143
+ expect(removeGroupMembersStub.called).to.be.false;
144
+ expect(
145
+ loggerStub.error.calledWith(
146
+ sinon.match("Please, make sure that you are logged in"),
147
+ ),
148
+ ).to.be.true;
149
+ });
150
+
151
+ it("should handle missing organization", async () => {
152
+ sandbox.restore();
153
+ sandbox = sinon.createSandbox();
154
+ removeGroupMembersStub = sandbox.stub();
155
+ loggerStub = sandbox.stub(logger);
156
+ processExitStub = sandbox.stub(process, "exit");
157
+
158
+ sandbox
159
+ .stub(ClientConfiguration.prototype, "doesConfigExists")
160
+ .returns(true);
161
+ sandbox
162
+ .stub(ClientConfiguration.prototype, "getOrganization")
163
+ .returns(undefined);
164
+ sandbox
165
+ .stub(GroupsApi.prototype, "removeGroupMembers")
166
+ .callsFake(removeGroupMembersStub);
167
+
168
+ await removeMember(
169
+ "http://test-server",
170
+ "test-group",
171
+ "user",
172
+ "test-user",
173
+ false,
174
+ );
175
+
176
+ expect(removeGroupMembersStub.called).to.be.false;
177
+ expect(
178
+ loggerStub.error.calledWith(
179
+ sinon.match(
180
+ "No organization set. Please login or set an organization.",
181
+ ),
182
+ ),
183
+ ).to.be.true;
184
+ });
185
+
186
+ it("should reject invalid member type", async () => {
187
+ await removeMember(
188
+ "http://test-server",
189
+ "test-group",
190
+ "invalid",
191
+ "test-user",
192
+ false,
193
+ );
194
+
195
+ expect(removeGroupMembersStub.called).to.be.false;
196
+ expect(
197
+ loggerStub.error.calledWith(
198
+ sinon.match("Error: memberType must be either 'user' or 'group'"),
199
+ ),
200
+ ).to.be.true;
201
+ expect(processExitStub.calledWith(1)).to.be.true;
202
+ });
203
+
204
+ it("should handle API errors", async () => {
205
+ const mockError = new Error("API Error");
206
+ removeGroupMembersStub.rejects(mockError);
207
+
208
+ await removeMember(
209
+ "http://test-server",
210
+ "test-group",
211
+ "user",
212
+ "test-user",
213
+ true,
214
+ );
215
+
216
+ expect(removeGroupMembersStub.calledOnce).to.be.true;
217
+ expect(
218
+ loggerStub.error.calledWith(
219
+ sinon.match("Failed to remove member from group"),
220
+ ),
221
+ ).to.be.true;
222
+ expect(processExitStub.calledWith(1)).to.be.true;
223
+ });
224
+ });
@@ -0,0 +1,75 @@
1
+ import {
2
+ GroupMember,
3
+ GroupsApi,
4
+ RemoveGroupMembersRequest,
5
+ } from "../../client/api";
6
+ import { Configuration } from "../../client/configuration";
7
+ import { ClientConfiguration } from "../../clientconfiguration";
8
+ import { UserGroupId } from "../../common/UserGroupId";
9
+ import { logger } from "../../logger";
10
+ import { printOutError } from "../../utils";
11
+
12
+ const groupsApi = new GroupsApi(new Configuration());
13
+
14
+ export async function removeMember(
15
+ controlPlane: string,
16
+ groupName: string,
17
+ memberType: string,
18
+ memberName: string,
19
+ debug: boolean,
20
+ ) {
21
+ const clientConfig = new ClientConfiguration();
22
+
23
+ if (!clientConfig.doesConfigExists()) {
24
+ logger.error("Please, make sure that you are logged in");
25
+ return;
26
+ }
27
+
28
+ const organizationName = clientConfig.getOrganization();
29
+ if (!organizationName) {
30
+ logger.error("No organization set. Please login or set an organization.");
31
+ return;
32
+ }
33
+
34
+ logger.info(
35
+ `Removing ${memberType} ${memberName} from group ${groupName} in organization ${organizationName}`,
36
+ );
37
+
38
+ // Create UserGroupId based on member type
39
+ let userGroupId: UserGroupId;
40
+ if (memberType.toLowerCase() === "user") {
41
+ userGroupId = UserGroupId.forUser(memberName);
42
+ } else if (memberType.toLowerCase() === "group") {
43
+ userGroupId = UserGroupId.forGroup(memberName);
44
+ } else {
45
+ logger.error("Error: memberType must be either 'user' or 'group'");
46
+ process.exit(1);
47
+ return;
48
+ }
49
+
50
+ const groupMember: GroupMember = {
51
+ userGroupId: userGroupId.getValue(),
52
+ // Note: status is not required for removal, only the member identifier
53
+ };
54
+
55
+ const request: RemoveGroupMembersRequest = {
56
+ members: [groupMember],
57
+ };
58
+
59
+ try {
60
+ await groupsApi.removeGroupMembers(organizationName, groupName, request, {
61
+ baseURL: controlPlane,
62
+ headers: {
63
+ Authorization: clientConfig.getAuthenticationHeader(),
64
+ },
65
+ });
66
+
67
+ logger.info(
68
+ `Successfully removed ${memberType} ${memberName} from group ${groupName}`,
69
+ );
70
+ } catch (error) {
71
+ logger.error("Failed to remove member from group");
72
+ printOutError(error, debug);
73
+ process.exit(1);
74
+ }
75
+ }
@@ -0,0 +1,211 @@
1
+ import { expect } from "chai";
2
+ import sinon from "sinon";
3
+ import { GroupsApi } from "../../client/api";
4
+ import { ClientConfiguration } from "../../clientconfiguration";
5
+ import { logger } from "../../logger";
6
+ import { createGroupAccessToken } from "./createToken";
7
+
8
+ describe("create-group-access-token", () => {
9
+ let sandbox: sinon.SinonSandbox;
10
+ let createGroupAccessTokenStub: sinon.SinonStub;
11
+ let loggerStub: sinon.SinonStubbedInstance<typeof logger>;
12
+ let consoleLogStub: sinon.SinonStub;
13
+ let processExitStub: sinon.SinonStub;
14
+
15
+ beforeEach(() => {
16
+ sandbox = sinon.createSandbox();
17
+ createGroupAccessTokenStub = sandbox.stub();
18
+ loggerStub = sandbox.stub(logger);
19
+ consoleLogStub = sandbox.stub(console, "log");
20
+ processExitStub = sandbox.stub(process, "exit");
21
+
22
+ sandbox
23
+ .stub(ClientConfiguration.prototype, "getOrganization")
24
+ .returns("test-org");
25
+ sandbox
26
+ .stub(ClientConfiguration.prototype, "doesConfigExists")
27
+ .returns(true);
28
+ sandbox
29
+ .stub(ClientConfiguration.prototype, "getAuthenticationHeader")
30
+ .returns("Bearer test-token");
31
+
32
+ sandbox
33
+ .stub(GroupsApi.prototype, "createGroupAccessToken")
34
+ .callsFake(createGroupAccessTokenStub);
35
+ });
36
+
37
+ afterEach(() => {
38
+ sandbox.restore();
39
+ });
40
+
41
+ it("should create group access token successfully", async () => {
42
+ const mockResponse = {
43
+ data: { tokenName: "test-token", secret: "secret-value" },
44
+ };
45
+ createGroupAccessTokenStub.resolves(mockResponse);
46
+
47
+ const result = await createGroupAccessToken(
48
+ "http://test-server",
49
+ "test-group",
50
+ "test-token",
51
+ undefined,
52
+ false,
53
+ false,
54
+ );
55
+
56
+ expect(createGroupAccessTokenStub.calledOnce).to.be.true;
57
+ expect(createGroupAccessTokenStub.firstCall.args[0]).to.equal("test-org");
58
+ expect(createGroupAccessTokenStub.firstCall.args[1]).to.equal(
59
+ "test-group",
60
+ );
61
+ expect(createGroupAccessTokenStub.firstCall.args[2]).to.equal(
62
+ "test-token",
63
+ );
64
+ expect(createGroupAccessTokenStub.firstCall.args[3]).to.be.undefined;
65
+ expect(consoleLogStub.called).to.be.true;
66
+ expect(
67
+ loggerStub.info.calledWith(
68
+ sinon.match("Group access token created successfully"),
69
+ ),
70
+ ).to.be.true;
71
+ expect(result).to.deep.equal(mockResponse.data);
72
+ });
73
+
74
+ it("should create token with expiration date", async () => {
75
+ const futureDate = new Date();
76
+ futureDate.setFullYear(futureDate.getFullYear() + 1);
77
+ const expiresAt = futureDate.toISOString();
78
+ const mockResponse = {
79
+ data: { tokenName: "test-token" },
80
+ };
81
+ createGroupAccessTokenStub.resolves(mockResponse);
82
+
83
+ await createGroupAccessToken(
84
+ "http://test-server",
85
+ "test-group",
86
+ "test-token",
87
+ expiresAt,
88
+ false,
89
+ false,
90
+ );
91
+
92
+ expect(createGroupAccessTokenStub.firstCall.args[3]).to.equal(expiresAt);
93
+ });
94
+
95
+ it("should reject invalid expiration date format", async () => {
96
+ await createGroupAccessToken(
97
+ "http://test-server",
98
+ "test-group",
99
+ "test-token",
100
+ "invalid-date",
101
+ false,
102
+ false,
103
+ );
104
+
105
+ expect(createGroupAccessTokenStub.called).to.be.false;
106
+ expect(
107
+ loggerStub.error.calledWith(
108
+ sinon.match(/Invalid expiration date format/),
109
+ ),
110
+ ).to.be.true;
111
+ expect(processExitStub.calledWith(1)).to.be.true;
112
+ });
113
+
114
+ it("should reject expiration date in the past", async () => {
115
+ const pastDate = new Date();
116
+ pastDate.setFullYear(pastDate.getFullYear() - 1);
117
+ const expiresAt = pastDate.toISOString();
118
+
119
+ await createGroupAccessToken(
120
+ "http://test-server",
121
+ "test-group",
122
+ "test-token",
123
+ expiresAt,
124
+ false,
125
+ false,
126
+ );
127
+
128
+ expect(createGroupAccessTokenStub.called).to.be.false;
129
+ expect(
130
+ loggerStub.error.calledWith(
131
+ sinon.match("Expiration date must be in the future"),
132
+ ),
133
+ ).to.be.true;
134
+ expect(processExitStub.calledWith(1)).to.be.true;
135
+ });
136
+
137
+ it("should return JSON output when jsonOutput is true", async () => {
138
+ const mockResponse = {
139
+ data: { tokenName: "test-token", secret: "secret-value" },
140
+ };
141
+ createGroupAccessTokenStub.resolves(mockResponse);
142
+
143
+ const result = await createGroupAccessToken(
144
+ "http://test-server",
145
+ "test-group",
146
+ "test-token",
147
+ undefined,
148
+ true,
149
+ false,
150
+ );
151
+
152
+ expect(result).to.deep.equal(mockResponse.data);
153
+ expect(
154
+ loggerStub.info.calledWith(
155
+ sinon.match("Group access token created successfully"),
156
+ ),
157
+ ).to.be.false;
158
+ });
159
+
160
+ it("should handle missing config", async () => {
161
+ sandbox.restore();
162
+ sandbox = sinon.createSandbox();
163
+ createGroupAccessTokenStub = sandbox.stub();
164
+ loggerStub = sandbox.stub(logger);
165
+ consoleLogStub = sandbox.stub(console, "log");
166
+ processExitStub = sandbox.stub(process, "exit");
167
+
168
+ sandbox
169
+ .stub(ClientConfiguration.prototype, "doesConfigExists")
170
+ .returns(false);
171
+ sandbox
172
+ .stub(GroupsApi.prototype, "createGroupAccessToken")
173
+ .callsFake(createGroupAccessTokenStub);
174
+
175
+ const result = await createGroupAccessToken(
176
+ "http://test-server",
177
+ "test-group",
178
+ "test-token",
179
+ undefined,
180
+ false,
181
+ false,
182
+ );
183
+
184
+ expect(createGroupAccessTokenStub.called).to.be.false;
185
+ expect(result).to.be.undefined;
186
+ expect(
187
+ loggerStub.error.calledWith(
188
+ sinon.match("Please, make sure that you are logged in"),
189
+ ),
190
+ ).to.be.true;
191
+ });
192
+
193
+ it("should handle API errors", async () => {
194
+ const mockError = new Error("API Error");
195
+ createGroupAccessTokenStub.rejects(mockError);
196
+
197
+ await createGroupAccessToken(
198
+ "http://test-server",
199
+ "test-group",
200
+ "test-token",
201
+ undefined,
202
+ false,
203
+ true,
204
+ );
205
+
206
+ expect(createGroupAccessTokenStub.calledOnce).to.be.true;
207
+ expect(loggerStub.error.calledWith(sinon.match("Operation failed"))).to.be
208
+ .true;
209
+ expect(processExitStub.calledWith(1)).to.be.true;
210
+ });
211
+ });
@@ -0,0 +1,72 @@
1
+ import kleur from "kleur";
2
+ import { logger } from "../../logger";
3
+ import { withGroupContext } from "./groupContainer";
4
+
5
+ export async function createGroupAccessToken(
6
+ controlPlane: string,
7
+ groupName: string,
8
+ tokenName: string,
9
+ expiresAt: string | undefined,
10
+ jsonOutput: boolean,
11
+ debug: boolean,
12
+ ) {
13
+ // Validate expiresAt format if provided
14
+ if (expiresAt) {
15
+ const expiresAtDate = new Date(expiresAt);
16
+ if (isNaN(expiresAtDate.getTime())) {
17
+ logger.error(
18
+ `Invalid expiration date format: ${expiresAt}. Please use ISO 8601 format (e.g., 2025-12-31T23:59:59Z)`,
19
+ );
20
+ process.exit(1);
21
+ return;
22
+ }
23
+ if (expiresAtDate <= new Date()) {
24
+ logger.error("Expiration date must be in the future");
25
+ process.exit(1);
26
+ return;
27
+ }
28
+ }
29
+
30
+ const result = await withGroupContext(
31
+ controlPlane,
32
+ async (context) => {
33
+ const { organizationName, groupsApi, options } = context;
34
+
35
+ const response = await groupsApi.createGroupAccessToken(
36
+ organizationName,
37
+ groupName,
38
+ tokenName,
39
+ expiresAt,
40
+ options,
41
+ );
42
+
43
+ return response.data;
44
+ },
45
+ undefined,
46
+ debug,
47
+ );
48
+
49
+ if (jsonOutput) {
50
+ return result;
51
+ }
52
+
53
+ // Display security warning after the response is printed
54
+ console.log("\n" + kleur.yellow().bold("⚠️ IMPORTANT SECURITY NOTICE ⚠️"));
55
+ console.log(
56
+ kleur.yellow("The token secret shown above will NOT be displayed again."),
57
+ );
58
+ console.log(
59
+ kleur.yellow(
60
+ "Please store it securely in a password manager or secure vault.",
61
+ ),
62
+ );
63
+ console.log(
64
+ kleur.yellow(
65
+ "If you lose this token, you will need to create a new one.",
66
+ ),
67
+ );
68
+ console.log("");
69
+ logger.info("Group access token created successfully");
70
+
71
+ return result;
72
+ }