Skip to content

Commit c8e3531

Browse files
fix(security): supply chain hardening — pin npm versions, add CI check
Anti-supply-chain-poisoning measures: 1. Pin all npm dependency versions to exact (remove ^ and ~ prefixes) across 10 package.json files. Engine constraints preserved. 2. Add supply-chain-check.yml CI workflow that: - Triggers on PRs changing dependency files - Rejects unpinned ^ or ~ version ranges - Checks for lockfile presence - SHA-pinned actions, minimal permissions 3. Update copilot-instructions.md with Supply Chain Security section: - 7-day rule for new versions - Exact version pinning requirements - Anomaly detection for Dependabot PRs - Lockfile integrity rules Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent fbf313f commit c8e3531

File tree

12 files changed

+169
-101
lines changed

12 files changed

+169
-101
lines changed

.github/copilot-instructions.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,24 @@ Before approving or merging ANY PR, verify ALL of the following:
4545
- No `unwrap()` in non-test Rust code paths (use `?` or explicit error handling)
4646
- Docker images must use pinned version tags or SHA digests (never `:latest`)
4747

48+
## Supply Chain Security (Anti-Poisoning)
49+
50+
### Version Selection
51+
- **7-Day Rule:** Never install a package version released less than 7 days ago. Prefer versions with at least one week of stability and consistent download metrics.
52+
- **Fallback:** If the latest version is < 7 days old, pin to the previous stable release.
53+
- **Verification:** Check release timestamps via `npm view <package> time` or `pip index versions <package>`.
54+
55+
### Version Locking
56+
- **Exact versions only:** Use exact versioning in `package.json` (e.g., `"axios": "1.14.0"`). Prohibit `^` or `~` ranges.
57+
- **Python pinning:** Use `==` in `requirements.txt` and pin in `pyproject.toml` with `>=x.y.z,<x.y+1.0`.
58+
- **Rust pinning:** Use exact versions in `Cargo.toml` (e.g., `serde = "=1.0.228"`).
59+
- **Lockfile integrity:** Ensure `package-lock.json`, `Cargo.lock`, or equivalent is committed to the repository.
60+
61+
### Anomaly Detection
62+
- **Pre-install audit:** Before adding any new dependency, check for red flags: unusual release spikes, sudden maintainer changes, new suspicious transitive dependencies.
63+
- **Alert:** If any anomaly is detected, halt the installation and flag for human review.
64+
- **Dependabot PRs:** Review Dependabot version bumps for major version jumps, new transitive deps, or maintainer changes before merging.
65+
4866
## Code Style
4967

5068
- Use conventional commits (feat:, fix:, docs:, etc.)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Supply Chain Check
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- '**/package.json'
7+
- '**/Cargo.toml'
8+
- '**/pyproject.toml'
9+
- '**/requirements*.txt'
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
check-version-pinning:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
19+
- name: Check for unpinned npm versions
20+
run: |
21+
echo "Checking for ^ or ~ version ranges in package.json files..."
22+
VIOLATIONS=0
23+
for f in $(find packages -name package.json -not -path '*/node_modules/*' -not -path '*/dist/*'); do
24+
if grep -P '": "[\^~]' "$f" 2>/dev/null; then
25+
echo "VIOLATION: $f has unpinned version ranges"
26+
VIOLATIONS=$((VIOLATIONS + 1))
27+
fi
28+
done
29+
if [ $VIOLATIONS -gt 0 ]; then
30+
echo ""
31+
echo "Found $VIOLATIONS package.json files with ^ or ~ version ranges."
32+
echo "Pin to exact versions (e.g., \"1.2.3\" not \"^1.2.3\")."
33+
exit 1
34+
fi
35+
echo "OK: All package.json files use exact versions"
36+
37+
- name: Check lockfile presence
38+
run: |
39+
echo "Checking for lockfiles..."
40+
MISSING=0
41+
for f in $(find packages -name package.json -not -path '*/node_modules/*' -not -path '*/dist/*'); do
42+
DIR=$(dirname "$f")
43+
if [ ! -f "$DIR/package-lock.json" ] && [ ! -f "$DIR/pnpm-lock.yaml" ] && [ ! -f "$DIR/yarn.lock" ]; then
44+
# Only flag if there are actual dependencies (not just name+version)
45+
if grep -q '"dependencies"' "$f" 2>/dev/null; then
46+
echo "WARNING: $DIR has dependencies but no lockfile"
47+
fi
48+
fi
49+
done
50+
echo "Lockfile check complete"

