Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

util: fix parseEnv handling of invalid lines #56778

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

AugustinMauroy
Copy link
Member

This PR fixes an issue with util.parseEnv() where invalid lines in the input were being incorrectly concatenated into key names instead of being skipped. The fix ensures that lines without an equals sign are properly skipped during parsing

Fixes: #56775

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. labels Jan 26, 2025
@AugustinMauroy AugustinMauroy force-pushed the util-fix-parseEnv-handling-of-invalid-lines branch from de3dd86 to 8dd566f Compare January 26, 2025 23:53
Copy link
Member

@anonrig anonrig left a comment

Choose a reason for hiding this comment

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

Nice work!

Even though this test pass, I strongly recommend adding as much as comment possible while simplifying your code. Our parser is already complex (due to not using a regex) and it would help a lot if we know why such decision is taken in the parser.

test/parallel/test-dotenv-invalid-syntax.js Outdated Show resolved Hide resolved
src/node_dotenv.cc Outdated Show resolved Hide resolved
src/node_dotenv.cc Show resolved Hide resolved
src/node_dotenv.cc Outdated Show resolved Hide resolved
src/node_dotenv.cc Outdated Show resolved Hide resolved
continue;
} else {
break;
Copy link
Member

Choose a reason for hiding this comment

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

Please add a comment here. Explain it as much as you can. Possibly with examples so it is more readable/understandable to reviewers/contributors.

Copy link

codecov bot commented Jan 27, 2025

Codecov Report

Attention: Patch coverage is 85.71429% with 5 lines in your changes missing coverage. Please review.

Project coverage is 89.22%. Comparing base (ea7ab16) to head (db57145).
Report is 13 commits behind head on main.

Files with missing lines Patch % Lines
src/node_dotenv.cc 85.71% 3 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #56778      +/-   ##
==========================================
- Coverage   89.24%   89.22%   -0.03%     
==========================================
  Files         662      663       +1     
  Lines      191919   191990      +71     
  Branches    36911    36921      +10     
==========================================
+ Hits       171284   171297      +13     
- Misses      13525    13566      +41     
- Partials     7110     7127      +17     
Files with missing lines Coverage Δ
src/node_dotenv.cc 92.85% <85.71%> (+0.07%) ⬆️

... and 44 files with indirect coverage changes

@AugustinMauroy
Copy link
Member Author

Yup yagizz, I had tried to apply yours suggestions. I'm reaching my limit in C++. So I hope that this time if it's good.

if (content.front() == '\n' || content.front() == '#') {
auto newline = content.find('\n');
if (newline != std::string_view::npos) {
content.remove_prefix(newline + 1);
// Trim spaces after skipping comments or empty lines to handle
// cases where there might be trailing whitespace
Copy link
Member

Choose a reason for hiding this comment

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

Can you give an example to this statement?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure but:

Suggested change
// cases where there might be trailing whitespace
// cases where there might be trailing whitespace
// Example: " # comment\n KEY=value"

// Example:
// # This is a comment
//
// KEY=value
if (content.front() == '\n' || content.front() == '#') {
auto newline = content.find('\n');
Copy link
Member

Choose a reason for hiding this comment

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

If content.front() is \n this will always return 0 (the first character). I wonder why we did it like this...

Copy link
Member

Choose a reason for hiding this comment

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

We can simply replace line 144 with if (content.front() == '\n') and remove the content.find('\n') check I guess...

src/node_dotenv.cc Outdated Show resolved Hide resolved
auto pos = content.find_first_of("=\n");

// If we found nothing or found a newline before equals, the line is invalid
if (pos == std::string_view::npos || content[pos] == '\n') {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (pos == std::string_view::npos || content[pos] == '\n') {
if (pos == std::string_view::npos || content.at(pos) == '\n') {

Copy link
Member Author

Choose a reason for hiding this comment

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

what is diff bettween [xxx] and .at(xxx) ?

if (equal == std::string_view::npos) {
// Find the next equals sign or newline in a single pass
// This optimizes the search by avoiding multiple iterations
auto pos = content.find_first_of("=\n");
Copy link
Member

Choose a reason for hiding this comment

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

Can we change the variable name to be something more readable?

Suggested change
auto pos = content.find_first_of("=\n");
auto equal_or_newline = content.find_first_of("=\n");

if (key.empty()) {
auto newline = content.find('\n');
if (newline != std::string_view::npos) {
content.remove_prefix(newline + 1);
Copy link
Member

Choose a reason for hiding this comment

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

if newline is the last character, this will literally clear the content and we don't need to call trim_spaces afterwards.

}

// SAFETY: Content is guaranteed to have at least one character
// If content is empty after the equals sign, store empty value and break
Copy link
Member

Choose a reason for hiding this comment

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

This comment is unneccessary. It explains the code, not how it got end up here. I recommend this article: https://swimm.io/learn/code-collaboration/comments-in-code-best-practices-and-mistakes-to-avoid

Specifically:

Explain the reasoning behind the code, not just what the code is doing.

Copy link
Member Author

Choose a reason for hiding this comment

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

Got it

store_.insert_or_assign(std::string(key), "");
break;
}

// Expand new line if \n it's inside double quotes
// Example: EXPAND_NEWLINES = 'expand\nnew\nlines'
// Handle different types of value formats (quoted, multi-line, etc)
Copy link
Member

Choose a reason for hiding this comment

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

Can you revert this code change. The previous comment was better for understanding where we are at the parser.

if (closing_quote == std::string_view::npos) {
// Check if newline exist. If it does, take the entire line as the value
// Example: KEY="value\nKEY2=value2
Copy link
Member

Choose a reason for hiding this comment

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

Can you revert comments for the changes that are unrelated to your code? This change for example doesn't make things better.

@anonrig
Copy link
Member

anonrig commented Jan 27, 2025

Yup yagizz, I had tried to apply yours suggestions. I'm reaching my limit in C++. So I hope that this time if it's good.

I see lots of changes unrelated to your PR. Can you revert everything that is unrelated to your change?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

util.parseEnv creates keys from invalid, newline-separated lines
3 participants