@shieldly/cli 1.0.0
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/LICENSE +21 -0
- package/README.md +81 -0
- package/dist/cli.cjs +249 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Shieldly
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# @shieldly/cli
|
|
2
|
+
|
|
3
|
+
**AI-Powered Security Analysis for AWS — official CLI.**
|
|
4
|
+
|
|
5
|
+
Analyze AWS IAM policies and CloudFormation templates for security risks from
|
|
6
|
+
any terminal, shell script, or CI/CD pipeline. Powered by
|
|
7
|
+
[Shieldly](https://www.shieldly.io).
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g @shieldly/cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Authenticate (get a key at https://www.shieldly.io/app/api)
|
|
17
|
+
export SHIELDLY_API_KEY=sk_live_...
|
|
18
|
+
|
|
19
|
+
# Analyze an IAM policy
|
|
20
|
+
shieldly analyze-iam policy.json
|
|
21
|
+
|
|
22
|
+
# Analyze a CloudFormation template
|
|
23
|
+
shieldly analyze-cf template.yaml
|
|
24
|
+
|
|
25
|
+
# Manage API keys
|
|
26
|
+
shieldly api-keys list
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Without an API key, `analyze-iam` runs in demo mode (5 lifetime analyses, IAM only).
|
|
30
|
+
`analyze-cf` and `api-keys` require a key.
|
|
31
|
+
|
|
32
|
+
## Commands
|
|
33
|
+
|
|
34
|
+
| Command | Description |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| `shieldly analyze-iam <policy-file>` | Analyze an IAM policy for security issues |
|
|
37
|
+
| `shieldly analyze-cf <template-file>` | Analyze a CloudFormation template |
|
|
38
|
+
| `shieldly api-keys list\|create\|revoke` | Manage API keys |
|
|
39
|
+
| `shieldly completion bash\|zsh\|install` | Shell completion |
|
|
40
|
+
|
|
41
|
+
## Global options
|
|
42
|
+
|
|
43
|
+
| Option | Description |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `--api-key <key>` | API key (or set `SHIELDLY_API_KEY`) |
|
|
46
|
+
| `--version` | Show version |
|
|
47
|
+
| `-h`, `--help` | Show help |
|
|
48
|
+
|
|
49
|
+
## Use in CI
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
- name: AI-Powered IAM Analysis
|
|
53
|
+
run: |
|
|
54
|
+
npm install -g @shieldly/cli
|
|
55
|
+
shieldly analyze-iam ./iam-policy.json
|
|
56
|
+
env:
|
|
57
|
+
SHIELDLY_API_KEY: ${{ secrets.SHIELDLY_API_KEY }}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
For pull-request gating with PR comments, use the
|
|
61
|
+
[Shieldly GitHub Action](https://github.com/shieldly-io/action) instead.
|
|
62
|
+
|
|
63
|
+
## Privacy
|
|
64
|
+
|
|
65
|
+
Shieldly does **not** log your policy input. Cache keys are one-way SHA-256
|
|
66
|
+
hashes of the input.
|
|
67
|
+
|
|
68
|
+
## Links
|
|
69
|
+
|
|
70
|
+
- Web app & demo: https://www.shieldly.io
|
|
71
|
+
- API reference: https://www.shieldly.io/docs/api
|
|
72
|
+
- Issues: https://github.com/shieldly-io/cli/issues
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT © Shieldly
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
*Amazon Web Services (AWS) is a trademark of Amazon.com, Inc. Shieldly is not
|
|
81
|
+
affiliated with, endorsed by, or sponsored by Amazon Web Services.*
|
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var J=Object.create;var O=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var V=Object.getPrototypeOf,Z=Object.prototype.hasOwnProperty;var Q=(e,o,t,n)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of q(o))!Z.call(e,s)&&s!==t&&O(e,s,{get:()=>o[s],enumerable:!(n=B(o,s))||n.enumerable});return e};var C=(e,o,t)=>(t=e!=null?J(V(e)):{},Q(o||!e||!e.__esModule?O(t,"default",{value:e,enumerable:!0}):t,e));var $=require("node:fs"),j=require("node:os"),D=require("node:path"),b="Shieldly-CLI/1.0.0",z=(0,D.join)((0,j.homedir)(),".shieldly","config.json"),X="https://api.shieldly.io",ee="https://www.shieldly.io";function g(e){if(e)return e;if(process.env.SHIELDLY_API_KEY)return process.env.SHIELDLY_API_KEY;if((0,$.existsSync)(z))try{let o=JSON.parse((0,$.readFileSync)(z,"utf8"));if(o.apiKey)return o.apiKey}catch{}return null}function _(){return(process.env.SHIELDLY_API_URL||X).replace(/\/$/,"")}function oe(){return(process.env.SHIELDLY_WEB_URL||ee).replace(/\/$/,"")}async function R(e,o){let t=oe(),n=await fetch(`${t}${e}`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":b},body:JSON.stringify(o)});if(!n.ok){let s=await n.json().catch(()=>({}));throw new Error(s.error||`API error ${n.status}`)}return n.json()}async function I(e,o,t){let n=_(),s=await fetch(`${n}${e}`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":b,Authorization:`Bearer ${t}`},body:JSON.stringify(o)});if(s.status===202){let r=await s.json().catch(()=>({}));if(r.jobId)return se(r.jobId,t)}if(!s.ok){let r=await s.json().catch(()=>({}));throw new Error(r.error||`API error ${s.status}`)}return s.json()}async function se(e,o){let t=[2e3,3e3,5e3],n=Date.now(),s=0;for(let r=0;r<180;r++){let i=t[Math.min(r,t.length-1)];await new Promise(c=>setTimeout(c,i));let l=Math.round((Date.now()-n)/1e3);process.stderr.write(`\rAI-Powered analysis in progress\u2026 (${l}s)`);let a;try{a=await v(`/v1/jobs/${encodeURIComponent(e)}`,o),s=0}catch(c){if(++s>=3)throw process.stderr.write(`
|
|
3
|
+
`),c;continue}if(a.status==="complete")return process.stderr.write(`
|
|
4
|
+
`),{...a.result,unitInfo:a.unitInfo};if(a.status==="failed")throw process.stderr.write(`
|
|
5
|
+
`),new Error(a.error||"Analysis failed")}throw process.stderr.write(`
|
|
6
|
+
`),new Error("Analysis timed out after polling")}async function v(e,o){let t=_(),n=await fetch(`${t}${e}`,{headers:{Authorization:`Bearer ${o}`,"User-Agent":b}});if(!n.ok){let s=await n.json().catch(()=>({}));throw new Error(s.error||`API error ${n.status}`)}return n.json()}async function M(e,o,t){let n=_(),s=await fetch(`${n}${e}`,{method:"DELETE",headers:{"Content-Type":"application/json","User-Agent":b,Authorization:`Bearer ${t}`},body:JSON.stringify(o)});if(!s.ok){let r=await s.json().catch(()=>({}));throw new Error(r.error||`API error ${s.status}`)}return s.json()}function w(e){return(0,$.existsSync)(e)||(console.error(`Error: File not found: ${e}`),process.exit(1)),(0,$.readFileSync)(e,"utf8")}var K={CRITICAL:"\x1B[31m",HIGH:"\x1B[33m",MEDIUM:"\x1B[36m",LOW:"\x1B[32m",INFO:"\x1B[90m"},m="\x1B[0m",k="\x1B[1m",L="\x1B[2m",Y="\x1B[36m";function x(e,o){if(o==="json"){console.log(JSON.stringify(e,null,2));return}let{score:t,riskLevel:n,findings:s=[],cached:r}=e;if(console.log(""),console.log(`${k}AI-Powered Security Analysis \u2014 Shieldly${m}`),console.log(`${L}${"\u2500".repeat(50)}${m}`),console.log(` ${k}Security Score:${m} ${te(t)}${t}/100${m}`),console.log(` ${k}Risk Level:${m} ${ne(n)}${n}${m}`),r&&console.log(` ${L}(cached result)${m}`),console.log(""),s.length===0)console.log(` ${Y}[PASS] No findings${m}`);else{console.log(`${k}Findings (${s.length}):${m}`);for(let i of s){let l=K[(i.severity||"").toUpperCase()]||"";console.log(`
|
|
7
|
+
${l}[${i.severity}]${m} ${k}${i.title}${m}`),i.description&&console.log(` ${L}${i.description}${m}`),i.remediation&&console.log(` ${Y}Fix:${m} ${i.remediation}`)}}console.log("")}function te(e){return e>=80?"\x1B[32m":e>=50?"\x1B[33m":"\x1B[31m"}function ne(e){let o=(e||"").toUpperCase();return K[o]||""}var le=`
|
|
8
|
+
Usage: shieldly analyze-cf <template-file> [options]
|
|
9
|
+
|
|
10
|
+
Analyze a CloudFormation template for security issues using AI.
|
|
11
|
+
|
|
12
|
+
Arguments:
|
|
13
|
+
template-file Path to a JSON or YAML CloudFormation template
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
--format <fmt> Output format: table | json (default: table)
|
|
17
|
+
--api-key <key> API key (or set SHIELDLY_API_KEY env var)
|
|
18
|
+
-h, --help Show this help
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
shieldly analyze-cf template.json
|
|
22
|
+
shieldly analyze-cf template.yaml --format json
|
|
23
|
+
`;async function H(e){if(e.includes("-h")||e.includes("--help")||e.length===0){console.log(le);return}let o=e.find(l=>!l.startsWith("--"));o||(console.error("Error: template-file argument is required"),process.exit(1));let t=e.indexOf("--format"),n=t!==-1?e[t+1]:"table",s=e.indexOf("--api-key"),r=g(s!==-1?e[s+1]:null);r||(console.error(`Error: API key required. Set SHIELDLY_API_KEY env var or use --api-key.
|
|
24
|
+
Get your free key at https://www.shieldly.io/app/api`),process.exit(1));let i=w(o);n!=="json"&&console.log(`Analyzing ${o}\u2026`);try{let l=await I("/v1/analyze/cf",{template:i},r);x(l,n);let a=(l.findings||[]).filter(y=>y.severity==="CRITICAL").length,c=(l.findings||[]).filter(y=>y.severity==="HIGH").length;(a>0||c>0)&&process.exit(1)}catch(l){console.error(`Error: ${l.message}`),process.exit(1)}}var re=`
|
|
25
|
+
Usage: shieldly analyze-iam <policy-file> [options]
|
|
26
|
+
|
|
27
|
+
Analyze an AWS IAM policy for security issues using AI.
|
|
28
|
+
|
|
29
|
+
Arguments:
|
|
30
|
+
policy-file Path to a JSON file containing the IAM policy
|
|
31
|
+
|
|
32
|
+
Options:
|
|
33
|
+
--type <type> identity (default) | cross_account
|
|
34
|
+
Any IAM or resource policy JSON works as 'identity'.
|
|
35
|
+
'cross_account' expects {"identityPolicy":\u2026,"trustPolicy":\u2026}.
|
|
36
|
+
--format <fmt> Output format: table | json (default: table)
|
|
37
|
+
--api-key <key> API key (or set SHIELDLY_API_KEY env var)
|
|
38
|
+
-h, --help Show this help
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
shieldly analyze-iam policy.json
|
|
42
|
+
shieldly analyze-iam policy.json --type resource --format json
|
|
43
|
+
SHIELDLY_API_KEY=sk_... shieldly analyze-iam policy.json
|
|
44
|
+
`;async function F(e){if(e.includes("-h")||e.includes("--help")||e.length===0){console.log(re);return}let o=e.find(y=>!y.startsWith("--"));o||(console.error("Error: policy-file argument is required"),process.exit(1));let t=e.indexOf("--type"),n=t!==-1?e[t+1]:"identity",s=e.indexOf("--format"),r=s!==-1?e[s+1]:"table",i=e.indexOf("--api-key"),l=g(i!==-1?e[i+1]:null),a=w(o),c;try{c=JSON.parse(a)}catch{console.error("Error: policy-file must be valid JSON"),process.exit(1)}r!=="json"&&(console.log(`Analyzing ${o} (type: ${n})\u2026`),l||console.log("Demo mode (5 lifetime analyses). Get a free key at https://www.shieldly.io/app/api"));try{let y=l?await I("/v1/analyze/iam",{policy:c,policyType:n},l):await R("/api/demo/analyze-iam",{policy:c,policyType:n});x(y,r);let E=(y.findings||[]).filter(S=>S.severity==="CRITICAL").length,d=(y.findings||[]).filter(S=>S.severity==="HIGH").length;(E>0||d>0)&&process.exit(1)}catch(y){console.error(`Error: ${y.message}`),process.exit(1)}}var U=`
|
|
45
|
+
Usage: shieldly api-keys <subcommand> [options]
|
|
46
|
+
|
|
47
|
+
Manage Shieldly API keys.
|
|
48
|
+
|
|
49
|
+
Subcommands:
|
|
50
|
+
list List all your API keys
|
|
51
|
+
create --label <label> Create a new API key
|
|
52
|
+
--scopes <scopes> Comma-separated scopes: iam,cf,cost (default: iam,cf)
|
|
53
|
+
revoke <key-id> Revoke an API key by ID
|
|
54
|
+
|
|
55
|
+
Options:
|
|
56
|
+
--api-key <key> API key (or set SHIELDLY_API_KEY env var)
|
|
57
|
+
--format json Output as JSON
|
|
58
|
+
-h, --help Show this help
|
|
59
|
+
|
|
60
|
+
Examples:
|
|
61
|
+
shieldly api-keys list
|
|
62
|
+
shieldly api-keys create --label "CI/CD Key" --scopes iam,cf
|
|
63
|
+
shieldly api-keys revoke key_abc123
|
|
64
|
+
`,u="\x1B[1m",N="\x1B[2m",T="\x1B[36m",h="\x1B[0m";function ie(e){return e?new Date(e).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"}):"\u2014"}async function G(e){if(e.includes("-h")||e.includes("--help")||e.length===0){console.log(U);return}let o=e[0],t=e.slice(1),n=t.indexOf("--api-key"),s=g(n!==-1?t[n+1]:null),r=t.indexOf("--format"),i=r!==-1?t[r+1]:"table";if(s||(console.error(`Error: API key required. Set SHIELDLY_API_KEY env var or use --api-key.
|
|
65
|
+
Get your free key at https://www.shieldly.io/app/api`),process.exit(1)),o==="list"){try{let a=(await v("/v1/api-keys",s)).keys||[];if(i==="json"){console.log(JSON.stringify(a,null,2));return}if(a.length===0){console.log("No API keys found. Create one at https://www.shieldly.io/app/api");return}console.log(""),console.log(`${u}API Keys (${a.length}):${h}`),console.log(`${N}${"\u2500".repeat(60)}${h}`);for(let c of a){let y=(c.scopes||[]).join(", ")||"all";console.log(` ${T}${c.keyId}${h}`),console.log(` ${u}Label:${h} ${c.label||"(unlabeled)"}`),console.log(` ${u}Scopes:${h} ${y}`),console.log(` ${u}Uses:${h} ${c.usageCount||0}`),console.log(` ${u}Created:${h} ${ie(c.createdAt)}`),console.log("")}}catch(l){console.error(`Error: ${l.message}`),process.exit(1)}return}if(o==="create"){let l=t.indexOf("--label"),a=l!==-1?t[l+1]:"CLI Key",c=t.indexOf("--scopes"),E=(c!==-1?t[c+1]:"iam,cf").split(",").map(d=>d.trim()).filter(Boolean);try{let d=await I("/v1/api-keys",{label:a,scopes:E},s);if(i==="json"){console.log(JSON.stringify(d,null,2));return}console.log(""),console.log(`${u}[OK] API key created${h}`),console.log(` ${u}Key ID:${h} ${d.keyId}`),console.log(` ${u}API Key:${h} ${T}${d.apiKey}${h}`),console.log(` ${N}Store this key securely \u2014 it won't be shown again.${h}`),console.log("")}catch(d){console.error(`Error: ${d.message}`),process.exit(1)}return}if(o==="revoke"){let l=t.find(a=>!a.startsWith("--")&&a!=="revoke");l||(console.error(`Error: key-id argument is required
|
|
66
|
+
Usage: shieldly api-keys revoke <key-id>`),process.exit(1));try{if(await M("/v1/api-keys",{keyId:l},s),i==="json"){console.log(JSON.stringify({success:!0,keyId:l}));return}console.log(`[OK] API key ${l} revoked`)}catch(a){console.error(`Error: ${a.message}`),process.exit(1)}return}console.error(`Unknown subcommand: ${o}`),console.log(U),process.exit(1)}var ae=`
|
|
67
|
+
_shieldly() {
|
|
68
|
+
local cur prev words cword
|
|
69
|
+
_init_completion || return
|
|
70
|
+
|
|
71
|
+
local commands="analyze-iam analyze-cf api-keys completion"
|
|
72
|
+
local global_opts="--api-key --help -h --version -v"
|
|
73
|
+
|
|
74
|
+
case $prev in
|
|
75
|
+
analyze-iam)
|
|
76
|
+
if [[ $cur == -* ]]; then
|
|
77
|
+
COMPREPLY=($(compgen -W "--type --format --api-key --help -h" -- "$cur"))
|
|
78
|
+
else
|
|
79
|
+
COMPREPLY=($(compgen -f -- "$cur"))
|
|
80
|
+
fi
|
|
81
|
+
return
|
|
82
|
+
;;
|
|
83
|
+
analyze-cf)
|
|
84
|
+
if [[ $cur == -* ]]; then
|
|
85
|
+
COMPREPLY=($(compgen -W "--format --api-key --help -h" -- "$cur"))
|
|
86
|
+
else
|
|
87
|
+
COMPREPLY=($(compgen -f -- "$cur"))
|
|
88
|
+
fi
|
|
89
|
+
return
|
|
90
|
+
;;
|
|
91
|
+
api-keys)
|
|
92
|
+
COMPREPLY=($(compgen -W "list create revoke" -- "$cur"))
|
|
93
|
+
return
|
|
94
|
+
;;
|
|
95
|
+
completion)
|
|
96
|
+
COMPREPLY=($(compgen -W "bash zsh install" -- "$cur"))
|
|
97
|
+
return
|
|
98
|
+
;;
|
|
99
|
+
--type)
|
|
100
|
+
COMPREPLY=($(compgen -W "identity resource trust s3 sqs kms sns cross_account" -- "$cur"))
|
|
101
|
+
return
|
|
102
|
+
;;
|
|
103
|
+
--format)
|
|
104
|
+
COMPREPLY=($(compgen -W "table json" -- "$cur"))
|
|
105
|
+
return
|
|
106
|
+
;;
|
|
107
|
+
--label)
|
|
108
|
+
return
|
|
109
|
+
;;
|
|
110
|
+
--scopes)
|
|
111
|
+
COMPREPLY=($(compgen -W "iam cf cost" -- "$cur"))
|
|
112
|
+
return
|
|
113
|
+
;;
|
|
114
|
+
--api-key)
|
|
115
|
+
return
|
|
116
|
+
;;
|
|
117
|
+
esac
|
|
118
|
+
|
|
119
|
+
if [[ $cur == -* ]]; then
|
|
120
|
+
COMPREPLY=($(compgen -W "$global_opts" -- "$cur"))
|
|
121
|
+
elif [[ $cword -eq 1 ]]; then
|
|
122
|
+
COMPREPLY=($(compgen -W "$commands" -- "$cur"))
|
|
123
|
+
fi
|
|
124
|
+
} &&
|
|
125
|
+
complete -F _shieldly shieldly
|
|
126
|
+
`,ce=`
|
|
127
|
+
#compdef shieldly
|
|
128
|
+
|
|
129
|
+
_shieldly() {
|
|
130
|
+
local -a opts
|
|
131
|
+
local curcontext="$curcontext" state line ret=1
|
|
132
|
+
|
|
133
|
+
_arguments -C '(-h --help)'{-h,--help}'[Show help]' '(-v --version)'{-v,--version}'[Show version]' '--api-key[API key]:api key' '1: :->command' '*: :->args' && ret=0
|
|
134
|
+
|
|
135
|
+
case $state in
|
|
136
|
+
command)
|
|
137
|
+
local commands; commands=(
|
|
138
|
+
'analyze-iam:Analyze an IAM policy for security issues'
|
|
139
|
+
'analyze-cf:Analyze a CloudFormation template'
|
|
140
|
+
'api-keys:Manage API keys'
|
|
141
|
+
'completion:Generate shell completion script'
|
|
142
|
+
)
|
|
143
|
+
_describe 'command' commands && ret=0
|
|
144
|
+
;;
|
|
145
|
+
args)
|
|
146
|
+
case $words[1] in
|
|
147
|
+
analyze-iam)
|
|
148
|
+
_arguments '--type[Policy type]:type:(identity resource trust s3 sqs kms sns cross_account)' '--format[Output format]:format:(table json)' '--api-key[API key]:api key' '(-h --help)'{-h,--help}'[Show help]' '*:policy file:_files' && ret=0
|
|
149
|
+
;;
|
|
150
|
+
analyze-cf)
|
|
151
|
+
_arguments '--format[Output format]:format:(table json)' '--api-key[API key]:api key' '(-h --help)'{-h,--help}'[Show help]' '*:template file:_files' && ret=0
|
|
152
|
+
;;
|
|
153
|
+
api-keys)
|
|
154
|
+
_arguments '--format[Output format]:format:(table json)' '--api-key[API key]:api key' '1: :->subcommand' '*: :->args' && ret=0
|
|
155
|
+
case $state in
|
|
156
|
+
subcommand)
|
|
157
|
+
local subcommands; subcommands=(
|
|
158
|
+
'list:List all API keys'
|
|
159
|
+
'create:Create a new API key'
|
|
160
|
+
'revoke:Revoke an API key'
|
|
161
|
+
)
|
|
162
|
+
_describe 'subcommand' subcommands && ret=0
|
|
163
|
+
;;
|
|
164
|
+
args)
|
|
165
|
+
case $words[2] in
|
|
166
|
+
create)
|
|
167
|
+
_arguments '--label[Key label]' '--scopes[Comma-separated scopes]:scopes:(iam cf cost)' && ret=0
|
|
168
|
+
;;
|
|
169
|
+
revoke)
|
|
170
|
+
_arguments '*:key id' && ret=0
|
|
171
|
+
;;
|
|
172
|
+
esac
|
|
173
|
+
;;
|
|
174
|
+
esac
|
|
175
|
+
;;
|
|
176
|
+
completion)
|
|
177
|
+
_arguments '1: :->shell' && ret=0
|
|
178
|
+
case $state in
|
|
179
|
+
shell)
|
|
180
|
+
local shells; shells=(
|
|
181
|
+
'bash:Generate bash completion'
|
|
182
|
+
'zsh:Generate zsh completion'
|
|
183
|
+
'install:Install completion for current shell'
|
|
184
|
+
)
|
|
185
|
+
_describe 'shell' shells && ret=0
|
|
186
|
+
;;
|
|
187
|
+
esac
|
|
188
|
+
;;
|
|
189
|
+
esac
|
|
190
|
+
;;
|
|
191
|
+
esac
|
|
192
|
+
|
|
193
|
+
return ret
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
_shieldly
|
|
197
|
+
`,pe=`
|
|
198
|
+
Usage: shieldly completion <shell>
|
|
199
|
+
|
|
200
|
+
Generate shell completion scripts for the shieldly CLI.
|
|
201
|
+
|
|
202
|
+
Shells:
|
|
203
|
+
bash Generate bash completion
|
|
204
|
+
zsh Generate zsh completion
|
|
205
|
+
install Auto-detect shell and install completion
|
|
206
|
+
|
|
207
|
+
Examples:
|
|
208
|
+
eval "$(shieldly completion bash)" # Source bash completion
|
|
209
|
+
shieldly completion zsh > /usr/local/share/zsh/site-functions/_shieldly # Install zsh completion
|
|
210
|
+
shieldly completion install # Auto-detect and install
|
|
211
|
+
`;async function W(e){if(!e.length||e.includes("-h")||e.includes("--help")){console.log(pe);return}let o=e[0];switch(o){case"bash":console.log(ae.trimStart());break;case"zsh":console.log(ce.trimStart());break;case"install":await ye();break;default:console.error(`Unsupported shell: ${o}`),console.log("Supported shells: bash, zsh"),process.exit(1)}}async function ye(){let e=process.env.SHELL||"",o=process.env.HOME||"";if(e.includes("zsh")){let t=`${o}/.zshrc`,n=`
|
|
212
|
+
# shieldly CLI completion
|
|
213
|
+
autoload -Uz compinit && compinit -C 2>/dev/null
|
|
214
|
+
eval "$(shieldly completion zsh)" 2>/dev/null`;try{let{readFileSync:s,appendFileSync:r,existsSync:i}=await import("node:fs");if(i(t)&&s(t,"utf8").includes("shieldly completion")){console.log("shieldly completion already installed in ~/.zshrc");return}r(t,n),console.log("Installed shieldly completion in ~/.zshrc"),console.log("Run: source ~/.zshrc")}catch(s){console.error(`Failed to install: ${s.message}`),process.exit(1)}}else if(e.includes("bash")){let t=`${o}/.bashrc`,n=`
|
|
215
|
+
# shieldly CLI completion
|
|
216
|
+
source /dev/stdin <<< "$(shieldly completion bash)" 2>/dev/null`;try{let{readFileSync:s,appendFileSync:r,existsSync:i}=await import("node:fs");if(i(t)&&s(t,"utf8").includes("shieldly completion")){console.log("shieldly completion already installed in ~/.bashrc");return}r(t,n),console.log("Installed shieldly completion in ~/.bashrc"),console.log("Run: source ~/.bashrc")}catch(s){console.error(`Failed to install: ${s.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 f="\x1B[1m",A="\x1B[36m",P="\x1B[2m",p="\x1B[0m",me="1.0.0",he=`
|
|
217
|
+
${f}shieldly${p} \u2014 AI-Powered Security Analysis for AWS
|
|
218
|
+
|
|
219
|
+
${f}Usage:${p}
|
|
220
|
+
shieldly <command> [args] [options]
|
|
221
|
+
|
|
222
|
+
${f}Commands:${p}
|
|
223
|
+
${A}analyze-iam${p} <policy-file> Analyze an IAM policy for security issues
|
|
224
|
+
${A}analyze-cf${p} <template-file> Analyze a CloudFormation template
|
|
225
|
+
${A}api-keys${p} list|create|revoke Manage API keys
|
|
226
|
+
${A}completion${p} bash|zsh|install Generate shell completion
|
|
227
|
+
|
|
228
|
+
${f}Global Options:${p}
|
|
229
|
+
--api-key <key> API key (or set SHIELDLY_API_KEY env var)
|
|
230
|
+
--version Show version
|
|
231
|
+
-h, --help Show this help
|
|
232
|
+
|
|
233
|
+
${f}Authentication:${p}
|
|
234
|
+
Set your API key via env var: export SHIELDLY_API_KEY=sk_...
|
|
235
|
+
Get a free API key at: ${A}https://www.shieldly.io/app/api${p}
|
|
236
|
+
|
|
237
|
+
${f}Examples:${p}
|
|
238
|
+
${P}# Analyze an IAM policy${p}
|
|
239
|
+
shieldly analyze-iam policy.json
|
|
240
|
+
|
|
241
|
+
${P}# Analyze a CloudFormation template${p}
|
|
242
|
+
shieldly analyze-cf template.yaml
|
|
243
|
+
|
|
244
|
+
${P}# List API keys${p}
|
|
245
|
+
shieldly api-keys list
|
|
246
|
+
|
|
247
|
+
${P}# Use in CI${p}
|
|
248
|
+
SHIELDLY_API_KEY=\${{ secrets.SHIELDLY_API_KEY }} shieldly analyze-iam policy.json
|
|
249
|
+
`;async function de(){let[,,e,...o]=process.argv;switch((!e||e==="-h"||e==="--help")&&(console.log(he),process.exit(0)),(e==="--version"||e==="-v")&&(console.log(me),process.exit(0)),e){case"analyze-iam":await F(o);break;case"analyze-cf":await H(o);break;case"api-keys":await G(o);break;case"completion":await W(o);break;default:console.error(`Unknown command: ${e}`),console.log(`Run ${f}shieldly --help${p} for usage`),process.exit(1)}}de().catch(e=>{console.error("Fatal error:",e.message),process.exit(1)});
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shieldly/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "AI-Powered Security Analysis for AWS — official CLI",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://www.shieldly.io",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/shieldly-io/cli.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/shieldly-io/cli/issues"
|
|
13
|
+
},
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"bin": {
|
|
19
|
+
"shieldly": "dist/cli.cjs"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist/cli.cjs"
|
|
23
|
+
],
|
|
24
|
+
"keywords": [
|
|
25
|
+
"aws",
|
|
26
|
+
"iam",
|
|
27
|
+
"security",
|
|
28
|
+
"cloudformation",
|
|
29
|
+
"ai",
|
|
30
|
+
"shieldly",
|
|
31
|
+
"cli"
|
|
32
|
+
],
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=22.0.0"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "node build.js",
|
|
38
|
+
"build:dev": "node build.js --dev",
|
|
39
|
+
"prepublishOnly": "npm run build"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"esbuild": "^0.25.0"
|
|
43
|
+
}
|
|
44
|
+
}
|