fix(scripts): eliminate false positives in dependency pinning npm pattern#273
Conversation
…tern Replace regex-based pattern matching with JSON parsing for package.json validation, targeting only dependency sections. - Add Get-NpmDependencyViolations function that parses package.json as structured JSON and checks only dependencies, devDependencies, peerDependencies, and optionalDependencies sections - Update npm pattern config to use ValidationFunc dispatcher instead of VersionPatterns - Add ValidationFunc dispatch logic to Get-DependencyViolation for type-specific validation functions - Create test fixtures for metadata-only and with-dependencies npm scenarios - Add Pester tests covering JSON parsing, dependency extraction, and version pattern matching Resolves false positives from metadata fields like name, version, description, and repository URLs being flagged as unpinned dependencies. Fixes #267 🔧 - Generated by Copilot
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #273 +/- ##
==========================================
+ Coverage 28.78% 29.44% +0.66%
==========================================
Files 14 14
Lines 2738 2785 +47
==========================================
+ Hits 788 820 +32
- Misses 1950 1965 +15
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR fixes false positives in npm dependency pinning checks by moving from regex matching to structured JSON parsing of package.json, so only actual dependency sections are validated.
Changes:
- Added
Get-NpmDependencyViolationsto parsepackage.jsonand scan only dependency sections. - Introduced
ValidationFuncdispatch inGet-DependencyViolationto support type-specific validators. - Updated/added Pester tests and npm JSON fixtures, and aligned
Test-ShellDownloadSecurityto accept a consistentFileInfohashtable.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| scripts/security/Test-DependencyPinning.ps1 | Adds JSON-based npm validation and ValidationFunc dispatch; updates shell download validator signature. |
| scripts/tests/security/Test-DependencyPinning.Tests.ps1 | Updates shell-download tests to pass FileInfo; adds unit tests for npm JSON parsing/validation. |
| scripts/tests/Fixtures/Npm/metadata-only-package.json | Fixture to ensure metadata-only package.json doesn’t produce violations. |
| scripts/tests/Fixtures/Npm/with-dependencies-package.json | Fixture containing multiple dependency sections to validate detection logic. |
- add invalid-json-package.json fixture for JSON parse error testing - add empty-version-package.json fixture for whitespace version testing - add test contexts for invalid JSON and empty version edge cases 🧪 - Generated by Copilot
- update Get-NpmDependencyViolations to return DependencyViolation objects - update Test-ShellDownloadSecurity to return DependencyViolation objects - add dispatcher validation with type checking and field normalization - fix test path separators to forward slashes for cross-platform compatibility - update test assertions to use Name and Metadata.Section properties 🔧 - Generated by Copilot
|
Not addressing codecov in this PR as there's a separate backlog item for improved testing of the code touched in this PR. |
| $violation.Line = $i + 1 | ||
| $violation.Type = $FileInfo.Type | ||
| $violation.Name = $line.Trim() | ||
| $violation.Severity = 'warning' |
There was a problem hiding this comment.
Test-ShellDownloadSecurity sets DependencyViolation.Severity to 'warning', but the rest of the report pipeline (summary counts and SARIF level mapping) only recognizes 'High'|'Medium'|'Low'|'Info'. This will undercount these violations in the summary and downgrade SARIF results to note. Use the existing severity scheme (e.g., Medium/High) for shell-download violations (and adjust tests accordingly).
| $violation.Severity = 'warning' | |
| $violation.Severity = 'Medium' |
| .PARAMETER FileInfo | ||
| Hashtable with Path, Type, and RelativePath keys from Get-FilesToScan. | ||
| .OUTPUTS | ||
| Array of PSCustomObjects representing dependency violations. |
There was a problem hiding this comment.
Get-NpmDependencyViolations documents returning PSCustomObjects, but it actually constructs and returns [DependencyViolation] instances. Update the comment-based help .OUTPUTS to match the real return type so callers/tests know what to expect.
| Array of PSCustomObjects representing dependency violations. | |
| [DependencyViolation[]] representing dependency violations. |
| if (-not $isPinned) { | ||
| $violation = [DependencyViolation]::new() | ||
| $violation.File = $relativePath | ||
| $violation.Line = 0 |
There was a problem hiding this comment.
NPM violations are emitted with Line = 0, which produces invalid/ambiguous locations in outputs (notably SARIF region.startLine, which is expected to be 1-based) and makes reports harder to act on. Compute a real line number for the dependency entry (or at minimum set it to 1) so downstream formats remain valid.
| $violation.Line = 0 | |
| $violation.Line = 1 |
| $violation.Type = $type | ||
| $violation.Name = $packageName | ||
| $violation.Version = $version | ||
| $violation.Severity = 'warning' |
There was a problem hiding this comment.
Get-NpmDependencyViolations sets Severity to 'warning', but the report summary and SARIF export only recognize High/Medium/Low/Info. This will under-report npm violations in summaries and downgrade SARIF results to note. Align npm severity with the existing scheme (e.g., Medium).
| $violation.Severity = 'warning' | |
| $violation.Severity = 'Medium' |
| } | ||
|
|
||
| if ($v.Line -lt 1) { | ||
| $v.Line = 0 |
There was a problem hiding this comment.
In the validation-function path, violations with Line < 1 are normalized to 0. That propagates invalid line numbers into SARIF/markdown outputs. Prefer normalizing to 1 (or leave unset and handle formatting elsewhere) so outputs always have valid 1-based line numbers.
| $v.Line = 0 | |
| $v.Line = 1 |
| } | ||
| $result = Test-ShellDownloadSecurity -FileInfo $fileInfo | ||
| $result | Should -Not -BeNullOrEmpty | ||
| $result[0].Severity | Should -Be 'warning' |
There was a problem hiding this comment.
This test asserts Severity equals 'warning', but the report/export pipeline in Test-DependencyPinning.ps1 uses High/Medium/Low/Info for summaries and SARIF levels. If shell-download violations keep 'warning', they’ll be downgraded to SARIF note and won’t be counted in High/Medium/Low summaries. Update the implementation to use the standard severities and update this assertion accordingly.
| $result[0].Severity | Should -Be 'warning' | |
| $result[0].Severity | Should -Be 'High' |
🤖 I have created a release *beep* *boop* --- ## [2.0.0](hve-core-v1.1.0...hve-core-v2.0.0) (2026-01-28) ### ⚠ BREAKING CHANGES * **agents:** add Task Reviewer and expand RPI to 4-phase workflow ([#277](#277)) ### ✨ Features * **agents:** add hve-core-installer agent to extension package ([#297](#297)) ([c0e48c6](c0e48c6)) * **agents:** add Task Reviewer and expand RPI to 4-phase workflow ([#277](#277)) ([ae76cab](ae76cab)) * **build:** add code coverage reporting to Pester workflow ([#230](#230)) ([a34822a](a34822a)) * **docs:** add GOVERNANCE.md for OSSF Silver Badge compliance ([#235](#235)) ([b0e752c](b0e752c)) * **docs:** add ROADMAP.md for OSSF Silver badge compliance ([#238](#238)) ([4a41c16](4a41c16)) * **mcp:** add MCP server configuration guidance and installer enhancements ([#225](#225)) ([0bce418](0bce418)) * **scripts:** add YAML linting with actionlint ([#234](#234)) ([d9301f9](d9301f9)) * **security:** add OpenSSF Scorecard workflow and badge ([#271](#271)) ([7c6d788](7c6d788)) * **skills:** add video-to-gif conversion skill with FFmpeg two-pass optimization ([#247](#247)) ([8d65c42](8d65c42)) * **tests:** add Pester tests for LintingHelpers and Validate-MarkdownFrontmatter ([#197](#197), [#198](#198)) ([#205](#205)) ([51ae563](51ae563)) ### 🐛 Bug Fixes * **build:** detect table formatting changes via git diff ([#261](#261)) ([985eee0](985eee0)) * **build:** disable MD024 lint rule in CHANGELOG for release-please ([#220](#220)) ([971df94](971df94)) * **build:** quote shell variables and group redirects in workflow files ([#299](#299)) ([3372509](3372509)) * **build:** resolve scorecard badge and workflow security issues ([#301](#301)) ([aeaed13](aeaed13)) * **extension:** remove frontmatter from README and exclude from markdown linting ([#223](#223)) ([4272529](4272529)) * **instructions:** quote applyTo glob pattern for YAML compatibility ([#216](#216)) ([085199c](085199c)) * **scripts:** add FooterExcludePaths parameter to frontmatter validation ([#334](#334)) ([64db98d](64db98d)) * **scripts:** add GHSA word and logs/ exclusion to cspell config ([#214](#214)) ([5c99b3f](5c99b3f)) * **scripts:** correct type assertions in Invoke-YamlLint.Tests.ps1 ([#332](#332)) ([af7050d](af7050d)) * **scripts:** eliminate false positives in dependency pinning npm pattern ([#273](#273)) ([ccbdfa3](ccbdfa3)) * **security:** add artifact attestation for signed releases ([#257](#257)) ([c52d6e2](c52d6e2)) * standardize markdown footers and complete frontmatter ([#217](#217)) ([b4e7556](b4e7556)) ### 📚 Documentation * add OpenSSF Best Practices Passing badge to README ([#239](#239)) ([91bc529](91bc529)) * **architecture:** add architecture documentation and value proposition ([#252](#252)) ([0e4b02f](0e4b02f)) * **contributing:** add testing requirements for OSSF compliance ([#254](#254)) ([4db1a18](4db1a18)) * **docs:** add enterprise status badges to README header ([#270](#270)) ([ccb68a4](ccb68a4)) * **security:** add security assurance case and threat model for OSSF Silver ([#259](#259)) ([a390e26](a390e26)) ### ♻️ Refactoring * **application:** wrap execution with try blocks, ensure proper … ([#296](#296)) ([35c4417](35c4417)) * **scripts:** extract frontmatter validation to testable module ([#293](#293)) ([4e8707e](4e8707e)) * **scripts:** extract pure functions for Pester testability ([#221](#221)) ([d40e742](d40e742)) ### 🔧 Maintenance * **deps-dev:** bump cspell from 9.4.0 to 9.6.0 in the npm-dependencies group ([#208](#208)) ([855914b](855914b)) * **deps-dev:** bump cspell from 9.6.0 to 9.6.1 in the npm-dependencies group ([#294](#294)) ([1e45ad6](1e45ad6)) * **deps:** bump actions/setup-node from 6.1.0 to 6.2.0 in the github-actions group ([#209](#209)) ([c4c69e2](c4c69e2)) * **deps:** bump the github-actions group with 4 updates ([#295](#295)) ([d8337b8](d8337b8)) * remove step-security/harden-runner from workflows ([#246](#246)) ([c5708d8](c5708d8)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: hve-core-release-please[bot] <254602402+hve-core-release-please[bot]@users.noreply.github.com>
Description
Replace regex-based pattern matching with JSON parsing for package.json validation, targeting only actual dependency sections. The previous regex approach incorrectly flagged metadata fields like
name,version,description, andrepositoryURLs as unpinned dependencies.Get-NpmDependencyViolationsfunction that parses package.json as structured JSON and checks onlydependencies,devDependencies,peerDependencies, andoptionalDependenciessectionsValidationFuncdispatcher instead ofVersionPatternsregex approachGet-DependencyViolationfor type-specific validation functionsTest-ShellDownloadSecurityto use consistentFileInfohashtable parameterRelated Issue(s)
Fixes #267
Type of Change
Select all that apply:
Code & Documentation:
Infrastructure & Configuration:
AI Artifacts:
prompt-builderagent and addressed all feedback.github/instructions/*.instructions.md).github/prompts/*.prompt.md).github/agents/*.agent.md)Other:
.ps1,.sh,.py)Sample Prompts (for AI Artifact Contributions)
Testing
Get-NpmDependencyViolations)Checklist
Required Checks
AI Artifact Contributions
Required Automated Checks
The following validation commands must pass before merging:
npm run lint:mdnpm run spell-checknpm run lint:frontmatternpm run lint:md-linksnpm run lint:psSecurity Considerations
Additional Notes
The
ValidationFuncdispatcher pattern enables type-specific validation functions without relying on regex patterns. This approach provides better accuracy for structured file formats like JSON and can be extended to other dependency types in the future.🔧 - Generated by Copilot