codify-plugin-lib 1.0.107 → 1.0.109
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.
|
@@ -2,11 +2,13 @@ import { Plugin } from '../plugin/plugin.js';
|
|
|
2
2
|
export declare class MessageHandler {
|
|
3
3
|
private ajv;
|
|
4
4
|
private readonly plugin;
|
|
5
|
-
private
|
|
5
|
+
private messageSchemaValidatorV1;
|
|
6
|
+
private messageSchemaValidatorV2;
|
|
6
7
|
private requestValidators;
|
|
7
8
|
private responseValidators;
|
|
8
9
|
constructor(plugin: Plugin);
|
|
9
10
|
onMessage(message: unknown): Promise<void>;
|
|
10
11
|
private validateMessage;
|
|
12
|
+
private validateMessageV2;
|
|
11
13
|
private handleErrors;
|
|
12
14
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Ajv } from 'ajv';
|
|
2
2
|
import addFormats from 'ajv-formats';
|
|
3
|
-
import { ApplyRequestDataSchema, ApplyResponseDataSchema, GetResourceInfoRequestDataSchema, GetResourceInfoResponseDataSchema, ImportRequestDataSchema, ImportResponseDataSchema, InitializeRequestDataSchema, InitializeResponseDataSchema, IpcMessageSchema, MessageStatus, PlanRequestDataSchema, PlanResponseDataSchema, ResourceSchema, ValidateRequestDataSchema, ValidateResponseDataSchema } from 'codify-schemas';
|
|
3
|
+
import { ApplyRequestDataSchema, ApplyResponseDataSchema, GetResourceInfoRequestDataSchema, GetResourceInfoResponseDataSchema, ImportRequestDataSchema, ImportResponseDataSchema, InitializeRequestDataSchema, InitializeResponseDataSchema, IpcMessageSchema, IpcMessageV2Schema, MessageStatus, PlanRequestDataSchema, PlanResponseDataSchema, ResourceSchema, ValidateRequestDataSchema, ValidateResponseDataSchema } from 'codify-schemas';
|
|
4
4
|
import { SudoError } from '../errors.js';
|
|
5
5
|
const SupportedRequests = {
|
|
6
6
|
'initialize': {
|
|
@@ -40,7 +40,8 @@ const SupportedRequests = {
|
|
|
40
40
|
export class MessageHandler {
|
|
41
41
|
ajv;
|
|
42
42
|
plugin;
|
|
43
|
-
|
|
43
|
+
messageSchemaValidatorV1;
|
|
44
|
+
messageSchemaValidatorV2;
|
|
44
45
|
requestValidators;
|
|
45
46
|
responseValidators;
|
|
46
47
|
constructor(plugin) {
|
|
@@ -48,7 +49,8 @@ export class MessageHandler {
|
|
|
48
49
|
addFormats.default(this.ajv);
|
|
49
50
|
this.ajv.addSchema(ResourceSchema);
|
|
50
51
|
this.plugin = plugin;
|
|
51
|
-
this.
|
|
52
|
+
this.messageSchemaValidatorV1 = this.ajv.compile(IpcMessageSchema);
|
|
53
|
+
this.messageSchemaValidatorV2 = this.ajv.compile(IpcMessageV2Schema);
|
|
52
54
|
this.requestValidators = new Map(Object.entries(SupportedRequests)
|
|
53
55
|
.map(([k, v]) => [k, this.ajv.compile(v.requestValidator)]));
|
|
54
56
|
this.responseValidators = new Map(Object.entries(SupportedRequests)
|
|
@@ -56,8 +58,8 @@ export class MessageHandler {
|
|
|
56
58
|
}
|
|
57
59
|
async onMessage(message) {
|
|
58
60
|
try {
|
|
59
|
-
if (!this.validateMessage(message)) {
|
|
60
|
-
throw new Error(`Plugin: ${this.plugin}. Message is malformed: ${JSON.stringify(this.
|
|
61
|
+
if (!this.validateMessageV2(message) && !this.validateMessage(message)) {
|
|
62
|
+
throw new Error(`Plugin: ${this.plugin}. Message is malformed: ${JSON.stringify(this.messageSchemaValidatorV1.errors, null, 2)}`);
|
|
61
63
|
}
|
|
62
64
|
if (!this.requestValidators.has(message.cmd)) {
|
|
63
65
|
throw new Error(`Plugin: ${this.plugin}. Unsupported message: ${message.cmd}`);
|
|
@@ -74,6 +76,8 @@ export class MessageHandler {
|
|
|
74
76
|
process.send({
|
|
75
77
|
cmd: message.cmd + '_Response',
|
|
76
78
|
data: result,
|
|
79
|
+
// @ts-expect-error TS2239
|
|
80
|
+
requestId: message.requestId || undefined,
|
|
77
81
|
status: MessageStatus.SUCCESS,
|
|
78
82
|
});
|
|
79
83
|
}
|
|
@@ -82,7 +86,10 @@ export class MessageHandler {
|
|
|
82
86
|
}
|
|
83
87
|
}
|
|
84
88
|
validateMessage(message) {
|
|
85
|
-
return this.
|
|
89
|
+
return this.messageSchemaValidatorV1(message);
|
|
90
|
+
}
|
|
91
|
+
validateMessageV2(message) {
|
|
92
|
+
return this.messageSchemaValidatorV2(message);
|
|
86
93
|
}
|
|
87
94
|
handleErrors(message, e) {
|
|
88
95
|
if (!message) {
|
|
@@ -91,11 +98,13 @@ export class MessageHandler {
|
|
|
91
98
|
if (!message.hasOwnProperty('cmd')) {
|
|
92
99
|
return;
|
|
93
100
|
}
|
|
94
|
-
// @ts-
|
|
101
|
+
// @ts-expect-error TS2239
|
|
95
102
|
const cmd = message.cmd + '_Response';
|
|
96
103
|
if (e instanceof SudoError) {
|
|
97
104
|
return process.send?.({
|
|
98
105
|
cmd,
|
|
106
|
+
// @ts-expect-error TS2239
|
|
107
|
+
requestId: message.requestId || undefined,
|
|
99
108
|
data: `Plugin: '${this.plugin.name}'. Forbidden usage of sudo for command '${e.command}'. Please contact the plugin developer to fix this.`,
|
|
100
109
|
status: MessageStatus.ERROR,
|
|
101
110
|
});
|
|
@@ -103,6 +112,8 @@ export class MessageHandler {
|
|
|
103
112
|
const isDebug = process.env.DEBUG?.includes('*') ?? false;
|
|
104
113
|
process.send?.({
|
|
105
114
|
cmd,
|
|
115
|
+
// @ts-expect-error TS2239
|
|
116
|
+
requestId: message.requestId || undefined,
|
|
106
117
|
data: isDebug ? e.stack : e.message,
|
|
107
118
|
status: MessageStatus.ERROR,
|
|
108
119
|
});
|
|
@@ -263,13 +263,13 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
263
263
|
const result = {};
|
|
264
264
|
const sortedEntries = Object.entries(statefulParametersConfig)
|
|
265
265
|
.sort(([key1], [key2]) => this.parsedSettings.statefulParameterOrder.get(key1) - this.parsedSettings.statefulParameterOrder.get(key2));
|
|
266
|
-
|
|
266
|
+
await Promise.all(sortedEntries.map(async ([key, desiredValue]) => {
|
|
267
267
|
const statefulParameter = this.parsedSettings.statefulParameters.get(key);
|
|
268
268
|
if (!statefulParameter) {
|
|
269
269
|
throw new Error(`Stateful parameter ${key} was not found`);
|
|
270
270
|
}
|
|
271
271
|
result[key] = await statefulParameter.refresh(desiredValue ?? null, allParameters);
|
|
272
|
-
}
|
|
272
|
+
}));
|
|
273
273
|
return result;
|
|
274
274
|
}
|
|
275
275
|
validatePlanInputs(desired, current, statefulMode) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codify-plugin-lib",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.109",
|
|
4
4
|
"description": "Library plugin library",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"ajv": "^8.12.0",
|
|
16
16
|
"ajv-formats": "^2.1.1",
|
|
17
|
-
"codify-schemas": "1.0.
|
|
17
|
+
"codify-schemas": "1.0.53",
|
|
18
18
|
"@npmcli/promise-spawn": "^7.0.1",
|
|
19
19
|
"uuid": "^10.0.0",
|
|
20
20
|
"lodash.isequal": "^4.5.0"
|
|
@@ -207,7 +207,6 @@ describe('Message handler tests', () => {
|
|
|
207
207
|
it('handles errors for apply (destroy)', async () => {
|
|
208
208
|
const resource = new TestResource()
|
|
209
209
|
const plugin = testPlugin(resource);
|
|
210
|
-
|
|
211
210
|
const handler = new MessageHandler(plugin);
|
|
212
211
|
|
|
213
212
|
process.send = (message) => {
|
|
@@ -228,6 +227,71 @@ describe('Message handler tests', () => {
|
|
|
228
227
|
}
|
|
229
228
|
}
|
|
230
229
|
})).rejects.to.not.throw;
|
|
230
|
+
|
|
231
|
+
process.send = undefined;
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
it('Supports ipc message v2 (success)', async () => {
|
|
235
|
+
const resource = new TestResource()
|
|
236
|
+
const plugin = testPlugin(resource);
|
|
237
|
+
const handler = new MessageHandler(plugin);
|
|
238
|
+
|
|
239
|
+
process.send = (message) => {
|
|
240
|
+
console.log(message)
|
|
241
|
+
expect(message).toMatchObject({
|
|
242
|
+
cmd: 'plan_Response',
|
|
243
|
+
requestId: 'abcdef',
|
|
244
|
+
status: MessageStatus.SUCCESS,
|
|
245
|
+
})
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
await expect(handler.onMessage({
|
|
250
|
+
cmd: 'plan',
|
|
251
|
+
requestId: 'abcdef',
|
|
252
|
+
data: {
|
|
253
|
+
desired: {
|
|
254
|
+
type: 'type',
|
|
255
|
+
name: 'name',
|
|
256
|
+
prop1: 'A',
|
|
257
|
+
prop2: 'B',
|
|
258
|
+
},
|
|
259
|
+
isStateful: false,
|
|
260
|
+
}
|
|
261
|
+
})).resolves.to.eq(undefined);
|
|
262
|
+
|
|
263
|
+
process.send = undefined;
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
it('Supports ipc message v2 (error)', async () => {
|
|
267
|
+
const resource = new TestResource()
|
|
268
|
+
const plugin = testPlugin(resource);
|
|
269
|
+
const handler = new MessageHandler(plugin);
|
|
270
|
+
|
|
271
|
+
process.send = (message) => {
|
|
272
|
+
expect(message).toMatchObject({
|
|
273
|
+
cmd: 'apply_Response',
|
|
274
|
+
requestId: 'abcdef',
|
|
275
|
+
status: MessageStatus.ERROR,
|
|
276
|
+
})
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
await expect(handler.onMessage({
|
|
281
|
+
cmd: 'apply', // Supposed to be a plan so that's why it throws
|
|
282
|
+
requestId: 'abcdef',
|
|
283
|
+
data: {
|
|
284
|
+
desired: {
|
|
285
|
+
type: 'type',
|
|
286
|
+
name: 'name',
|
|
287
|
+
prop1: 'A',
|
|
288
|
+
prop2: 'B',
|
|
289
|
+
},
|
|
290
|
+
isStateful: false,
|
|
291
|
+
}
|
|
292
|
+
})).resolves.to.eq(undefined);
|
|
293
|
+
|
|
294
|
+
process.send = undefined;
|
|
231
295
|
})
|
|
232
296
|
});
|
|
233
297
|
|
package/src/messages/handlers.ts
CHANGED
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
InitializeResponseDataSchema,
|
|
12
12
|
IpcMessage,
|
|
13
13
|
IpcMessageSchema,
|
|
14
|
+
IpcMessageV2,
|
|
15
|
+
IpcMessageV2Schema,
|
|
14
16
|
MessageStatus,
|
|
15
17
|
PlanRequestDataSchema,
|
|
16
18
|
PlanResponseDataSchema,
|
|
@@ -61,7 +63,8 @@ const SupportedRequests: Record<string, { handler: (plugin: Plugin, data: any) =
|
|
|
61
63
|
export class MessageHandler {
|
|
62
64
|
private ajv: Ajv;
|
|
63
65
|
private readonly plugin: Plugin;
|
|
64
|
-
private
|
|
66
|
+
private messageSchemaValidatorV1: ValidateFunction;
|
|
67
|
+
private messageSchemaValidatorV2: ValidateFunction;
|
|
65
68
|
private requestValidators: Map<string, ValidateFunction>;
|
|
66
69
|
private responseValidators: Map<string, ValidateFunction>;
|
|
67
70
|
|
|
@@ -71,7 +74,9 @@ export class MessageHandler {
|
|
|
71
74
|
this.ajv.addSchema(ResourceSchema);
|
|
72
75
|
this.plugin = plugin;
|
|
73
76
|
|
|
74
|
-
this.
|
|
77
|
+
this.messageSchemaValidatorV1 = this.ajv.compile(IpcMessageSchema);
|
|
78
|
+
this.messageSchemaValidatorV2 = this.ajv.compile(IpcMessageV2Schema);
|
|
79
|
+
|
|
75
80
|
this.requestValidators = new Map(
|
|
76
81
|
Object.entries(SupportedRequests)
|
|
77
82
|
.map(([k, v]) => [k, this.ajv.compile(v.requestValidator)])
|
|
@@ -84,8 +89,8 @@ export class MessageHandler {
|
|
|
84
89
|
|
|
85
90
|
async onMessage(message: unknown): Promise<void> {
|
|
86
91
|
try {
|
|
87
|
-
if (!this.validateMessage(message)) {
|
|
88
|
-
throw new Error(`Plugin: ${this.plugin}. Message is malformed: ${JSON.stringify(this.
|
|
92
|
+
if (!this.validateMessageV2(message) && !this.validateMessage(message)) {
|
|
93
|
+
throw new Error(`Plugin: ${this.plugin}. Message is malformed: ${JSON.stringify(this.messageSchemaValidatorV1.errors, null, 2)}`);
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
if (!this.requestValidators.has(message.cmd)) {
|
|
@@ -107,6 +112,8 @@ export class MessageHandler {
|
|
|
107
112
|
process.send!({
|
|
108
113
|
cmd: message.cmd + '_Response',
|
|
109
114
|
data: result,
|
|
115
|
+
// @ts-expect-error TS2239
|
|
116
|
+
requestId: message.requestId || undefined,
|
|
110
117
|
status: MessageStatus.SUCCESS,
|
|
111
118
|
})
|
|
112
119
|
|
|
@@ -116,7 +123,11 @@ export class MessageHandler {
|
|
|
116
123
|
}
|
|
117
124
|
|
|
118
125
|
private validateMessage(message: unknown): message is IpcMessage {
|
|
119
|
-
return this.
|
|
126
|
+
return this.messageSchemaValidatorV1(message);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private validateMessageV2(message: unknown): message is IpcMessageV2 {
|
|
130
|
+
return this.messageSchemaValidatorV2(message);
|
|
120
131
|
}
|
|
121
132
|
|
|
122
133
|
private handleErrors(message: unknown, e: Error) {
|
|
@@ -128,12 +139,14 @@ export class MessageHandler {
|
|
|
128
139
|
return;
|
|
129
140
|
}
|
|
130
141
|
|
|
131
|
-
// @ts-
|
|
142
|
+
// @ts-expect-error TS2239
|
|
132
143
|
const cmd = message.cmd + '_Response';
|
|
133
144
|
|
|
134
145
|
if (e instanceof SudoError) {
|
|
135
146
|
return process.send?.({
|
|
136
147
|
cmd,
|
|
148
|
+
// @ts-expect-error TS2239
|
|
149
|
+
requestId: message.requestId || undefined,
|
|
137
150
|
data: `Plugin: '${this.plugin.name}'. Forbidden usage of sudo for command '${e.command}'. Please contact the plugin developer to fix this.`,
|
|
138
151
|
status: MessageStatus.ERROR,
|
|
139
152
|
})
|
|
@@ -143,6 +156,8 @@ export class MessageHandler {
|
|
|
143
156
|
|
|
144
157
|
process.send?.({
|
|
145
158
|
cmd,
|
|
159
|
+
// @ts-expect-error TS2239
|
|
160
|
+
requestId: message.requestId || undefined,
|
|
146
161
|
data: isDebug ? e.stack : e.message,
|
|
147
162
|
status: MessageStatus.ERROR,
|
|
148
163
|
})
|
|
@@ -362,14 +362,14 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
362
362
|
([key1], [key2]) => this.parsedSettings.statefulParameterOrder.get(key1)! - this.parsedSettings.statefulParameterOrder.get(key2)!
|
|
363
363
|
)
|
|
364
364
|
|
|
365
|
-
|
|
365
|
+
await Promise.all(sortedEntries.map(async ([key, desiredValue]) => {
|
|
366
366
|
const statefulParameter = this.parsedSettings.statefulParameters.get(key);
|
|
367
367
|
if (!statefulParameter) {
|
|
368
368
|
throw new Error(`Stateful parameter ${key} was not found`);
|
|
369
369
|
}
|
|
370
370
|
|
|
371
371
|
(result as Record<string, unknown>)[key] = await statefulParameter.refresh(desiredValue ?? null, allParameters)
|
|
372
|
-
}
|
|
372
|
+
}))
|
|
373
373
|
|
|
374
374
|
return result;
|
|
375
375
|
}
|