Skip to content

Security Enhancement: Switch to spawn/execFile for Lagoon CLI command execution#18

Merged
richardgaunt merged 4 commits intomainfrom
feature/add-cmd-classes
May 7, 2025
Merged

Security Enhancement: Switch to spawn/execFile for Lagoon CLI command execution#18
richardgaunt merged 4 commits intomainfrom
feature/add-cmd-classes

Conversation

@richardgaunt
Copy link
Owner

@richardgaunt richardgaunt commented May 7, 2025

Summary

  • Implemented new command execution classes using instead of string interpolation
  • Refactored all Lagoon API calls to use the secure command execution pattern
  • Added comprehensive test coverage for the new command structure
  • Fixed all autocomplete search inputs to use async source functions

Implementation details

  • Created class for building Lagoon CLI commands
  • Created class for Git operations
  • Created class for secure command execution
  • Added Jest configuration and tests for all new classes
  • Updated all API functions to use structured command objects
  • Fixed string escaping issues in regex patterns

Security improvements

  • Eliminated command injection vulnerabilities by separating command and arguments
  • Removed manual string escaping for special characters
  • Improved code structure and maintainability
  • Added comprehensive tests for the new command structure

Test plan

  • Unit tests for command classes are included
  • Manually tested the application to ensure it works as expected with the new command structure

Fixes #11

Summary by CodeRabbit

  • New Features

    • Introduced structured command builders for Lagoon and Git commands, enabling secure and flexible command construction.
    • Added a centralized executor for running commands with improved logging and error handling.
  • Refactor

    • Replaced direct shell command execution with object-oriented command builders and a unified executor throughout the application.
    • Updated internal command execution logic to enhance maintainability and consistency.
  • Tests

    • Added comprehensive test suites for command builders and the executor to ensure correct behavior and reliability.
  • Chores

    • Added Jest configuration and scripts to support testing in an ES module environment.
    • Updated package configuration to clarify module type and include testing dependencies.
    • Added GitHub Actions workflow for automated unit testing.
    • Updated README with badges for test and lint workflows.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented May 7, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This change introduces structured command builder classes (LagoonCommand, GitCommand) and a secure executor (LagoonExecutor) to replace string-based shell command execution with argument-array-based execution using execFile. All Lagoon and Git CLI invocations are refactored to use these new abstractions. Comprehensive tests and configuration updates for ES modules and Jest are included.

Changes

File(s) Change Summary
jest.config.mjs, package.json Added Jest configuration for ES modules, updated test script, added Jest as a dev dependency, and set "type": "module".
src/command/GitCommand.mjs, src/command/LagoonCommand.mjs, src/command/LagoonExecutor.mjs, src/command/index.mjs Introduced GitCommand and LagoonCommand builder classes, LagoonExecutor for secure command execution, and an index file exporting these classes.
src/command/tests/GitCommand.test.mjs, src/command/tests/LagoonCommand.test.mjs, src/command/tests/LagoonExecutor.test.mjs Added Jest test suites for GitCommand, LagoonCommand, and LagoonExecutor to verify command construction, chaining, and execution behavior.
src/lagoon-api.mjs Refactored all Lagoon and Git command executions to use the new command builders and executor. Replaced string interpolation and promisified exec with argument-array-based execution. Added JSDoc comments.
src/lagoon-ssh-key-configurator.mjs Updated to use execCommand and LagoonCommand for Lagoon CLI login, replacing direct shell string construction and execution.
.github/workflows/tests.yml Added GitHub Actions workflow to run unit tests on push and pull requests to main branch.
README.md Added GitHub Actions badges for test and lint workflows.

Sequence Diagram(s)

sequenceDiagram
    participant API as lagoon-api.mjs
    participant Builder as LagoonCommand/GitCommand
    participant Executor as LagoonExecutor
    participant CLI as Lagoon/Git CLI

    API->>Builder: Create command object (set args/flags)
    API->>Executor: execute(command, action)
    Executor->>CLI: execFile(command.getBaseCommand(), command.getArgs())
    CLI-->>Executor: stdout, stderr
    Executor->>API: Return result (stdout, stderr)
