policylayer 0.1.2 → 0.1.3

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.
Files changed (2) hide show
  1. package/dist/index.js +3 -3
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import{Command as D}from"commander";import{readFileSync as $}from"fs";import{existsSync as v,readFileSync as j}from"fs";import{join as p}from"path";import{homedir as a}from"os";import{parse as h}from"smol-toml";function x(r){return[{path:p(r,".mcp.json"),source:".mcp.json (project)",type:"json-mcp"},{path:p(r,".cursor/mcp.json"),source:".cursor/mcp.json (project)",type:"json-mcp"},{path:p(r,".vscode/settings.json"),source:"VS Code (project)",type:"json-vscode"},{path:p(r,".codex/config.toml"),source:".codex/config.toml (project)",type:"toml-codex"},{path:p(a(),".claude.json"),source:"~/.claude.json (user)",type:"json-mcp"},{path:p(a(),"Library/Application Support/Claude/claude_desktop_config.json"),source:"Claude Desktop (user)",type:"json-mcp"},{path:p(a(),".codeium/windsurf/mcp_config.json"),source:"Windsurf (user)",type:"json-mcp"},{path:p(a(),".codex/config.toml"),source:"~/.codex/config.toml (user)",type:"toml-codex"}]}function R(r){return JSON.parse(r).mcpServers||{}}function w(r){let e=JSON.parse(r);return e.mcp?e.mcp.servers||{}:null}function C(r){return h(r).mcp_servers||{}}function u(r){let e=[],o=x(r);for(let{path:n,source:t,type:s}of o)if(v(n))try{let i=j(n,"utf-8"),c=null;switch(s){case"json-mcp":c=R(i);break;case"json-vscode":c=w(i);break;case"toml-codex":c=C(i);break}if(c===null)continue;e.push({source:t,path:n,servers:Object.keys(c),raw:{mcpServers:c}})}catch{}return e}var k=[/^sk-/,/^ghp_/,/^gho_/,/^ghu_/,/^ghs_/,/^glpat-/,/^xoxb-/,/^xoxp-/,/^Bearer\s/,/^pk_/,/^sk_live_/,/^sk_test_/,/^ict_/,/^[a-z]{2,6}_[a-f0-9]{16,}$/i,/^[a-f0-9]{32,}$/i],E=[/\/Users\//,/\/home\//,/\\Users\\/,/^[A-Z]:\\/,/^\//];function b(r){return k.some(e=>e.test(r))}function M(r){return E.some(e=>e.test(r))}function _(r){return!!(r.startsWith("@")&&r.includes("/")||/^[a-z][\w.-]*$/.test(r))}function g(r){let e={};for(let[o,n]of Object.entries(r)){let t={};if(n.command){let s=n.command.split(/[/\\]/);t.command=s[s.length-1]||n.command}Array.isArray(n.args)&&(t.args=n.args.filter(s=>typeof s!="string"||b(s)||M(s)||s.startsWith("-")?!1:_(s))),e[o]=t}return e}async function l(r,e){let o=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mcpServers:r})}),n=await o.json();if(!o.ok)throw new Error(n.error||`Scan failed with status ${o.status}`);return n}function m(r){let e=[];for(let o of r)e.push(` Found ${o.servers.length} server${o.servers.length===1?"":"s"} in ${o.source}`);return e.join(`
2
+ import{Command as D}from"commander";import{readFileSync as P}from"fs";import{existsSync as v,readFileSync as h}from"fs";import{join as p}from"path";import{homedir as a}from"os";import{parse as j}from"smol-toml";function R(r){return[{path:p(r,".mcp.json"),source:".mcp.json (project)",type:"json-mcp"},{path:p(r,".cursor/mcp.json"),source:".cursor/mcp.json (project)",type:"json-mcp"},{path:p(r,".vscode/settings.json"),source:"VS Code (project)",type:"json-vscode"},{path:p(r,".codex/config.toml"),source:".codex/config.toml (project)",type:"toml-codex"},{path:p(a(),".claude.json"),source:"~/.claude.json (user)",type:"json-mcp"},{path:p(a(),"Library/Application Support/Claude/claude_desktop_config.json"),source:"Claude Desktop (user)",type:"json-mcp"},{path:p(a(),".codeium/windsurf/mcp_config.json"),source:"Windsurf (user)",type:"json-mcp"},{path:p(a(),".codex/config.toml"),source:"~/.codex/config.toml (user)",type:"toml-codex"}]}function x(r){return JSON.parse(r).mcpServers||{}}function w(r){let e=JSON.parse(r);return e.mcp?e.mcp.servers||{}:null}function C(r){return j(r).mcp_servers||{}}function f(r){let e=[],o=R(r);for(let{path:s,source:t,type:n}of o)if(v(s))try{let i=h(s,"utf-8"),c=null;switch(n){case"json-mcp":c=x(i);break;case"json-vscode":c=w(i);break;case"toml-codex":c=C(i);break}if(c===null)continue;e.push({source:t,path:s,servers:Object.keys(c),raw:{mcpServers:c}})}catch{}return e}var k=[/^sk-/,/^ghp_/,/^gho_/,/^ghu_/,/^ghs_/,/^glpat-/,/^xoxb-/,/^xoxp-/,/^Bearer\s/,/^pk_/,/^sk_live_/,/^sk_test_/,/^ict_/,/^[a-z]{2,6}_[a-f0-9]{16,}$/i,/^[a-f0-9]{32,}$/i],b=[/\/Users\//,/\/home\//,/\\Users\\/,/^[A-Z]:\\/,/^\//];function E(r){return k.some(e=>e.test(r))}function M(r){return b.some(e=>e.test(r))}function _(r){return!!(r.startsWith("@")&&r.includes("/")||/^[a-z][\w.-]*$/.test(r))}function g(r){let e={};for(let[o,s]of Object.entries(r)){let t={};if(s.command){let n=s.command.split(/[/\\]/);t.command=n[n.length-1]||s.command}Array.isArray(s.args)&&(t.args=s.args.filter(n=>typeof n!="string"||E(n)||M(n)||n.startsWith("-")?!1:_(n))),e[o]=t}return e}async function l(r,e){let o=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mcpServers:r})}),s=await o.json();if(!o.ok)throw new Error(s.error||`Scan failed with status ${o.status}`);return s}function m(r){let e=[];for(let o of r)e.push(` Found ${o.servers.length} server${o.servers.length===1?"":"s"} in ${o.source}`);return e.join(`
3
3
  `)}function d(r){return["No MCP configuration found.","","Checked:",...r.map(o=>` - ${o}`),"","Use --config <path> to specify a config file,","or try the web scanner at https://policylayer.com/scan"].join(`
4
- `)}function y(r){return[""," Report ready:",` ${r}`,""].join(`
4
+ `)}function y(r){return[""," Report ready:",` ${r}`,""," Run this scan on every PR:"," https://github.com/PolicyLayer/scan-action",""].join(`
5
5
  `)}function S(r){return["","Dry run -- would send:",JSON.stringify(r,null,2)].join(`
6
- `)}var f=new D;f.name("policylayer").description("Scan your MCP config for security risks").version("0.1.0");f.command("scan").description("Scan MCP server configuration").option("--config <path>","Path to MCP config file").option("--dry-run","Show what would be sent without sending").option("--api-url <url>","Scan API URL","https://policylayer.com/api/scan").action(async r=>{try{let e={};if(r.config)try{let t=JSON.parse($(r.config,"utf-8")),s=t.mcpServers||t;e=s;let i=Object.keys(s).length;console.log(` Found ${i} server${i===1?"":"s"} in ${r.config}`)}catch(t){console.error(`Error reading config: ${r.config}`),console.error(t.message),process.exit(1)}else{let t=u(process.cwd());t.length===0&&(console.log(d([".mcp.json (project root)","~/.claude.json (user-level)","Claude Desktop config (macOS)",".cursor/mcp.json (project)",".vscode/settings.json (project)","Windsurf config (user)",".codex/config.toml (project)","~/.codex/config.toml (user)"])),process.exit(0)),console.log(m(t));let s=t.filter(c=>c.source.includes("user")),i=t.filter(c=>!c.source.includes("user"));for(let c of s)Object.assign(e,c.raw.mcpServers);for(let c of i)Object.assign(e,c.raw.mcpServers)}let o=g(e);if(r.dryRun){console.log(S({mcpServers:o}));return}console.log(" Sending server identifiers only -- secrets stripped");let n=await l(o,r.apiUrl);console.log(y(n.url))}catch(e){console.error(`Error: ${e.message}`),process.exit(1)}});f.parse();
6
+ `)}var u=new D;u.name("policylayer").description("Scan your MCP config for security risks").version("0.1.0");u.command("scan").description("Scan MCP server configuration").option("--config <path>","Path to MCP config file").option("--dry-run","Show what would be sent without sending").option("--api-url <url>","Scan API URL","https://policylayer.com/api/scan").action(async r=>{try{let e={};if(r.config)try{let t=JSON.parse(P(r.config,"utf-8")),n=t.mcpServers||t;e=n;let i=Object.keys(n).length;console.log(` Found ${i} server${i===1?"":"s"} in ${r.config}`)}catch(t){console.error(`Error reading config: ${r.config}`),console.error(t.message),process.exit(1)}else{let t=f(process.cwd());t.length===0&&(console.log(d([".mcp.json (project root)","~/.claude.json (user-level)","Claude Desktop config (macOS)",".cursor/mcp.json (project)",".vscode/settings.json (project)","Windsurf config (user)",".codex/config.toml (project)","~/.codex/config.toml (user)"])),process.exit(0)),console.log(m(t));let n=t.filter(c=>c.source.includes("user")),i=t.filter(c=>!c.source.includes("user"));for(let c of n)Object.assign(e,c.raw.mcpServers);for(let c of i)Object.assign(e,c.raw.mcpServers)}let o=g(e);if(r.dryRun){console.log(S({mcpServers:o}));return}console.log(" Sending server identifiers only -- secrets stripped");let s=await l(o,r.apiUrl);console.log(y(s.url))}catch(e){console.error(`Error: ${e.message}`),process.exit(1)}});u.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "policylayer",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "description": "Scan your MCP config for security risks",
6
6
  "bin": {