Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
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