packages/agent-mesh/packages/mcp-proxy/package.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,18 @@
4444
"prepublishOnly": "npm run build"
4545
},
4646
"dependencies": {
47-
"@modelcontextprotocol/sdk": "^1.0.0",
48-
"commander": "^12.0.0",
49-
"chalk": "^5.3.0",
50-
"yaml": "^2.4.0",
51-
"winston": "^3.11.0",
52-
"crypto-js": "^4.2.0"
47+
"@modelcontextprotocol/sdk": "1.0.0",
48+
"commander": "12.0.0",
49+
"chalk": "5.3.0",
50+
"yaml": "2.4.0",
51+
"winston": "3.11.0",
52+
"crypto-js": "4.2.0"
5353
},
5454
"devDependencies": {
55-
"@types/node": "^20.0.0",
56-
"typescript": "^5.4.0",
57-
"vitest": "^1.4.0",
58-
"eslint": "^8.57.0"
55+
"@types/node": "20.0.0",
56+
"typescript": "5.4.0",
57+
"vitest": "1.4.0",
58+
"eslint": "8.57.0"
5959
},
6060
"engines": {
6161
"node": ">=18.0.0"

packages/agent-mesh/sdks/typescript/package.json

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,19 @@
3131
"directory": "packages/agent-mesh/sdks/typescript"
3232
},
3333
"devDependencies": {
34-
"typescript": "^5.7.0",
35-
"@types/node": "^25.5.0",
36-
"jest": "^30.3.0",
37-
"ts-jest": "^29.1.0",
38-
"@types/jest": "^30.0.0",
39-
"eslint": "^9.0.0",
40-
"@typescript-eslint/parser": "^8.58.0",
41-
"@typescript-eslint/eslint-plugin": "^8.58.0",
42-
"rimraf": "^6.1.3"
34+
"typescript": "5.7.0",
35+
"@types/node": "25.5.0",
36+
"jest": "30.3.0",
37+
"ts-jest": "29.1.0",
38+
"@types/jest": "30.0.0",
39+
"eslint": "9.0.0",
40+
"@typescript-eslint/parser": "8.58.0",
41+
"@typescript-eslint/eslint-plugin": "8.58.0",
42+
"rimraf": "6.1.3"
4343
},
4444
"dependencies": {
45-
"js-yaml": "^4.1.0",
46-
"@noble/ed25519": "^2.0.0"
45+
"js-yaml": "4.1.0",
46+
"@noble/ed25519": "2.0.0"
4747
},
4848
"engines": {
4949
"node": ">=18.0.0"

packages/agent-mesh/services/api/package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@
1919
},
2020
"homepage": "https://github.com/microsoft/agent-governance-toolkit/tree/main/packages/agent-mesh/services/api",
2121
"dependencies": {
22-
"express": "^4.18.2",
23-
"uuid": "^9.0.0"
22+
"express": "4.18.2",
23+
"uuid": "9.0.0"
2424
},
2525
"devDependencies": {
26-
"@types/express": "^4.17.21",
27-
"@types/node": "^20.10.0",
28-
"@types/uuid": "^9.0.7",
29-
"ts-node": "^10.9.2",
30-
"typescript": "^5.3.2"
26+
"@types/express": "4.17.21",
27+
"@types/node": "20.10.0",
28+
"@types/uuid": "9.0.7",
29+
"ts-node": "10.9.2",
30+
"typescript": "5.3.2"
3131
},
3232
"engines": {
3333
"node": ">=18.0.0"

packages/agent-os-vscode/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -390,15 +390,15 @@
390390
"publish": "vsce publish"
391391
},
392392
"devDependencies": {
393-
"@types/node": "^20.0.0",
394-
"@types/vscode": "^1.85.0",
395-
"@typescript-eslint/eslint-plugin": "^6.0.0",
396-
"@typescript-eslint/parser": "^6.0.0",
397-
"@vscode/vsce": "^2.22.0",
398-
"eslint": "^8.0.0",
399-
"typescript": "^5.3.0"
393+
"@types/node": "20.0.0",
394+
"@types/vscode": "1.85.0",
395+
"@typescript-eslint/eslint-plugin": "6.0.0",
396+
"@typescript-eslint/parser": "6.0.0",
397+
"@vscode/vsce": "2.22.0",
398+
"eslint": "8.0.0",
399+
"typescript": "5.3.0"
400400
},
401401
"dependencies": {
402-
"axios": "^1.6.0"
402+
"axios": "1.6.0"
403403
}
404404
}

