Skip to content

Fix issue #20: safer dump output and diff mode handling#21

Merged
justin808 merged 5 commits intomainfrom
jg/fix-issue-20
Apr 2, 2026
Merged

Fix issue #20: safer dump output and diff mode handling#21
justin808 merged 5 commits intomainfrom
jg/fix-issue-20

Conversation

@justin808
Copy link
Copy Markdown
Member

@justin808 justin808 commented Apr 2, 2026

Addresses issue #20 by adding diff mode control for JS/TS config factories, warning when dump runs without --clean, and validating --env key names. It fixes resolveRealPath path stitching, hardens YAML metadata headers against newline injection, and makes build-matrix NODE_ENV fallback explicit at runtime. The change also deduplicates constructor-name/env-var helper logic and updates README/CLI/input-format docs to document the new behavior and safety notes. Validation: npm test and npm run lint.


Note

Medium Risk
Touches core CLI execution paths for loading configs and dumping outputs, which could change behavior in CI/local workflows; changes are well-scoped and covered by new tests but affect config evaluation and file writing.

Overview
Adds new CLI controls and safety hardening for config evaluation and exports. diff and dump now accept --mode to set the argv.mode passed to JS/TS function-export configs (default production), while dump keeps --environment as metadata-only.

Improves dump security/robustness by warning when running without --clean (suppressible via --no-warn-sensitive), validating --env keys before mutating process.env, and sanitizing YAML header metadata to prevent newline/header injection. Also fixes FileWriter.resolveRealPath path stitching, clarifies trusted build-matrix path/env expansion behavior, deduplicates helper logic (envVar, objectIntrospection), and adds lefthook pre-commit/pre-push automation plus updated docs/tests.

Written by Cursor Bugbot for commit b88875e. This will update automatically on new commits. Configure here.

Summary by CodeRabbit

  • New Features

    • Add --mode for diff/dump and --no-warn-sensitive to control dump warnings; expanded examples and environment labeling.
    • Git hooks and helper scripts to enforce linting, formatting, and trailing-newline fixes; postinstall hook to set up hooks.
  • Bug Fixes

    • Stronger validation for --env keys.
    • Sanitize YAML header metadata to prevent newline injection; improved file path resolution.
  • Documentation

    • Updated CLI docs, README, and examples for mode, environment, and security guidance.
  • Tests

    • New integration and unit tests for CLI behavior and YAML header escaping.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 2, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d3cdeedc-02db-4a10-b712-281b1bfd6640

📥 Commits

Reviewing files that changed from the base of the PR and between 0139d67 and b88875e.

📒 Files selected for processing (1)
  • bin/lefthook/lint-branch

Walkthrough

Adds a CLI --mode option propagated into JS/TS config factories, centralizes constructor-name and env-name utilities, tightens --env validation and dump sensitive-output warnings, sanitizes YAML header newlines, and adds lefthook scripts, tests, and docs updates.

Changes

