This is an automated email from the ASF dual-hosted git repository.
hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-gateway.git
The following commit(s) were added to refs/heads/master by this push:
new 3eb88f3 fix(agent): detect agents under a custom npm prefix
3eb88f3 is described below
commit 3eb88f3f8efb52e899e4890ef5e4ff2a051219a0
Author: Yang Luo <[email protected]>
AuthorDate: Thu Aug 20 10:08:44 2026 +0800
fix(agent): detect agents under a custom npm prefix
---
agent/scan_common.go | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++
agent/scan_unix.go | 2 +-
agent/scan_windows.go | 6 ++--
3 files changed, 84 insertions(+), 4 deletions(-)
diff --git a/agent/scan_common.go b/agent/scan_common.go
index aa72c53..b25c12d 100644
--- a/agent/scan_common.go
+++ b/agent/scan_common.go
@@ -21,6 +21,7 @@ import (
"os/exec"
"os/user"
"path/filepath"
+ "regexp"
"runtime"
"sort"
"strings"
@@ -31,6 +32,12 @@ import (
// maxPackageJSONSize limits reads from glob-matched manifests.
const maxPackageJSONSize = 1024 * 1024
+// maxNpmrcSize limits reads from npmrc files.
+const maxNpmrcSize = 64 * 1024
+
+// npmrcEnvRef matches the ${VAR} references npm expands in npmrc values.
+var npmrcEnvRef = regexp.MustCompile(`\$\{([^{}]+)\}`)
+
// scanNpmPatterns validates npm packages found by known glob patterns.
func scanNpmPatterns(ctx context.Context, fingerprint *Fingerprint, patterns
[]string, owner string, ownerFor func(string) string) []Installation {
if fingerprint.NpmPackage == "" {
@@ -79,6 +86,79 @@ func (f *Fingerprint) npmPackagePath() string {
return filepath.FromSlash(f.NpmPackage)
}
+// isCurrentHome reports whether path is the home of the user this process runs
+// as, the only profile the environment describes.
+func isCurrentHome(path string) bool {
+ current, err := os.UserHomeDir()
+ if err != nil {
+ return false
+ }
+ current, path = filepath.Clean(current), filepath.Clean(path)
+ if runtime.GOOS == "windows" {
+ return strings.EqualFold(current, path)
+ }
+ return current == path
+}
+
+// npmrcPrefix returns the "prefix" setting of an npmrc file, later keys
winning
+// as in npm's own ini parsing.
+func npmrcPrefix(path string) string {
+ info, err := os.Stat(path)
+ if err != nil || !info.Mode().IsRegular() || info.Size() > maxNpmrcSize
{
+ return ""
+ }
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return ""
+ }
+ prefix := ""
+ for _, line := range strings.Split(string(data), "\n") {
+ key, value, ok := strings.Cut(line, "=")
+ if !ok || strings.TrimSpace(key) != "prefix" {
+ continue
+ }
+ prefix = strings.Trim(strings.TrimSpace(value), `"'`)
+ }
+ return npmrcEnvRef.ReplaceAllStringFunc(prefix, func(ref string) string
{
+ return os.Getenv(ref[2 : len(ref)-1])
+ })
+}
+
+// npmPrefixPatterns cover a global root relocated with "npm config set
prefix",
+// which falls outside every fixed layout. Windows keeps the packages directly
+// under the prefix, Unix under lib/.
+func npmPrefixPatterns(fingerprint *Fingerprint, home string) []string {
+ var prefixes []string
+ if isCurrentHome(home) {
+ // npm accepts either case for its environment config.
+ prefixes = append(prefixes, os.Getenv("npm_config_prefix"),
os.Getenv("NPM_CONFIG_PREFIX"))
+ }
+ prefixes = append(prefixes, npmrcPrefix(filepath.Join(home, ".npmrc")))
+
+ pkg := fingerprint.npmPackagePath()
+ seen := map[string]bool{}
+ var patterns []string
+ for _, prefix := range prefixes {
+ prefix = filepath.Clean(strings.TrimSpace(prefix))
+ if !filepath.IsAbs(prefix) {
+ continue
+ }
+ key := prefix
+ if runtime.GOOS == "windows" {
+ key = strings.ToLower(key)
+ }
+ if seen[key] {
+ continue
+ }
+ seen[key] = true
+ patterns = append(patterns,
+ filepath.Join(prefix, "node_modules", pkg,
"package.json"),
+ filepath.Join(prefix, "lib", "node_modules", pkg,
"package.json"),
+ )
+ }
+ return patterns
+}
+
func stampAgentId(installations []Installation, mark int, agentId string) {
for i := mark; i < len(installations); i++ {
installations[i].AgentId = agentId
diff --git a/agent/scan_unix.go b/agent/scan_unix.go
index 8883c06..ca8e58c 100644
--- a/agent/scan_unix.go
+++ b/agent/scan_unix.go
@@ -73,7 +73,7 @@ func userNpmPatterns(fingerprint *Fingerprint, home string)
[]string {
for _, dir := range fingerprint.ExtraUnixNpmDirs {
patterns = append(patterns, filepath.Join(home,
filepath.FromSlash(dir), "node_modules", pkg, "package.json"))
}
- return patterns
+ return append(patterns, npmPrefixPatterns(fingerprint, home)...)
}
func fileOwner(path string) string {
diff --git a/agent/scan_windows.go b/agent/scan_windows.go
index f9feb43..ae30d36 100644
--- a/agent/scan_windows.go
+++ b/agent/scan_windows.go
@@ -147,7 +147,7 @@ func windowsHomes(ctx context.Context) []homeDir {
// appDataDir respects relocated AppData paths for the current user.
func appDataDir(home homeDir, kind, variable string) string {
- if current, err := os.UserHomeDir(); err == nil &&
strings.EqualFold(filepath.Clean(current), filepath.Clean(home.path)) {
+ if isCurrentHome(home.path) {
if configured := os.Getenv(variable); configured != "" {
return configured
}
@@ -160,8 +160,7 @@ func roamingAppData(home homeDir) string { return
appDataDir(home, "Roaming", "A
func scanHermesWindows(home homeDir) []Installation {
hermesHome := filepath.Join(localAppData(home), "hermes")
- if current, err := os.UserHomeDir(); err == nil &&
- strings.EqualFold(filepath.Clean(current),
filepath.Clean(home.path)) {
+ if isCurrentHome(home.path) {
if configured := os.Getenv("HERMES_HOME"); configured != "" {
hermesHome = configured
}
@@ -329,5 +328,6 @@ func scanWindowsNpm(ctx context.Context, fingerprint
*Fingerprint, home homeDir)
for _, dir := range fingerprint.ExtraWindowsNpmDirs {
patterns = append(patterns, filepath.Join(local,
filepath.FromSlash(dir), "node_modules", pkg, "package.json"))
}
+ patterns = append(patterns, npmPrefixPatterns(fingerprint,
home.path)...)
return scanNpmPatterns(ctx, fingerprint, patterns, home.owner, nil)
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]