packages/agent-os/extensions/chrome/package.json

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,27 @@
1111
"clean": "rimraf dist"
1212
},
1313
"devDependencies": {
14-
"@types/chrome": "^0.0.268",
15-
"@types/react": "^18.2.48",
16-
"@types/react-dom": "^18.2.18",
17-
"@typescript-eslint/eslint-plugin": "^6.19.1",
18-
"@typescript-eslint/parser": "^6.19.1",
19-
"copy-webpack-plugin": "^12.0.2",
20-
"css-loader": "^6.9.1",
21-
"eslint": "^8.56.0",
22-
"eslint-plugin-react": "^7.33.2",
23-
"eslint-plugin-react-hooks": "^4.6.0",
24-
"html-webpack-plugin": "^5.6.0",
25-
"rimraf": "^5.0.5",
26-
"style-loader": "^3.3.4",
27-
"ts-loader": "^9.5.1",
28-
"typescript": "^5.3.3",
29-
"webpack": "^5.90.0",
30-
"webpack-cli": "^5.1.4"
14+
"@types/chrome": "0.0.268",
15+
"@types/react": "18.2.48",
16+
"@types/react-dom": "18.2.18",
17+
"@typescript-eslint/eslint-plugin": "6.19.1",
18+
"@typescript-eslint/parser": "6.19.1",
19+
"copy-webpack-plugin": "12.0.2",
20+
"css-loader": "6.9.1",
21+
"eslint": "8.56.0",
22+
"eslint-plugin-react": "7.33.2",
23+
"eslint-plugin-react-hooks": "4.6.0",
24+
"html-webpack-plugin": "5.6.0",
25+
"rimraf": "5.0.5",
26+
"style-loader": "3.3.4",
27+
"ts-loader": "9.5.1",
28+
"typescript": "5.3.3",
29+
"webpack": "5.90.0",
30+
"webpack-cli": "5.1.4"
3131
},
3232
"dependencies": {
33-
"react": "^18.2.0",
34-
"react-dom": "^18.2.0",
35-
"webextension-polyfill": "^0.10.0"
33+
"react": "18.2.0",
34+
"react-dom": "18.2.0",
35+
"webextension-polyfill": "0.10.0"
3636
}
3737
}