Cohort / File(s) Summary
Documentation
README.md, docs/cli-reference.md, docs/input-formats.md
Document --mode=<name> for diff/dump, clarify --environment semantics/defaulting, add dump sensitive-output warning and --no-warn-sensitive, and expand examples.
CLI Logic
src/cli.ts
Parse --mode, add mode to parsed args and forward into config loading/dump, validate --env keys with new util, add --no-warn-sensitive and conditional dump warnings, change build-environment resolution to {label, source}, minor output formatting tweaks.
Env validation util
src/envVar.ts
Add exported isValidEnvVarName(name: string): boolean for validating environment-variable-like keys and used by CLI and loader.
Constructor-name util
src/objectIntrospection.ts
Add exported `getConstructorName(value: unknown): string
Serializers & Cleaner
src/configCleaner.ts, src/configSerializer.ts, src/yamlSerializer.ts
Replace in-file constructor-name logic with getConstructorName imports; sanitize YAML header metadata by escaping newline characters.
Build config loader
src/buildConfigFile.ts
Remove local env-name validator and delegate checks to isValidEnvVarName; small comment added near early-return.
Filesystem helper
src/fileWriter.ts
Refactor resolveRealPath to repeatedly attempt realpathSync while ascending ancestors and use resolve()/relative() to build the resolved path.
CLI tests
test/cli.integration.test.js
Add integration tests for --mode propagation into factory argv, --env key validation behavior, dump warning emission and suppression, and mode vs environment semantics.
YAML tests
test/yamlSerializer.test.js
Add unit test ensuring YAML header metadata newlines are escaped/serialized as \\n.
Git hooks & scripts
bin/lefthook/check-trailing-newlines, bin/lefthook/lint-branch, lefthook.yml, .gitignore, package.json
Add lefthook config, two hook scripts (trailing-newlines, lint-branch), ignore lefthook-local.yml, and add conditional postinstall lefthook install in package.json.
Misc
.gitignore, README.md (examples)
Ignore local lefthook file and update README examples for dump/diff demonstrating --mode and --environment usages.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI
    participant ConfigLoader
    participant ConfigFactory
    participant DumpRunner

    User->>CLI: run diff --left=a.js --right=b.js --mode=development
    CLI->>ConfigLoader: loadConfigFile(a.js, mode="development")
    ConfigLoader->>ConfigFactory: call exported({}, { mode: "development" })
    ConfigFactory-->>ConfigLoader: return configA
    CLI->>ConfigLoader: loadConfigFile(b.js, mode="development")
    ConfigLoader->>ConfigFactory: call exported({}, { mode: "development" })
    ConfigFactory-->>ConfigLoader: return configB
    CLI->>CLI: compare configA vs configB
    CLI-->>User: print diff summary

    User->>CLI: run dump config.js [--no-warn-sensitive] [--environment=staging]
    CLI->>ConfigLoader: loadConfigFile(config.js, mode=(parsed.mode||"production"))
    ConfigLoader->>ConfigFactory: call exported({}, { mode })
    ConfigFactory-->>ConfigLoader: return config
    CLI->>DumpRunner: run dump with config, warnSensitive flag, environment label
    DumpRunner-->>User: emit YAML/JSON (header sanitized), maybe warn about sensitive output
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through modes and factories bright,
I fetched constructor names in gentle light,
I guarded env keys before they spread,
I escaped newlines so headers stay read,
Hooks, tests, and docs — a small celebratory bite. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and specifically addresses the PR's main objectives: implementing safer dump output (via warnings and --clean validation), and adding diff/dump mode handling (via --mode flag for config factory control).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jg/fix-issue-20

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread src/yamlSerializer.ts
Comment thread src/cli.ts
Comment thread src/objectIntrospection.ts
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2ce46a0186

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/cli.ts Outdated
Comment thread src/cli.ts
@claude
Copy link
Copy Markdown

claude Bot commented Apr 2, 2026

Review: Fix issue #20 — safer dump output and diff mode handling

Overall this is a solid, well-scoped PR. The security hardening (YAML header injection fix, --env key validation, dump sensitivity warning) is good, the code deduplication is clean, and the tests cover the new behaviors. A few issues worth addressing:

Notable issues

1. dump lacks independent --mode control (see inline comment on cli.ts:863)

--mode is wired only to parseDiffArgs. The dump subcommand passes the --environment label directly to loadConfigFile as argv.mode, which means --environment=staging accidentally sets argv.mode="staging" on the factory call. These two concepts should be independent, just as they now are for diff.

2. Dump warning has no suppression path (see inline comment on cli.ts:840)

The warning fires on every dump invocation without --clean. CI users who intentionally run without --clean will see it on every run with no way to opt out. A --quiet flag or acknowledgement opt-out would prevent noise fatigue.

Minor

  • sanitize(metadata.configCount) in yamlSerializer.ts is a no-op since configCount is a number — see inline comment with suggestion.
  • The getConstructorName consolidation silently changes behavior for array parents in configCleaner.ts (arrays previously returned "Array", now return null). Functionally harmless today since no code checks for parentConstructor === "Array", but worth a note in case new callers appear — see inline comment on objectIntrospection.ts.

What looks good

  • resolveRealPath fix is correct: resolve(realCurrent, relative(current, target)) properly stitches the resolved ancestor with the remaining path suffix, avoiding the old string-slice stitching bug.
  • YAML header newline sanitization is the right defense for comment injection.
  • --env key validation with isValidEnvVarName is a good security improvement.
  • Extracting isValidEnvVarName and getConstructorName into shared modules is clean.
  • The resolveBuildEnvironmentLabel refactor (returning {label, source}) makes the runtime logging explicit and easy to read.

Copy link
Copy Markdown

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/cli.ts (1)

555-567: ⚠️ Potential issue | 🟠 Major

Validate all --env keys before mutating process.env.

Line 556 can throw after earlier entries in the same list have already been written at Line 566, so run(["dump", ..., "--env=NODE_ENV=production", "--env=INVALID-NAME=value"]) returns 2 but leaves NODE_ENV behind for the rest of the process. The same partial-apply bug also affects invalid keys coming from build.environment.

💡 Suggested fix
 function applyEnvVariables(entries: string[]): () => void {
   const parsedEntries = entries.map((entry) => {
     const delimiterIndex = entry.indexOf("=");
     if (delimiterIndex <= 0) {
       throw new Error(`Invalid --env value: ${entry}. Expected KEY=VALUE.`);
     }

     return {
       key: entry.slice(0, delimiterIndex),
       value: entry.slice(delimiterIndex + 1),
     };
   });
+
+  parsedEntries.forEach(({ key }) => {
+    if (!isValidEnvVarName(key)) {
+      throw new Error(
+        `Invalid --env key: ${key}. Expected a shell-style env var name (e.g. NODE_ENV).`,
+      );
+    }
+  });

   const previousValues = new Map<string, string | undefined>();

   parsedEntries.forEach(({ key, value }) => {
-    if (!isValidEnvVarName(key)) {
-      throw new Error(
-        `Invalid --env key: ${key}. Expected a shell-style env var name (e.g. NODE_ENV).`,
-      );
-    }
-
     if (!previousValues.has(key)) {
       previousValues.set(key, process.env[key]);
     }

     process.env[key] = value;
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli.ts` around lines 555 - 567, Validate all candidate env keys before
mutating process.env: first iterate parsedEntries (and any build.environment
inputs) and run isValidEnvVarName on every key, throwing if any invalid are
found, then in a separate loop perform previousValues.set(key, process.env[key])
and assign process.env[key] = value; reference parsedEntries, isValidEnvVarName,
previousValues and process.env to locate the logic to split validation and
mutation so no partial updates occur.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/cli.ts`:
- Around line 555-567: Validate all candidate env keys before mutating
process.env: first iterate parsedEntries (and any build.environment inputs) and
run isValidEnvVarName on every key, throwing if any invalid are found, then in a
separate loop perform previousValues.set(key, process.env[key]) and assign
process.env[key] = value; reference parsedEntries, isValidEnvVarName,
previousValues and process.env to locate the logic to split validation and
mutation so no partial updates occur.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8897ff09-1331-48b2-9082-e69a5436c1f0

📥 Commits

Reviewing files that changed from the base of the PR and between db80824 and 2ce46a0.

📒 Files selected for processing (13)
  • README.md
  • docs/cli-reference.md
  • docs/input-formats.md
  • src/buildConfigFile.ts
  • src/cli.ts
  • src/configCleaner.ts
  • src/configSerializer.ts
  • src/envVar.ts
  • src/fileWriter.ts
  • src/objectIntrospection.ts
  • src/yamlSerializer.ts
  • test/cli.integration.test.js
  • test/yamlSerializer.test.js

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Misleading error message for build config env keys
    • Updated env key validation messaging to use source-agnostic wording and added an integration test covering invalid build-config environment keys.

Create PR

Or push these changes by commenting:

@cursor push 7adce3bd88
Preview (7adce3bd88)
diff --git a/src/cli.ts b/src/cli.ts
--- a/src/cli.ts
+++ b/src/cli.ts
@@ -555,7 +555,7 @@
   parsedEntries.forEach(({ key, value }) => {
     if (!isValidEnvVarName(key)) {
       throw new Error(
-        `Invalid --env key: ${key}. Expected a shell-style env var name (e.g. NODE_ENV).`,
+        `Invalid environment key: ${key}. Expected a shell-style env var name (e.g. NODE_ENV).`,
       );
     }
 

diff --git a/test/cli.integration.test.js b/test/cli.integration.test.js
--- a/test/cli.integration.test.js
+++ b/test/cli.integration.test.js
@@ -386,10 +386,36 @@
 
     expect(code).toBe(2);
     expect(errorSpy).toHaveBeenCalledWith(
-      expect.stringContaining("Invalid --env key: INVALID-NAME"),
+      expect.stringContaining("Invalid environment key: INVALID-NAME"),
     );
   });
 
+  test("dump --build reports invalid environment keys without --env wording", () => {
+    const configPath = path.join(tempDir, "webpack.config.js");
+    const buildConfig = path.join(tempDir, "pack-config-diff-builds.yml");
+
+    fs.writeFileSync(configPath, "module.exports = { mode: 'production' }\n", "utf8");
+    fs.writeFileSync(
+      buildConfig,
+      [
+        "builds:",
+        "  prod:",
+        `    config: "${configPath}"`,
+        "    environment:",
+        "      INVALID-NAME: value",
+      ].join("\n"),
+      "utf8",
+    );
+
+    const code = run(["dump", "--build=prod", `--config-file=${buildConfig}`]);
+
+    expect(code).toBe(2);
+    expect(errorSpy).toHaveBeenCalledWith(
+      expect.stringContaining("Invalid environment key: INVALID-NAME"),
+    );
+    expect(errorSpy).not.toHaveBeenCalledWith(expect.stringContaining("Invalid --env key"));
+  });
+
   test("dump --annotate injects inline docs for known keys", () => {
     const configPath = path.join(tempDir, "webpack.config.js");
     fs.writeFileSync(configPath, "module.exports = { mode: 'production' }\n", "utf8");

You can send follow-ups to this agent here.

Comment thread src/cli.ts
@justin808
Copy link
Copy Markdown
Member Author

Replying to #21 (comment): addressed the selected actionable items in f44ba0a. Specifically, dump now has independent --mode handling, env-key validation happens before mutation, and --no-warn-sensitive was added for warning suppression. I left the minor cleanup suggestions (metadata sanitize no-op, array constructor-name note) as follow-up scope.

@justin808
Copy link
Copy Markdown
Member Author

Replying to #21 (comment): thanks for the walkthrough. No additional action needed from that summary/status comment beyond the concrete items already handled in f44ba0a.

@claude
Copy link
Copy Markdown

claude Bot commented Apr 2, 2026

Review: Fix issue #20 — safer dump output and diff mode handling

Overall this is a well-structured PR. The changes are logically grouped, tests cover the new behavior, and documentation is updated in sync. A few observations:

Solid fixes

  • resolveRealPath path stitching (fileWriter.ts): The old realpathSync(current) + target.slice(current.length) string concatenation was fragile — it would produce a wrong path any time the resolved real path had a different byte length than the logical path (e.g. a symlink named sym pointing to symlink-target). The new resolve(realCurrent, relative(current, target)) is semantically correct. Both imports were already present, so no new dependency surface.

  • YAML header injection guard (yamlSerializer.ts): Replacing newlines before embedding user-controlled strings into YAML comment lines is the right call. exportedAt comes from new Date().toISOString() (safe), but environment, bundler, and configType flow from user input or config file content, so the sanitization is warranted.

  • Env-var validation before mutation (cli.ts applyEnvVariables): Validating all keys in a first pass before touching process.env is the correct approach. The test that verifies NODE_ENV is unchanged after a validation failure is a good safety net.

  • getConstructorName deduplication: Three slightly-divergent copies collapsed into one is the right call. One silent behaviour change worth noting: the old configCleaner.ts version lacked the Array.isArray short-circuit and would return "Array" for actual arrays; the new version returns null early. None of the call sites treated "Array" as a meaningful match, so this is safe in practice.

Concerns / questions

NODE_ENV info message is not suppressed by --no-warn-sensitive — when --build / --all-builds resolves a build whose environment.NODE_ENV is set, a console.error is emitted per build. --no-warn-sensitive has no effect on this message. Users who set that flag expecting a quiet stderr will be surprised. Consider gating it on parsed.warnSensitive or using console.log (it is a transparency note, not a warning).

Two minor issues are left as inline comments.

Comment thread src/yamlSerializer.ts
Comment thread src/objectIntrospection.ts
Fix the no-useless-escape lint error in test/cli.integration.test.js
that was failing CI. Add lefthook for pre-commit hooks (inspired by
shakacode/react_on_rails) that run ESLint, Prettier, and trailing
newline checks in parallel on staged files before each commit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 20fa89cb8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread package.json Outdated
Copy link
Copy Markdown

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bin/lefthook/check-trailing-newlines`:
- Around line 18-20: The pre-commit hooks are running in parallel which causes
concurrent file modifications (the trailing-newlines script writes to files and
then git adds them), producing race conditions and index lock errors; update the
lefthook configuration by setting the top-level or relevant hook group option
parallel: false (change the existing parallel: true to parallel: false) so
eslint, prettier and trailing-newlines run serially when stage_fixed: true is
used, preventing concurrent git index writes.

