-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Enable CorePack Installing Package Managers from Private Registries #11077
Enable CorePack Installing Package Managers from Private Registries #11077
Conversation
Related issue: |
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.
The logic looks ok, but I'm not sure about adding another class and another level of code indirection to this ecosystem
|
||
module Dependabot | ||
module NpmAndYarn | ||
class RegistryHelper |
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's not entirely clear why this is its own class when it's calls are already fully encapsulated within PackageManagerHelper
If this is meant to be reused in other places, WDYT about providing a RegistryHelper
instance to PackageManagerHelper.new
instead of creating it in the constructor?
Otherwise if it's not reused elsewhere could this be collapsed into PackageManagerHelper
? This could always be broken out into a separate class later if/when needed for reuse or portability.
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.
can be moved into PackageManagerHelper
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 is just moved.
let(:yarnrc_file) do | ||
Dependabot::DependencyFile.new( | ||
name: ".yarnrc", | ||
content: <<~YARNRC |
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.
.yarnrc
is usually space delimited https://github.com/search?q=path%3A.yarnrc&type=code
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.
Checking
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.
fixed.
def find_registry_and_token | ||
# Step 1: Check dependabot.yml configuration | ||
dependabot_config = config_npm_registry_and_token | ||
return dependabot_config if dependabot_config[:registry] |
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.
Not every NPM registry is also a reverse-proxy style registry, for instance npm.pkg.github.com which is usually scoped to a specific package. So if a customer had a private scoped package on a registry that wasn't a reverse-proxy, and they used dependabot.yml to provide credentials, corepack would try to download from there which would fail.
It might be better to look for replaces-base
only which indicates it's a reverse-proxy style registry.
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’ve updated the code to ensure that the config_npm_registry_and_token
method only returns the object if the registry is reverse-proxy-enabled (i.e., when replaces-base
is true
). Could you please confirm if this aligns with what you meant in your comment?
@@ -305,6 +304,126 @@ def unsupported? | |||
end | |||
end | |||
|
|||
class RegistryHelper |
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.
Sorry if my previous comment was confusing, I was not referring to the location of the class. What I meant to ask was why this needed to be a standalone class at all?
The class contains two instance variables which are also known by PackageManagerHelper
, and all other logic is entirely functional in that there are no changes to stored state. The class is also instantiated in one place only - the constructor of PackageManagerHelper
.
The functional nature of the class combined with it's highly scoped usage makes me think that one of two things should be going on here:
- If the registry helper is meant to be reusable outside of
PackageManagerHelper
then it should be instantiated outside ofPackageManagerHelper
and passed in as an argument. In this way thePackageManagerHelper
is entirely agnostic to the idea of registry credentials and configurations
e.g. PackageManagerHelper.new(package_json, lockfiles, registry_helper)
- If the
RegistryHelper
is only ever going to be used within the code ofPackageManagerHelper
, thenRegistryHelper
should not be a standalone class. If you want to isolate this logic, you could easily make the class into a module that gets included intoPackageManagerHelper
e.g.
module RegistryHelper
# expect anything including this helper to have accesors for registry_config_files and credentials
...
end
class PackageManagerHelper
include RegistryHelper
attr_reader :registry_config_files, :credentials
def initialize(package_json, lockfiles, registry_config_files, credentials)
...
@registry_config_files = registry_config_files
@credentials = credentials
...
end
end
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.
Thank you for the feedback! The reason I structured it this way is that the long-term goal is to centralize all registry-related logic within the RegistryHelper
class. This approach allows us to handle all registry-related operations in one place, making it easier for others to extend or modify the logic in the future, should the need arise for additional registry-related functionality.
By encapsulating the related constants, variables, and logic in a dedicated class, I’m aiming to keep the code clean, modular, and reusable. Using a module would require passing parameters to each function or tightly coupling the logic to PackageManagerHelper
, which I believe would reduce flexibility and reusability.
I hope this clarifies my rationale, and I’m happy to discuss further if needed!
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 can pass registry helper as a object into package manager helper. That can be another way of using it but I am also using similar parameters such as lockfiles
. So that's why I initiated the registry helper in the package manager helper.
|
||
# Environment variable keys | ||
COREPACK_NPM_REGISTRY_ENV = "COREPACK_NPM_REGISTRY" | ||
COREPACK_NPM_TOKEN_ENV = "COREPACK_NPM_TOKEN" |
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 suspect setting COREPACK_NPM_TOKEN_ENV
is not necessary as the Proxy container will inject the needed credentials. But there may be folks out there still using the Ruby directly and handing it tokens. So fine to leave for now.
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.
Functionality seems good though I don't like the amount of parsing we need to do to extract the registry. Seems like a source of bugs in the future. Perhaps this will allow us to delete all this code some day: nodejs/corepack#540
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'm not a fan of pre-optimizing code for unknown future usage, but if the solution works and @jakecoffman has no other feedback then I wouldn't block this moving forward
What are you trying to accomplish?
This PR addresses an issue where Corepack was unable to install a package manager from private registries. The problem was encountered in a private repository, and the proposed solution ensures that the correct registry and authentication token are provided for Corepack to successfully install the package manager.
By creating a
RegistryHelper
class and enabling it to parse and provide the required environment variables (COREPACK_NPM_REGISTRY
andCOREPACK_NPM_TOKEN
), this change fixes the issue and adds support for private registries.Anything you want to highlight for special attention from reviewers?
The following changes were implemented:
RegistryHelper
from a module to a class for better encapsulation.dependabot.yml
credentials,.npmrc
,.yarnrc
,yarnrc.yml
, and lockfiles when determining the registry and authentication token.How will you know you've accomplished your goal?
The following steps demonstrate the success of this change:
dependabot.yml
credentials,.npmrc
,.yarnrc
,yarnrc.yml
, or lockfile configurations are provided.Checklist