@credibledata/cred-cli 0.1.4 → 0.1.5
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/.prettierignore +2 -1
- package/README.md +0 -2
- package/bun.lock +182 -283
- package/dist/client/api.js +796 -111
- package/dist/client/api.js.map +1 -1
- package/dist/clientconfiguration.js +55 -13
- package/dist/clientconfiguration.js.map +1 -1
- package/dist/clientconfiguration.spec.js +305 -16
- package/dist/clientconfiguration.spec.js.map +1 -1
- package/dist/commands/add.js +6 -3
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/connection/createconnections.js +18 -3
- package/dist/commands/connection/createconnections.js.map +1 -1
- package/dist/commands/connection/createconnections.spec.js +219 -0
- package/dist/commands/connection/createconnections.spec.js.map +1 -0
- package/dist/commands/connection/deleteconnection.spec.js +130 -0
- package/dist/commands/connection/deleteconnection.spec.js.map +1 -0
- package/dist/commands/connection/listconnections.js +9 -3
- package/dist/commands/connection/listconnections.js.map +1 -1
- package/dist/commands/connection/listconnections.spec.js +117 -0
- package/dist/commands/connection/listconnections.spec.js.map +1 -0
- package/dist/commands/group/addmember.js +2 -0
- package/dist/commands/group/addmember.js.map +1 -1
- package/dist/commands/group/addmember.spec.js +148 -0
- package/dist/commands/group/addmember.spec.js.map +1 -0
- package/dist/commands/group/creategroup.spec.js +122 -0
- package/dist/commands/group/creategroup.spec.js.map +1 -0
- package/dist/commands/group/deletegroup.spec.js +104 -0
- package/dist/commands/group/deletegroup.spec.js.map +1 -0
- package/dist/commands/group/getgroup.spec.js +111 -0
- package/dist/commands/group/getgroup.spec.js.map +1 -0
- package/dist/commands/group/listgroups.spec.js +118 -0
- package/dist/commands/group/listgroups.spec.js.map +1 -0
- package/dist/commands/group/removemember.js +1 -0
- package/dist/commands/group/removemember.js.map +1 -1
- package/dist/commands/group/removemember.spec.js +138 -0
- package/dist/commands/group/removemember.spec.js.map +1 -0
- package/dist/commands/groupaccesstoken/createToken.js +6 -2
- package/dist/commands/groupaccesstoken/createToken.js.map +1 -1
- package/dist/commands/groupaccesstoken/createToken.spec.js +127 -0
- package/dist/commands/groupaccesstoken/createToken.spec.js.map +1 -0
- package/dist/commands/groupaccesstoken/deleteToken.js.map +1 -1
- package/dist/commands/groupaccesstoken/deleteToken.spec.js +103 -0
- package/dist/commands/groupaccesstoken/deleteToken.spec.js.map +1 -0
- package/dist/commands/groupaccesstoken/groupContainer.js.map +1 -1
- package/dist/commands/groupaccesstoken/listTokens.js.map +1 -1
- package/dist/commands/groupaccesstoken/listTokens.spec.js +115 -0
- package/dist/commands/groupaccesstoken/listTokens.spec.js.map +1 -0
- package/dist/commands/list.js +10 -3
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/misc/login.js +146 -22
- package/dist/commands/misc/login.js.map +1 -1
- package/dist/commands/misc/login.spec.js +111 -6
- package/dist/commands/misc/login.spec.js.map +1 -1
- package/dist/commands/misc/logout.spec.js +30 -0
- package/dist/commands/misc/logout.spec.js.map +1 -0
- package/dist/commands/misc/loopbackOAuth.js +110 -0
- package/dist/commands/misc/loopbackOAuth.js.map +1 -0
- package/dist/commands/misc/set-access-token.js.map +1 -1
- package/dist/commands/misc/set-access-token.spec.js +65 -0
- package/dist/commands/misc/set-access-token.spec.js.map +1 -0
- package/dist/commands/package/deletepackage.spec.js +136 -0
- package/dist/commands/package/deletepackage.spec.js.map +1 -0
- package/dist/commands/package/listpackages.js +10 -5
- package/dist/commands/package/listpackages.js.map +1 -1
- package/dist/commands/package/listpackages.spec.js +129 -0
- package/dist/commands/package/listpackages.spec.js.map +1 -0
- package/dist/commands/package/publish.js +23 -0
- package/dist/commands/package/publish.js.map +1 -1
- package/dist/commands/package/publish.spec.js +511 -0
- package/dist/commands/package/publish.spec.js.map +1 -0
- package/dist/commands/package/updatepackage.spec.js +50 -0
- package/dist/commands/package/updatepackage.spec.js.map +1 -1
- package/dist/commands/project/createproject.js +11 -1
- package/dist/commands/project/createproject.js.map +1 -1
- package/dist/commands/project/createproject.spec.js +154 -0
- package/dist/commands/project/createproject.spec.js.map +1 -0
- package/dist/commands/project/deleteproject.spec.js +106 -0
- package/dist/commands/project/deleteproject.spec.js.map +1 -0
- package/dist/commands/project/getproject.spec.js +99 -0
- package/dist/commands/project/getproject.spec.js.map +1 -0
- package/dist/commands/project/listprojects.js +13 -7
- package/dist/commands/project/listprojects.js.map +1 -1
- package/dist/commands/project/listprojects.spec.js +111 -0
- package/dist/commands/project/listprojects.spec.js.map +1 -0
- package/dist/commands/project/setproject.spec.js +58 -0
- package/dist/commands/project/setproject.spec.js.map +1 -0
- package/dist/commands/project/updateproject.js +68 -0
- package/dist/commands/project/updateproject.js.map +1 -0
- package/dist/commands/project/updateproject.spec.js +129 -0
- package/dist/commands/project/updateproject.spec.js.map +1 -0
- package/dist/commands/rm.js.map +1 -1
- package/dist/commands/update.js +13 -0
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/version/listversions.spec.js +121 -0
- package/dist/commands/version/listversions.spec.js.map +1 -0
- package/dist/common/UserGroupId.spec.js +92 -0
- package/dist/common/UserGroupId.spec.js.map +1 -0
- package/dist/constants.js +49 -13
- package/dist/constants.js.map +1 -1
- package/dist/index.js +40 -18
- package/dist/index.js.map +1 -1
- package/dist/logger.spec.js +125 -0
- package/dist/logger.spec.js.map +1 -0
- package/dist/polyfills/file.polyfill.js.map +1 -1
- package/dist/utils.js +59 -0
- package/dist/utils.js.map +1 -1
- package/dist/utils.spec.js +158 -0
- package/dist/utils.spec.js.map +1 -0
- package/docker/Dockerfile.ci +11 -3
- package/eslint.config.mjs +45 -0
- package/generate-client.sh +3 -0
- package/package.json +24 -16
- package/src/client/.openapi-generator/FILES +1 -0
- package/src/client/api.ts +1347 -161
- package/src/clientconfiguration.spec.ts +394 -20
- package/src/clientconfiguration.ts +74 -15
- package/src/commands/add.ts +15 -6
- package/src/commands/connection/createconnections.spec.ts +403 -0
- package/src/commands/connection/createconnections.ts +30 -5
- package/src/commands/connection/deleteconnection.spec.ts +189 -0
- package/src/commands/connection/listconnections.spec.ts +132 -0
- package/src/commands/connection/listconnections.ts +22 -3
- package/src/commands/group/addmember.spec.ts +257 -0
- package/src/commands/group/addmember.ts +2 -0
- package/src/commands/group/creategroup.spec.ts +146 -0
- package/src/commands/group/deletegroup.spec.ts +120 -0
- package/src/commands/group/getgroup.spec.ts +129 -0
- package/src/commands/group/listgroups.spec.ts +137 -0
- package/src/commands/group/removemember.spec.ts +224 -0
- package/src/commands/group/removemember.ts +1 -0
- package/src/commands/groupaccesstoken/createToken.spec.ts +211 -0
- package/src/commands/groupaccesstoken/createToken.ts +55 -51
- package/src/commands/groupaccesstoken/deleteToken.spec.ts +147 -0
- package/src/commands/groupaccesstoken/deleteToken.ts +16 -11
- package/src/commands/groupaccesstoken/groupContainer.ts +51 -51
- package/src/commands/groupaccesstoken/listTokens.spec.ts +147 -0
- package/src/commands/groupaccesstoken/listTokens.ts +16 -11
- package/src/commands/list.ts +50 -9
- package/src/commands/misc/login.spec.ts +91 -6
- package/src/commands/misc/login.ts +208 -25
- package/src/commands/misc/logout.spec.ts +32 -0
- package/src/commands/misc/loopbackOAuth.ts +127 -0
- package/src/commands/misc/set-access-token.spec.ts +95 -0
- package/src/commands/misc/set-access-token.ts +16 -16
- package/src/commands/package/deletepackage.spec.ts +164 -0
- package/src/commands/package/listpackages.spec.ts +147 -0
- package/src/commands/package/listpackages.ts +28 -5
- package/src/commands/package/publish.spec.ts +597 -0
- package/src/commands/package/publish.ts +32 -0
- package/src/commands/package/updatepackage.spec.ts +98 -0
- package/src/commands/project/createproject.spec.ts +247 -0
- package/src/commands/project/createproject.ts +12 -1
- package/src/commands/project/deleteproject.spec.ts +123 -0
- package/src/commands/project/getproject.spec.ts +109 -0
- package/src/commands/project/listprojects.spec.ts +121 -0
- package/src/commands/project/listprojects.ts +33 -7
- package/src/commands/project/setproject.spec.ts +63 -0
- package/src/commands/project/updateproject.spec.ts +217 -0
- package/src/commands/project/updateproject.ts +82 -0
- package/src/commands/rm.ts +1 -6
- package/src/commands/update.ts +24 -1
- package/src/commands/version/listversions.spec.ts +138 -0
- package/src/common/UserGroupId.spec.ts +117 -0
- package/src/constants.ts +59 -13
- package/src/index.ts +46 -20
- package/src/logger.spec.ts +158 -0
- package/src/polyfills/file.polyfill.ts +1 -0
- package/src/utils.spec.ts +135 -0
- package/src/utils.ts +81 -0
- package/tsconfig.json +15 -18
- package/.eslintrc +0 -33
|
@@ -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
|
+
});
|
|
@@ -3,66 +3,70 @@ import { logger } from "../../logger";
|
|
|
3
3
|
import { withGroupContext } from "./groupContainer";
|
|
4
4
|
|
|
5
5
|
export async function createGroupAccessToken(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
controlPlane: string,
|
|
7
|
+
groupName: string,
|
|
8
|
+
tokenName: string,
|
|
9
|
+
expiresAt: string | undefined,
|
|
10
|
+
jsonOutput: boolean,
|
|
11
|
+
debug: boolean,
|
|
11
12
|
) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
+
}
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
const result = await withGroupContext(
|
|
31
|
+
controlPlane,
|
|
32
|
+
async (context) => {
|
|
33
|
+
const { organizationName, groupsApi, options } = context;
|
|
31
34
|
|
|
32
|
-
|
|
33
|
-
`Creating access token ${tokenName} for group ${groupName} in organization ${organizationName}${expiresAt ? ` (expires: ${expiresAt})` : ""}`,
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
const response = await groupsApi.createGroupAccessToken(
|
|
35
|
+
const response = await groupsApi.createGroupAccessToken(
|
|
37
36
|
organizationName,
|
|
38
37
|
groupName,
|
|
39
38
|
tokenName,
|
|
40
39
|
expiresAt,
|
|
41
40
|
options,
|
|
42
|
-
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return response.data;
|
|
44
|
+
},
|
|
45
|
+
undefined,
|
|
46
|
+
debug,
|
|
47
|
+
);
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
if (jsonOutput) {
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
46
52
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
console.log("");
|
|
65
|
-
logger.info("Group access token created successfully");
|
|
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");
|
|
66
70
|
|
|
67
|
-
|
|
71
|
+
return result;
|
|
68
72
|
}
|
|
@@ -0,0 +1,147 @@
|
|
|
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 { deleteGroupAccessToken } from "./deleteToken";
|
|
7
|
+
|
|
8
|
+
describe("delete-group-access-token", () => {
|
|
9
|
+
let sandbox: sinon.SinonSandbox;
|
|
10
|
+
let deleteGroupAccessTokenStub: sinon.SinonStub;
|
|
11
|
+
let loggerStub: sinon.SinonStubbedInstance<typeof logger>;
|
|
12
|
+
let processExitStub: sinon.SinonStub;
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
sandbox = sinon.createSandbox();
|
|
16
|
+
deleteGroupAccessTokenStub = 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, "deleteGroupAccessToken")
|
|
32
|
+
.callsFake(deleteGroupAccessTokenStub);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
afterEach(() => {
|
|
36
|
+
sandbox.restore();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should delete group access token successfully", async () => {
|
|
40
|
+
deleteGroupAccessTokenStub.resolves({ status: 200 });
|
|
41
|
+
|
|
42
|
+
await deleteGroupAccessToken(
|
|
43
|
+
"http://test-server",
|
|
44
|
+
"test-group",
|
|
45
|
+
"test-token",
|
|
46
|
+
false,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
expect(deleteGroupAccessTokenStub.calledOnce).to.be.true;
|
|
50
|
+
expect(deleteGroupAccessTokenStub.firstCall.args[0]).to.equal("test-org");
|
|
51
|
+
expect(deleteGroupAccessTokenStub.firstCall.args[1]).to.equal(
|
|
52
|
+
"test-group",
|
|
53
|
+
);
|
|
54
|
+
expect(deleteGroupAccessTokenStub.firstCall.args[2]).to.equal(
|
|
55
|
+
"test-token",
|
|
56
|
+
);
|
|
57
|
+
expect(
|
|
58
|
+
loggerStub.info.calledWith(
|
|
59
|
+
sinon.match(
|
|
60
|
+
"Successfully deleted access token test-token. This token has been immediately revoked.",
|
|
61
|
+
),
|
|
62
|
+
),
|
|
63
|
+
).to.be.true;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should handle missing config", async () => {
|
|
67
|
+
sandbox.restore();
|
|
68
|
+
sandbox = sinon.createSandbox();
|
|
69
|
+
deleteGroupAccessTokenStub = sandbox.stub();
|
|
70
|
+
loggerStub = sandbox.stub(logger);
|
|
71
|
+
processExitStub = sandbox.stub(process, "exit");
|
|
72
|
+
|
|
73
|
+
sandbox
|
|
74
|
+
.stub(ClientConfiguration.prototype, "doesConfigExists")
|
|
75
|
+
.returns(false);
|
|
76
|
+
sandbox
|
|
77
|
+
.stub(GroupsApi.prototype, "deleteGroupAccessToken")
|
|
78
|
+
.callsFake(deleteGroupAccessTokenStub);
|
|
79
|
+
|
|
80
|
+
const result = await deleteGroupAccessToken(
|
|
81
|
+
"http://test-server",
|
|
82
|
+
"test-group",
|
|
83
|
+
"test-token",
|
|
84
|
+
false,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
expect(deleteGroupAccessTokenStub.called).to.be.false;
|
|
88
|
+
expect(result).to.be.undefined;
|
|
89
|
+
expect(
|
|
90
|
+
loggerStub.error.calledWith(
|
|
91
|
+
sinon.match("Please, make sure that you are logged in"),
|
|
92
|
+
),
|
|
93
|
+
).to.be.true;
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("should handle missing organization", async () => {
|
|
97
|
+
sandbox.restore();
|
|
98
|
+
sandbox = sinon.createSandbox();
|
|
99
|
+
deleteGroupAccessTokenStub = sandbox.stub();
|
|
100
|
+
loggerStub = sandbox.stub(logger);
|
|
101
|
+
processExitStub = sandbox.stub(process, "exit");
|
|
102
|
+
|
|
103
|
+
sandbox
|
|
104
|
+
.stub(ClientConfiguration.prototype, "doesConfigExists")
|
|
105
|
+
.returns(true);
|
|
106
|
+
sandbox
|
|
107
|
+
.stub(ClientConfiguration.prototype, "getOrganization")
|
|
108
|
+
.returns(undefined);
|
|
109
|
+
sandbox
|
|
110
|
+
.stub(GroupsApi.prototype, "deleteGroupAccessToken")
|
|
111
|
+
.callsFake(deleteGroupAccessTokenStub);
|
|
112
|
+
|
|
113
|
+
const result = await deleteGroupAccessToken(
|
|
114
|
+
"http://test-server",
|
|
115
|
+
"test-group",
|
|
116
|
+
"test-token",
|
|
117
|
+
false,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
expect(deleteGroupAccessTokenStub.called).to.be.false;
|
|
121
|
+
expect(result).to.be.undefined;
|
|
122
|
+
expect(
|
|
123
|
+
loggerStub.error.calledWith(
|
|
124
|
+
sinon.match(
|
|
125
|
+
"No organization set. Please login or set an organization.",
|
|
126
|
+
),
|
|
127
|
+
),
|
|
128
|
+
).to.be.true;
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("should handle API errors", async () => {
|
|
132
|
+
const mockError = new Error("API Error");
|
|
133
|
+
deleteGroupAccessTokenStub.rejects(mockError);
|
|
134
|
+
|
|
135
|
+
await deleteGroupAccessToken(
|
|
136
|
+
"http://test-server",
|
|
137
|
+
"test-group",
|
|
138
|
+
"test-token",
|
|
139
|
+
true,
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
expect(deleteGroupAccessTokenStub.calledOnce).to.be.true;
|
|
143
|
+
expect(loggerStub.error.calledWith(sinon.match("Operation failed"))).to.be
|
|
144
|
+
.true;
|
|
145
|
+
expect(processExitStub.calledWith(1)).to.be.true;
|
|
146
|
+
});
|
|
147
|
+
});
|
|
@@ -2,23 +2,28 @@ import { logger } from "../../logger";
|
|
|
2
2
|
import { withGroupContext } from "./groupContainer";
|
|
3
3
|
|
|
4
4
|
export async function deleteGroupAccessToken(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
controlPlane: string,
|
|
6
|
+
groupName: string,
|
|
7
|
+
tokenName: string,
|
|
8
|
+
debug: boolean,
|
|
9
9
|
) {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
return withGroupContext(
|
|
11
|
+
controlPlane,
|
|
12
|
+
async (context) => {
|
|
13
|
+
const { organizationName, groupsApi, options } = context;
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
logger.info(
|
|
14
16
|
`Deleting access token ${tokenName} from group ${groupName} in organization ${organizationName}`,
|
|
15
|
-
|
|
17
|
+
);
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
await groupsApi.deleteGroupAccessToken(
|
|
18
20
|
organizationName,
|
|
19
21
|
groupName,
|
|
20
22
|
tokenName,
|
|
21
23
|
options,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
);
|
|
25
|
+
},
|
|
26
|
+
`Successfully deleted access token ${tokenName}. This token has been immediately revoked.`,
|
|
27
|
+
debug,
|
|
28
|
+
);
|
|
24
29
|
}
|
|
@@ -5,23 +5,23 @@ import { logger } from "../../logger";
|
|
|
5
5
|
import { printOutError } from "../../utils";
|
|
6
6
|
|
|
7
7
|
export interface ApiOptions {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
baseURL: string;
|
|
9
|
+
headers: {
|
|
10
|
+
Authorization: string;
|
|
11
|
+
};
|
|
12
|
+
params?: Record<string, unknown>;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export interface GroupContext {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
organizationName: string;
|
|
17
|
+
groupsApi: GroupsApi;
|
|
18
|
+
options: ApiOptions;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Container function that handles common ClientConfiguration checks, setup,
|
|
23
23
|
* error handling, and response printing for group access token operations.
|
|
24
|
-
*
|
|
24
|
+
*
|
|
25
25
|
* @param controlPlane The control plane URL
|
|
26
26
|
* @param handler The handler function to execute with the configured context
|
|
27
27
|
* @param successMessage Optional success message to display after the operation
|
|
@@ -29,55 +29,55 @@ export interface GroupContext {
|
|
|
29
29
|
* @returns The result of the handler function, or void if validation fails
|
|
30
30
|
*/
|
|
31
31
|
export async function withGroupContext<T>(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
controlPlane: string,
|
|
33
|
+
handler: (context: GroupContext) => Promise<T>,
|
|
34
|
+
successMessage?: string,
|
|
35
|
+
debug: boolean = false,
|
|
36
36
|
): Promise<T | void> {
|
|
37
|
-
|
|
37
|
+
const clientConfig = new ClientConfiguration();
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
if (!clientConfig.doesConfigExists()) {
|
|
40
|
+
logger.error("Please, make sure that you are logged in");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
const organizationName = clientConfig.getOrganization();
|
|
45
|
+
if (!organizationName) {
|
|
46
|
+
logger.error("No organization set. Please login or set an organization.");
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
const options: ApiOptions = {
|
|
51
|
+
baseURL: controlPlane,
|
|
52
|
+
headers: {
|
|
53
|
+
Authorization: clientConfig.getAuthenticationHeader(),
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
const context: GroupContext = {
|
|
58
|
+
organizationName,
|
|
59
|
+
groupsApi: new GroupsApi(new Configuration()),
|
|
60
|
+
options,
|
|
61
|
+
};
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
try {
|
|
64
|
+
const result = await handler(context);
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
// Print response if it exists
|
|
67
|
+
if (result !== undefined && result !== null) {
|
|
68
|
+
const jsonString = JSON.stringify(result, null, 2);
|
|
69
|
+
console.log(jsonString);
|
|
70
|
+
}
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
// Print success message if provided
|
|
73
|
+
if (successMessage) {
|
|
74
|
+
logger.info(successMessage);
|
|
75
|
+
}
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
return result;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
logger.error("Operation failed");
|
|
80
|
+
printOutError(error, debug);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
83
|
}
|