-
Notifications
You must be signed in to change notification settings - Fork 70
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
Expose E2E build errors #940
Expose E2E build errors #940
Conversation
50d63f7
to
586c8a1
Compare
acd31f4
to
be841aa
Compare
be841aa
to
aebbccc
Compare
aebbccc
to
9f0d8b2
Compare
node-src/tasks/build.ts
Outdated
// It's hard to know if this is the case as each package manager has a different type of | ||
// error for this, but we'll try to figure it out. | ||
const errorRegexes = ['command not found', `[\\W]?${e2eBuildBinName}[\\W]? not found`, 'code E404', 'exit code 127', `command failed.*${e2eBuildBinName}.*$`]; | ||
return errorRegexes.some((regex) => errorMessage.match(new RegExp(regex, 'gi'))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is decent advice (be careful about dynamic regexps) from Codacy but the solution doesn't make sense to me -- I could be off though. cc @paulelliott I think the AI has jumped off the deep end a bit:
a) you can't do regex.replace('${e2eBuildBinName}',...
in a previously interpolated string regex
, it's already been replaced.
b) it doesn't change anything to do it at that stage anyway (say if we changed the original string :
// from
`[\\W]?${e2eBuildBinName}[\\W]? not found`
// to
'[\\W]?${e2eBuildBinName}[\\W]? not found'
Then the string wouldn't automatically get interpolated with the var, but I don't understand why it would be better to later do a .replace()
to manually interpolate.
node-src/tasks/build.ts
Outdated
// It's hard to know if this is the case as each package manager has a different type of | ||
// error for this, but we'll try to figure it out. | ||
const errorRegexes = ['command not found', `[\\W]?${e2eBuildBinName}[\\W]? not found`, 'code E404', 'exit code 127', `command failed.*${e2eBuildBinName}.*$`]; | ||
return errorRegexes.some((regex) => errorMessage.match(new RegExp(regex, 'gi'))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@paulelliott my feeling is the AI is getting really wordy here and I am glazing over and missing the key points:
- Be careful about dynamic strings in regexps
- You can comment away the warning
- However, be super careful if you are going to do that, and document why it's safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it, thanks for working through it @tevanoff
'exit code 127', // Exit code 127 is a generic not found exit code | ||
`command failed.*${e2eBuildBinName}.*$`]; // A single line error from execa like `Command failed: yarn build-archive-storybook ...` | ||
|
||
return errorRegexes.some((regex) => (new RegExp(regex, 'gi')).test(errorMessage)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RegExp
constructor was called with a non-literal value.
The security issue identified by Semgrep is related to the use of the RegExp
constructor with a non-literal value. This can potentially lead to a Regular Expression Denial of Service (ReDoS) attack if an attacker is able to control the pattern passed to RegExp
, especially if they can provide a complex pattern that can cause the application to hang due to excessive backtracking.
In this specific case, the variable e2eBuildBinName
is interpolated into a regex pattern, which could be a concern if e2eBuildBinName
is user-controlled or can be manipulated. However, without more context, it's unclear if e2eBuildBinName
is a constant, an environment variable, or user input.
Assuming e2eBuildBinName
is a safe, constant value that does not come from user input, you could pre-compile the regexes with the interpolated value to both improve performance and satisfy the linter. If e2eBuildBinName
is not a constant and can vary at runtime, it's important to sanitize or escape it before using it in a regex pattern to prevent ReDoS attacks.
Here's a single line code suggestion that pre-compiles the regexes assuming e2eBuildBinName
is a safe, constant value:
return errorRegexes.some((regex) => (new RegExp(regex, 'gi')).test(errorMessage)); | |
return errorRegexes.some((regex) => RegExp(regex.replace('${e2eBuildBinName}', e2eBuildBinName), 'gi').test(errorMessage)); |
This suggestion replaces the backticks and ${e2eBuildBinName}
interpolation with a replace
call that only happens once, assuming e2eBuildBinName
is not dynamic. If e2eBuildBinName
is dynamic, you would need to ensure it is properly escaped to prevent it from being used in an attack.
This comment was generated by an experimental AI tool.
'exit code 127', // Exit code 127 is a generic not found exit code | ||
`command failed.*${e2eBuildBinName}.*$`]; // A single line error from execa like `Command failed: yarn build-archive-storybook ...` | ||
|
||
return errorRegexes.some((regex) => (new RegExp(regex, 'gi')).test(errorMessage)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
regex
function argument, this might allow an attacker to cause a Regular Expression Denial-of-Service (ReDoS) within your application as RegExP blocks the main thread.
The issue identified by Semgrep is related to the potential for a Regular Expression Denial of Service (ReDoS) attack. This can happen when user input or a variable that can be influenced by user input is used to dynamically create a regular expression. If an attacker provides a specially crafted input, it can create a regular expression that takes a very long time to evaluate, effectively blocking the main thread and causing a denial of service.
In the provided code, the variable e2eBuildBinName
is interpolated into a string that is then used to create a regular expression. If e2eBuildBinName
is or can be influenced by user input, it could be exploited to cause a ReDoS attack.
To mitigate this, we need to sanitize or escape the variable e2eBuildBinName
before using it in the regular expression. However, since the code suggestion must be a single line change and we don't have the context for where e2eBuildBinName
is coming from, a general solution could be to use a library like lodash
to escape RegExp special characters.
Here's a single line code suggestion that uses the escapeRegExp
function from lodash
to escape any special characters in e2eBuildBinName
before using it in the regex:
return errorRegexes.some((regex) => (new RegExp(regex, 'gi')).test(errorMessage)); | |
`[\\W]?${_.escapeRegExp(e2eBuildBinName)}[\\W]? not found`, // `Command "build-archive-storybook" not found` |
Please note that for this suggestion to work, you must ensure that the lodash
library is installed and imported in your code as _
. If lodash
is not already a dependency, you will need to add it to your project and import the escapeRegExp
function:
return errorRegexes.some((regex) => (new RegExp(regex, 'gi')).test(errorMessage)); | |
import _ from 'lodash'; |
Or, if you prefer to import only the needed function:
return errorRegexes.some((regex) => (new RegExp(regex, 'gi')).test(errorMessage)); | |
import { escapeRegExp } from 'lodash'; |
This comment was generated by an experimental AI tool.
🚀 PR was released in |
Currently, any error thrown during the build step of an E2E build is treated as a missing dependency error, and the error message output is very specific to that. However, the build can fail for other reasons, such as archive directory not found. These other legit errors are swallowed and the resulting output is confusing.
This flips things around to try to determine if the error is due to a missing dependency, where the error usually has something to do about a command not being found. If the error message doesn't match, this will output a more generic error message that includes the original error message.
How to test
chromaui/action-canary@v1
), test a project with the above two scenarios and see that the errors are correct.📦 Published PR as canary version:
11.0.7--canary.940.8195253022.0
✨ Test out this PR locally via: