@shieldly/cli 1.0.4 → 1.0.5
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 +8 -0
- package/dist/cli.cjs +42 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,6 +101,14 @@ hashes of the input.
|
|
|
101
101
|
- API reference: https://www.shieldly.io/docs/api
|
|
102
102
|
- Issues: https://github.com/shieldly-io/cli/issues
|
|
103
103
|
|
|
104
|
+
## Free tools & references (no signup)
|
|
105
|
+
|
|
106
|
+
No account required — these run in your browser or document the risks:
|
|
107
|
+
|
|
108
|
+
- [IAM Privilege Escalation Cheat Sheet](https://www.shieldly.io/iam/cheatsheet?utm_source=github&utm_medium=readme) — every common escalation path on one page, with fixes
|
|
109
|
+
- [Free browser tools](https://www.shieldly.io/tools?utm_source=github&utm_medium=readme) — IAM policy linter, trust policy explainer, S3 bucket policy checker, CloudFormation IAM checker
|
|
110
|
+
- [IAM privilege escalation reference](https://www.shieldly.io/iam?utm_source=github&utm_medium=readme) — each method with a vulnerable policy, the exploit, and the fix
|
|
111
|
+
|
|
104
112
|
## License
|
|
105
113
|
|
|
106
114
|
MIT © Shieldly
|
package/dist/cli.cjs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
`)}catch{}}function
|
|
2
|
+
var ie=Object.create;var W=Object.defineProperty;var le=Object.getOwnPropertyDescriptor;var ae=Object.getOwnPropertyNames;var ce=Object.getPrototypeOf,pe=Object.prototype.hasOwnProperty;var de=(e,s,o,n)=>{if(s&&typeof s=="object"||typeof s=="function")for(let t of ae(s))!pe.call(e,t)&&t!==o&&W(e,t,{get:()=>s[t],enumerable:!(n=le(s,t))||n.enumerable});return e};var B=(e,s,o)=>(o=e!=null?ie(ce(e)):{},de(s||!e||!e.__esModule?W(o,"default",{value:e,enumerable:!0}):o,e));var k=require("node:fs"),Y=require("node:path");var I=require("node:fs"),q=require("node:os"),j=require("node:path"),D="Shieldly-CLI/1.0.5",F=(0,j.join)((0,q.homedir)(),".shieldly","config.json"),ye="https://api.shieldly.io",me="https://www.shieldly.io",K=5;function N(){try{return JSON.parse((0,I.readFileSync)(F,"utf8"))}catch{return{}}}function ue(e){try{(0,I.mkdirSync)((0,j.dirname)(F),{recursive:!0}),(0,I.writeFileSync)(F,`${JSON.stringify(e,null,2)}
|
|
3
|
+
`)}catch{}}function P(e){return e||(process.env.SHIELDLY_API_KEY?process.env.SHIELDLY_API_KEY:N().apiKey||null)}function V(){let e=N().demoCount;return typeof e=="number"&&e>0?e:0}function _(){return V()>=K}function M(){let e=N();return e.demoCount=V()+1,ue(e),Math.max(0,K-e.demoCount)}function R(){return`You've used all ${K} free demo analyses.
|
|
4
4
|
|
|
5
5
|
Get an API key (Builder plan or above) for higher limits: https://www.shieldly.io/app/api
|
|
6
6
|
|
|
7
|
-
Then set SHIELDLY_API_KEY or pass --api-key.`}function
|
|
8
|
-
`),r;continue}if(
|
|
9
|
-
`),{...
|
|
10
|
-
`),new Error(
|
|
11
|
-
`),new Error("Analysis timed out after polling")}async function
|
|
12
|
-
For a CDK output directory, use: shieldly analyze-cf ${e}`),process.exit(1)),(0
|
|
13
|
-
${
|
|
7
|
+
Then set SHIELDLY_API_KEY or pass --api-key.`}function T(){return(process.env.SHIELDLY_API_URL||ye).replace(/\/$/,"")}function Z(){return(process.env.SHIELDLY_WEB_URL||me).replace(/\/$/,"")}function C(e){let s=Z(),o=e==null?"":`?score=${encodeURIComponent(e)}`;return`[](${s})`}async function v(e,s){let o=Z(),n=await fetch(`${o}${e}`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":D},body:JSON.stringify(s)});if(n.status===429)throw new Error("Demo rate limit reached. Get an API key (Builder plan or above) for higher limits: https://www.shieldly.io/app/api");if(!n.ok){let t=await n.json().catch(()=>({}));throw new Error(t.error||`API error ${n.status}`)}return n.json()}async function x(e,s,o){let n=T(),t=await fetch(`${n}${e}`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":D,Authorization:`Bearer ${o}`},body:JSON.stringify(s)});if(t.status===202){let i=await t.json().catch(()=>({}));if(i.jobId)return fe(i.jobId,o);throw new Error("Analysis queued but no job ID returned \u2014 try again")}if(!t.ok){let i=await t.json().catch(()=>({}));throw new Error(i.error||`API error ${t.status}`)}return t.json()}async function fe(e,s){let o=[2e3,3e3,5e3],n=Date.now(),t=0;for(let i=0;i<180;i++){let l=o[Math.min(i,o.length-1)];await new Promise(r=>setTimeout(r,l));let d=Math.round((Date.now()-n)/1e3);process.stderr.write(`\rAI-Powered analysis in progress\u2026 (${d}s)`);let c;try{c=await G(`/v1/jobs/${encodeURIComponent(e)}`,s),t=0}catch(r){if(++t>=3)throw process.stderr.write(`
|
|
8
|
+
`),r;continue}if(c.status==="complete")return process.stderr.write(`
|
|
9
|
+
`),{...c.result,unitInfo:c.unitInfo};if(c.status==="failed")throw process.stderr.write(`
|
|
10
|
+
`),new Error(c.error||"Analysis failed")}throw process.stderr.write(`
|
|
11
|
+
`),new Error("Analysis timed out after polling")}async function G(e,s){let o=T(),n=await fetch(`${o}${e}`,{headers:{Authorization:`Bearer ${s}`,"User-Agent":D}});if(!n.ok){let t=await n.json().catch(()=>({}));throw new Error(t.error||`API error ${n.status}`)}return n.json()}async function Q(e,s,o){let n=T(),t=await fetch(`${n}${e}`,{method:"DELETE",headers:{"Content-Type":"application/json","User-Agent":D,Authorization:`Bearer ${o}`},body:JSON.stringify(s)});if(!t.ok){let i=await t.json().catch(()=>({}));throw new Error(i.error||`API error ${t.status}`)}return t.json()}function U(e){return(0,I.existsSync)(e)||(console.error(`Error: File not found: ${e}`),process.exit(1)),(0,I.statSync)(e).isDirectory()&&(console.error(`Error: ${e} is a directory, not a file.
|
|
12
|
+
For a CDK output directory, use: shieldly analyze-cf ${e}`),process.exit(1)),(0,I.readFileSync)(e,"utf8")}var H={CRITICAL:"\x1B[31m",HIGH:"\x1B[33m",MEDIUM:"\x1B[36m",LOW:"\x1B[32m",INFO:"\x1B[90m"},y="\x1B[0m",S="\x1B[1m",b="\x1B[2m",J="\x1B[36m";function L(e,s){if(s==="json"){console.log(JSON.stringify(e,null,2));return}let{score:o,riskLevel:n,findings:t=[],cached:i,summary:l,positives:d=[],unitInfo:c}=e,r=o==null?"\u2014":`${o}/100`;if(console.log(""),console.log(`${S}AI-Powered Security Analysis \u2014 Shieldly${y}`),console.log(`${b}${"\u2500".repeat(50)}${y}`),console.log(` ${S}Security Score:${y} ${he(o)}${r}${y}`),console.log(` ${S}Risk Level:${y} ${$e(n)}${n||"Unknown"}${y}`),i&&console.log(` ${b}(cached result)${y}`),l&&(console.log(""),console.log(` ${b}${l}${y}`)),console.log(""),d.length>0){console.log(`${S}What's good:${y}`);for(let p of d)console.log(` ${H.LOW}[+]${y} ${b}${p}${y}`);console.log("")}if(t.length===0)console.log(` ${J}[PASS] No findings${y}`);else{console.log(`${S}Findings (${t.length}):${y}`);for(let p of t){let h=H[(p.severity||"").toUpperCase()]||"";console.log(`
|
|
13
|
+
${h}[${p.severity}]${y} ${S}${p.title}${y}`),p.resource&&p.resource!=="*"&&console.log(` ${b}Resource: ${p.resource}${y}`),p.description&&console.log(` ${b}${p.description}${y}`),p.remediation&&console.log(` ${J}Fix:${y} ${p.remediation}`)}}c&&typeof c.unitsUsed=="number"&&typeof c.cap=="number"&&(console.log(""),console.log(` ${b}Units used: ${c.unitsUsed}/${c.cap}${y}`)),e.demoInfo&&typeof e.demoInfo.analysesRemaining=="number"&&(console.log(""),console.log(` ${b}Demo analyses remaining: ${e.demoInfo.analysesRemaining}. Get an API key (Builder plan or above) for more: https://www.shieldly.io/app/api${y}`)),console.log("")}function he(e){return e==null?"":e>=80?"\x1B[32m":e>=50?"\x1B[33m":"\x1B[31m"}function $e(e){let s=(e||"").toUpperCase();return H[s]||""}var ge=`
|
|
14
14
|
Usage: shieldly analyze-cf <template-file-or-dir> [options]
|
|
15
15
|
|
|
16
16
|
Analyze a CloudFormation template (or directory of templates) for security issues using AI.
|
|
@@ -23,6 +23,7 @@ Arguments:
|
|
|
23
23
|
Options:
|
|
24
24
|
--format <fmt> Output format: table | json (default: table)
|
|
25
25
|
--api-key <key> API key (or set SHIELDLY_API_KEY env var)
|
|
26
|
+
--badge Print a shareable score badge (Markdown, for a README)
|
|
26
27
|
-h, --help Show this help
|
|
27
28
|
|
|
28
29
|
Authentication:
|
|
@@ -43,13 +44,13 @@ cdk.json hook (runs after every cdk synth):
|
|
|
43
44
|
"afterSynth": ["sh", "-c", "shieldly analyze-cf cdk.out/ || true"]
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
|
-
`;function
|
|
47
|
+
`;function Ie(e){try{let s=(0,k.readFileSync)((0,Y.join)(e,"manifest.json"),"utf8"),o=JSON.parse(s);if(!o.artifacts||typeof o.artifacts!="object")return null;let n=Object.values(o.artifacts).filter(t=>t.type==="aws:cloudformation:stack"&&t.properties?.templateFile).map(t=>(0,Y.join)(e,t.properties.templateFile)).filter(t=>(0,k.existsSync)(t));return n.length>0?n:null}catch{return null}}function ke(e){let s=Ie(e);if(s)return s;let o=[],n;try{n=(0,k.readdirSync)(e,{withFileTypes:!0})}catch{return o}for(let t of n){if(!t.isFile())continue;let i=t.name;(i.endsWith(".template.json")||i.endsWith(".template.yaml"))&&o.push((0,Y.join)(e,i))}return o}async function be(e,s,o,n,t){let i=(0,k.readFileSync)(e,"utf8");o!=="json"&&t>1?process.stdout.write(`[${n}/${t}] Analyzing ${e}\u2026
|
|
47
48
|
`):o!=="json"&&process.stdout.write(`Analyzing ${e}\u2026
|
|
48
|
-
`);let l=s?await
|
|
49
|
+
`);let l=s?await x("/v1/analyze/cf",{template:i},s):await v("/api/demo/analyze-iam",{template:i,policyType:"cf"});return!s&&!l.cached&&M(),{filePath:e,data:l}}async function X(e){if(e.includes("-h")||e.includes("--help")||e.length===0){console.log(ge);return}let s=e.indexOf("--format"),o=s!==-1?e[s+1]:"table";s!==-1&&!["table","json"].includes(o)&&(console.error(`Error: invalid --format "${o}". Use: table | json`),process.exit(1));let n=e.indexOf("--api-key"),t=P(n!==-1?e[n+1]:null),i=new Set;for(let r of[s,n])r!==-1&&(i.add(r),i.add(r+1));let l=e.find((r,p)=>!i.has(p)&&!r.startsWith("--"));l||(console.error("Error: template-file-or-dir argument is required"),process.exit(1)),!t&&_()&&(console.error(R()),process.exit(1)),!t&&o!=="json"&&console.log("Demo mode (rate-limited, no signup required). Get an API key (Builder plan or above) for higher limits: https://www.shieldly.io/app/api");let d=(0,k.statSync)(l,{throwIfNoEntry:!1});if(d||(console.error(`Error: path not found: ${l}`),process.exit(1)),d.isDirectory()){let r=ke(l);r.length===0&&(console.error(`Error: no CloudFormation templates (*.template.json / *.template.yaml) found in ${l}
|
|
49
50
|
Run "cdk synth" first to generate stack templates.`),process.exit(1)),o!=="json"&&console.log(`Found ${r.length} stack template(s) in ${l}
|
|
50
|
-
`);let
|
|
51
|
-
Demo allowance reached \u2014 remaining stacks skipped. Get an API key (Builder plan or above): https://www.shieldly.io/app/api`);break}try{let{filePath
|
|
52
|
-
Summary: ${r.length} stacks \xB7 ${
|
|
51
|
+
`);let p=[],h=0,a=0;for(let u=0;u<r.length;u++){if(!t&&_()){o!=="json"&&console.error(`
|
|
52
|
+
Demo allowance reached \u2014 remaining stacks skipped. Get an API key (Builder plan or above): https://www.shieldly.io/app/api`);break}try{let{filePath:$,data:f}=await be(r[u],t,o,u+1,r.length);p.push({filePath:$,data:f}),h+=(f.findings||[]).filter(A=>A.severity?.toUpperCase()==="CRITICAL").length,a+=(f.findings||[]).filter(A=>A.severity?.toUpperCase()==="HIGH").length,o!=="json"&&L(f,o)}catch($){if(console.error(`Error analyzing ${r[u]}: ${$.message}`),!t&&/rate limit/i.test($.message))break}}if(o==="json")console.log(JSON.stringify(p.map(({filePath:u,data:$})=>({stack:u,...$})),null,2));else if(r.length>1){let u=p.reduce(($,f)=>$+(f.data.findings||[]).length,0);console.log(`
|
|
53
|
+
Summary: ${r.length} stacks \xB7 ${u} total findings \xB7 ${h} critical \xB7 ${a} high`)}if(e.includes("--badge")&&p.length>0){let u=p.map(({data:A})=>A.score).filter(A=>typeof A=="number"),$=u.length>0?Math.min(...u):null,f=C($);o==="json"?console.error(f):console.log(f)}(h>0||a>0)&&process.exit(1);return}let c=U(l);o!=="json"&&console.log(`Analyzing ${l}\u2026`);try{let r=t?await x("/v1/analyze/cf",{template:c},t):await v("/api/demo/analyze-iam",{template:c,policyType:"cf"});if(L(r,o),e.includes("--badge")){let a=C(r.score);o==="json"?console.error(a):console.log(a)}let p=(r.findings||[]).filter(a=>a.severity?.toUpperCase()==="CRITICAL").length,h=(r.findings||[]).filter(a=>a.severity?.toUpperCase()==="HIGH").length;(p>0||h>0)&&process.exit(1)}catch(r){console.error(`Error: ${r.message}`),process.exit(1)}}var we=`
|
|
53
54
|
Usage: shieldly analyze-iam <policy-file> [options]
|
|
54
55
|
|
|
55
56
|
Analyze an AWS IAM policy for security issues using AI.
|
|
@@ -63,13 +64,15 @@ Options:
|
|
|
63
64
|
'cross_account' expects {"identityPolicy":\u2026,"trustPolicy":\u2026}.
|
|
64
65
|
--format <fmt> Output format: table | json (default: table)
|
|
65
66
|
--api-key <key> API key (or set SHIELDLY_API_KEY env var)
|
|
67
|
+
--badge Print a shareable score badge (Markdown, for a README)
|
|
66
68
|
-h, --help Show this help
|
|
67
69
|
|
|
68
70
|
Examples:
|
|
69
71
|
shieldly analyze-iam policy.json
|
|
70
72
|
shieldly analyze-iam policy.json --type cross_account --format json
|
|
73
|
+
shieldly analyze-iam policy.json --badge
|
|
71
74
|
SHIELDLY_API_KEY=sk_... shieldly analyze-iam policy.json
|
|
72
|
-
`;async function
|
|
75
|
+
`;async function ee(e){if(e.includes("-h")||e.includes("--help")||e.length===0){console.log(we);return}let s=e.indexOf("--type"),o=s!==-1?e[s+1]:"identity",n=e.indexOf("--format"),t=n!==-1?e[n+1]:"table";s!==-1&&!["identity","iam_identity","cross_account"].includes(o)&&(console.error(`Error: invalid --type "${o}". Use: identity | cross_account`),process.exit(1)),n!==-1&&!["table","json"].includes(t)&&(console.error(`Error: invalid --format "${t}". Use: table | json`),process.exit(1));let i=e.indexOf("--api-key"),l=P(i!==-1?e[i+1]:null);!l&&_()&&(console.error(R()),process.exit(1));let d=new Set;for(let a of[s,n,i])a!==-1&&(d.add(a),d.add(a+1));let c=e.find((a,u)=>!d.has(u)&&!a.startsWith("--"));c||(console.error("Error: policy-file argument is required"),process.exit(1));let r=U(c);try{JSON.parse(r)}catch{console.error("Error: policy-file must be valid JSON"),process.exit(1)}let p=r.trim(),h=o==="identity"||o==="iam_identity"?"iam_identity":o==="cross_account"?"cross_account":"iam_identity";t!=="json"&&(console.log(`Analyzing ${c} (type: ${h})\u2026`),l||console.log("Demo mode (rate-limited, no signup required). Get an API key (Builder plan or above) for higher limits: https://www.shieldly.io/app/api"));try{let a=l?await x("/v1/analyze/iam",{policy:p,policyType:h},l):await v("/api/demo/analyze-iam",{policy:p,policyType:h});if(!l&&!a.cached&&M(),L(a,t),e.includes("--badge")){let f=C(a.score);t==="json"?console.error(f):console.log(f)}let u=(a.findings||[]).filter(f=>f.severity?.toUpperCase()==="CRITICAL").length,$=(a.findings||[]).filter(f=>f.severity?.toUpperCase()==="HIGH").length;(u>0||$>0)&&process.exit(1)}catch(a){console.error(`Error: ${a.message}`),process.exit(1)}}var oe=`
|
|
73
76
|
Usage: shieldly api-keys <subcommand> [options]
|
|
74
77
|
|
|
75
78
|
Manage Shieldly API keys.
|
|
@@ -89,12 +92,12 @@ Examples:
|
|
|
89
92
|
shieldly api-keys list
|
|
90
93
|
shieldly api-keys create --label "CI/CD Key" --scopes iam,cf
|
|
91
94
|
shieldly api-keys revoke key_abc123
|
|
92
|
-
`,
|
|
95
|
+
`,w="\x1B[1m",te="\x1B[2m",se="\x1B[36m",g="\x1B[0m";function Ae(e){return e?new Date(e).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"}):"\u2014"}async function ne(e){if(e.includes("-h")||e.includes("--help")||e.length===0){console.log(oe);return}let s=e[0],o=e.slice(1),n=o.indexOf("--api-key"),t=P(n!==-1?o[n+1]:null),i=o.indexOf("--format"),l=i!==-1?o[i+1]:"table";if(i!==-1&&!["table","json"].includes(l)&&(console.error(`Error: invalid --format "${l}". Use: table | json`),process.exit(1)),t||(console.error(`API key management requires an API key to authenticate.
|
|
93
96
|
|
|
94
97
|
Get an API key (Builder plan or above): https://www.shieldly.io/app/api
|
|
95
98
|
|
|
96
|
-
Set SHIELDLY_API_KEY or use --api-key once you have your key.`),process.exit(1)),s==="list"){try{let
|
|
97
|
-
Usage: shieldly api-keys revoke <key-id>`),process.exit(1));try{if(await
|
|
99
|
+
Set SHIELDLY_API_KEY or use --api-key once you have your key.`),process.exit(1)),s==="list"){try{let c=(await G("/v1/api-keys",t)).keys||[];if(l==="json"){console.log(JSON.stringify(c,null,2));return}if(c.length===0){console.log("No API keys found. Create one at https://www.shieldly.io/app/api");return}console.log(""),console.log(`${w}API Keys (${c.length}):${g}`),console.log(`${te}${"\u2500".repeat(60)}${g}`);for(let r of c){let p=(r.scopes||[]).join(", ")||"all";console.log(` ${se}${r.keyId}${g}`),console.log(` ${w}Label:${g} ${r.label||"(unlabeled)"}`),console.log(` ${w}Scopes:${g} ${p}`),console.log(` ${w}Uses:${g} ${r.usageCount||0}`),console.log(` ${w}Created:${g} ${Ae(r.createdAt)}`),console.log("")}}catch(d){console.error(`Error: ${d.message}`),process.exit(1)}return}if(s==="create"){let d=o.indexOf("--label"),c=d!==-1?o[d+1]:"CLI Key",r=o.indexOf("--scopes"),h=(r!==-1?o[r+1]:"iam,cf").split(",").map(a=>a.trim()).filter(Boolean);try{let a=await x("/v1/api-keys",{label:c,scopes:h},t);if(l==="json"){console.log(JSON.stringify(a,null,2));return}console.log(""),console.log(`${w}[OK] API key created${g}`),console.log(` ${w}Key ID:${g} ${a.keyId}`),console.log(` ${w}API Key:${g} ${se}${a.apiKey}${g}`),console.log(` ${te}Store this key securely \u2014 it won't be shown again.${g}`),console.log("")}catch(a){console.error(`Error: ${a.message}`),process.exit(1)}return}if(s==="revoke"){let d=new Set;n!==-1&&(d.add(n),d.add(n+1)),i!==-1&&(d.add(i),d.add(i+1));let c=o.find((r,p)=>!d.has(p)&&!r.startsWith("--"));c||(console.error(`Error: key-id argument is required
|
|
100
|
+
Usage: shieldly api-keys revoke <key-id>`),process.exit(1));try{if(await Q("/v1/api-keys",{keyId:c},t),l==="json"){console.log(JSON.stringify({success:!0,keyId:c}));return}console.log(`[OK] API key ${c} revoked`)}catch(r){console.error(`Error: ${r.message}`),process.exit(1)}return}console.error(`Unknown subcommand: ${s}`),console.log(oe),process.exit(1)}var xe=`
|
|
98
101
|
_shieldly() {
|
|
99
102
|
local cur prev words cword
|
|
100
103
|
_init_completion || return
|
|
@@ -154,7 +157,7 @@ _shieldly() {
|
|
|
154
157
|
fi
|
|
155
158
|
} &&
|
|
156
159
|
complete -F _shieldly shieldly
|
|
157
|
-
`,
|
|
160
|
+
`,Ee=`
|
|
158
161
|
#compdef shieldly
|
|
159
162
|
|
|
160
163
|
_shieldly() {
|
|
@@ -225,7 +228,7 @@ _shieldly() {
|
|
|
225
228
|
}
|
|
226
229
|
|
|
227
230
|
_shieldly
|
|
228
|
-
`,
|
|
231
|
+
`,Se=`
|
|
229
232
|
Usage: shieldly completion <shell>
|
|
230
233
|
|
|
231
234
|
Generate shell completion scripts for the shieldly CLI.
|
|
@@ -239,45 +242,45 @@ Examples:
|
|
|
239
242
|
eval "$(shieldly completion bash)" # Source bash completion
|
|
240
243
|
shieldly completion zsh > /usr/local/share/zsh/site-functions/_shieldly # Install zsh completion
|
|
241
244
|
shieldly completion install # Auto-detect and install
|
|
242
|
-
`;async function
|
|
245
|
+
`;async function re(e){if(!e.length||e.includes("-h")||e.includes("--help")){console.log(Se);return}let s=e[0];switch(s){case"bash":console.log(xe.trimStart());break;case"zsh":console.log(Ee.trimStart());break;case"install":await Pe();break;default:console.error(`Unsupported shell: ${s}`),console.log("Supported shells: bash, zsh"),process.exit(1)}}async function Pe(){let e=process.env.SHELL||"",s=process.env.HOME||"";if(e.includes("zsh")){let o=`${s}/.zshrc`,n=`
|
|
243
246
|
# shieldly CLI completion
|
|
244
247
|
autoload -Uz compinit && compinit -C 2>/dev/null
|
|
245
248
|
eval "$(shieldly completion zsh)" 2>/dev/null`;try{let{readFileSync:t,appendFileSync:i,existsSync:l}=await import("node:fs");if(l(o)&&t(o,"utf8").includes("shieldly completion")){console.log("shieldly completion already installed in ~/.zshrc");return}i(o,n),console.log("Installed shieldly completion in ~/.zshrc"),console.log("Run: source ~/.zshrc")}catch(t){console.error(`Failed to install: ${t.message}`),process.exit(1)}}else if(e.includes("bash")){let o=`${s}/.bashrc`,n=`
|
|
246
249
|
# shieldly CLI completion
|
|
247
|
-
source /dev/stdin <<< "$(shieldly completion bash)" 2>/dev/null`;try{let{readFileSync:t,appendFileSync:i,existsSync:l}=await import("node:fs");if(l(o)&&t(o,"utf8").includes("shieldly completion")){console.log("shieldly completion already installed in ~/.bashrc");return}i(o,n),console.log("Installed shieldly completion in ~/.bashrc"),console.log("Run: source ~/.bashrc")}catch(t){console.error(`Failed to install: ${t.message}`),process.exit(1)}}else console.error(`Unsupported shell: ${e}. Install manually:`),console.log(' eval "$(shieldly completion bash)" # For bash'),console.log(' eval "$(shieldly completion zsh)" # For zsh'),process.exit(1)}var
|
|
248
|
-
${
|
|
250
|
+
source /dev/stdin <<< "$(shieldly completion bash)" 2>/dev/null`;try{let{readFileSync:t,appendFileSync:i,existsSync:l}=await import("node:fs");if(l(o)&&t(o,"utf8").includes("shieldly completion")){console.log("shieldly completion already installed in ~/.bashrc");return}i(o,n),console.log("Installed shieldly completion in ~/.bashrc"),console.log("Run: source ~/.bashrc")}catch(t){console.error(`Failed to install: ${t.message}`),process.exit(1)}}else console.error(`Unsupported shell: ${e}. Install manually:`),console.log(' eval "$(shieldly completion bash)" # For bash'),console.log(' eval "$(shieldly completion zsh)" # For zsh'),process.exit(1)}var E="\x1B[1m",z="\x1B[36m",O="\x1B[2m",m="\x1B[0m",_e="1.0.5",Ce=`
|
|
251
|
+
${E}shieldly${m} \u2014 AI-Powered Security Analysis for AWS
|
|
249
252
|
|
|
250
|
-
${
|
|
253
|
+
${E}Usage:${m}
|
|
251
254
|
shieldly <command> [args] [options]
|
|
252
255
|
|
|
253
|
-
${
|
|
254
|
-
${
|
|
255
|
-
${
|
|
256
|
-
${
|
|
257
|
-
${
|
|
256
|
+
${E}Commands:${m}
|
|
257
|
+
${z}analyze-iam${m} <policy-file> Analyze an IAM policy for security issues
|
|
258
|
+
${z}analyze-cf${m} <template-file-or-dir> Analyze a CloudFormation template or CDK output directory
|
|
259
|
+
${z}api-keys${m} list|create|revoke Manage API keys
|
|
260
|
+
${z}completion${m} bash|zsh|install Generate shell completion
|
|
258
261
|
|
|
259
|
-
${
|
|
262
|
+
${E}Global Options:${m}
|
|
260
263
|
--api-key <key> API key (or set SHIELDLY_API_KEY env var)
|
|
261
264
|
--version Show version
|
|
262
265
|
-h, --help Show this help
|
|
263
266
|
|
|
264
|
-
${
|
|
267
|
+
${E}Authentication:${m}
|
|
265
268
|
Set your API key via env var: export SHIELDLY_API_KEY=sk_...
|
|
266
|
-
Get an API key (Builder plan or above) at: ${
|
|
269
|
+
Get an API key (Builder plan or above) at: ${z}https://www.shieldly.io/app/api${m}
|
|
267
270
|
|
|
268
|
-
${
|
|
269
|
-
${
|
|
271
|
+
${E}Examples:${m}
|
|
272
|
+
${O}# Analyze an IAM policy or CF template (no API key needed \u2014 demo mode)${m}
|
|
270
273
|
shieldly analyze-iam policy.json
|
|
271
274
|
|
|
272
|
-
${
|
|
275
|
+
${O}# Analyze a single CloudFormation template${m}
|
|
273
276
|
shieldly analyze-cf template.json
|
|
274
277
|
|
|
275
|
-
${
|
|
278
|
+
${O}# Scan all CDK stacks after synthesis (reads manifest.json \u2014 current stacks only)${m}
|
|
276
279
|
cdk synth && shieldly analyze-cf cdk.out/
|
|
277
280
|
|
|
278
|
-
${
|
|
281
|
+
${O}# List API keys${m}
|
|
279
282
|
shieldly api-keys list
|
|
280
283
|
|
|
281
|
-
${
|
|
284
|
+
${O}# Use in CI${m}
|
|
282
285
|
SHIELDLY_API_KEY=\${{ secrets.SHIELDLY_API_KEY }} shieldly analyze-iam policy.json
|
|
283
|
-
`;async function ve(){let[,,e,...s]=process.argv;switch((!e||e==="-h"||e==="--help")&&(console.log(
|
|
286
|
+
`;async function ve(){let[,,e,...s]=process.argv;switch((!e||e==="-h"||e==="--help")&&(console.log(Ce),process.exit(0)),(e==="--version"||e==="-v")&&(console.log(_e),process.exit(0)),e){case"analyze-iam":await ee(s);break;case"analyze-cf":await X(s);break;case"api-keys":await ne(s);break;case"completion":await re(s);break;default:console.error(`Unknown command: ${e}`),console.log(`Run ${E}shieldly --help${m} for usage`),process.exit(1)}}ve().catch(e=>{console.error("Fatal error:",e.message),process.exit(1)});
|