In `@bin/lefthook/lint-branch`:
- Line 10: The script stores git paths in plain strings (changed_files,
js_files, format_files) and later expands them unquoted, which breaks on
filenames with spaces or names starting with '-'; update the git commands to
emit NUL-delimited output (use git diff --name-only -z or git ls-files -z), read
that into arrays with mapfile -d $'\0' -t (e.g., mapfile -d $'\0' -t
changed_files < <(git diff --name-only -z "$base_branch"...HEAD)), then iterate
and pass paths using quoted array expansions like "${changed_files[@]}",
"${js_files[@]}", and "${format_files[@]}" so no word-splitting or
option-parsing occurs; replace any uses of unquoted $js_files/$format_files in
loops and commands with the quoted array forms.

In `@package.json`:
- Line 64: The current POSIX-only "postinstall" npm script using shell built-ins
should be replaced with a cross-platform Node-based check: create a small Node
script (e.g., scripts/install-lefthook.js) that checks for the presence of
"lefthook.yml" and a .git directory (using fs.existsSync or fs.stat) and, if
present, spawns "npx lefthook install" (using child_process.spawnSync or
execSync) and exits gracefully on failure; then update the "postinstall" entry
to run "node ./scripts/install-lefthook.js" instead of the POSIX command so
installation works on Windows, macOS, and Linux while preserving the original
behavior around lefthook.yml and npx lefthook install.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 26485055-b98a-4cbc-8f75-76eb207d634d

