Skip to content

Commit ff694a0

Browse files
a-orenclaude
andauthored
feat: expose package manager name in componentAnalysis result (guacsec#518)
* feat: expose package manager name in componentAnalysis result Attach the matched provider's command name (e.g. pip, uv, poetry) as `packageManager` on the component analysis result so IDE consumers can display provider-specific instructions without re-implementing detection. Jira: TC-4336 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: add packageManagerName as public API for all providers Keep _cmdName as the internal/protected method for binary resolution and add packageManagerName() as the proper public method on every provider. This ensures result.packageManager is always set for all providers, not just when _cmdName happens to exist. Jira: TC-4336 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent bbe2094 commit ff694a0

8 files changed

Lines changed: 31 additions & 5 deletions

File tree

src/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,9 @@ async function componentAnalysis(manifest, opts = {}) {
210210
fs.accessSync(manifest, fs.constants.R_OK)
211211
opts["manifest-type"] = path.basename(manifest)
212212
let provider = match(manifest, availableProviders, opts) // throws error if no matching provider
213-
return await analysis.requestComponent(provider, manifest, theUrl, opts) // throws error request sending failed
213+
const result = await analysis.requestComponent(provider, manifest, theUrl, opts) // throws error request sending failed
214+
result.packageManager = provider.packageManagerName()
215+
return result
214216
}
215217

216218
/**

src/provider.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import Python_uv from './providers/python_uv.js'
1515
import rustCargoProvider from './providers/rust_cargo.js'
1616

1717
/** @typedef {{ecosystem: string, contentType: string, content: string}} Provided */
18-
/** @typedef {{isSupported: function(string): boolean, validateLockFile: function(string, Object): void, provideComponent: function(string, {}): Provided | Promise<Provided>, provideStack: function(string, {}): Provided | Promise<Provided>, readLicenseFromManifest: function(string): string | null}} Provider */
18+
/** @typedef {{isSupported: function(string): boolean, validateLockFile: function(string, Object): void, provideComponent: function(string, {}): Provided | Promise<Provided>, provideStack: function(string, {}): Provided | Promise<Provided>, readLicenseFromManifest: function(string): string | null, packageManagerName: function(): string}} Provider */
1919

2020
/**
2121
* MUST include all providers here.

src/providers/base_java.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ export default class Base_Java {
3535
this.localWrapper = localWrapper
3636
}
3737

38+
/**
39+
* Returns the package manager name (e.g. mvn, gradle)
40+
* @returns {string}
41+
*/
42+
packageManagerName() {
43+
return this.globalBinary
44+
}
45+
3846
/**
3947
* Recursively populates the SBOM instance with the parsed graph
4048
* @param {string} src - Source dependency to start the calculations from

src/providers/base_javascript.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ export default class Base_javascript {
8282
throw new TypeError("_cmdName must be implemented");
8383
}
8484

85+
/**
86+
* Returns the package manager name (e.g. npm, yarn, pnpm, bun)
87+
* @returns {string} The package manager name
88+
*/
89+
packageManagerName() {
90+
return this._cmdName();
91+
}
92+
8593
/**
8694
* Returns the command arguments for listing dependencies
8795
* @returns {Array<string>} The command arguments

src/providers/base_pyproject.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,14 @@ export default class Base_pyproject {
168168
throw new TypeError('_cmdName must be implemented')
169169
}
170170

171+
/**
172+
* Returns the package manager name (e.g. pip, poetry, uv)
173+
* @returns {string}
174+
*/
175+
packageManagerName() {
176+
return this._cmdName()
177+
}
178+
171179
/**
172180
* Resolve dependencies using the tool-specific command and parser.
173181
*

src/providers/golang_gomodules.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { filterManifestPathsByDiscoveryIgnore, resolveWorkspaceDiscoveryIgnore }
1010

1111
import { getParser, getRequireQuery } from './gomod_parser.js'
1212

13-
export default { isSupported, validateLockFile, provideComponent, provideStack, readLicenseFromManifest }
13+
export default { isSupported, validateLockFile, provideComponent, provideStack, readLicenseFromManifest, packageManagerName() { return 'go' } }
1414

1515
/** @typedef {import('../provider').Provider} */
1616

src/providers/python_pip.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
import Python_controller from './python_controller.js'
1515
import { getParser, getIgnoreQuery, getPinnedVersionQuery } from './requirements_parser.js'
1616

17-
export default { isSupported, validateLockFile, provideComponent, provideStack, readLicenseFromManifest }
17+
export default { isSupported, validateLockFile, provideComponent, provideStack, readLicenseFromManifest, packageManagerName() { return 'pip' } }
1818

1919
/** @typedef {{name: string, version: string, dependencies: DependencyEntry[], hashes?: Array<{alg: string, content: string}>}} DependencyEntry */
2020

src/providers/rust_cargo.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { getLicense } from '../license/license_utils.js'
88
import Sbom from '../sbom.js'
99
import { getCustom, getCustomPath, invokeCommand } from '../tools.js'
1010

11-
export default { isSupported, validateLockFile, provideComponent, provideStack, readLicenseFromManifest }
11+
export default { isSupported, validateLockFile, provideComponent, provideStack, readLicenseFromManifest, packageManagerName() { return 'cargo' } }
1212

1313
/** @typedef {import('../provider').Provider} */
1414

0 commit comments

Comments
 (0)