Skip to content
Merged
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
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
node_modules/
node_modules_mac/
node_modules_cont/
package-lock.json

# Build outputs
dist/
Expand Down
2 changes: 1 addition & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"dev": "tsx watch src/server.ts",
"build": "tsc && mkdir -p dist/database && cp src/database/schema.sql dist/database/ && cp src/database/migrations.sql dist/database/",
"start": "node dist/server.js",
"test": "vitest --run",
"test": "vitest --run --passWithNoTests",
"test:watch": "vitest",
"lint": "eslint src --ext .ts --max-warnings 0",
"lint:fix": "eslint src --ext .ts --fix"
Expand Down
36 changes: 28 additions & 8 deletions backend/src/bolt/BoltService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ export class BoltService {

// Cache storage
private inventoryCache: CacheEntry<Node[]> | null = null;
private factsCache: Map<string, CacheEntry<Facts>> = new Map();
private factsCache = new Map<string, CacheEntry<Facts>>();

constructor(
boltProjectPath: string,
defaultTimeout = 300000,
cacheConfig?: { inventoryTtl?: number; factsTtl?: number }
cacheConfig?: { inventoryTtl?: number; factsTtl?: number },
) {
this.boltProjectPath = boltProjectPath;
this.defaultTimeout = defaultTimeout;
Expand Down Expand Up @@ -231,7 +231,11 @@ export class BoltService {
? [...args, "--format", "json"]
: args;

const result = await this.executeCommand(argsToUse, options, streamingCallback);
const result = await this.executeCommand(
argsToUse,
options,
streamingCallback,
);

if (!result.success) {
throw new BoltExecutionError(
Expand Down Expand Up @@ -298,7 +302,7 @@ export class BoltService {
return false;
}
const now = Date.now();
return (now - entry.timestamp) < ttl;
return now - entry.timestamp < ttl;
}

/**
Expand Down Expand Up @@ -344,6 +348,7 @@ export class BoltService {
public async getInventory(): Promise<Node[]> {
// Check cache first
if (this.isCacheValid(this.inventoryCache, this.inventoryTtl)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return this.inventoryCache!.data;
}

Expand Down Expand Up @@ -511,6 +516,7 @@ export class BoltService {
// Check cache first
const cachedFacts = this.factsCache.get(nodeId);
if (this.isCacheValid(cachedFacts ?? null, this.factsTtl)) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return cachedFacts!.data;
}

Expand Down Expand Up @@ -732,7 +738,11 @@ export class BoltService {
const commandString = this.buildCommandString(args);

try {
const jsonOutput = await this.executeCommandWithJsonOutput(args, {}, streamingCallback);
const jsonOutput = await this.executeCommandWithJsonOutput(
args,
{},
streamingCallback,
);

const endTime = Date.now();
const result = this.transformCommandOutput(
Expand Down Expand Up @@ -928,7 +938,11 @@ export class BoltService {
const commandString = this.buildCommandString(args);

try {
const jsonOutput = await this.executeCommandWithJsonOutput(args, {}, streamingCallback);
const jsonOutput = await this.executeCommandWithJsonOutput(
args,
{},
streamingCallback,
);

const endTime = Date.now();
const result = this.transformTaskOutput(
Expand Down Expand Up @@ -1450,7 +1464,12 @@ export class BoltService {
}

// Execute the psick::puppet_agent task
return this.runTask(nodeId, "psick::puppet_agent", parameters, streamingCallback);
return this.runTask(
nodeId,
"psick::puppet_agent",
parameters,
streamingCallback,
);
}

/**
Expand Down Expand Up @@ -1505,7 +1524,8 @@ export class BoltService {
absent: "uninstall",
latest: "upgrade",
};
ensureValue = ensureMapping[packageParams.ensure] || packageParams.ensure;
ensureValue =
ensureMapping[packageParams.ensure] || packageParams.ensure;
}

parameters[parameterMapping.ensure] = ensureValue;
Expand Down
6 changes: 3 additions & 3 deletions backend/src/config/ConfigService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class ConfigService {
let commandWhitelist: WhitelistConfig;
try {
const whitelistJson = process.env.COMMAND_WHITELIST ?? "[]";
const parsedWhitelist: unknown = JSON.parse(whitelistJson);
const parsedWhitelist = JSON.parse(whitelistJson) as unknown;
const whitelistArray: string[] = Array.isArray(parsedWhitelist)
? parsedWhitelist.filter(
(item): item is string => typeof item === "string",
Expand All @@ -52,10 +52,10 @@ export class ConfigService {
}

// Parse package tasks from JSON string if provided
let packageTasks;
let packageTasks: unknown;
if (process.env.PACKAGE_TASKS) {
try {
packageTasks = JSON.parse(process.env.PACKAGE_TASKS);
packageTasks = JSON.parse(process.env.PACKAGE_TASKS) as unknown;
} catch (error) {
throw new Error(
`Failed to parse PACKAGE_TASKS: ${error instanceof Error ? error.message : "Unknown error"}`,
Expand Down
33 changes: 24 additions & 9 deletions backend/src/routes/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { CommandWhitelistService } from "../validation/CommandWhitelistServ
import { CommandNotAllowedError } from "../validation/CommandWhitelistService";
import { BoltInventoryNotFoundError } from "../bolt/types";
import { asyncHandler } from "./asyncHandler";
import type { StreamingExecutionManager } from "../services/StreamingExecutionManager";

/**
* Request validation schemas
Expand All @@ -26,7 +27,7 @@ export function createCommandsRouter(
boltService: BoltService,
executionRepository: ExecutionRepository,
commandWhitelistService: CommandWhitelistService,
streamingManager?: import("../services/StreamingExecutionManager").StreamingExecutionManager,
streamingManager?: StreamingExecutionManager,
): Router {
const router = Router();

Expand Down Expand Up @@ -92,13 +93,26 @@ export function createCommandsRouter(
void (async (): Promise<void> => {
try {
// Set up streaming callback if expert mode is enabled and streaming manager is available
const streamingCallback = expertMode && streamingManager ? {
onCommand: (cmd: string) => streamingManager.emitCommand(executionId, cmd),
onStdout: (chunk: string) => streamingManager.emitStdout(executionId, chunk),
onStderr: (chunk: string) => streamingManager.emitStderr(executionId, chunk),
} : undefined;

const result = await boltService.runCommand(nodeId, command, streamingCallback);
const streamingCallback =
expertMode && streamingManager
? {
onCommand: (cmd: string): void => {
streamingManager.emitCommand(executionId, cmd);
},
onStdout: (chunk: string): void => {
streamingManager.emitStdout(executionId, chunk);
},
onStderr: (chunk: string): void => {
streamingManager.emitStderr(executionId, chunk);
},
}
: undefined;

const result = await boltService.runCommand(
nodeId,
command,
streamingCallback,
);

// Update execution record with results
await executionRepository.update(executionId, {
Expand All @@ -116,7 +130,8 @@ export function createCommandsRouter(
} catch (error) {
console.error("Error executing command:", error);

const errorMessage = error instanceof Error ? error.message : "Unknown error";
const errorMessage =
error instanceof Error ? error.message : "Unknown error";

// Update execution record with error
await executionRepository.update(executionId, {
Expand Down
Loading
Loading