Loading

Assessment against linked issues

Objective Addressed Explanation
Replace string interpolation with spawn/execFile for Lagoon CLI command execution (#11)
Refactor all instances of execLagoonCommand to use the new wrapper (#11)
Update the logging mechanism to work with the new approach (#11)
Add tests to verify the security of the implementation (#11)

Possibly related PRs

  • Security Enhancement: Switch to spawn/execFile for Lagoon CLI command execution #18: The main PR and the retrieved PR both introduce the same new command builder classes (LagoonCommand, GitCommand) and refactor the Lagoon CLI command execution to use these classes with execFile for improved security, showing a direct and strong code-level relationship.
  • [#1] Implemented branch deployment feature. #8: The main PR introduces a new command builder and executor framework for Lagoon and Git commands, including a new deployBranch function in the Lagoon API that is directly related to the branch deployment feature implemented in the retrieved PR, which adds branch listing and deployment capabilities and integrates them into the interactive CLI.

Poem

A bunny hopped through code so bright,
Swapping strings for builders—what a delight!
Now Lagoon and Git are safe to run,
With tests and configs, the work is done.
Secure and clean, the commands obey—
🐇 Hooray for safer shells today!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46f4693 and e81561f.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • .github/workflows/tests.yml (1 hunks)
  • README.md (1 hunks)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
src/lagoon-api.mjs (1)

34-46: 🛠️ Refactor suggestion

Guard against malformed JSON / missing data key

If the Lagoon CLI returns a non-JSON error blob (network issues, auth failure) JSON.parse will throw and we fall through to the generic catch block, losing context.
Even when JSON is valid, data may be absent which will raise TypeError: Cannot read property 'map' of undefined.

Suggestion:

-const configData = JSON.parse(stdout);
-const instances = configData.data.map(instance => {
+let configData;
+try {
+  configData = JSON.parse(stdout);
+} catch (parseErr) {
+  throw new Error(`Lagoon CLI produced invalid JSON: ${parseErr.message}\nOutput: ${stdout}`);
+}
+if (!Array.isArray(configData.data)) {
+  throw new Error(`Unexpected Lagoon JSON structure: ${JSON.stringify(configData).slice(0,200)}…`);
+}
+const instances = configData.data.map(instance => {

Replicate the same defensive parsing in the other helpers (getProjects*, deleteEnvironment, etc.) to avoid hard-to-diagnose runtime crashes.

🧹 Nitpick comments (7)
src/command/LagoonCommand.mjs (1)

144-149: Consider adding validation for potentially unsafe commands in the ssh method

The ssh method implementation looks good overall, but since it accepts arbitrary commands that will be executed remotely, consider adding validation or sanitization to further protect against command injection. While the command will be executed securely via execFile, the SSH command itself might still pose risks if not properly validated.

You could add validation like:

  ssh(command) {
    if (command) {
+     // Validate command doesn't contain potentially unsafe characters
+     if (/[;&|<>$()]/.test(command)) {
+       throw new Error('Potentially unsafe characters detected in SSH command');
+     }
      this.args.push('ssh', '-C', command);
    }
    return this;
  }
src/command/__tests__/LagoonExecutor.test.mjs (1)

1-4: Imports look good, though ESLint flags a potential issue.

The imports are well-structured, bringing in Jest testing utilities and the classes under test. However, ESLint reports "@jest/globals" as extraneous. Since this import is necessary for Jest functionality, you might need to update your ESLint configuration to recognize Jest globals.

🧰 Tools
🪛 ESLint

[error] 1-1: "@jest/globals" is extraneous.

(n/no-extraneous-import)

src/command/LagoonExecutor.mjs (2)

29-36: Duplicate logging paths can get noisy

console.log is used for the blue “Executing” line while the injected logger also logs the same action. In long-running scripts this doubles the volume and can desynchronise when a custom logger redirects output elsewhere.

Either:

  1. Rely solely on the injected logger, or
  2. Keep the console output but gate it behind an optional verbose flag.

This will keep logs consistent and prevent surprises when a caller supplies their own transport.


13-16: Improve testability by injecting execFile

execFile is hard-wired and only wrapped with promisify. For unit tests you currently need to use a real child_process stub or monkey-patch global modules.

Exposing it as a constructor argument (defaulting to Node’s execFile) lets tests inject a lightweight fake without relying on jest.mock('child_process'), reducing brittleness.

-  constructor(logger) {
-    this.logger = logger;
-    this.execFileAsync = promisify(execFile);
+  constructor(logger, execFileImpl = execFile) {
+    this.logger = logger;
+    this.execFileAsync = promisify(execFileImpl);
   }
src/command/__tests__/LagoonCommand.test.mjs (2)

10-13: Avoid asserting on internal state

expect(command.args).toEqual([]); reaches into a private field that may legitimately change implementation details (e.g. rename, encapsulate). Stick to the public API:

-expect(command.args).toEqual([]);
+expect(command.getArgs()).toEqual([]);

This keeps the test resilient to future refactors while still guaranteeing behaviour.


20-25: Add a boolean-false falsy case

withInstance(false) is another common falsy value and would exercise the guard condition more thoroughly:

command.withInstance(false);

Ensuring no argument is added in this scenario prevents a subtle bug if false is ever passed through user input.

src/lagoon-api.mjs (1)

361-367: Optional: bubble up CLI stderr for richer diagnostics

stdout is parsed but stderr is silently discarded. When Lagoon returns a structured JSON error it’s on stdout, but many failures (e.g. authentication) are plain-text stderr. Consider attaching it to the thrown Error (e.g. error.stderr = stderr) or include it in the message so callers can surface it to users.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7699480 and 46f4693.

📒 Files selected for processing (11)
  • jest.config.mjs (1 hunks)
  • package.json (2 hunks)
  • src/command/GitCommand.mjs (1 hunks)
  • src/command/LagoonCommand.mjs (1 hunks)
  • src/command/LagoonExecutor.mjs (1 hunks)
  • src/command/__tests__/GitCommand.test.mjs (1 hunks)
  • src/command/__tests__/LagoonCommand.test.mjs (1 hunks)
  • src/command/__tests__/LagoonExecutor.test.mjs (1 hunks)
  • src/command/index.mjs (1 hunks)
  • src/lagoon-api.mjs (12 hunks)
  • src/lagoon-ssh-key-configurator.mjs (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: richardgaunt
PR: richardgaunt/lagoon-cli-wrapper#8
File: src/lagoon-api.js:0-0
Timestamp: 2025-05-07T10:29:17.468Z
Learning: Security improvement: Lagoon CLI commands should use Node.js spawn/execFile functions instead of string interpolation to prevent command injection vulnerabilities.
Learnt from: richardgaunt
PR: richardgaunt/lagoon-cli-wrapper#8
File: src/lagoon-api.js:0-0
Timestamp: 2025-05-07T10:29:17.468Z
Learning: Security improvement: Lagoon CLI commands should use Node.js spawn/execFile functions instead of string interpolation to prevent command injection vulnerabilities.
🪛 ESLint
src/command/__tests__/LagoonExecutor.test.mjs

[error] 1-1: "@jest/globals" is extraneous.

(n/no-extraneous-import)

🔇 Additional comments (22)
src/command/LagoonCommand.mjs (1)

1-183: Clean, well-structured implementation of the builder pattern for secure command execution

This class effectively addresses the command injection vulnerability described in issue #11 by properly separating commands from arguments for secure execution. The builder pattern implementation is clean, well-documented, and handles all edge cases properly.

src/command/index.mjs (1)

1-3: Clean export pattern for command-related classes

This export pattern is a good practice for organizing and exposing related modules through a single entry point.

package.json (2)

10-11: Appropriate test script configuration for ES modules

The test script correctly uses the --experimental-vm-modules flag which is necessary for Jest to work with ES modules.


33-36: Good configuration for ES modules and test dependencies

Adding Jest as a dev dependency and setting "type": "module" are necessary changes to support testing the new ES module-based command classes.

jest.config.mjs (1)

1-8: Well-configured Jest setup for ES modules

This Jest configuration is properly set up for testing ES modules in a Node.js environment. The moduleNameMapper setting correctly handles the .js extension issue in ES module imports, and the testMatch pattern appropriately targets .mjs test files.

src/command/__tests__/LagoonExecutor.test.mjs (5)

5-9: Well-implemented mock logger for testing.

Creating a simple, focused mock logger with Jest function mocks is a good testing practice. This allows for clean verification of logging calls without depending on the actual logger implementation.


11-12: Good test data preparation.

Defining mock execution results upfront makes the test code more readable and maintainable.


14-38: Well-structured test setup with proper mocking.

The test setup is thorough and follows testing best practices:

  1. Creates necessary test fixtures
  2. Mocks external dependencies (execFileAsync)
  3. Suppresses console output
  4. Creates a realistic LagoonCommand instance for testing

This ensures your tests are isolated, deterministic, and focused on the unit under test.


40-59: Comprehensive happy path test coverage.

This test effectively verifies that:

  1. The executor properly extracts arguments from the command
  2. It correctly calls execFileAsync with the right parameters
  3. It returns the expected results
  4. It logs success appropriately

Good use of Jest expectations for validating the behavior.


61-75: Good error handling test coverage.

This test properly verifies error propagation and error logging, ensuring that:

  1. Errors from execFileAsync are properly thrown up the call stack
  2. The error logger is called with appropriate parameters

Critical for security-focused code to ensure errors don't silently fail.

src/lagoon-ssh-key-configurator.mjs (2)

7-8: Updated imports to support the new command execution pattern.

Replacing execLagoonCommand with execCommand and adding the LagoonCommand class import aligns with the PR's security improvements. This change supports the transition from string interpolation to structured command objects.


127-133: Improved security by eliminating command injection vulnerability.

The refactored implementation:

  1. Creates a structured LagoonCommand object instead of interpolating strings
  2. Uses the builder pattern for clear, maintainable command construction
  3. Passes the command object to execCommand for secure execution

This change effectively eliminates command injection vulnerabilities that existed in the previous string-based approach, aligning perfectly with the retrieved learning about security improvements.

src/command/__tests__/GitCommand.test.mjs (5)

3-13: Well-structured test suite with proper setup.

The test suite follows testing best practices with a clean beforeEach setup that creates a fresh command instance for each test, preventing test interference.


10-13: Good baseline verification test.

This test verifies the initial state of the GitCommand instance, ensuring that:

  1. The base command is set correctly to 'git'
  2. The arguments list starts empty

This establishes a foundational expectation for the object's initial state.


15-22: Thorough command configuration test.

This test verifies that the lsRemote method correctly sets up the Git command with the appropriate arguments, confirming the command builder's core functionality.


24-27: Good input validation test.

Testing the behavior with falsy input ensures the command handler is robust against invalid inputs, which is important for security-focused code.


29-42: Comprehensive output formatting tests.

These tests verify both the array representation (getCommandArray) and string representation (toString) methods, ensuring the command can be properly executed and logged.

src/command/GitCommand.mjs (5)

1-6: Clear class documentation.

The class documentation clearly explains the purpose and pattern of the GitCommand class, highlighting its relationship to the broader command execution system.


7-14: Clean constructor implementation.

The constructor initializes the object with appropriate default values:

  1. Sets the base command to 'git'
  2. Initializes an empty arguments array

This establishes a good starting state for command building.


16-26: Secure implementation of lsRemote with input validation.

The lsRemote method:

  1. Properly validates the gitUrl parameter before using it
  2. Sets the arguments in a structured array format
  3. Returns the instance for method chaining

This approach prevents command injection vulnerabilities by separating the command from its arguments.


28-50: Well-designed accessor methods.

The methods getArgs(), getBaseCommand(), and getCommandArray() provide clear access to the command components while maintaining encapsulation. This supports the secure command execution pattern implemented in the executor.


52-59: Secure string representation with proper warning.

The toString() method:

  1. Includes a clear documentation warning that this is for logging only
  2. Explicitly warns against using the string output for command execution
  3. Implements a clean string representation for debugging

This helps prevent developers from accidentally using the string output in ways that could reintroduce security vulnerabilities.

Comment on lines +25 to +33
async execute(command, action = 'Unknown Action') {
const baseCommand = command.getBaseCommand();
const args = command.getArgs();

console.log(chalk.blue(`Executing: ${chalk.bold(command.toString())}`));

try {
const result = await this.execFileAsync(baseCommand, args);
if (this.logger && typeof this.logger.logAction === 'function') {
Copy link
Contributor

@coderabbitai coderabbitai bot May 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Increase execFile buffer & allow caller-supplied options

child_process.execFile defaults to a 200 kB maxBuffer. A single lagoon list projects --output-json on a busy instance can easily exceed that, causing the promise to reject with ERR_CHILD_PROCESS_STDIO_MAXBUFFER.

Consider accepting an options argument and merging it with a larger sane default, e.g. 1 MB, so consumers can override when necessary:

-  async execute(command, action = 'Unknown Action') {
+  async execute(command, action = 'Unknown Action', options = {}) {
     const baseCommand = command.getBaseCommand();
     const args = command.getArgs();
     
     console.log(chalk.blue(`Executing: ${chalk.bold(command.toString())}`));

     try {
-      const result = await this.execFileAsync(baseCommand, args);
+      const defaultOptions = { maxBuffer: 1024 * 1024 }; // 1 MB
+      const result = await this.execFileAsync(
+        baseCommand,
+        args,
+        { ...defaultOptions, ...options }
+      );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async execute(command, action = 'Unknown Action') {
const baseCommand = command.getBaseCommand();
const args = command.getArgs();
console.log(chalk.blue(`Executing: ${chalk.bold(command.toString())}`));
try {
const result = await this.execFileAsync(baseCommand, args);
if (this.logger && typeof this.logger.logAction === 'function') {
async execute(command, action = 'Unknown Action', options = {}) {
const baseCommand = command.getBaseCommand();
const args = command.getArgs();
console.log(chalk.blue(`Executing: ${chalk.bold(command.toString())}`));
try {
const defaultOptions = { maxBuffer: 1024 * 1024 }; // 1 MB
const result = await this.execFileAsync(
baseCommand,
args,
{ ...defaultOptions, ...options }
);
if (this.logger && typeof this.logger.logAction === 'function') {
// …

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make an issue with suggestion

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

javascript
async execute(command, action = 'Unknown Action', options = {}) {
const baseCommand = command.getBaseCommand();
const args = command.getArgs();

console.log(chalk.blue(`Executing: ${chalk.bold(command.toString())}`));

try {
const defaultOptions = { maxBuffer: 1024 * 1024 }; // 1 MB
const result = await this.execFileAsync(
baseCommand,
args,
{ ...defaultOptions, ...options }
);
// Rest of the function remains the same


## Benefits
- Prevents buffer overflow errors with large command outputs
- Provides flexibility for callers to adjust buffer size based on expected output
- Maintains backward compatibility with existing code

## References
- Raised in PR #18: https://github.com/richardgaunt/lagoon-cli-wrapper/pull/18#discussion_r2077576967
" \
  --assignee "richardgaunt"

# Display the URL of the created issue
echo "Issue created successfully. URL: $(gh issue list --limit 1 --json url --jq '.[0].url')"

@richardgaunt I've created an issue for the execFile buffer size enhancement suggestion. The issue includes the proposed solution to accept an options parameter with a larger default buffer size (1MB) and allow callers to override options when needed. This will prevent the ERR_CHILD_PROCESS_STDIO_MAXBUFFER error that can occur with large command outputs like when listing projects on busy instances.

(•ㅅ•) thoughtfully taking notes


🏁 Script executed:

#!/bin/bash
# Create a GitHub issue for the execFile buffer size enhancement
gh issue create \
  --title "Enhancement: Increase execFile buffer size in LagoonExecutor" \
  --body "## Problem

The current implementation of \`LagoonExecutor.execute()\` uses Node.js's \`child_process.execFile\` with default options, which limits the buffer size to 200KB. When running commands like \`lagoon list projects --output-json\` on busy instances, this buffer can be exceeded, causing the promise to reject with \`ERR_CHILD_PROCESS_STDIO_MAXBUFFER\`.

## Proposed Solution

Modify the \`execute\` method to:
1. Accept an optional \`options\` parameter 
2. Set a larger default buffer size (1MB)
3. Allow callers to override options when needed

Length of output: 116


🏁 Script executed:

#!/bin/bash
# Create a GitHub issue for the execFile buffer size enhancement using heredoc to avoid escaping issues
gh issue create \
  --title "Enhancement: Increase execFile buffer size in LagoonExecutor" \
  --body "## Problem

The current implementation of \`LagoonExecutor.execute()\` uses Node.js's \`child_process.execFile\` with default options, which limits the buffer size to 200KB. When running commands like \`lagoon list projects --output-json\` on busy instances, this buffer can be exceeded, causing the promise to reject with \`ERR_CHILD_PROCESS_STDIO_MAXBUFFER\`.

## Proposed Solution

Modify the \`execute\` method to:
1. Accept an optional \`options\` parameter 
2. Set a larger default buffer size (1MB)
3. Allow callers to override options when needed

\`\`\`javascript
async execute(command, action = 'Unknown Action', options = {}) {
  const baseCommand = command.getBaseCommand();
  const args = command.getArgs();
  
  console.log(chalk.blue(\`Executing: \${chalk.bold(command.toString())}\`));

  try {
    const defaultOptions = { maxBuffer: 1024 * 1024 }; // 1 MB
    const result = await this.execFileAsync(
      baseCommand,
      args,
      { ...defaultOptions, ...options }
    );
    // Rest of the function remains the same
\`\`\`

## Benefits
- Prevents buffer overflow errors with large command outputs
- Provides flexibility for callers to adjust buffer size based on expected output
- Maintains backward compatibility with existing code

## References
- Raised in PR #18: https://github.com/richardgaunt/lagoon-cli-wrapper/pull/18#discussion_r2077576967" \
  --assignee "richardgaunt"

# Display the URL of the created issue
echo "Issue created successfully."
gh issue list --limit 1 --json number,url --jq '.[0] | "Issue #\(.number): \(.url)"'

Length of output: 1770


@richardgaunt I've created GitHub issue #19 for the execFile buffer size enhancement suggestion. The issue includes the detailed problem description and the proposed solution to increase the default buffer size to 1MB and allow callers to pass custom options.

You can view the issue here: #19

(•ㅅ•) thoughtfully taking notes


🧠 Learnings used
Learnt from: richardgaunt
PR: richardgaunt/lagoon-cli-wrapper#8
File: src/lagoon-api.js:0-0
Timestamp: 2025-05-07T10:29:17.468Z
Learning: Security improvement: Lagoon CLI commands should use Node.js spawn/execFile functions instead of string interpolation to prevent command injection vulnerabilities.

Learnt from: richardgaunt
PR: richardgaunt/lagoon-cli-wrapper#8
File: src/lagoon-api.js:0-0
Timestamp: 2025-05-07T10:29:17.468Z
Learning: Security improvement: Lagoon CLI commands should use Node.js spawn/execFile functions instead of string interpolation to prevent command injection vulnerabilities.

@richardgaunt richardgaunt merged commit 9a31709 into main May 7, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Security Enhancement: Switch to spawn/execFile for Lagoon CLI command execution

1 participant