-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
feat: Implement Yarn Berry Analyser #7319
base: main
Are you sure you want to change the base?
Conversation
Thank you so much for this! This really simplifies our lives with multi-language projects driven by a Maven build (Java backend, JavaScript frontend). Btw, it might also fix #4215. I think this can and should be improved to reduce future maintenance costs. Think about what happens when Yarn releases the next breaking change (like classic --> Berry)? I would like to see a Yarn analyzer abstraction with some sort of auto-detection mechanism. IMO users should only have to set the Can you extract a |
@marcelstoer completely agree - your suggestions are spot on. |
With the updated PR, I have refactored |
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.
LGTM - I left some suggestions around the yarn version number. I prefer to use something like semver4j
as we already have it on the classpath.
protected String getYarnMajorVersion() { | ||
if (StringUtils.isBlank(yarnVersion)) { | ||
throw new IllegalArgumentException("Version string cannot be null or empty"); | ||
} | ||
String[] parts = yarnVersion.split("\\."); | ||
if (parts.length == 0) { | ||
throw new IllegalArgumentException("Invalid version string format"); | ||
} | ||
return parts[0]; | ||
} |
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.
Consider:
protected String getYarnMajorVersion() { | |
if (StringUtils.isBlank(yarnVersion)) { | |
throw new IllegalArgumentException("Version string cannot be null or empty"); | |
} | |
String[] parts = yarnVersion.split("\\."); | |
if (parts.length == 0) { | |
throw new IllegalArgumentException("Invalid version string format"); | |
} | |
return parts[0]; | |
} | |
protected int getYarnMajorVersion() { | |
if (StringUtils.isBlank(yarnVersion)) { | |
throw new IllegalArgumentException("Version string cannot be null or empty"); | |
} | |
try { | |
Semver semver = new Semver(yarnVersion); | |
return semver.getMajor(); | |
} catch (SemverException e) { | |
throw new IllegalArgumentException("Invalid version string format", e); | |
} | |
} |
import org.owasp.dependencycheck.dependency.Dependency; | ||
import org.owasp.dependencycheck.exception.InitializationException; | ||
import org.owasp.dependencycheck.utils.FileFilterBuilder; | ||
import org.owasp.dependencycheck.utils.Settings; | ||
import org.owasp.dependencycheck.utils.URLConnectionFailureException; | ||
import org.owasp.dependencycheck.utils.processing.ProcessReader; | ||
import org.slf4j.Logger; |
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.
import org.slf4j.Logger; | |
import org.semver4j.Semver; | |
import org.semver4j.SemverException; | |
import org.slf4j.Logger; |
return; | ||
} | ||
var yarnMajorVersion = getYarnMajorVersion(); | ||
if ("1".equals(yarnMajorVersion)) { |
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.
if ("1".equals(yarnMajorVersion)) { | |
if (yarnMajorVersion == 1) { |
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.
Changing the comparison isn't addressing the real issue IMO.
I'm with all those who see magic numbers or magic strings as an anti-pattern. The suggested fix usually is to use (properly) named constants. In this case, however, that would only improve the legibility of the code but would not improve its long-term stability.
At this point, all we know is that the Yarn classic analyzer supports Yarn v1 and that the Yarn Berry analyzer supports Yarn v2. We are not in a position to make any promises as for a potential future Yarn v3. The Berry analyzer may or may not support it. To play it safe, I'd like to see an ok-list approach.
Suggestion:
- Declare an
abstract supportedNodeMajorVersions()
method inAbstractYarnAuditAnalyzer
that returns an array ofint
s or a set ofInt
s. - Let both sub classes implement it to the best of their knowledge. Hence, both would currently return a set containing a single value.
- Add a
boolean isYarnVersionSupported()
method toAbstractYarnAuditAnalyzer
that comparessupportedNodeVersions()
against the return value ofgetYarnMajorVersion()
(major contained in list of supported). Nice side effect:getYarnMajorVersion()
can likely be madeprivate
. - The
prepareFileTypeAnalyzer()
implementations would thus be shielded from all that complexity as they would only need to do anif (!isYarnVersionSupported())
-then-disable-analyzer.
This idea could be spun even further but that would require more refactoring.
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.
Yarn v3 and v4 already exist, and are considered part of the 'berry' family. Current version is 4.6.0. It's reasonable to consider this analyzer will be required indefinitely.
Is this a theoretical objection, or are you familiar with modern Yarn and its compat/history?
We don't lock other analyzers against software versions that might be released in future. Given the yarn analyzer has been broken for years now with respect to current yarn I don't think adding more maintenance overhead to specifically check new versions is necessary?
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.
As you might have guessed, I'm not at all familiar with anything related to Yarn. Also, I don't consider my comment to be an objection but merely a suggestion. When I scanned the PR initially, the magic numbers stuck out immediately.
It's reasonable to consider this analyzer will be required indefinitely.
If that's true, then my suggestion doesn't make much sense. Thanks for pointing that out.
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.
Yup, no worries - appreciate the thoughtful input - even if theoretical :-) Magic numbers can indeed be a bit gross and it's reasonable to debate about Yarn's compatibility guarantees for this stuff over time.
It does occur to me to contemplate whether the "berry" analyzer as it is here works the same back through yarn 2 / 3 /4 as I cannot recall off the top of my head when it was introduced or whether format has changed.
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.
Converting the comparison to use int
will make it easier to implement a new analyzer if a successor to yarn berry has a different format.
return; | ||
} | ||
var yarnMajorVersion = getYarnMajorVersion(); | ||
if (!"1".equals(yarnMajorVersion)) { |
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.
if (!"1".equals(yarnMajorVersion)) { | |
if (yarnMajorVersion > 1) { |
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.
Ditto
/** | ||
* Extracts the major version from a version string. | ||
* | ||
* @return the major version (e.g., "4" from "4.2.1") |
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.
* @return the major version (e.g., "4" from "4.2.1") | |
* @return the major version (e.g., `4` from "4.2.1") |
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.
It looks like the build failed:
YarnBerryAuditAnalyzerIT.testAnalyzePackageYarn:46 More than 1 dependency should be identified
Do we need to update the workflow itself to include yarn berry?
FWIW the canonical way to run and install yarn 2+ is via corepack and source controlling yarn itself alongside a package.json which defines the version number. https://yarnpkg.com/getting-started/install Although you can use yarn 1 to switch dynamically to yarn 2+.projects if you have to. Ideally the tests should test a project that has package.json etc preconfigured for yarn usage and 'corepack enable' run on the npm install. This has the advantage that specific yarn versions are source controlled alongside the tests in the |
@segovia thanks for the updated version. This is much more maintainable now! |
I have implemented an Analyzer to address the issue that DependencyCheck does not work with projects that use yarn berry (#4894). This is a first draft and I would be happy to implement tests and make any other modifications if there is interest to merge this to main.