Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 27 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@codifycli/plugin-core",
"version": "1.0.1",
"version": "1.1.0-beta24",
"description": "TypeScript library for building Codify plugins to manage system resources (applications, CLI tools, settings) through infrastructure-as-code",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
Expand Down Expand Up @@ -35,15 +35,15 @@
},
"license": "ISC",
"dependencies": {
"@codifycli/schemas": "1.0.0",
"@codifycli/schemas": "^1.1.0-beta8",
"@homebridge/node-pty-prebuilt-multiarch": "^0.13.1",
"ajv": "^8.18.0",
"ajv-formats": "^2.1.1",
"clean-deep": "^3.4.0",
"lodash.isequal": "^4.5.0",
"nanoid": "^5.0.9",
"strip-ansi": "^7.1.0",
"uuid": "^10.0.0",
"uuid": "^14.0.0",
"zod": "4.1.13"
},
"devDependencies": {
Expand Down
4 changes: 3 additions & 1 deletion src/common/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ export class ApplyValidationError extends Error {
resourceType: string;
resourceName?: string;
plan: Plan<any>;
logs: string[];

constructor(plan: Plan<any>) {
constructor(plan: Plan<any>, logs: string[] = []) {
super(`Failed to apply changes to resource: "${plan.resourceId}". Additional changes are needed to complete apply.\nChanges remaining:\n${ApplyValidationError.prettyPrintPlan(plan)}`);

this.resourceType = plan.coreParameters.type;
this.resourceName = plan.coreParameters.name;
this.plan = plan;
this.logs = logs;
}

private static prettyPrintPlan(plan: Plan<any>): string {
Expand Down
40 changes: 24 additions & 16 deletions src/messages/handlers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {

Check failure on line 1 in src/messages/handlers.ts

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

src/messages/handlers.test.ts

Error: Cannot find package '@codifycli/schemas' imported from '/Users/runner/work/codify-plugin-core/codify-plugin-core/src/messages/handlers.ts' ❯ src/messages/handlers.ts:1:1 ❯ src/messages/handlers.test.ts:1:1 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { code: 'ERR_MODULE_NOT_FOUND' }

Check failure on line 1 in src/messages/handlers.ts

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

src/messages/handlers.test.ts

Error: Cannot find package '@codifycli/schemas' imported from '/home/runner/work/codify-plugin-core/codify-plugin-core/src/messages/handlers.ts' ❯ src/messages/handlers.ts:1:1 ❯ src/messages/handlers.test.ts:1:1 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { code: 'ERR_MODULE_NOT_FOUND' }
ApplyRequestDataSchema,
EmptyResponseDataSchema,
GetResourceInfoRequestDataSchema,
Expand All @@ -16,6 +16,7 @@
MessageStatus,
PlanRequestDataSchema,
PlanResponseDataSchema,
PluginErrorData,
ResourceSchema,
SetVerbosityRequestDataSchema,
ValidateRequestDataSchema,
Expand All @@ -24,6 +25,7 @@
import { Ajv, SchemaObject, ValidateFunction } from 'ajv';
import addFormats from 'ajv-formats';

import { ApplyValidationError } from '../common/errors.js';
import { SudoError } from '../errors.js';
import { Plugin } from '../plugin/plugin.js';

Expand Down Expand Up @@ -157,25 +159,31 @@

// @ts-expect-error TS2239
const cmd = message.cmd + '_Response';
// @ts-expect-error TS2239
const requestId = message.requestId || undefined;

let errorPayload: PluginErrorData;

if (e instanceof SudoError) {
return process.send?.({
cmd,
// @ts-expect-error TS2239
requestId: message.requestId || undefined,
data: `Plugin: '${this.plugin.name}'. Forbidden usage of sudo for command '${e.command}'. Please contact the plugin developer to fix this.`,
status: MessageStatus.ERROR,
})
errorPayload = {
errorType: 'sudo_error',
message: `Plugin: '${this.plugin.name}'. Forbidden usage of sudo for command '${e.command}'. Please contact the plugin developer to fix this.`,
data: { command: e.command, pluginName: this.plugin.name },
};
} else if (e instanceof ApplyValidationError) {
errorPayload = {
errorType: 'apply_validation',
message: e.message,
data: { plan: e.plan.toResponse(), logs: e.logs },
};
} else {
const isDebug = process.env.DEBUG?.includes('*') ?? false;
errorPayload = {
errorType: 'unknown',
message: isDebug ? (e.stack ?? e.message) : e.message,
};
}

const isDebug = process.env.DEBUG?.includes('*') ?? false;

process.send?.({
cmd,
// @ts-expect-error TS2239
requestId: message.requestId || undefined,
data: isDebug ? e.stack : e.message,
status: MessageStatus.ERROR,
})
process.send?.({ cmd, requestId, data: errorPayload, status: MessageStatus.ERROR });
}
}
46 changes: 46 additions & 0 deletions src/plan/change-set.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ describe('Change set tests', () => {

const parameterSettings = new ParsedResourceSettings({
id: 'type',
operatingSystems: [],
parameterSettings: {
propA: { type: 'array' }
}
Expand All @@ -129,6 +130,7 @@ describe('Change set tests', () => {

const parameterSettings = new ParsedResourceSettings({
id: 'type',
operatingSystems: [],
parameterSettings: {
propA: { type: 'array' }
}
Expand All @@ -152,6 +154,7 @@ describe('Change set tests', () => {

const parameterSettings = new ParsedResourceSettings({
id: 'type',
operatingSystems: [],
parameterSettings: {
propA: { canModify: true }
}
Expand All @@ -176,6 +179,7 @@ describe('Change set tests', () => {

const parameterSettings = new ParsedResourceSettings({
id: 'type',
operatingSystems: [],
parameterSettings: {
propA: { canModify: true },
propB: { canModify: true }
Expand All @@ -196,6 +200,7 @@ describe('Change set tests', () => {

const parameterSettings = new ParsedResourceSettings({
id: 'type',
operatingSystems: [],
parameterSettings: {
propA: { type: 'array' }
},
Expand All @@ -213,6 +218,7 @@ describe('Change set tests', () => {

const parameterSettings = new ParsedResourceSettings({
id: 'type',
operatingSystems: [],
parameterSettings: {
propA: { type: 'array' }
},
Expand All @@ -229,6 +235,7 @@ describe('Change set tests', () => {

const parameterSettings = new ParsedResourceSettings({
id: 'type',
operatingSystems: [],
parameterSettings: {
propA: { type: 'array' }
},
Expand All @@ -245,6 +252,7 @@ describe('Change set tests', () => {

const parameterSettings = new ParsedResourceSettings({
id: 'type',
operatingSystems: [],
parameterSettings: {
propA: {
type: 'array',
Expand All @@ -259,12 +267,50 @@ describe('Change set tests', () => {
expect(result.parameterChanges[0].operation).to.eq(ParameterOperation.MODIFY);
})

it('excludes setting parameters from destroy change set', () => {
const settings = {
id: 'type',
operatingSystems: [],
parameterSettings: {
propA: {},
propB: { setting: true },
},
};

const cs = ChangeSet.destroy({ propA: 'val', propB: true }, settings as any);
expect(cs.parameterChanges.length).to.eq(1);
expect(cs.parameterChanges[0].name).to.eq('propA');
expect(cs.parameterChanges[0].operation).to.eq(ParameterOperation.REMOVE);
expect(cs.operation).to.eq(ResourceOperation.DESTROY);
})

it('excludes multiple setting parameters from destroy change set', () => {
const settings = {
id: 'type',
operatingSystems: [],
parameterSettings: {
skipAlreadyInstalledCasks: { type: 'boolean', default: true, setting: true },
onlyPlanUserInstalled: { type: 'boolean', default: true, setting: true },
directory: { type: 'directory' },
},
};

const cs = ChangeSet.destroy(
{ skipAlreadyInstalledCasks: true, onlyPlanUserInstalled: true, directory: '/opt/homebrew' },
settings as any
);
expect(cs.parameterChanges.length).to.eq(1);
expect(cs.parameterChanges[0].name).to.eq('directory');
expect(cs.operation).to.eq(ResourceOperation.DESTROY);
})

it('correctly determines array equality 5', () => {
const arrA = [{ key1: 'b' }, { key1: 'a' }, { key1: 'a' }];
const arrB = [{ key1: 'a' }, { key1: 'a' }, { key1: 'b' }];

const parameterSettings = new ParsedResourceSettings({
id: 'type',
operatingSystems: [],
parameterSettings: {
propA: {
type: 'array',
Expand Down
1 change: 1 addition & 0 deletions src/plan/change-set.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ParameterOperation, ResourceOperation, StringIndexedObject } from '@codifycli/schemas';

Check failure on line 1 in src/plan/change-set.ts

View workflow job for this annotation

GitHub Actions / build-and-test (macos-latest)

src/plan/change-set.test.ts

Error: Cannot find package '@codifycli/schemas' imported from '/Users/runner/work/codify-plugin-core/codify-plugin-core/src/plan/change-set.ts' ❯ src/plan/change-set.ts:1:1 ❯ src/plan/change-set.test.ts:1:1 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { code: 'ERR_MODULE_NOT_FOUND' }

Check failure on line 1 in src/plan/change-set.ts

View workflow job for this annotation

GitHub Actions / build-and-test (ubuntu-latest)

src/plan/change-set.test.ts

Error: Cannot find package '@codifycli/schemas' imported from '/home/runner/work/codify-plugin-core/codify-plugin-core/src/plan/change-set.ts' ❯ src/plan/change-set.ts:1:1 ❯ src/plan/change-set.test.ts:1:1 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { code: 'ERR_MODULE_NOT_FOUND' }

import { ParsedParameterSetting } from '../resource/parsed-resource-settings.js';
import { ResourceSettings } from '../resource/resource-settings.js';
Expand Down Expand Up @@ -94,6 +94,7 @@

static destroy<T extends StringIndexedObject>(current: Partial<T>, settings?: ResourceSettings<T>): ChangeSet<T> {
const parameterChanges = Object.entries(current)
.filter(([k]) => !settings?.parameterSettings?.[k]?.setting)
.map(([k, v]) => ({
name: k,
operation: ParameterOperation.REMOVE,
Expand Down
Loading
Loading