perimetercli 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/package.json +4 -4
- package/src/catalog.js +20 -4
- package/src/report.js +3 -3
package/README.md
CHANGED
|
@@ -11,6 +11,9 @@ perimeter audit
|
|
|
11
11
|
Zero runtime dependencies · Works offline · Open-core (MIT)
|
|
12
12
|
|
|
13
13
|
[](https://nodejs.org)
|
|
14
|
+
[](https://github.com/stealth-alpha/perimeter/actions/workflows/test.yml)
|
|
15
|
+
[](https://github.com/stealth-alpha/perimeter/actions/workflows/audit-ci.yml)
|
|
16
|
+
[](https://stealth-alpha.github.io/perimeter/)
|
|
14
17
|
[](https://www.npmjs.com/package/perimetercli)
|
|
15
18
|
[](LICENSE)
|
|
16
19
|
|
|
@@ -113,6 +116,10 @@ Cost: model claude-sonnet · ~8,652 tokens/load · $0.09/load
|
|
|
113
116
|
reports what was *really* called (Bash `×3`, Write `×1`…), with exact token
|
|
114
117
|
spend when the log records it.
|
|
115
118
|
|
|
119
|
+
See a full [example audit report](docs/example-audit.md) — a deliberately risky
|
|
120
|
+
toolchain (shell server, curl-piped hook, injected rules, credential-sniffing
|
|
121
|
+
skill) audited to a CRITICAL verdict with remediation for every finding.
|
|
122
|
+
|
|
116
123
|
## Runtime guard
|
|
117
124
|
|
|
118
125
|
`perimeter guard` proxies a real MCP server and **blocks risky tool calls at
|
|
@@ -154,11 +161,24 @@ you push.
|
|
|
154
161
|
## CI
|
|
155
162
|
|
|
156
163
|
```yaml
|
|
164
|
+
permissions:
|
|
165
|
+
contents: read
|
|
166
|
+
security-events: write # needed for the SARIF upload step below
|
|
167
|
+
steps:
|
|
168
|
+
- uses: actions/checkout@v4
|
|
169
|
+
- uses: actions/setup-node@v4
|
|
170
|
+
with:
|
|
171
|
+
node-version: 20
|
|
157
172
|
- run: npm install --global perimetercli
|
|
158
173
|
- run: perimeter baseline
|
|
159
174
|
- run: perimeter audit --enforce --fail-on high --out perimeter-report
|
|
160
175
|
- uses: actions/upload-artifact@v4
|
|
161
176
|
with: { path: perimeter-report/ }
|
|
177
|
+
# Optional: publish findings to GitHub code scanning
|
|
178
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
179
|
+
if: always()
|
|
180
|
+
with:
|
|
181
|
+
sarif_file: perimeter-report/audit.sarif
|
|
162
182
|
```
|
|
163
183
|
|
|
164
184
|
Perimeter emits **SARIF** too, so findings land directly in GitHub code scanning.
|
|
@@ -201,3 +221,7 @@ npm test
|
|
|
201
221
|
## License
|
|
202
222
|
|
|
203
223
|
[MIT](LICENSE)
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
Part of the [stealth-alpha toolkit](https://stealth-alpha.github.io/toolkit/) — eight zero-dependency CLIs for release automation, agent security, and repo hygiene.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "perimetercli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Security and cost audit for your AI agent toolchain — MCP servers, hooks, skills. One command finds poisoning, dangerous capabilities, context bloat and drift, and gates CI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -44,12 +44,12 @@
|
|
|
44
44
|
"name": "Perimeter Contributors",
|
|
45
45
|
"email": "hello@perimetercli.dev"
|
|
46
46
|
},
|
|
47
|
-
"homepage": "https://
|
|
47
|
+
"homepage": "https://stealth-alpha.github.io/perimeter/",
|
|
48
48
|
"repository": {
|
|
49
49
|
"type": "git",
|
|
50
|
-
"url": "git+https://github.com/
|
|
50
|
+
"url": "git+https://github.com/stealth-alpha/perimeter.git"
|
|
51
51
|
},
|
|
52
52
|
"bugs": {
|
|
53
|
-
"url": "https://github.com/
|
|
53
|
+
"url": "https://github.com/stealth-alpha/perimeter/issues"
|
|
54
54
|
}
|
|
55
55
|
}
|
package/src/catalog.js
CHANGED
|
@@ -269,18 +269,34 @@ const servers = [
|
|
|
269
269
|
|
|
270
270
|
export const KNOWN_SERVERS = servers;
|
|
271
271
|
|
|
272
|
+
/**
|
|
273
|
+
* Match a package name or config entry against the catalog.
|
|
274
|
+
*
|
|
275
|
+
* Rules:
|
|
276
|
+
* - empty/missing input never matches
|
|
277
|
+
* - exact alias match always wins
|
|
278
|
+
* - a key that fully embeds an alias matches (e.g. "org/server-slack")
|
|
279
|
+
* - a key may act as shorthand only when it equals a whole delimiter-separated
|
|
280
|
+
* segment of the alias (e.g. "github" ~ "server-github"), which prevents
|
|
281
|
+
* short generic names like "git" from hijacking unrelated profiles
|
|
282
|
+
*/
|
|
272
283
|
export function catalogFor(packageOrName) {
|
|
273
|
-
const key = String(packageOrName
|
|
284
|
+
const key = String(packageOrName ?? "").trim().toLowerCase();
|
|
285
|
+
if (!key) return null;
|
|
274
286
|
for (const s of servers) {
|
|
275
287
|
for (const m of s.match) {
|
|
276
|
-
if (key
|
|
277
|
-
return s;
|
|
278
|
-
}
|
|
288
|
+
if (matchesAlias(key, m.toLowerCase())) return s;
|
|
279
289
|
}
|
|
280
290
|
}
|
|
281
291
|
return null;
|
|
282
292
|
}
|
|
283
293
|
|
|
294
|
+
function matchesAlias(key, alias) {
|
|
295
|
+
if (alias === key) return true;
|
|
296
|
+
if (key.includes(alias)) return true;
|
|
297
|
+
return alias.split(/[^a-z0-9]+/).includes(key);
|
|
298
|
+
}
|
|
299
|
+
|
|
284
300
|
/** A default token/risk profile for an unknown server. */
|
|
285
301
|
export function unknownServerProfile(name) {
|
|
286
302
|
return {
|
package/src/report.js
CHANGED
|
@@ -162,7 +162,7 @@ export function formatMarkdown(audit) {
|
|
|
162
162
|
}
|
|
163
163
|
lines.push("");
|
|
164
164
|
lines.push("---", "");
|
|
165
|
-
lines.push(`_Generated by [Perimeter](https://
|
|
165
|
+
lines.push(`_Generated by [Perimeter](https://github.com/stealth-alpha/perimeter)._`);
|
|
166
166
|
return lines.join("\n");
|
|
167
167
|
}
|
|
168
168
|
|
|
@@ -215,7 +215,7 @@ export function formatSarif(audit) {
|
|
|
215
215
|
driver: {
|
|
216
216
|
name: "perimeter",
|
|
217
217
|
version: "0.1.0",
|
|
218
|
-
informationUri: "https://
|
|
218
|
+
informationUri: "https://github.com/stealth-alpha/perimeter",
|
|
219
219
|
rules: audit.findings.map((f, i) => ({
|
|
220
220
|
id: f.id,
|
|
221
221
|
name: f.title,
|
|
@@ -315,7 +315,7 @@ footer{margin-top:28px;color:var(--muted);font-size:13px;text-align:center}
|
|
|
315
315
|
<tbody>${serversHtml}</tbody></table>
|
|
316
316
|
<h2>Findings</h2>
|
|
317
317
|
${findingsHtml}
|
|
318
|
-
<footer>Generated by <a href="https://
|
|
318
|
+
<footer>Generated by <a href="https://github.com/stealth-alpha/perimeter">Perimeter</a></footer>
|
|
319
319
|
</div></body></html>`;
|
|
320
320
|
}
|
|
321
321
|
|