📥 Commits

Reviewing files that changed from the base of the PR and between 2ce46a0 and 20fa89c.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • .gitignore
  • README.md
  • bin/lefthook/check-trailing-newlines
  • bin/lefthook/lint-branch
  • docs/cli-reference.md
  • docs/input-formats.md
  • lefthook.yml
  • package.json
  • src/cli.ts
  • test/cli.integration.test.js
✅ Files skipped from review due to trivial changes (5)
  • .gitignore
  • lefthook.yml
  • README.md
  • test/cli.integration.test.js
  • docs/cli-reference.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/input-formats.md
  • src/cli.ts

Comment thread bin/lefthook/check-trailing-newlines
Comment thread bin/lefthook/lint-branch Outdated
Comment thread package.json Outdated
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Bash-only postinstall breaks Windows consumers' installs
    • Removed the bash-only postinstall and moved lefthook installation into a cross-platform Node-based prepare command gated on lefthook.yml and .git presence.
  • ✅ Fixed: Dev-only lefthook scripts shipped to npm consumers
    • Narrowed the published files entry from bin/ to bin/pack-config-diff so internal lefthook helper scripts are excluded from npm packages.

Create PR

Or push these changes by commenting:

@cursor push 767f8d2480
Preview (767f8d2480)
diff --git a/package.json b/package.json
--- a/package.json
+++ b/package.json
@@ -29,7 +29,7 @@
   },
   "files": [
     "dist/",
-    "bin/"
+    "bin/pack-config-diff"
   ],
   "engines": {
     "node": ">=16"
@@ -60,8 +60,7 @@
   },
   "scripts": {
     "build": "tsc",
-    "prepare": "npm run build",
-    "postinstall": "test -f lefthook.yml && test -d .git && npx lefthook install || true",
+    "prepare": "npm run build && node -e \"const fs=require('node:fs');const cp=require('node:child_process');if(fs.existsSync('lefthook.yml')&&fs.existsSync('.git')){cp.execSync('npx lefthook install',{stdio:'inherit'});}\"",
     "test": "jest",
     "lint": "eslint . && prettier --check .",
     "lint:fix": "eslint --fix . && prettier --write .",

You can send follow-ups to this agent here.

Comment thread package.json Outdated
Comment thread package.json
@justin808
Copy link
Copy Markdown
Member Author

Replying to #21 (comment): addressed in 0139d67. The build NODE_ENV label stderr note is now gated by warnSensitive, so --no-warn-sensitive suppresses it. I also added an integration test for this behavior.

@justin808
Copy link
Copy Markdown
Member Author

Replying to #21 (comment) and #21 (comment): treating these as summary/superseded feedback for this pass. The selected correctness issues are addressed in 0139d67, and the remaining minor points are intentionally deferred.

Copy link
Copy Markdown

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/cli.ts`:
- Around line 744-748: The fallback NODE_ENV warning is incorrectly tied to
parsed.warnSensitive; change the condition so the build fallback warning is
shown independently of parsed.warnSensitive. Update the if in the block
referencing resolvedEnvironment.source === "build-node-env" to not include
parsed.warnSensitive (or replace it with a new dedicated flag like
parsed.warnFallbackLabel if you want explicit opt-out), ensuring the
console.error about using build.name NODE_ENV envLabel is emitted when
resolvedEnvironment.source === "build-node-env" regardless of the
--no-warn-sensitive flag.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5859a68f-eb6f-43ac-a2a6-cbbc6527cc76

📥 Commits

Reviewing files that changed from the base of the PR and between 20fa89c and 0139d67.

📒 Files selected for processing (5)
  • bin/lefthook/lint-branch
  • lefthook.yml
  • package.json
  • src/cli.ts
  • test/cli.integration.test.js
✅ Files skipped from review due to trivial changes (2)
  • lefthook.yml
  • test/cli.integration.test.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • package.json
  • bin/lefthook/lint-branch

Comment thread src/cli.ts
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0139d67cdb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread bin/lefthook/lint-branch
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Developer tooling scripts leak into published npm package
    • I removed the consumer-facing postinstall lifecycle hook by moving lefthook installation into prepare and restricted published files to bin/pack-config-diff so bin/lefthook/* is no longer packaged.
  • ✅ Fixed: Flag overloads unrelated warning and informational message
    • I decoupled the build NODE_ENV label note from warnSensitive so --no-warn-sensitive now suppresses only the sensitive-output warning while preserving the environment-label diagnostic.

Create PR

Or push these changes by commenting:

@cursor push ab5bda8874
Preview (ab5bda8874)
diff --git a/package.json b/package.json
--- a/package.json
+++ b/package.json
@@ -29,7 +29,7 @@
   },
   "files": [
     "dist/",
-    "bin/"
+    "bin/pack-config-diff"
   ],
   "engines": {
     "node": ">=16"
@@ -60,8 +60,7 @@
   },
   "scripts": {
     "build": "tsc",
-    "prepare": "npm run build",
-    "postinstall": "node -e \"const fs=require('fs');const cp=require('child_process');if(fs.existsSync('lefthook.yml')&&fs.existsSync('.git')){try{cp.execSync('npx --no-install lefthook install',{stdio:'inherit'});}catch{}}\"",
+    "prepare": "npm run build && node -e \"const fs=require('fs');const cp=require('child_process');if(fs.existsSync('lefthook.yml')&&fs.existsSync('.git')){try{cp.execSync('npx --no-install lefthook install',{stdio:'inherit'});}catch{}}\"",
     "test": "jest",
     "lint": "eslint . && prettier --check .",
     "lint:fix": "eslint --fix . && prettier --write .",

diff --git a/src/cli.ts b/src/cli.ts
--- a/src/cli.ts
+++ b/src/cli.ts
@@ -741,7 +741,7 @@
     try {
       const resolvedEnvironment = resolveBuildEnvironmentLabel(build, parsed);
       const envLabel = resolvedEnvironment.label;
-      if (resolvedEnvironment.source === "build-node-env" && parsed.warnSensitive) {
+      if (resolvedEnvironment.source === "build-node-env") {
         console.error(
           `[pack-config-diff] Using build "${build.name}" NODE_ENV="${envLabel}" as dump environment label. Pass --environment to override.`,
         );

diff --git a/test/cli.integration.test.js b/test/cli.integration.test.js
--- a/test/cli.integration.test.js
+++ b/test/cli.integration.test.js
@@ -487,7 +487,7 @@
     expect(errorOutput).not.toContain("Warning: dump output without --clean");
   });
 
-  test("dump --build --no-warn-sensitive suppresses NODE_ENV label note", () => {
+  test("dump --build keeps NODE_ENV label note when suppressing sensitive warning", () => {
     const configPath = path.join(tempDir, "webpack.config.js");
     const buildConfig = path.join(tempDir, "pack-config-diff-builds.yml");
 
@@ -528,9 +528,7 @@
 
     expect(suppressedCode).toBe(0);
     errorOutput = errorSpy.mock.calls.map((args) => String(args[0])).join("\n");
-    expect(errorOutput).not.toContain(
-      'Using build "dev" NODE_ENV="development" as dump environment',
-    );
+    expect(errorOutput).toContain('Using build "dev" NODE_ENV="development" as dump environment');
   });
 
   test("dump --annotate injects inline docs for known keys", () => {

You can send follow-ups to this agent here.

Comment thread package.json
Comment thread src/cli.ts
@justin808
Copy link
Copy Markdown
Member Author

Posting rationale for skipped summary/superseded issue comments:

  • #issuecomment-4173906177, #issuecomment-4173926124, #issuecomment-4174297894, #issuecomment-4174297939, #issuecomment-4174307809, #issuecomment-4175066392, and #issuecomment-4175066456 are either review summaries, status updates, or already-superseded discussion for this pass.
  • No additional code/test/docs action is needed from those comments beyond the concrete items already handled in this branch.

@justin808 justin808 merged commit ddee4d4 into main Apr 2, 2026
13 of 14 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.

1 participant