Commit 4e9e31f
feat(build): enable npm pinning enforcement in dependency scan (#838)
## Description
Enabled **npm pinning enforcement** in the CI dependency-pinning scan
workflow. Updated the workflow default to scan
`github-actions,npm,workflow-npm-commands`, activating automatic
detection of unpinned npm commands in GitHub Actions workflow `run:`
blocks.
Three PowerShell functions were added to *Test-DependencyPinning.ps1*:
- **`Test-NpmCommandLine`** — regex-based detection of unpinned npm
commands (`npm install`, `npm i`, `npm update`, `npm install-test`)
while excluding safe variants (`npm ci`, `npm run`, `npm test`, `npm
audit`)
- **`Get-WorkflowNpmCommandViolations`** — indentation-aware YAML parser
that tracks nesting depth to confine detection to actual shell content
and avoid flagging comments
- **`New-NpmCommandViolation`** — constructs violation objects with
Medium severity and remediation guidance
Pester test coverage was added with fixture files for both safe and
unsafe npm command patterns.
### Scope Change: npm Exact-Version Enforcement
This PR introduces a **strategic departure** from SHA-pinning for npm
dependencies. Unlike GitHub Actions (which use 40-character commit SHAs
for immutable references), npm dependencies use **exact-version
enforcement** (`X.Y.Z` with no `^`, `~`, `*`, or range operators).
**Rationale for exact-version enforcement over SHA-pinning:**
| Factor | GitHub Actions (SHA) | npm (Exact Version) |
|--------|---------------------|---------------------|
| Registry model | Git repositories with mutable tags | Immutable
registry artifacts |
| Integrity verification | SHA pins to specific commit | Lockfile
integrity hashes (SHA-512) |
| Audit compatibility | N/A | `npm audit` requires semver versions |
| Reproducibility | SHA guarantees exact code | Lockfile + exact version
guarantees exact code |
| Human readability | 40-char hex strings | Semantic version numbers |
The validation regex enforces exact versions: `^\d+\.\d+\.\d+$` — no
ranges, no prefixes, no wildcards.
### Follow-Up Hardening (commit `b8bd099`)
Additional improvements shipped on this branch:
- **pip ExcludePatterns** — Virtual environment directories (`.venv`,
`venv`, `.tox`, `.nox`, `__pypackages__`) are now excluded from pip
dependency scanning to avoid false positives
- **SARIF integration tests** — Expanded from 1 weak assertion to 8
focused tests validating SARIF 2.1.0 schema compliance, severity mapping
(High→error, Medium→warning), location structure, and metadata
properties
- **Dependency pinning documentation** — New
`docs/security/dependency-pinning.md` page documenting all pinning
strategies with rationale, validation rules, CI integration flowchart,
and a dedicated comparison of SHA-pinning vs exact-version enforcement
for npm
## Related Issue(s)
Closes #526
## Type of Change
Select all that apply:
**Code & Documentation:**
* [ ] Bug fix (non-breaking change fixing an issue)
* [x] New feature (non-breaking change adding functionality)
* [ ] Breaking change (fix or feature causing existing functionality to
change)
* [x] Documentation update
**Infrastructure & Configuration:**
* [x] GitHub Actions workflow
* [ ] Linting configuration (markdown, PowerShell, etc.)
* [x] Security configuration
* [ ] DevContainer configuration
* [ ] Dependency update
**AI Artifacts:**
* [ ] Reviewed contribution with `prompt-builder` agent and addressed
all feedback
* [ ] Copilot instructions (`.github/instructions/*.instructions.md`)
* [ ] Copilot prompt (`.github/prompts/*.prompt.md`)
* [ ] Copilot agent (`.github/agents/*.agent.md`)
* [ ] Copilot skill (`.github/skills/*/SKILL.md`)
**Other:**
* [x] Script/automation (`.ps1`, `.sh`, `.py`)
* [ ] Other (please describe):
## Testing
Validated with 100 Pester tests covering:
- Detected 4 violations in multi-command fixture (install, update,
install-test, shorthand i)
- Returned zero violations for safe-only workflow (ci, run, test, audit)
- Handled nonexistent files gracefully
- Excluded commented-out commands
- Detected violations in multi-line run blocks with mixed safe/unsafe
commands
- SARIF 2.1.0 output: version, schema, tool driver, result count,
severity mapping (High→error, Medium→warning), location structure,
metadata properties (8 tests)
- pip ExcludePatterns for virtual environment directories
## Checklist
### Required Checks
* [x] Documentation is updated (if applicable)
* [x] Files follow existing naming conventions
* [x] Changes are backwards compatible (if applicable)
* [x] Tests added for new functionality (if applicable)
### Required Automated Checks
The following validation commands must pass before merging:
* [x] Markdown linting: `npm run lint:md`
* [x] Spell checking: `npm run spell-check`
* [x] Frontmatter validation: `npm run lint:frontmatter`
* [x] Skill structure validation: `npm run validate:skills`
* [x] Link validation: `npm run lint:md-links`
* [x] PowerShell analysis: `npm run lint:ps`
* [x] Plugin freshness: `npm run plugin:generate`
## Security Considerations
* [x] This PR does not contain any sensitive or NDA information
* [x] Any new dependencies have been reviewed for security issues
* [x] Security-related scripts follow the principle of least privilege
## Additional Notes
This PR enforces npm dependency pinning using exact-version enforcement
rather than SHA-pinning. The scanner uses regex-only analysis with no
code execution, and `Test-Path -LiteralPath` guards all file reads. Test
count increased from 93 to 100 with comprehensive SARIF integration
coverage.
---------
Signed-off-by: Marcel Bindseil <marcelbindseil@gmail.com>
Co-authored-by: Bill Berry <wbery@microsoft.com>
Co-authored-by: Marcel Bindseil <marcelbindseil@gmail.com>
Co-authored-by: Jordan Knight <jakkaj@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Vaughan Knight <vaughan@vaughanknight.com>1 parent a2f18e3 commit 4e9e31f
File tree
21 files changed
+923
-295
lines changed- .cspell
- .github
- instructions
- workflows
- docs
- architecture
- docusaurus
- security
- scripts
- security
- Modules
- tests
- Fixtures/Security
- security
21 files changed
+923
-295
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
| 26 | + | |
| 27 | + | |
27 | 28 | | |
28 | 29 | | |
29 | 30 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
131 | 131 | | |
132 | 132 | | |
133 | 133 | | |
| 134 | + | |
134 | 135 | | |
135 | 136 | | |
136 | 137 | | |
| |||
369 | 370 | | |
370 | 371 | | |
371 | 372 | | |
| 373 | + | |
372 | 374 | | |
373 | 375 | | |
374 | 376 | | |
| |||
799 | 801 | | |
800 | 802 | | |
801 | 803 | | |
| 804 | + | |
802 | 805 | | |
803 | 806 | | |
804 | 807 | | |
| |||
864 | 867 | | |
865 | 868 | | |
866 | 869 | | |
| 870 | + | |
867 | 871 | | |
868 | 872 | | |
869 | 873 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
312 | 312 | | |
313 | 313 | | |
314 | 314 | | |
315 | | - | |
| 315 | + | |
316 | 316 | | |
317 | 317 | | |
318 | 318 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
98 | 98 | | |
99 | 99 | | |
100 | 100 | | |
101 | | - | |
| 101 | + | |
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
| |||
126 | 126 | | |
127 | 127 | | |
128 | 128 | | |
129 | | - | |
| 129 | + | |
130 | 130 | | |
131 | 131 | | |
132 | 132 | | |
| |||
264 | 264 | | |
265 | 265 | | |
266 | 266 | | |
267 | | - | |
| 267 | + | |
268 | 268 | | |
269 | 269 | | |
270 | 270 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
| 15 | + | |
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| |||
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
62 | | - | |
| 62 | + | |
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
| |||
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
74 | | - | |
75 | 74 | | |
76 | 75 | | |
77 | 76 | | |
| |||
165 | 164 | | |
166 | 165 | | |
167 | 166 | | |
168 | | - | |
| 167 | + | |
169 | 168 | | |
170 | 169 | | |
171 | 170 | | |
| |||
175 | 174 | | |
176 | 175 | | |
177 | 176 | | |
178 | | - | |
| 177 | + | |
179 | 178 | | |
180 | 179 | | |
181 | 180 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
| 22 | + | |
23 | 23 | | |
24 | | - | |
| 24 | + | |
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| |||
81 | 81 | | |
82 | 82 | | |
83 | 83 | | |
84 | | - | |
| 84 | + | |
85 | 85 | | |
86 | 86 | | |
87 | 87 | | |
| |||
98 | 98 | | |
99 | 99 | | |
100 | 100 | | |
101 | | - | |
| 101 | + | |
102 | 102 | | |
103 | 103 | | |
104 | 104 | | |
105 | 105 | | |
106 | | - | |
| 106 | + | |
107 | 107 | | |
108 | 108 | | |
109 | 109 | | |
| |||
151 | 151 | | |
152 | 152 | | |
153 | 153 | | |
154 | | - | |
| 154 | + | |
155 | 155 | | |
156 | 156 | | |
157 | 157 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
| 2 | + | |
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
79 | | - | |
| 79 | + | |
80 | 80 | | |
81 | 81 | | |
82 | 82 | | |
| |||
135 | 135 | | |
136 | 136 | | |
137 | 137 | | |
138 | | - | |
| 138 | + | |
139 | 139 | | |
140 | 140 | | |
141 | 141 | | |
| |||
200 | 200 | | |
201 | 201 | | |
202 | 202 | | |
203 | | - | |
204 | | - | |
205 | | - | |
206 | | - | |
207 | | - | |
208 | | - | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
209 | 209 | | |
210 | 210 | | |
211 | 211 | | |
212 | | - | |
213 | | - | |
214 | | - | |
215 | | - | |
216 | | - | |
217 | | - | |
218 | | - | |
219 | | - | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
220 | 220 | | |
221 | 221 | | |
222 | 222 | | |
| |||
0 commit comments