packages/agent-os/extensions/copilot/package.json

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,24 @@
3838
"prepare": "npm run build"
3939
},
4040
"dependencies": {
41-
"@octokit/webhooks": "^14.2.0",
42-
"axios": "^1.14.0",
43-
"dotenv": "^17.3.1",
44-
"express": "^5.2.1",
41+
"@octokit/webhooks": "14.2.0",
42+
"axios": "1.14.0",
43+
"dotenv": "17.3.1",
44+
"express": "5.2.1",
4545
"path-to-regexp": "8.4.1",
46-
"winston": "^3.11.0"
46+
"winston": "3.11.0"
4747
},
4848
"devDependencies": {
49-
"@types/express": "^5.0.6",
50-
"@types/jest": "^30.0.0",
51-
"@types/node": "^25.5.0",
52-
"@typescript-eslint/eslint-plugin": "^8.58.0",
53-
"@typescript-eslint/parser": "^8.58.0",
54-
"eslint": "^10.1.0",
55-
"jest": "^30.3.0",
56-
"ts-jest": "^29.0.0",
57-
"ts-node": "^10.9.0",
58-
"typescript": "^6.0.2"
49+
"@types/express": "5.0.6",
50+
"@types/jest": "30.0.0",
51+
"@types/node": "25.5.0",
52+
"@typescript-eslint/eslint-plugin": "8.58.0",
53+
"@typescript-eslint/parser": "8.58.0",
54+
"eslint": "10.1.0",
55+
"jest": "30.3.0",
56+
"ts-jest": "29.0.0",
57+
"ts-node": "10.9.0",
58+
"typescript": "5.7.0"
5959
},
6060
"copilotExtension": {
6161
"name": "agentos",

packages/agent-os/extensions/cursor/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -248,15 +248,15 @@
248248
"publish": "vsce publish"
249249
},
250250
"devDependencies": {
251-
"@types/vscode": "^1.85.0",
252-
"@types/node": "^20.0.0",
253-
"@typescript-eslint/eslint-plugin": "^6.0.0",
254-
"@typescript-eslint/parser": "^6.0.0",
255-
"eslint": "^8.0.0",
256-
"typescript": "^5.3.0",
257-
"@vscode/vsce": "^2.22.0"
251+
"@types/vscode": "1.85.0",
252+
"@types/node": "20.0.0",
253+
"@typescript-eslint/eslint-plugin": "6.0.0",
254+
"@typescript-eslint/parser": "6.0.0",
255+
"eslint": "8.0.0",
256+
"typescript": "5.3.0",
257+
"@vscode/vsce": "2.22.0"
258258
},
259259
"dependencies": {
260-
"axios": "^1.6.0"
260+
"axios": "1.6.0"
261261
}
262262
}

packages/agent-os/extensions/mcp-server/package.json

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,21 @@
3939
"node": ">=18.0.0"
4040
},
4141
"dependencies": {
42-
"@modelcontextprotocol/sdk": "^1.29.0",
43-
"uuid": "^13.0.0",
44-
"winston": "^3.11.0",
45-
"yaml": "^2.8.3",
46-
"zod": "^4.3.6"
42+
"@modelcontextprotocol/sdk": "1.29.0",
43+
"uuid": "13.0.0",
44+
"winston": "3.11.0",
45+
"yaml": "2.8.3",
46+
"zod": "4.3.6"
4747
},
4848
"devDependencies": {
49-
"@types/node": "^25.4.0",
50-
"@types/uuid": "^11.0.0",
51-
"@typescript-eslint/eslint-plugin": "^8.58.0",
52-
"@typescript-eslint/parser": "^8.57.0",
53-
"@vitest/coverage-v8": "^4.1.2",
54-
"eslint": "^10.0.3",
55-
"typescript": "^6.0.2",
56-
"vitest": "^4.1.2"
49+
"@types/node": "25.4.0",
50+
"@types/uuid": "11.0.0",
51+
"@typescript-eslint/eslint-plugin": "8.58.0",
52+
"@typescript-eslint/parser": "8.57.0",
53+
"@vitest/coverage-v8": "4.1.2",
54+
"eslint": "10.0.3",
55+
"typescript": "6.0.2",
56+
"vitest": "4.1.2"
5757
},
5858
"files": [
5959
"dist",

0 commit comments

Comments
 (0)