xtra-cli 1.0.5 → 1.0.6
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/dist/bin/xtra.js +2 -2
- package/dist/commands/access.js +1 -1
- package/dist/commands/admin.js +3 -3
- package/dist/commands/audit.js +1 -1
- package/dist/commands/branch.js +1 -1
- package/dist/commands/checkout.js +1 -1
- package/dist/commands/ci.js +10 -10
- package/dist/commands/diff.js +6 -6
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/env.js +2 -2
- package/dist/commands/export.js +2 -2
- package/dist/commands/generate.js +3 -3
- package/dist/commands/history.js +3 -3
- package/dist/commands/import.js +1 -1
- package/dist/commands/init.js +4 -4
- package/dist/commands/integration.js +7 -7
- package/dist/commands/jit-run.js +3 -3
- package/dist/commands/local.js +5 -5
- package/dist/commands/login.js +6 -6
- package/dist/commands/login.test.js +4 -4
- package/dist/commands/logout.js +1 -1
- package/dist/commands/logs.js +3 -3
- package/dist/commands/project.js +1 -1
- package/dist/commands/rollback.js +1 -1
- package/dist/commands/rotate.js +2 -2
- package/dist/commands/run.js +5 -5
- package/dist/commands/secrets.js +5 -5
- package/dist/commands/service-account.js +7 -0
- package/dist/commands/simulate.js +3 -3
- package/dist/commands/status.js +2 -2
- package/dist/commands/template.js +4 -4
- package/dist/commands/ui.js +2 -2
- package/dist/commands/watch.js +8 -8
- package/dist/lib/api.js +1 -1
- package/dist/lib/api.test.js +1 -1
- package/dist/lib/audit.js +1 -1
- package/package.json +1 -1
package/dist/commands/login.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
var ae=Object.create;var
|
|
2
|
-
Error: ${t.response.data.error||"Login failed"}`)):console.error(
|
|
3
|
-
Error: ${t
|
|
4
|
-
Logged in as ${s.user.email}`)),t.succeed("Logged in successfully!");try{let{logAudit:n}=await Promise.resolve().then(()=>(I(),A));n("USER_LOGIN",null,null,{method:"api_key",email:s.user?.email})}catch{}}async function re(){let e=require("http"),{default:t}=await import("open");return new Promise(s=>{let n=e.createServer(async(r,a)=>{let p=new URL(r.url,`http://${r.headers.host}`),g=p.searchParams.get("token"),
|
|
1
|
+
var ae=Object.create;var $=Object.defineProperty;var ie=Object.getOwnPropertyDescriptor;var ce=Object.getOwnPropertyNames;var pe=Object.getPrototypeOf,ge=Object.prototype.hasOwnProperty;var x=(e,t)=>()=>(e&&(t=e(e=0)),t);var L=(e,t)=>{for(var s in t)$(e,s,{get:t[s],enumerable:!0})},D=(e,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of ce(t))!ge.call(e,r)&&r!==s&&$(e,r,{get:()=>t[r],enumerable:!(n=ie(t,r))||n.enumerable});return e};var c=(e,t,s)=>(s=e!=null?ae(pe(e)):{},D(t||!e||!e.__esModule?$(s,"default",{value:e,enumerable:!0}):s,e)),G=e=>D($({},"__esModule",{value:!0}),e);var q={};L(q,{clearConfig:()=>de,deleteConfig:()=>le,getAuthToken:()=>R,getBreakGlassSession:()=>ye,getConfig:()=>y,getConfigValue:()=>ue,getProjectConfig:()=>fe,getRcConfig:()=>he,setBreakGlassSession:()=>me,setConfig:()=>f});var J,l,O,U,i,C,y,ue,f,de,le,R,ye,me,fe,he,S=x(()=>{J=c(require("conf")),l=c(require("fs")),O=c(require("path")),U="https://www.xtrasecurity.in/api",i=new J.default({projectName:"xtra-cli",defaults:{apiUrl:U}}),C=i.get("apiUrl");C&&!process.env.XTRA_API_URL&&(C.includes("localhost")||C.includes("xtra-security.vercel.app"))&&i.set("apiUrl",U);y=()=>({...i.store,apiUrl:process.env.XTRA_API_URL||i.get("apiUrl")||U}),ue=e=>i.get(e),f=(e,t)=>{if(i.set(e,t),e==="token"&&process.platform!=="win32"&&l.default.existsSync(i.path))try{l.default.chmodSync(i.path,384)}catch{}},de=()=>i.clear(),le=e=>i.delete(e),R=()=>i.get("token"),ye=()=>i.get("breakGlassSessionId"),me=e=>{e?i.set("breakGlassSessionId",e):i.delete("breakGlassSessionId")},fe=async()=>{try{let e=O.default.join(process.cwd(),"xtra.json");if(l.default.existsSync(e)){let t=l.default.readFileSync(e,"utf-8");return JSON.parse(t)}return null}catch{return null}},he=()=>{let e={};try{let t=O.default.join(process.cwd(),".xtrarc");l.default.existsSync(t)&&(e=JSON.parse(l.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||i.get("project")||"",env:e.env||i.get("env")||"development",branch:e.branch||i.get("branch")||"main"}}});var F,H,V,we,o,k,E=x(()=>{F=c(require("axios"));S();H=c(require("fs")),V=c(require("path")),we=JSON.parse(H.readFileSync(V.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:e}=y(),t=R();return F.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":we.version,...t?{Authorization:`Bearer ${t}`}:{}}})},k={login:async(e,t,s)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,n,r="main")=>(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:n,branch:r})).data,getSecretDetails:async(e,t,s,n="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}?branch=${n}`)).data,syncLogs:async e=>(await o().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,s,n,r,a)=>(await o().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:n,sourceEnv:r,sourceKey:a})).data,rotateSecret:async(e,t,s,n,r)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:n,parsedNewValue:r})).data,promoteSecret:async(e,t,s)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(e,t,s,n)=>{let r={format:e};return t&&(r.startDate=t),s&&(r.endDate=s),n&&(r.projectId=n),(await o().post("/audit/export",r,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,s,n)=>(await o().post("/access/request",{projectId:e,secretId:n,reason:t,duration:s})).data,approveAccess:async(e,t)=>(await o().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=y(),s=t?`&workspaceId=${t}`:"";return(await o().get(`/access/list?mode=${e}${s}`)).data},getAccessRequestStatus:async e=>(await o().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=y(),t=e?`/project?workspaceId=${e}`:"/project";return(await o().get(t)).data},getBranches:async e=>(await o().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,s)=>(await o().post("/branch",{projectId:e,name:t,description:s})).data,deleteBranch:async e=>(await o().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await o().put("/branch",{id:e,...t})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await o().get(`/admin/users${t}`)).data},setUserRole:async(e,t,s)=>(await o().put("/admin/users/role",{email:e,role:t,teamId:s})).data,getIntegrationStatus:async e=>(await o().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await o().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await o().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,t)=>{let s=new URLSearchParams(t).toString();return(await o().get(`/projects/${e}/kubernetes?${s}`)).data},getSecretHistory:async(e,t,s)=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}/history`)).data,rollbackSecret:async(e,t,s,n)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/history`,{version:n})).data,cloneEnvironment:async(e,t,s,n,r)=>(await o().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,overwrite:n,branch:r})).data,generateJitLink:async e=>(await o().post("/jit/generate",e)).data,claimJitLink:async e=>(await o().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await o().get(`/jit/${e}`)).data,getServiceAccounts:async e=>(await o().get(`/projects/${e}/service-accounts`)).data,createServiceAccount:async(e,t)=>(await o().post(`/projects/${e}/service-accounts`,t)).data,deleteServiceAccount:async(e,t)=>(await o().delete(`/projects/${e}/service-accounts/${t}`)).data,getServiceAccountKeys:async(e,t)=>(await o().get(`/projects/${e}/service-accounts/${t}/keys`)).data,createServiceAccountKey:async(e,t,s,n)=>(await o().post(`/projects/${e}/service-accounts/${t}/keys`,{label:s,expiresAt:n})).data,deleteServiceAccountKey:async(e,t,s)=>(await o().delete(`/projects/${e}/service-accounts/${t}/keys/${s}`)).data,post:async(e,t)=>(await o().post(e,t)).data}});function Y(){let e=X.get("masterKey");e||(e=h.default.randomBytes(32).toString("hex"),X.set("masterKey",e));let t=(0,M.machineIdSync)();return h.default.createHash("sha256").update(e+t).digest()}var h,z,M,W,X,Q,Z,ee=x(()=>{h=c(require("crypto")),z=c(require("conf")),M=require("node-machine-id"),W="aes-256-gcm",X=new z.default({projectName:"xtra-cli-crypto"});Q=e=>{let t=h.default.randomBytes(16),s=Y(),n=h.default.createCipheriv(W,s,t),r=n.update(e,"utf8","hex");r+=n.final("hex");let a=n.getAuthTag();return{iv:t.toString("hex"),content:r,tag:a.toString("hex")}},Z=e=>{let t=Y(),s=Buffer.from(e.iv,"hex"),n=Buffer.from(e.tag,"hex"),r=h.default.createDecipheriv(W,t,s);r.setAuthTag(n);let a=r.update(e.content,"hex","utf8");return a+=r.final("utf8"),a}});var A={};L(A,{loadAuditLogs:()=>j,logAudit:()=>ke,saveAuditLogs:()=>b,syncAuditLogs:()=>ve});function Se(e){if(!e||typeof e!="object")return e;let t={...e},s=["password","token","secret","value","apiKey","secretValue"];for(let n of Object.keys(t))s.some(r=>n.toLowerCase().includes(r))&&(t[n]="[REDACTED]");return t}async function se(e){try{if(!y().token)return!1;let s={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:Se(e.details),timestamp:e.timestamp,projectId:e.projectId};return await k.post("/audit/cli-logs",{logs:[s]}),!0}catch(t){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",t),!1}}function ke(e,t,s,n){let r={id:(0,te.v4)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:s,details:n,synced:!1},a=j();a.push(r),b(a),se(r).then(p=>{if(p){r.synced=!0;let g=j(),u=g.findIndex(d=>d.id===r.id);u!==-1&&(g[u].synced=!0,b(g))}}).catch(()=>{})}function j(){if(!w.default.existsSync(N))return[];try{let e=w.default.readFileSync(N,"utf-8"),t=JSON.parse(e),s=Z(t);return JSON.parse(s)}catch{return[]}}function b(e){w.default.existsSync(P)||w.default.mkdirSync(P,{recursive:!0});let t=JSON.stringify(e),s=Q(t);w.default.writeFileSync(N,JSON.stringify(s),"utf-8")}async function ve(){let e=j(),t=e.filter(n=>!n.synced);if(t.length===0)return 0;let s=0;for(let n of t)await se(n)&&(n.synced=!0,s++);return s>0&&b(e),s}var w,T,te,P,N,I=x(()=>{w=c(require("fs")),T=c(require("path")),te=require("uuid");ee();S();E();P=T.default.join(process.cwd(),".xtra"),N=T.default.join(P,"audit.enc")});var xe={};L(xe,{loginCommand:()=>$e});module.exports=G(xe);var oe=require("commander"),v=c(require("inquirer"));E();S();var m=c(require("chalk")),_=c(require("ora")),$e=new oe.Command("login").description("Authenticate with XtraSecurity").option("-k, --key <key>","Login using an Access Key").option("-e, --email <email>","Login using Email").option("--sso","Login via Web (SSO)").action(async e=>{try{if(!e.key&&!e.email&&!e.sso){let{method:t}=await v.default.prompt([{type:"list",name:"method",message:"How would you like to login?",choices:[{name:"Browser Login (SSO)",value:"sso"},{name:"Access Key",value:"key"},{name:"Email & Password",value:"email"}]}]);if(t==="sso"){await re();return}else if(t==="key"){let{key:s}=await v.default.prompt([{type:"password",name:"key",message:"Enter Access Key:"}]);await ne(s);return}}if(e.sso)await re();else if(e.key)await ne(e.key);else{let{email:t}=e;t||(t=(await v.default.prompt([{type:"input",name:"email",message:"Email:"}])).email);let n=(await v.default.prompt([{type:"password",name:"password",message:"Password:"}])).password,r=(0,_.default)("Authenticating...").start(),a=await k.login(t,n);f("token",a.token),r.succeed("Logged in successfully!");try{let{logAudit:p}=await Promise.resolve().then(()=>(I(),A));p("USER_LOGIN",null,null,{method:"email",email:t})}catch{}}}catch(t){t.response?console.error(m.default.red(`
|
|
2
|
+
Error: ${t.response.data.error||"Login failed"}`)):console.error(m.default.red(`
|
|
3
|
+
Error: ${t?.response?.data?.error||"An unexpected error occurred"}`)),process.exit(1)}});async function ne(e){let t=(0,_.default)("Authenticating with Access Key...").start(),s=await k.login(void 0,void 0,e);f("token",s.token),s.user&&console.log(m.default.green(`
|
|
4
|
+
Logged in as ${s.user.email}`)),t.succeed("Logged in successfully!");try{let{logAudit:n}=await Promise.resolve().then(()=>(I(),A));n("USER_LOGIN",null,null,{method:"api_key",email:s.user?.email})}catch{}}async function re(){let e=require("http"),{default:t}=await import("open");return new Promise(s=>{let n=e.createServer(async(r,a)=>{let p=new URL(r.url,`http://${r.headers.host}`),g=p.searchParams.get("token"),u=p.searchParams.get("email"),d=p.searchParams.get("workspaceId"),B=p.searchParams.get("workspaceName");if(g){f("token",g),d&&f("workspace",d),a.writeHead(200,{"Content-Type":"text/html"}),a.end(`
|
|
5
5
|
<html>
|
|
6
6
|
<body style="background:#111;color:#eee;font-family:sans-serif;text-align:center;padding:50px;">
|
|
7
7
|
<h1>Login Successful</h1>
|
|
@@ -12,5 +12,5 @@ Logged in as ${s.user.email}`)),t.succeed("Logged in successfully!");try{let{log
|
|
|
12
12
|
</script>
|
|
13
13
|
</body>
|
|
14
14
|
</html>
|
|
15
|
-
`),console.log(
|
|
16
|
-
\u2714 SS0 Login Successful! Logged in as ${
|
|
15
|
+
`),console.log(m.default.green(`
|
|
16
|
+
\u2714 SS0 Login Successful! Logged in as ${u}`)),d&&console.log(m.default.dim(`Selected Workspace: ${B} (${d})`));try{let{logAudit:K}=await Promise.resolve().then(()=>(I(),A));K("USER_LOGIN",null,null,{method:"sso",email:u,workspaceId:d,workspaceName:B})}catch{}a.end(()=>{n.close(),setTimeout(()=>{process.exit(0)},1e3)})}else a.writeHead(400),a.end("Missing token")});n.listen(0,async()=>{let r=n.address(),p=`http://localhost:${typeof r=="string"?0:r?.port}`,{apiUrl:g}=(S(),G(q)).getConfig();g.includes("localhost")&&(g="https://www.xtrasecurity.in/api");let u=`${g}/auth/cli/sso?callbackUrl=${encodeURIComponent(p)}`;console.log(m.default.blue(`Waiting for browser login... (Opening ${u})`)),await t(u)})})}0&&(module.exports={loginCommand});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
var ie=Object.create;var
|
|
1
|
+
var ie=Object.create;var j=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var ge=Object.getPrototypeOf,de=Object.prototype.hasOwnProperty;var x=(e,t)=>()=>(e&&(t=e(e=0)),t);var K=(e,t)=>{for(var s in t)j(e,s,{get:t[s],enumerable:!0})},q=(e,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of pe(t))!de.call(e,r)&&r!==s&&j(e,r,{get:()=>t[r],enumerable:!(n=ce(t,r))||n.enumerable});return e};var c=(e,t,s)=>(s=e!=null?ie(ge(e)):{},q(t||!e||!e.__esModule?j(s,"default",{value:e,enumerable:!0}):s,e)),le=e=>q(j({},"__esModule",{value:!0}),e);var G={};K(G,{clearConfig:()=>me,deleteConfig:()=>ye,getAuthToken:()=>O,getBreakGlassSession:()=>fe,getConfig:()=>y,getConfigValue:()=>ue,getProjectConfig:()=>we,getRcConfig:()=>ke,setBreakGlassSession:()=>he,setConfig:()=>l});var D,m,_,U,i,R,y,ue,l,me,ye,O,fe,he,we,ke,w=x(()=>{D=c(require("conf")),m=c(require("fs")),_=c(require("path")),U="https://www.xtrasecurity.in/api",i=new D.default({projectName:"xtra-cli",defaults:{apiUrl:U}}),R=i.get("apiUrl");R&&!process.env.XTRA_API_URL&&(R.includes("localhost")||R.includes("xtra-security.vercel.app"))&&i.set("apiUrl",U);y=()=>({...i.store,apiUrl:process.env.XTRA_API_URL||i.get("apiUrl")||U}),ue=e=>i.get(e),l=(e,t)=>{if(i.set(e,t),e==="token"&&process.platform!=="win32"&&m.default.existsSync(i.path))try{m.default.chmodSync(i.path,384)}catch{}},me=()=>i.clear(),ye=e=>i.delete(e),O=()=>i.get("token"),fe=()=>i.get("breakGlassSessionId"),he=e=>{e?i.set("breakGlassSessionId",e):i.delete("breakGlassSessionId")},we=async()=>{try{let e=_.default.join(process.cwd(),"xtra.json");if(m.default.existsSync(e)){let t=m.default.readFileSync(e,"utf-8");return JSON.parse(t)}return null}catch{return null}},ke=()=>{let e={};try{let t=_.default.join(process.cwd(),".xtrarc");m.default.existsSync(t)&&(e=JSON.parse(m.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||i.get("project")||"",env:e.env||i.get("env")||"development",branch:e.branch||i.get("branch")||"main"}}});var V,J,F,ve,o,f,$=x(()=>{V=c(require("axios"));w();J=c(require("fs")),F=c(require("path")),ve=JSON.parse(J.readFileSync(F.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:e}=y(),t=O();return V.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":ve.version,...t?{Authorization:`Bearer ${t}`}:{}}})},f={login:async(e,t,s)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,n,r="main")=>(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:n,branch:r})).data,getSecretDetails:async(e,t,s,n="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}?branch=${n}`)).data,syncLogs:async e=>(await o().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,s,n,r,a)=>(await o().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:n,sourceEnv:r,sourceKey:a})).data,rotateSecret:async(e,t,s,n,r)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:n,parsedNewValue:r})).data,promoteSecret:async(e,t,s)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(e,t,s,n)=>{let r={format:e};return t&&(r.startDate=t),s&&(r.endDate=s),n&&(r.projectId=n),(await o().post("/audit/export",r,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,s,n)=>(await o().post("/access/request",{projectId:e,secretId:n,reason:t,duration:s})).data,approveAccess:async(e,t)=>(await o().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=y(),s=t?`&workspaceId=${t}`:"";return(await o().get(`/access/list?mode=${e}${s}`)).data},getAccessRequestStatus:async e=>(await o().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=y(),t=e?`/project?workspaceId=${e}`:"/project";return(await o().get(t)).data},getBranches:async e=>(await o().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,s)=>(await o().post("/branch",{projectId:e,name:t,description:s})).data,deleteBranch:async e=>(await o().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await o().put("/branch",{id:e,...t})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await o().get(`/admin/users${t}`)).data},setUserRole:async(e,t,s)=>(await o().put("/admin/users/role",{email:e,role:t,teamId:s})).data,getIntegrationStatus:async e=>(await o().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await o().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await o().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,t)=>{let s=new URLSearchParams(t).toString();return(await o().get(`/projects/${e}/kubernetes?${s}`)).data},getSecretHistory:async(e,t,s)=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}/history`)).data,rollbackSecret:async(e,t,s,n)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/history`,{version:n})).data,cloneEnvironment:async(e,t,s,n,r)=>(await o().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,overwrite:n,branch:r})).data,generateJitLink:async e=>(await o().post("/jit/generate",e)).data,claimJitLink:async e=>(await o().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await o().get(`/jit/${e}`)).data,getServiceAccounts:async e=>(await o().get(`/projects/${e}/service-accounts`)).data,createServiceAccount:async(e,t)=>(await o().post(`/projects/${e}/service-accounts`,t)).data,deleteServiceAccount:async(e,t)=>(await o().delete(`/projects/${e}/service-accounts/${t}`)).data,getServiceAccountKeys:async(e,t)=>(await o().get(`/projects/${e}/service-accounts/${t}/keys`)).data,createServiceAccountKey:async(e,t,s,n)=>(await o().post(`/projects/${e}/service-accounts/${t}/keys`,{label:s,expiresAt:n})).data,deleteServiceAccountKey:async(e,t,s)=>(await o().delete(`/projects/${e}/service-accounts/${t}/keys/${s}`)).data,post:async(e,t)=>(await o().post(e,t)).data}});function Y(){let e=M.get("masterKey");e||(e=k.default.randomBytes(32).toString("hex"),M.set("masterKey",e));let t=(0,X.machineIdSync)();return k.default.createHash("sha256").update(e+t).digest()}var k,W,X,z,M,Q,Z,ee=x(()=>{k=c(require("crypto")),W=c(require("conf")),X=require("node-machine-id"),z="aes-256-gcm",M=new W.default({projectName:"xtra-cli-crypto"});Q=e=>{let t=k.default.randomBytes(16),s=Y(),n=k.default.createCipheriv(z,s,t),r=n.update(e,"utf8","hex");r+=n.final("hex");let a=n.getAuthTag();return{iv:t.toString("hex"),content:r,tag:a.toString("hex")}},Z=e=>{let t=Y(),s=Buffer.from(e.iv,"hex"),n=Buffer.from(e.tag,"hex"),r=k.default.createDecipheriv(z,t,s);r.setAuthTag(n);let a=r.update(e.content,"hex","utf8");return a+=r.final("utf8"),a}});var I={};K(I,{loadAuditLogs:()=>b,logAudit:()=>je,saveAuditLogs:()=>A,syncAuditLogs:()=>xe});function Se(e){if(!e||typeof e!="object")return e;let t={...e},s=["password","token","secret","value","apiKey","secretValue"];for(let n of Object.keys(t))s.some(r=>n.toLowerCase().includes(r))&&(t[n]="[REDACTED]");return t}async function se(e){try{if(!y().token)return!1;let s={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:Se(e.details),timestamp:e.timestamp,projectId:e.projectId};return await f.post("/audit/cli-logs",{logs:[s]}),!0}catch(t){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",t),!1}}function je(e,t,s,n){let r={id:(0,te.v4)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:s,details:n,synced:!1},a=b();a.push(r),A(a),se(r).then(p=>{if(p){r.synced=!0;let g=b(),d=g.findIndex(u=>u.id===r.id);d!==-1&&(g[d].synced=!0,A(g))}}).catch(()=>{})}function b(){if(!v.default.existsSync(T))return[];try{let e=v.default.readFileSync(T,"utf-8"),t=JSON.parse(e),s=Z(t);return JSON.parse(s)}catch{return[]}}function A(e){v.default.existsSync(E)||v.default.mkdirSync(E,{recursive:!0});let t=JSON.stringify(e),s=Q(t);v.default.writeFileSync(T,JSON.stringify(s),"utf-8")}async function xe(){let e=b(),t=e.filter(n=>!n.synced);if(t.length===0)return 0;let s=0;for(let n of t)await se(n)&&(n.synced=!0,s++);return s>0&&A(e),s}var v,P,te,E,T,C=x(()=>{v=c(require("fs")),P=c(require("path")),te=require("uuid");ee();w();$();E=P.default.join(process.cwd(),".xtra"),T=P.default.join(E,"audit.enc")});var oe=require("commander"),S=c(require("inquirer"));$();w();var h=c(require("chalk")),B=c(require("ora")),L=new oe.Command("login").description("Authenticate with XtraSecurity").option("-k, --key <key>","Login using an Access Key").option("-e, --email <email>","Login using Email").option("--sso","Login via Web (SSO)").action(async e=>{try{if(!e.key&&!e.email&&!e.sso){let{method:t}=await S.default.prompt([{type:"list",name:"method",message:"How would you like to login?",choices:[{name:"Browser Login (SSO)",value:"sso"},{name:"Access Key",value:"key"},{name:"Email & Password",value:"email"}]}]);if(t==="sso"){await re();return}else if(t==="key"){let{key:s}=await S.default.prompt([{type:"password",name:"key",message:"Enter Access Key:"}]);await ne(s);return}}if(e.sso)await re();else if(e.key)await ne(e.key);else{let{email:t}=e;t||(t=(await S.default.prompt([{type:"input",name:"email",message:"Email:"}])).email);let n=(await S.default.prompt([{type:"password",name:"password",message:"Password:"}])).password,r=(0,B.default)("Authenticating...").start(),a=await f.login(t,n);l("token",a.token),r.succeed("Logged in successfully!");try{let{logAudit:p}=await Promise.resolve().then(()=>(C(),I));p("USER_LOGIN",null,null,{method:"email",email:t})}catch{}}}catch(t){t.response?console.error(h.default.red(`
|
|
2
2
|
Error: ${t.response.data.error||"Login failed"}`)):console.error(h.default.red(`
|
|
3
|
-
Error: ${t
|
|
4
|
-
Logged in as ${s.user.email}`)),t.succeed("Logged in successfully!");try{let{logAudit:n}=await Promise.resolve().then(()=>(C(),
|
|
3
|
+
Error: ${t?.response?.data?.error||"An unexpected error occurred"}`)),process.exit(1)}});async function ne(e){let t=(0,B.default)("Authenticating with Access Key...").start(),s=await f.login(void 0,void 0,e);l("token",s.token),s.user&&console.log(h.default.green(`
|
|
4
|
+
Logged in as ${s.user.email}`)),t.succeed("Logged in successfully!");try{let{logAudit:n}=await Promise.resolve().then(()=>(C(),I));n("USER_LOGIN",null,null,{method:"api_key",email:s.user?.email})}catch{}}async function re(){let e=require("http"),{default:t}=await import("open");return new Promise(s=>{let n=e.createServer(async(r,a)=>{let p=new URL(r.url,`http://${r.headers.host}`),g=p.searchParams.get("token"),d=p.searchParams.get("email"),u=p.searchParams.get("workspaceId"),N=p.searchParams.get("workspaceName");if(g){l("token",g),u&&l("workspace",u),a.writeHead(200,{"Content-Type":"text/html"}),a.end(`
|
|
5
5
|
<html>
|
|
6
6
|
<body style="background:#111;color:#eee;font-family:sans-serif;text-align:center;padding:50px;">
|
|
7
7
|
<h1>Login Successful</h1>
|
|
@@ -13,4 +13,4 @@ Logged in as ${s.user.email}`)),t.succeed("Logged in successfully!");try{let{log
|
|
|
13
13
|
</body>
|
|
14
14
|
</html>
|
|
15
15
|
`),console.log(h.default.green(`
|
|
16
|
-
\u2714 SS0 Login Successful! Logged in as ${
|
|
16
|
+
\u2714 SS0 Login Successful! Logged in as ${d}`)),u&&console.log(h.default.dim(`Selected Workspace: ${N} (${u})`));try{let{logAudit:H}=await Promise.resolve().then(()=>(C(),I));H("USER_LOGIN",null,null,{method:"sso",email:d,workspaceId:u,workspaceName:N})}catch{}a.end(()=>{n.close(),setTimeout(()=>{process.exit(0)},1e3)})}else a.writeHead(400),a.end("Missing token")});n.listen(0,async()=>{let r=n.address(),p=`http://localhost:${typeof r=="string"?0:r?.port}`,{apiUrl:g}=(w(),le(G)).getConfig();g.includes("localhost")&&(g="https://www.xtrasecurity.in/api");let d=`${g}/auth/cli/sso?callbackUrl=${encodeURIComponent(p)}`;console.log(h.default.blue(`Waiting for browser login... (Opening ${d})`)),await t(d)})})}$();w();var ae=c(require("inquirer"));jest.mock("../lib/api");jest.mock("../lib/config");jest.mock("inquirer");jest.mock("ora",()=>jest.fn(()=>({start:jest.fn().mockReturnThis(),succeed:jest.fn().mockReturnThis(),fail:jest.fn().mockReturnThis()})));describe("Login Command",()=>{let e=f,t=ae.default;beforeEach(()=>{jest.clearAllMocks()}),it("should login with API key option",async()=>{e.login.mockResolvedValue({token:"test-token-from-key"});let s={key:"xtra_key_abc123"};await L._actionHandler(s),expect(e.login).toHaveBeenCalledWith(void 0,void 0,"xtra_key_abc123"),expect(l).toHaveBeenCalledWith("token","test-token-from-key")}),it("should prompt for email and password if no options provided",async()=>{t.prompt.mockResolvedValueOnce({method:"email"}).mockResolvedValueOnce({email:"test@example.com"}).mockResolvedValueOnce({password:"password123"}),e.login.mockResolvedValue({token:"email-token"}),await L._actionHandler({}),expect(t.prompt).toHaveBeenCalledTimes(3),expect(e.login).toHaveBeenCalledWith("test@example.com","password123",void 0)}),it("should handle login failure gracefully",async()=>{e.login.mockRejectedValue(new Error("Invalid credentials"));let s={key:"bad-key"};await expect(L._actionHandler(s)).rejects.toThrow("Invalid credentials")})});
|
package/dist/commands/logout.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var y=Object.create;var c=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var S=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty;var b=(e,t)=>{for(var o in t)c(e,o,{get:t[o],enumerable:!0})},f=(e,t,o,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let
|
|
1
|
+
var y=Object.create;var c=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var S=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty;var b=(e,t)=>{for(var o in t)c(e,o,{get:t[o],enumerable:!0})},f=(e,t,o,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of k(t))!C.call(e,r)&&r!==o&&c(e,r,{get:()=>t[r],enumerable:!(s=x(t,r))||s.enumerable});return e};var i=(e,t,o)=>(o=e!=null?y(S(e)):{},f(t||!e||!e.__esModule?c(o,"default",{value:e,enumerable:!0}):o,e)),j=e=>f(c({},"__esModule",{value:!0}),e);var v={};b(v,{logoutCommand:()=>U});module.exports=j(v);var u=require("commander"),a=i(require("chalk")),m=i(require("ora"));var d=i(require("conf"));var g="https://www.xtrasecurity.in/api",n=new d.default({projectName:"xtra-cli",defaults:{apiUrl:g}}),l=n.get("apiUrl");l&&!process.env.XTRA_API_URL&&(l.includes("localhost")||l.includes("xtra-security.vercel.app"))&&n.set("apiUrl",g);var h=()=>({...n.store,apiUrl:process.env.XTRA_API_URL||n.get("apiUrl")||g});var p=e=>n.delete(e);var U=new u.Command("logout").description("Logout and clear all local credentials and caches").action(async()=>{let e=(0,m.default)("Logging out...").start();try{p("token");let t=h(),s=Object.keys(t).filter(r=>r.startsWith("cache."));for(let r of s)p(r);e.succeed(a.default.green("\u2714 Successfully logged out.")),console.log(a.default.gray("Local authentication token and secret caches have been purged."))}catch(t){e.fail(a.default.red(`Logout failed: ${t?.response?.data?.error||"An unexpected error occurred"}`))}});0&&(module.exports={logoutCommand});
|
package/dist/commands/logs.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var it=Object.create;var $=Object.defineProperty;var at=Object.getOwnPropertyDescriptor;var ct=Object.getOwnPropertyNames;var pt=Object.getPrototypeOf,gt=Object.prototype.hasOwnProperty;var b=(t,e)=>()=>(t&&(e=t(t=0)),e);var
|
|
2
|
-
`);return}let v=[[p.default.bold("Timestamp"),p.default.bold("Action"),p.default.bold("Project"),p.default.bold("Sync"),p.default.bold("Details")]];
|
|
3
|
-
Local Audit Logs${rt}`)),console.log((0,nt.table)(v)),console.log(p.default.gray(` Showing ${
|
|
1
|
+
var it=Object.create;var $=Object.defineProperty;var at=Object.getOwnPropertyDescriptor;var ct=Object.getOwnPropertyNames;var pt=Object.getPrototypeOf,gt=Object.prototype.hasOwnProperty;var b=(t,e)=>()=>(t&&(e=t(t=0)),e);var I=(t,e)=>{for(var s in e)$(t,s,{get:e[s],enumerable:!0})},B=(t,e,s,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of ct(e))!gt.call(t,r)&&r!==s&&$(t,r,{get:()=>e[r],enumerable:!(n=at(e,r))||n.enumerable});return t};var u=(t,e,s)=>(s=t!=null?it(pt(t)):{},B(e||!t||!t.__esModule?$(s,"default",{value:t,enumerable:!0}):s,t)),C=t=>B($({},"__esModule",{value:!0}),t);function q(){let t=_.get("masterKey");t||(t=y.default.randomBytes(32).toString("hex"),_.set("masterKey",t));let e=(0,J.machineIdSync)();return y.default.createHash("sha256").update(t+e).digest()}var y,F,J,K,_,G,V,H=b(()=>{y=u(require("crypto")),F=u(require("conf")),J=require("node-machine-id"),K="aes-256-gcm",_=new F.default({projectName:"xtra-cli-crypto"});G=t=>{let e=y.default.randomBytes(16),s=q(),n=y.default.createCipheriv(K,s,e),r=n.update(t,"utf8","hex");r+=n.final("hex");let a=n.getAuthTag();return{iv:e.toString("hex"),content:r,tag:a.toString("hex")}},V=t=>{let e=q(),s=Buffer.from(t.iv,"hex"),n=Buffer.from(t.tag,"hex"),r=y.default.createDecipheriv(K,e,s);r.setAuthTag(n);let a=r.update(t.content,"hex","utf8");return a+=r.final("utf8"),a}});var z,U,j,L,f,M,R=b(()=>{z=u(require("conf")),U="https://www.xtrasecurity.in/api",j=new z.default({projectName:"xtra-cli",defaults:{apiUrl:U}}),L=j.get("apiUrl");L&&!process.env.XTRA_API_URL&&(L.includes("localhost")||L.includes("xtra-security.vercel.app"))&&j.set("apiUrl",U);f=()=>({...j.store,apiUrl:process.env.XTRA_API_URL||j.get("apiUrl")||U}),M=()=>j.get("token")});var Y={};I(Y,{api:()=>T});var X,Q,W,dt,o,T,D=b(()=>{X=u(require("axios"));R();Q=u(require("fs")),W=u(require("path")),dt=JSON.parse(Q.readFileSync(W.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:t}=f(),e=M();return X.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":dt.version,...e?{Authorization:`Bearer ${e}`}:{}}})},T={login:async(t,e,s)=>(await o().post("/auth/cli-login",{email:t,password:e,apiKey:s})).data,getSecrets:async(t,e,s="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets?branch=${s}`)).data,getSecretVersions:async(t,e,s="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(t,e,s,n,r="main")=>(await o().post(`/projects/${t}/envs/${e}/secrets`,{secrets:s,expectedVersions:n,branch:r})).data,getSecretDetails:async(t,e,s,n="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets/${s}?branch=${n}`)).data,syncLogs:async t=>(await o().post("/audit/cli-logs",{logs:t})).data,linkSecret:async(t,e,s,n,r,a)=>(await o().post(`/projects/${t}/envs/${e}/secrets/link`,{key:s,sourceProjectId:n,sourceEnv:r,sourceKey:a})).data,rotateSecret:async(t,e,s,n,r)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/rotate`,{strategy:n,parsedNewValue:r})).data,promoteSecret:async(t,e,s)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(t,e,s,n)=>{let r={format:t};return e&&(r.startDate=e),s&&(r.endDate=s),n&&(r.projectId=n),(await o().post("/audit/export",r,{responseType:t==="csv"?"text":"json"})).data},requestAccess:async(t,e,s,n)=>(await o().post("/access/request",{projectId:t,secretId:n,reason:e,duration:s})).data,approveAccess:async(t,e)=>(await o().post("/access/approve",{requestId:t,decision:e})).data,listAccessRequests:async t=>{let{workspace:e}=f(),s=e?`&workspaceId=${e}`:"";return(await o().get(`/access/list?mode=${t}${s}`)).data},getAccessRequestStatus:async t=>(await o().get(`/access/request?id=${t}`)).data,getProjects:async()=>{let{workspace:t}=f(),e=t?`/project?workspaceId=${t}`:"/project";return(await o().get(e)).data},getBranches:async t=>(await o().get(`/branch?projectId=${t}`)).data,createBranch:async(t,e,s)=>(await o().post("/branch",{projectId:t,name:e,description:s})).data,deleteBranch:async t=>(await o().delete(`/branch/${t}`)).data,updateBranch:async(t,e)=>(await o().put("/branch",{id:t,...e})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async t=>{let e=t?`?teamId=${t}`:"";return(await o().get(`/admin/users${e}`)).data},setUserRole:async(t,e,s)=>(await o().put("/admin/users/role",{email:t,role:e,teamId:s})).data,getIntegrationStatus:async t=>(await o().get(`/integrations/${t}`)).data,getIntegrationRepos:async t=>(await o().get(`/integrations/${t}/sync`)).data.repos,syncSecretsToGithub:async t=>(await o().post("/integrations/github/sync",t)).data,exportKubernetesSecret:async(t,e)=>{let s=new URLSearchParams(e).toString();return(await o().get(`/projects/${t}/kubernetes?${s}`)).data},getSecretHistory:async(t,e,s)=>(await o().get(`/projects/${t}/envs/${e}/secrets/${s}/history`)).data,rollbackSecret:async(t,e,s,n)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/history`,{version:n})).data,cloneEnvironment:async(t,e,s,n,r)=>(await o().post(`/projects/${t}/envs/clone`,{fromEnv:e,toEnv:s,overwrite:n,branch:r})).data,generateJitLink:async t=>(await o().post("/jit/generate",t)).data,claimJitLink:async t=>(await o().post("/jit/claim",{token:t})).data,getJitInfo:async t=>(await o().get(`/jit/${t}`)).data,getServiceAccounts:async t=>(await o().get(`/projects/${t}/service-accounts`)).data,createServiceAccount:async(t,e)=>(await o().post(`/projects/${t}/service-accounts`,e)).data,deleteServiceAccount:async(t,e)=>(await o().delete(`/projects/${t}/service-accounts/${e}`)).data,getServiceAccountKeys:async(t,e)=>(await o().get(`/projects/${t}/service-accounts/${e}/keys`)).data,createServiceAccountKey:async(t,e,s,n)=>(await o().post(`/projects/${t}/service-accounts/${e}/keys`,{label:s,expiresAt:n})).data,deleteServiceAccountKey:async(t,e,s)=>(await o().delete(`/projects/${t}/service-accounts/${e}/keys/${s}`)).data,post:async(t,e)=>(await o().post(t,e)).data}});var et={};I(et,{loadAuditLogs:()=>h,logAudit:()=>lt,saveAuditLogs:()=>x,syncAuditLogs:()=>yt});function ut(t){if(!t||typeof t!="object")return t;let e={...t},s=["password","token","secret","value","apiKey","secretValue"];for(let n of Object.keys(e))s.some(r=>n.toLowerCase().includes(r))&&(e[n]="[REDACTED]");return e}async function tt(t){try{if(!f().token)return!1;let s={action:t.action,entity:"cli-project",entityId:t.projectId||"global",details:ut(t.details),timestamp:t.timestamp,projectId:t.projectId};return await T.post("/audit/cli-logs",{logs:[s]}),!0}catch(e){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",e),!1}}function lt(t,e,s,n){let r={id:(0,Z.v4)(),timestamp:new Date().toISOString(),action:t,projectId:e,environment:s,details:n,synced:!1},a=h();a.push(r),x(a),tt(r).then(S=>{if(S){r.synced=!0;let c=h(),l=c.findIndex(v=>v.id===r.id);l!==-1&&(c[l].synced=!0,x(c))}}).catch(()=>{})}function h(){if(!m.default.existsSync(E))return[];try{let t=m.default.readFileSync(E,"utf-8"),e=JSON.parse(t),s=V(e);return JSON.parse(s)}catch{return[]}}function x(t){m.default.existsSync(O)||m.default.mkdirSync(O,{recursive:!0});let e=JSON.stringify(t),s=G(e);m.default.writeFileSync(E,JSON.stringify(s),"utf-8")}async function yt(){let t=h(),e=t.filter(n=>!n.synced);if(e.length===0)return 0;let s=0;for(let n of e)await tt(n)&&(n.synced=!0,s++);return s>0&&x(t),s}var m,N,Z,O,E,P=b(()=>{m=u(require("fs")),N=u(require("path")),Z=require("uuid");H();R();D();O=N.default.join(process.cwd(),".xtra"),E=N.default.join(O,"audit.enc")});var mt={};I(mt,{logsCommand:()=>ft});module.exports=C(mt);var st=require("commander");P();var p=u(require("chalk")),nt=require("table"),ft=new st.Command("logs").description("View local audit logs").option("-n, --limit <number>","Number of logs to show","20").option("--sync","Sync logs to cloud",!1).option("--event <type>","Filter by event type (e.g. SECRET_UPDATE, SECRET_ROTATE)").option("--project <projectId>","Filter by project ID").option("--since <duration>","Show logs since (e.g. 1h, 24h, 7d, 30d)","").option("--json","Output raw JSON instead of table",!1).action(async t=>{let{limit:e,sync:s,event:n,project:r,since:a,json:S}=t;try{let c=h();if(s){let i=c.filter(d=>!d.synced);if(i.length===0){console.log(p.default.green("All logs are already synced."));return}let g=require("ora")(`Syncing ${i.length} logs to cloud...`).start();try{let{api:d}=(D(),C(Y)),{saveAuditLogs:k}=(P(),C(et));await d.syncLogs(i),i.forEach(A=>A.synced=!0),k(c),g.succeed(`Successfully synced ${i.length} logs.`)}catch(d){g.fail("Sync failed."),console.error(p.default.red(d.message))}return}if(c.length===0){console.log(p.default.yellow("No local audit logs found."));return}if(n){let i=n.toUpperCase();c=c.filter(g=>g.action?.toUpperCase().includes(i))}if(r&&(c=c.filter(i=>i.projectId===r)),a){let i=a.match(/^(\d+)(h|d|m)$/i);i||(console.error(p.default.red(`Invalid --since format: '${a}'. Use e.g. 1h, 24h, 7d, 30d`)),process.exit(1));let g=parseInt(i[1]),d=i[2].toLowerCase(),k={h:36e5,d:864e5,m:6e4},A=new Date(Date.now()-g*k[d]);c=c.filter(ot=>new Date(ot.timestamp)>=A)}c.sort((i,g)=>new Date(g.timestamp).getTime()-new Date(i.timestamp).getTime());let l=c.slice(0,parseInt(e));if(l.length===0){console.log(p.default.yellow("No logs matched your filters."));return}if(S){process.stdout.write(JSON.stringify(l,null,2)+`
|
|
2
|
+
`);return}let v=[[p.default.bold("Timestamp"),p.default.bold("Action"),p.default.bold("Project"),p.default.bold("Sync"),p.default.bold("Details")]];l.forEach(i=>{let g="";i.details&&(i.details.keys?g=`Keys: ${i.details.keys.join(", ")}`:i.details.key?g=`Key: ${i.details.key}`:g=JSON.stringify(i.details));let d=i.projectId?i.projectId.substring(0,8)+"...":"-";v.push([new Date(i.timestamp).toLocaleString(),i.action,d,i.synced?p.default.green("\u2714"):p.default.yellow("\u2716"),g.substring(0,50)+(g.length>50?"...":"")])});let w=[];n&&w.push(`event: ${n.toUpperCase()}`),r&&w.push(`project: ${r}`),a&&w.push(`since: ${a}`);let rt=w.length>0?p.default.gray(` [${w.join(" | ")}]`):"";console.log(p.default.bold(`
|
|
3
|
+
Local Audit Logs${rt}`)),console.log((0,nt.table)(v)),console.log(p.default.gray(` Showing ${l.length} of ${c.length} total logs.`))}catch(c){console.error(p.default.red("Failed to load logs: "+c?.response?.data?.error||"An unexpected error occurred"))}});0&&(module.exports={logsCommand});
|
package/dist/commands/project.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var L=Object.create;var u=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var O=(e,t)=>{for(var s in t)u(e,s,{get:t[s],enumerable:!0})},
|
|
1
|
+
var L=Object.create;var u=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var O=(e,t)=>{for(var s in t)u(e,s,{get:t[s],enumerable:!0})},v=(e,t,s,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of _(t))!J.call(e,o)&&o!==s&&u(e,o,{get:()=>t[o],enumerable:!(r=N(t,o))||r.enumerable});return e};var p=(e,t,s)=>(s=e!=null?L(B(e)):{},v(t||!e||!e.__esModule?u(s,"default",{value:e,enumerable:!0}):s,e)),T=e=>v(u({},"__esModule",{value:!0}),e);var D={};O(D,{projectCommand:()=>$});module.exports=T(D);var C=require("commander"),a=p(require("chalk")),P=p(require("ora")),I=p(require("inquirer"));var S=p(require("conf")),f=p(require("fs"));var w="https://www.xtrasecurity.in/api",g=new S.default({projectName:"xtra-cli",defaults:{apiUrl:w}}),m=g.get("apiUrl");m&&!process.env.XTRA_API_URL&&(m.includes("localhost")||m.includes("xtra-security.vercel.app"))&&g.set("apiUrl",w);var y=()=>({...g.store,apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||w}),l=e=>g.get(e),j=(e,t)=>{if(g.set(e,t),e==="token"&&process.platform!=="win32"&&f.default.existsSync(g.path))try{f.default.chmodSync(g.path,384)}catch{}};var x=()=>g.get("token");var b=p(require("axios"));var k=p(require("fs")),A=p(require("path")),q=JSON.parse(k.readFileSync(A.join(__dirname,"../../package.json"),"utf-8")),n=()=>{let{apiUrl:e}=y(),t=x();return b.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":q.version,...t?{Authorization:`Bearer ${t}`}:{}}})},h={login:async(e,t,s)=>(await n().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await n().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await n().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,r,o="main")=>(await n().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:r,branch:o})).data,getSecretDetails:async(e,t,s,r="main")=>(await n().get(`/projects/${e}/envs/${t}/secrets/${s}?branch=${r}`)).data,syncLogs:async e=>(await n().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,s,r,o,i)=>(await n().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:r,sourceEnv:o,sourceKey:i})).data,rotateSecret:async(e,t,s,r,o)=>(await n().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:r,parsedNewValue:o})).data,promoteSecret:async(e,t,s)=>(await n().post(`/projects/${e}/envs/${t}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await n().get("/audit/verify")).data,exportAuditLogs:async(e,t,s,r)=>{let o={format:e};return t&&(o.startDate=t),s&&(o.endDate=s),r&&(o.projectId=r),(await n().post("/audit/export",o,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,s,r)=>(await n().post("/access/request",{projectId:e,secretId:r,reason:t,duration:s})).data,approveAccess:async(e,t)=>(await n().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=y(),s=t?`&workspaceId=${t}`:"";return(await n().get(`/access/list?mode=${e}${s}`)).data},getAccessRequestStatus:async e=>(await n().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=y(),t=e?`/project?workspaceId=${e}`:"/project";return(await n().get(t)).data},getBranches:async e=>(await n().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,s)=>(await n().post("/branch",{projectId:e,name:t,description:s})).data,deleteBranch:async e=>(await n().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await n().put("/branch",{id:e,...t})).data,getRoles:async()=>(await n().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await n().get(`/admin/users${t}`)).data},setUserRole:async(e,t,s)=>(await n().put("/admin/users/role",{email:e,role:t,teamId:s})).data,getIntegrationStatus:async e=>(await n().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await n().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await n().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,t)=>{let s=new URLSearchParams(t).toString();return(await n().get(`/projects/${e}/kubernetes?${s}`)).data},getSecretHistory:async(e,t,s)=>(await n().get(`/projects/${e}/envs/${t}/secrets/${s}/history`)).data,rollbackSecret:async(e,t,s,r)=>(await n().post(`/projects/${e}/envs/${t}/secrets/${s}/history`,{version:r})).data,cloneEnvironment:async(e,t,s,r,o)=>(await n().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,overwrite:r,branch:o})).data,generateJitLink:async e=>(await n().post("/jit/generate",e)).data,claimJitLink:async e=>(await n().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await n().get(`/jit/${e}`)).data,getServiceAccounts:async e=>(await n().get(`/projects/${e}/service-accounts`)).data,createServiceAccount:async(e,t)=>(await n().post(`/projects/${e}/service-accounts`,t)).data,deleteServiceAccount:async(e,t)=>(await n().delete(`/projects/${e}/service-accounts/${t}`)).data,getServiceAccountKeys:async(e,t)=>(await n().get(`/projects/${e}/service-accounts/${t}/keys`)).data,createServiceAccountKey:async(e,t,s,r)=>(await n().post(`/projects/${e}/service-accounts/${t}/keys`,{label:s,expiresAt:r})).data,deleteServiceAccountKey:async(e,t,s)=>(await n().delete(`/projects/${e}/service-accounts/${t}/keys/${s}`)).data,post:async(e,t)=>(await n().post(e,t)).data};var d=p(require("fs")),R=p(require("path")),$=new C.Command("project").alias("projects").description("Manage project context"),U=(e,t)=>{let s=l("project");j("project",e),s!==e&&j("branch","main");let r=R.join(process.cwd(),".xtrarc"),o={};if(d.existsSync(r))try{o=JSON.parse(d.readFileSync(r,"utf-8"))}catch(c){console.error(a.default.yellow(` \u26A0 Could not parse existing local .xtrarc: ${c instanceof Error?c?.response?.data?.error||"An unexpected error occurred":"Unknown error"}`))}o.project=e,s!==e&&(o.branch="main"),o.env||(o.env="development"),o.apiUrl||(o.apiUrl=l("apiUrl")||"https://www.xtrasecurity.in/api");try{d.writeFileSync(r,JSON.stringify(o,null,2),"utf8"),console.log(a.default.gray(" \u2714 Updated local .xtrarc (Project context locked to this folder)"))}catch(c){console.error(a.default.yellow(` \u26A0 Could not write local .xtrarc: ${c instanceof Error?c?.response?.data?.error||"An unexpected error occurred":"Unknown error"}`))}console.log(a.default.green(`\u2714 Default project set to '${t}'`));let i=l("branch");i&&console.log(a.default.gray(` Active branch: ${i}`))};$.command("set").description("Set the default project ID").argument("[projectId]","Project ID to set as default (optional - will show list if not provided)").action(async e=>{if(e){U(e,e);return}let t=(0,P.default)("Fetching your projects...").start();try{let s=await h.getProjects();if(t.stop(),!Array.isArray(s)||s.length===0){console.log(a.default.yellow("No projects found."));return}let r=s.map(c=>({name:`${c.name} (${c.id})`,value:c.id,short:c.name})),{selectedProject:o}=await I.default.prompt([{type:"list",name:"selectedProject",message:"Select a project:",choices:r}]),i=s.find(c=>c.id===o)?.name||o;U(o,i)}catch(s){t.fail("Failed to fetch projects"),s.response?.data?.error?console.error(a.default.red(`Error: ${s.response.data.error}`)):console.error(a.default.red(s?.response?.data?.error||"An unexpected error occurred"))}});$.command("current").description("Show the current default project").action(async()=>{let e=l("project"),t=l("branch");if(e)try{let r=(await h.getProjects()).find(o=>o.id===e);console.log(r?a.default.cyan(`Project: ${r.name} (${e})`):a.default.cyan(`Project: ${e}`))}catch{console.log(a.default.cyan(`Project: ${e}`))}else console.log(a.default.yellow("No default project set. Use 'xtra project set' to set one."));t&&console.log(a.default.cyan(`Branch: ${t}`))});0&&(module.exports={projectCommand});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var ie=Object.create;var w=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var ge=Object.getPrototypeOf,de=Object.prototype.hasOwnProperty;var S=(e,t)=>()=>(e&&(t=e(e=0)),t);var P=(e,t)=>{for(var s in t)w(e,s,{get:t[s],enumerable:!0})},T=(e,t,s,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of pe(t))!de.call(e,o)&&o!==s&&w(e,o,{get:()=>t[o],enumerable:!(r=ce(t,o))||r.enumerable});return e};var i=(e,t,s)=>(s=e!=null?ie(ge(e)):{},T(t||!e||!e.__esModule?w(s,"default",{value:e,enumerable:!0}):s,e)),_=e=>T(w({},"__esModule",{value:!0}),e);var J,C,V,R,g,I,l,K,F,j=S(()=>{J=i(require("conf")),C=i(require("fs")),V=i(require("path")),R="https://www.xtrasecurity.in/api",g=new J.default({projectName:"xtra-cli",defaults:{apiUrl:R}}),I=g.get("apiUrl");I&&!process.env.XTRA_API_URL&&(I.includes("localhost")||I.includes("xtra-security.vercel.app"))&&g.set("apiUrl",R);l=()=>({...g.store,apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||R}),K=()=>g.get("token"),F=()=>{let e={};try{let t=V.default.join(process.cwd(),".xtrarc");C.default.existsSync(t)&&(e=JSON.parse(C.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||g.get("project")||"",env:e.env||g.get("env")||"development",branch:e.branch||g.get("branch")||"main"}}});var q,G,z,ue,n,m,L=S(()=>{q=i(require("axios"));j();G=i(require("fs")),z=i(require("path")),ue=JSON.parse(G.readFileSync(z.join(__dirname,"../../package.json"),"utf-8")),n=()=>{let{apiUrl:e}=l(),t=K();return q.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":ue.version,...t?{Authorization:`Bearer ${t}`}:{}}})},m={login:async(e,t,s)=>(await n().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await n().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await n().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,r,o="main")=>(await n().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:r,branch:o})).data,getSecretDetails:async(e,t,s,r="main")=>(await n().get(`/projects/${e}/envs/${t}/secrets/${s}?branch=${r}`)).data,syncLogs:async e=>(await n().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,s,r,o,a)=>(await n().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:r,sourceEnv:o,sourceKey:a})).data,rotateSecret:async(e,t,s,r,o)=>(await n().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:r,parsedNewValue:o})).data,promoteSecret:async(e,t,s)=>(await n().post(`/projects/${e}/envs/${t}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await n().get("/audit/verify")).data,exportAuditLogs:async(e,t,s,r)=>{let o={format:e};return t&&(o.startDate=t),s&&(o.endDate=s),r&&(o.projectId=r),(await n().post("/audit/export",o,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,s,r)=>(await n().post("/access/request",{projectId:e,secretId:r,reason:t,duration:s})).data,approveAccess:async(e,t)=>(await n().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=l(),s=t?`&workspaceId=${t}`:"";return(await n().get(`/access/list?mode=${e}${s}`)).data},getAccessRequestStatus:async e=>(await n().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=l(),t=e?`/project?workspaceId=${e}`:"/project";return(await n().get(t)).data},getBranches:async e=>(await n().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,s)=>(await n().post("/branch",{projectId:e,name:t,description:s})).data,deleteBranch:async e=>(await n().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await n().put("/branch",{id:e,...t})).data,getRoles:async()=>(await n().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await n().get(`/admin/users${t}`)).data},setUserRole:async(e,t,s)=>(await n().put("/admin/users/role",{email:e,role:t,teamId:s})).data,getIntegrationStatus:async e=>(await n().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await n().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await n().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,t)=>{let s=new URLSearchParams(t).toString();return(await n().get(`/projects/${e}/kubernetes?${s}`)).data},getSecretHistory:async(e,t,s)=>(await n().get(`/projects/${e}/envs/${t}/secrets/${s}/history`)).data,rollbackSecret:async(e,t,s,r)=>(await n().post(`/projects/${e}/envs/${t}/secrets/${s}/history`,{version:r})).data,cloneEnvironment:async(e,t,s,r,o)=>(await n().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,overwrite:r,branch:o})).data,generateJitLink:async e=>(await n().post("/jit/generate",e)).data,claimJitLink:async e=>(await n().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await n().get(`/jit/${e}`)).data,getServiceAccounts:async e=>(await n().get(`/projects/${e}/service-accounts`)).data,createServiceAccount:async(e,t)=>(await n().post(`/projects/${e}/service-accounts`,t)).data,deleteServiceAccount:async(e,t)=>(await n().delete(`/projects/${e}/service-accounts/${t}`)).data,getServiceAccountKeys:async(e,t)=>(await n().get(`/projects/${e}/service-accounts/${t}/keys`)).data,createServiceAccountKey:async(e,t,s,r)=>(await n().post(`/projects/${e}/service-accounts/${t}/keys`,{label:s,expiresAt:r})).data,deleteServiceAccountKey:async(e,t,s)=>(await n().delete(`/projects/${e}/service-accounts/${t}/keys/${s}`)).data,post:async(e,t)=>(await n().post(e,t)).data}});function W(){let e=H.get("masterKey");e||(e=y.default.randomBytes(32).toString("hex"),H.set("masterKey",e));let t=(0,X.machineIdSync)();return y.default.createHash("sha256").update(e+t).digest()}var y,M,X,Q,H,Y,h,U=S(()=>{y=i(require("crypto")),M=i(require("conf")),X=require("node-machine-id"),Q="aes-256-gcm",H=new M.default({projectName:"xtra-cli-crypto"});Y=e=>{let t=y.default.randomBytes(16),s=W(),r=y.default.createCipheriv(Q,s,t),o=r.update(e,"utf8","hex");o+=r.final("hex");let a=r.getAuthTag();return{iv:t.toString("hex"),content:o,tag:a.toString("hex")}},h=e=>{let t=W(),s=Buffer.from(e.iv,"hex"),r=Buffer.from(e.tag,"hex"),o=y.default.createDecipheriv(Q,t,s);o.setAuthTag(r);let a=o.update(e.content,"hex","utf8");return a+=o.final("utf8"),a}});var te={};P(te,{loadAuditLogs:()=>$,logAudit:()=>ye,saveAuditLogs:()=>x,syncAuditLogs:()=>fe});function le(e){if(!e||typeof e!="object")return e;let t={...e},s=["password","token","secret","value","apiKey","secretValue"];for(let r of Object.keys(t))s.some(o=>r.toLowerCase().includes(o))&&(t[r]="[REDACTED]");return t}async function ee(e){try{if(!l().token)return!1;let s={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:le(e.details),timestamp:e.timestamp,projectId:e.projectId};return await m.post("/audit/cli-logs",{logs:[s]}),!0}catch(t){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",t),!1}}function ye(e,t,s,r){let o={id:(0,Z.v4)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:s,details:r,synced:!1},a=$();a.push(o),x(a),ee(o).then(c=>{if(c){o.synced=!0;let d=$(),b=d.findIndex(u=>u.id===o.id);b!==-1&&(d[b].synced=!0,x(d))}}).catch(()=>{})}function $(){if(!f.default.existsSync(B))return[];try{let e=f.default.readFileSync(B,"utf-8"),t=JSON.parse(e),s=h(t);return JSON.parse(s)}catch{return[]}}function x(e){f.default.existsSync(O)||f.default.mkdirSync(O,{recursive:!0});let t=JSON.stringify(e),s=Y(t);f.default.writeFileSync(B,JSON.stringify(s),"utf-8")}async function fe(){let e=$(),t=e.filter(r=>!r.synced);if(t.length===0)return 0;let s=0;for(let r of t)await ee(r)&&(r.synced=!0,s++);return s>0&&x(e),s}var f,D,Z,O,B,se=S(()=>{f=i(require("fs")),D=i(require("path")),Z=require("uuid");U();j();L();O=D.default.join(process.cwd(),".xtra"),B=D.default.join(O,"audit.enc")});var he={};P(he,{rollbackCommand:()=>me});module.exports=_(he);var re=require("commander");L();var v=i(require("chalk")),E=i(require("ora")),ne=i(require("inquirer"));U();j();var me=new re.Command("rollback").description("Rollback a secret to a previous version").argument("<key>","Secret Key to rollback").option("-p, --project <projectId>","Project ID").option("-e, --env <environment>","Environment (dev, stg, prod)","dev").action(async(e,t)=>{let{project:s,env:r}=t;s||(s=F().project),s||(console.error(v.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first.")),process.exit(1)),r={dev:"development",stg:"staging",prod:"production"}[r]||r;let a=(0,E.default)(`Fetching history for ${e}...`).start();try{let c=await m.getSecretDetails(s,r,e);if(a.stop(),!c.history||!Array.isArray(c.history)||c.history.length===0){console.log(v.default.yellow(`No history found for ${e}. Cannot rollback.`));return}let d=[];[...c.history].reverse().forEach(p=>{let A="********";try{let N=JSON.parse(p.value[0]);A=h(N)}catch{A=p.value[0]}d.push({name:`v${p.version} - ${new Date(p.updatedAt).toLocaleString()} (Value: ${A.substring(0,10)}...)`,value:p})});let{selectedVersion:u}=await ne.default.prompt([{type:"list",name:"selectedVersion",message:"Select version to restore:",choices:d}]),oe=(0,E.default)(`Restoring version v${u.version}...`).start(),k=u.value[0];try{let p=JSON.parse(k);k=h(p)}catch{}let ae={[e]:k};await m.setSecrets(s,r,ae),oe.succeed(`Successfully rolled back ${e} to v${u.version}`);try{let{logAudit:p}=(se(),_(te));p("SECRET_ROLLBACK",s,r,{key:e,version:u.version})}catch{}}catch(c){a.fail("Failed to rollback."),c.response&&c.response.status===404?console.error(v.default.red("Secret not found.")):console.error(v.default.red(c?.response?.data?.error||"An unexpected error occurred"))}});0&&(module.exports={rollbackCommand});
|
package/dist/commands/rotate.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var te=Object.create;var w=Object.defineProperty;var re=Object.getOwnPropertyDescriptor;var se=Object.getOwnPropertyNames;var ne=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var S=(e,t)=>()=>(e&&(t=e(e=0)),t);var L=(e,t)=>{for(var r in t)w(e,r,{get:t[r],enumerable:!0})},D=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of se(t))!oe.call(e,n)&&n!==r&&w(e,n,{get:()=>t[n],enumerable:!(s=re(t,n))||s.enumerable});return e};var p=(e,t,r)=>(r=e!=null?te(ne(e)):{},D(t||!e||!e.__esModule?w(r,"default",{value:e,enumerable:!0}):r,e)),A=e=>D(w({},"__esModule",{value:!0}),e);var B,I,N,k,d,b,u,_,q,$=S(()=>{B=p(require("conf")),I=p(require("fs")),N=p(require("path")),k="https://www.xtrasecurity.in/api",d=new B.default({projectName:"xtra-cli",defaults:{apiUrl:k}}),b=d.get("apiUrl");b&&!process.env.XTRA_API_URL&&(b.includes("localhost")||b.includes("xtra-security.vercel.app"))&&d.set("apiUrl",k);u=()=>({...d.store,apiUrl:process.env.XTRA_API_URL||d.get("apiUrl")||k}),_=()=>d.get("token"),q=()=>{let e={};try{let t=N.default.join(process.cwd(),".xtrarc");I.default.existsSync(t)&&(e=JSON.parse(I.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||d.get("project")||"",env:e.env||d.get("env")||"development",branch:e.branch||d.get("branch")||"main"}}});var J,K,V,ae,o,m,C=S(()=>{J=p(require("axios"));$();K=p(require("fs")),V=p(require("path")),ae=JSON.parse(K.readFileSync(V.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:e}=u(),t=_();return J.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":ae.version,...t?{Authorization:`Bearer ${t}`}:{}}})},m={login:async(e,t,r)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:r})).data,getSecrets:async(e,t,r="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?branch=${r}`)).data,getSecretVersions:async(e,t,r="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${r}`)).data,setSecrets:async(e,t,r,s,n="main")=>(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:r,expectedVersions:s,branch:n})).data,getSecretDetails:async(e,t,r,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${r}?branch=${s}`)).data,syncLogs:async e=>(await o().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,r,s,n,i)=>(await o().post(`/projects/${e}/envs/${t}/secrets/link`,{key:r,sourceProjectId:s,sourceEnv:n,sourceKey:i})).data,rotateSecret:async(e,t,r,s,n)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${r}/rotate`,{strategy:s,parsedNewValue:n})).data,promoteSecret:async(e,t,r)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${r}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(e,t,r,s)=>{let n={format:e};return t&&(n.startDate=t),r&&(n.endDate=r),s&&(n.projectId=s),(await o().post("/audit/export",n,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,r,s)=>(await o().post("/access/request",{projectId:e,secretId:s,reason:t,duration:r})).data,approveAccess:async(e,t)=>(await o().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=u(),r=t?`&workspaceId=${t}`:"";return(await o().get(`/access/list?mode=${e}${r}`)).data},getAccessRequestStatus:async e=>(await o().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=u(),t=e?`/project?workspaceId=${e}`:"/project";return(await o().get(t)).data},getBranches:async e=>(await o().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,r)=>(await o().post("/branch",{projectId:e,name:t,description:r})).data,deleteBranch:async e=>(await o().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await o().put("/branch",{id:e,...t})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await o().get(`/admin/users${t}`)).data},setUserRole:async(e,t,r)=>(await o().put("/admin/users/role",{email:e,role:t,teamId:r})).data,getIntegrationStatus:async e=>(await o().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await o().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await o().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,t)=>{let r=new URLSearchParams(t).toString();return(await o().get(`/projects/${e}/kubernetes?${r}`)).data},getSecretHistory:async(e,t,r)=>(await o().get(`/projects/${e}/envs/${t}/secrets/${r}/history`)).data,rollbackSecret:async(e,t,r,s)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${r}/history`,{version:s})).data,cloneEnvironment:async(e,t,r,s,n)=>(await o().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:r,overwrite:s,branch:n})).data,generateJitLink:async e=>(await o().post("/jit/generate",e)).data,claimJitLink:async e=>(await o().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await o().get(`/jit/${e}`)).data,getServiceAccounts:async e=>(await o().get(`/projects/${e}/service-accounts`)).data,createServiceAccount:async(e,t)=>(await o().post(`/projects/${e}/service-accounts`,t)).data,deleteServiceAccount:async(e,t)=>(await o().delete(`/projects/${e}/service-accounts/${t}`)).data,getServiceAccountKeys:async(e,t)=>(await o().get(`/projects/${e}/service-accounts/${t}/keys`)).data,createServiceAccountKey:async(e,t,r,s)=>(await o().post(`/projects/${e}/service-accounts/${t}/keys`,{label:r,expiresAt:s})).data,deleteServiceAccountKey:async(e,t,r)=>(await o().delete(`/projects/${e}/service-accounts/${t}/keys/${r}`)).data,post:async(e,t)=>(await o().post(e,t)).data}});function H(){let e=F.get("masterKey");e||(e=l.default.randomBytes(32).toString("hex"),F.set("masterKey",e));let t=(0,M.machineIdSync)();return l.default.createHash("sha256").update(e+t).digest()}var l,G,M,z,F,X,Y,Z=S(()=>{l=p(require("crypto")),G=p(require("conf")),M=require("node-machine-id"),z="aes-256-gcm",F=new G.default({projectName:"xtra-cli-crypto"});X=e=>{let t=l.default.randomBytes(16),r=H(),s=l.default.createCipheriv(z,r,t),n=s.update(e,"utf8","hex");n+=s.final("hex");let i=s.getAuthTag();return{iv:t.toString("hex"),content:n,tag:i.toString("hex")}},Y=e=>{let t=H(),r=Buffer.from(e.iv,"hex"),s=Buffer.from(e.tag,"hex"),n=l.default.createDecipheriv(z,t,r);n.setAuthTag(s);let i=n.update(e.content,"hex","utf8");return i+=n.final("utf8"),i}});var T={};L(T,{loadAuditLogs:()=>j,logAudit:()=>ce,saveAuditLogs:()=>x,syncAuditLogs:()=>pe});function ie(e){if(!e||typeof e!="object")return e;let t={...e},r=["password","token","secret","value","apiKey","secretValue"];for(let s of Object.keys(t))r.some(n=>s.toLowerCase().includes(n))&&(t[s]="[REDACTED]");return t}async function W(e){try{if(!u().token)return!1;let r={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:ie(e.details),timestamp:e.timestamp,projectId:e.projectId};return await m.post("/audit/cli-logs",{logs:[r]}),!0}catch(t){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",t),!1}}function ce(e,t,r,s){let n={id:(0,Q.v4)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:r,details:s,synced:!1},i=j();i.push(n),x(i),W(n).then(h=>{if(h){n.synced=!0;let v=j(),g=v.findIndex(a=>a.id===n.id);g!==-1&&(v[g].synced=!0,x(v))}}).catch(()=>{})}function j(){if(!y.default.existsSync(P))return[];try{let e=y.default.readFileSync(P,"utf-8"),t=JSON.parse(e),r=Y(t);return JSON.parse(r)}catch{return[]}}function x(e){y.default.existsSync(R)||y.default.mkdirSync(R,{recursive:!0});let t=JSON.stringify(e),r=X(t);y.default.writeFileSync(P,JSON.stringify(r),"utf-8")}async function pe(){let e=j(),t=e.filter(s=>!s.synced);if(t.length===0)return 0;let r=0;for(let s of t)await W(s)&&(s.synced=!0,r++);return r>0&&x(e),r}var y,E,Q,R,P,U=S(()=>{y=p(require("fs")),E=p(require("path")),Q=require("uuid");Z();$();C();R=E.default.join(process.cwd(),".xtra"),P=E.default.join(R,"audit.enc")});var de={};L(de,{rotateCommand:()=>ge});module.exports=A(de);var ee=require("commander");C();$();var c=p(require("chalk")),O=p(require("ora")),ge=new ee.Command("rotate").description("Rotate a secret (Zero-Downtime Shadow Mode)").argument("<key>","Key of the secret to rotate").option("-p, --project <projectId>","Project ID").option("-e, --env <environment>","Environment","development").option("--strategy <strategy>","Rotation strategy","shadow").option("--promote","Promote the shadow value to active",!1).option("--value <value>","New value for the secret (optional)").action(async(e,t)=>{let{project:r,env:s,strategy:n,promote:i,value:h}=t;if(r||(r=q().project),s={dev:"development",stg:"staging",prod:"production"}[s]||s,r||(console.error(c.default.red("Error: Project ID is required. Use -p <id> or checkout a branch.")),process.exit(1)),s==="production"){let g=require("inquirer"),{confirmProd:a}=await g.prompt([{type:"confirm",name:"confirmProd",message:c.default.red(`\u26A0 You are about to rotate a secret in PRODUCTION (${e}). Proceed?`),default:!1}]);if(!a){console.log(c.default.yellow("Aborted."));return}}if(i){let g=(0,O.default)(`Promoting secret '${e}' in ${s}...`).start();try{let a=await m.promoteSecret(r,s,e);g.succeed(c.default.green(`Successfully promoted '${e}' to version ${a.version}`));try{let{logAudit:f}=(U(),A(T));f("SECRET_PROMOTE",r,s,{key:e,newVersion:a.version})}catch{}}catch(a){g.fail("Promotion failed"),a.response&&a.response.data&&a.response.data.error?console.error(c.default.red(`Server Error: ${a.response.data.error}`)):console.error(c.default.red(a?.response?.data?.error||"An unexpected error occurred"))}}else{let g=(0,O.default)(`Starting rotation for '${e}' (Strategy: ${n})...`).start();try{let a=await m.rotateSecret(r,s,e,n,h);g.succeed(c.default.green(`Rotation initiated for '${e}'`)),console.log(c.default.dim(`Shadow Value: ${a.shadowValue}`)),console.log(c.default.dim(`Expires At: ${a.expiresAt}`)),console.log(c.default.blue(`
|
|
2
2
|
To verify, run your app. To finalize, run:
|
|
3
|
-
xtra rotate ${
|
|
3
|
+
xtra rotate ${e} --promote -p ${r} -e ${s}`));try{let{logAudit:f}=(U(),A(T));f("SECRET_ROTATE",r,s,{key:e,strategy:n,expiresAt:a.expiresAt})}catch{}}catch(a){g.fail("Rotation failed"),a.response&&a.response.data&&a.response.data.error?console.error(c.default.red(`Server Error: ${a.response.data.error}`)):console.error(c.default.red(a?.response?.data?.error||"An unexpected error occurred"))}}});0&&(module.exports={rotateCommand});
|
package/dist/commands/run.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
var Ie=Object.create;var O=Object.defineProperty;var ke=Object.getOwnPropertyDescriptor;var Ae=Object.getOwnPropertyNames;var Ee=Object.getPrototypeOf,Ce=Object.prototype.hasOwnProperty;var $=(e,t)=>()=>(e&&(t=e(e=0)),t);var b=(e,t)=>{for(var s in t)O(e,s,{get:t[s],enumerable:!0})},Q=(e,t,s,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Ae(t))!Ce.call(e,n)&&n!==s&&O(e,n,{get:()=>t[n],enumerable:!(r=ke(t,n))||r.enumerable});return e};var p=(e,t,s)=>(s=e!=null?Ie(Ee(e)):{},Q(t||!e||!e.__esModule?O(s,"default",{value:e,enumerable:!0}):s,e)),I=e=>Q(O({},"__esModule",{value:!0}),e);var ee={};b(ee,{clearConfig:()=>Oe,deleteConfig:()=>Re,getAuthToken:()=>q,getBreakGlassSession:()=>Le,getConfig:()=>h,getConfigValue:()=>R,getProjectConfig:()=>Te,getRcConfig:()=>K,setBreakGlassSession:()=>Ne,setConfig:()=>J});var Z,y,G,B,g,M,h,R,J,Oe,Re,q,Le,Ne,Te,K,k=$(()=>{Z=p(require("conf")),y=p(require("fs")),G=p(require("path")),B="https://www.xtrasecurity.in/api",g=new Z.default({projectName:"xtra-cli",defaults:{apiUrl:B}}),M=g.get("apiUrl");M&&!process.env.XTRA_API_URL&&(M.includes("localhost")||M.includes("xtra-security.vercel.app"))&&g.set("apiUrl",B);h=()=>({...g.store,apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||B}),R=e=>g.get(e),J=(e,t)=>{if(g.set(e,t),e==="token"&&process.platform!=="win32"&&y.default.existsSync(g.path))try{y.default.chmodSync(g.path,384)}catch{}},Oe=()=>g.clear(),Re=e=>g.delete(e),q=()=>g.get("token"),Le=()=>g.get("breakGlassSessionId"),Ne=e=>{e?g.set("breakGlassSessionId",e):g.delete("breakGlassSessionId")},Te=async()=>{try{let e=G.default.join(process.cwd(),"xtra.json");if(y.default.existsSync(e)){let t=y.default.readFileSync(e,"utf-8");return JSON.parse(t)}return null}catch{return null}},K=()=>{let e={};try{let t=G.default.join(process.cwd(),".xtrarc");y.default.existsSync(t)&&(e=JSON.parse(y.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||g.get("project")||"",env:e.env||g.get("env")||"development",branch:e.branch||g.get("branch")||"main"}}});var te,se,re,Ue,o,L,H=$(()=>{te=p(require("axios"));k();se=p(require("fs")),re=p(require("path")),Ue=JSON.parse(se.readFileSync(re.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:e}=h(),t=q();return te.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":Ue.version,...t?{Authorization:`Bearer ${t}`}:{}}})},L={login:async(e,t,s)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,r,n="main")=>(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:r,branch:n})).data,getSecretDetails:async(e,t,s,r="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}?branch=${r}`)).data,syncLogs:async e=>(await o().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,s,r,n,a)=>(await o().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:r,sourceEnv:n,sourceKey:a})).data,rotateSecret:async(e,t,s,r,n)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:r,parsedNewValue:n})).data,promoteSecret:async(e,t,s)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(e,t,s,r)=>{let n={format:e};return t&&(n.startDate=t),s&&(n.endDate=s),r&&(n.projectId=r),(await o().post("/audit/export",n,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,s,r)=>(await o().post("/access/request",{projectId:e,secretId:r,reason:t,duration:s})).data,approveAccess:async(e,t)=>(await o().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=h(),s=t?`&workspaceId=${t}`:"";return(await o().get(`/access/list?mode=${e}${s}`)).data},getAccessRequestStatus:async e=>(await o().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=h(),t=e?`/project?workspaceId=${e}`:"/project";return(await o().get(t)).data},getBranches:async e=>(await o().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,s)=>(await o().post("/branch",{projectId:e,name:t,description:s})).data,deleteBranch:async e=>(await o().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await o().put("/branch",{id:e,...t})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await o().get(`/admin/users${t}`)).data},setUserRole:async(e,t,s)=>(await o().put("/admin/users/role",{email:e,role:t,teamId:s})).data,getIntegrationStatus:async e=>(await o().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await o().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await o().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,t)=>{let s=new URLSearchParams(t).toString();return(await o().get(`/projects/${e}/kubernetes?${s}`)).data},getSecretHistory:async(e,t,s)=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}/history`)).data,rollbackSecret:async(e,t,s,r)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/history`,{version:r})).data,cloneEnvironment:async(e,t,s,r,n)=>(await o().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,overwrite:r,branch:n})).data,generateJitLink:async e=>(await o().post("/jit/generate",e)).data,claimJitLink:async e=>(await o().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await o().get(`/jit/${e}`)).data,post:async(e,t)=>(await o().post(e,t)).data}});var pe={};b(pe,{decrypt:()=>E,encrypt:()=>A,hash:()=>De});function ce(){let e=ne.get("masterKey");e||(e=S.default.randomBytes(32).toString("hex"),ne.set("masterKey",e));let t=(0,ie.machineIdSync)();return S.default.createHash("sha256").update(e+t).digest()}var S,oe,ie,ae,ne,A,E,De,N=$(()=>{S=p(require("crypto")),oe=p(require("conf")),ie=require("node-machine-id"),ae="aes-256-gcm",ne=new oe.default({projectName:"xtra-cli-crypto"});A=e=>{let t=S.default.randomBytes(16),s=ce(),r=S.default.createCipheriv(ae,s,t),n=r.update(e,"utf8","hex");n+=r.final("hex");let a=r.getAuthTag();return{iv:t.toString("hex"),content:n,tag:a.toString("hex")}},E=e=>{let t=ce(),s=Buffer.from(e.iv,"hex"),r=Buffer.from(e.tag,"hex"),n=S.default.createDecipheriv(ae,t,s);n.setAuthTag(r);let a=n.update(e.content,"hex","utf8");return a+=n.final("utf8"),a},De=e=>S.default.createHash("sha256").update(e).digest("hex")});var le={};b(le,{MANIFEST_DIR:()=>T,MANIFEST_FILE:()=>U,loadManifest:()=>ge,saveManifest:()=>de,updateManifest:()=>Fe});function ge(){if(!w.default.existsSync(U))return null;try{let e=w.default.readFileSync(U,"utf-8");return JSON.parse(e)}catch{return null}}function de(e){w.default.existsSync(T)||w.default.mkdirSync(T,{recursive:!0}),w.default.writeFileSync(U,JSON.stringify(e,null,2),"utf-8")}function Fe(e,t,s,r){let n=ge()||{projectId:e,environment:t,lastSyncedAt:new Date().toISOString(),secrets:{}};n.projectId=e,n.environment=t,n.lastSyncedAt=new Date().toISOString(),Object.entries(s).forEach(([a,m])=>{let u=r(m);n.secrets[a]={hash:u,updatedAt:new Date().toISOString()}}),de(n)}var w,V,T,U,ue=$(()=>{w=p(require("fs")),V=p(require("path")),T=V.default.join(process.cwd(),".xtra"),U=V.default.join(T,"manifest.json")});var ye={};b(ye,{loadAuditLogs:()=>D,logAudit:()=>Pe,saveAuditLogs:()=>F,syncAuditLogs:()=>Me});function _e(e){if(!e||typeof e!="object")return e;let t={...e},s=["password","token","secret","value","apiKey","secretValue"];for(let r of Object.keys(t))s.some(n=>r.toLowerCase().includes(n))&&(t[r]="[REDACTED]");return t}async function me(e){try{if(!h().token)return!1;let s={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:_e(e.details),timestamp:e.timestamp,projectId:e.projectId};return await L.post("/audit/cli-logs",{logs:[s]}),!0}catch(t){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",t),!1}}function Pe(e,t,s,r){let n={id:(0,fe.v4)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:s,details:r,synced:!1},a=D();a.push(n),F(a),me(n).then(m=>{if(m){n.synced=!0;let u=D(),P=u.findIndex(l=>l.id===n.id);P!==-1&&(u[P].synced=!0,F(u))}}).catch(()=>{})}function D(){if(!j.default.existsSync(X))return[];try{let e=j.default.readFileSync(X,"utf-8"),t=JSON.parse(e),s=E(t);return JSON.parse(s)}catch{return[]}}function F(e){j.default.existsSync(z)||j.default.mkdirSync(z,{recursive:!0});let t=JSON.stringify(e),s=A(t);j.default.writeFileSync(X,JSON.stringify(s),"utf-8")}async function Me(){let e=D(),t=e.filter(r=>!r.synced);if(t.length===0)return 0;let s=0;for(let r of t)await me(r)&&(r.synced=!0,s++);return s>0&&F(e),s}var j,W,fe,z,X,he=$(()=>{j=p(require("fs")),W=p(require("path")),fe=require("uuid");N();k();H();z=W.default.join(process.cwd(),".xtra"),X=W.default.join(z,"audit.enc")});var Je={};b(Je,{runCommand:()=>Be});module.exports=I(Je);var Se=require("commander");H();var ve=require("child_process"),d=p(require("chalk")),xe=p(require("ora"));k();N();var _=p(require("fs")),we=p(require("path")),je=p(require("dotenv")),Be=new Se.Command("run").description("Run a command with injected secrets").option("-p, --project <projectId>","Project ID").option("-e, --env <environment>","Environment (development, staging, production)","development").option("-b, --branch <branchName>","Branch Name").option("--shell","Enable shell mode (needed for npm run, shell built-ins on Windows)",!1).argument("<command>","Command to run").argument("[args...]","Command arguments").addHelpText("after",`
|
|
1
|
+
var ke=Object.create;var O=Object.defineProperty;var Ae=Object.getOwnPropertyDescriptor;var Ie=Object.getOwnPropertyNames;var Ee=Object.getPrototypeOf,Ce=Object.prototype.hasOwnProperty;var $=(e,t)=>()=>(e&&(t=e(e=0)),t);var b=(e,t)=>{for(var s in t)O(e,s,{get:t[s],enumerable:!0})},Q=(e,t,s,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Ie(t))!Ce.call(e,n)&&n!==s&&O(e,n,{get:()=>t[n],enumerable:!(r=Ae(t,n))||r.enumerable});return e};var p=(e,t,s)=>(s=e!=null?ke(Ee(e)):{},Q(t||!e||!e.__esModule?O(s,"default",{value:e,enumerable:!0}):s,e)),k=e=>Q(O({},"__esModule",{value:!0}),e);var ee={};b(ee,{clearConfig:()=>Oe,deleteConfig:()=>Re,getAuthToken:()=>q,getBreakGlassSession:()=>Le,getConfig:()=>h,getConfigValue:()=>R,getProjectConfig:()=>Te,getRcConfig:()=>K,setBreakGlassSession:()=>Ne,setConfig:()=>J});var Z,m,G,B,g,M,h,R,J,Oe,Re,q,Le,Ne,Te,K,A=$(()=>{Z=p(require("conf")),m=p(require("fs")),G=p(require("path")),B="https://www.xtrasecurity.in/api",g=new Z.default({projectName:"xtra-cli",defaults:{apiUrl:B}}),M=g.get("apiUrl");M&&!process.env.XTRA_API_URL&&(M.includes("localhost")||M.includes("xtra-security.vercel.app"))&&g.set("apiUrl",B);h=()=>({...g.store,apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||B}),R=e=>g.get(e),J=(e,t)=>{if(g.set(e,t),e==="token"&&process.platform!=="win32"&&m.default.existsSync(g.path))try{m.default.chmodSync(g.path,384)}catch{}},Oe=()=>g.clear(),Re=e=>g.delete(e),q=()=>g.get("token"),Le=()=>g.get("breakGlassSessionId"),Ne=e=>{e?g.set("breakGlassSessionId",e):g.delete("breakGlassSessionId")},Te=async()=>{try{let e=G.default.join(process.cwd(),"xtra.json");if(m.default.existsSync(e)){let t=m.default.readFileSync(e,"utf-8");return JSON.parse(t)}return null}catch{return null}},K=()=>{let e={};try{let t=G.default.join(process.cwd(),".xtrarc");m.default.existsSync(t)&&(e=JSON.parse(m.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||g.get("project")||"",env:e.env||g.get("env")||"development",branch:e.branch||g.get("branch")||"main"}}});var te,se,re,Ue,o,L,H=$(()=>{te=p(require("axios"));A();se=p(require("fs")),re=p(require("path")),Ue=JSON.parse(se.readFileSync(re.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:e}=h(),t=q();return te.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":Ue.version,...t?{Authorization:`Bearer ${t}`}:{}}})},L={login:async(e,t,s)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,r,n="main")=>(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:r,branch:n})).data,getSecretDetails:async(e,t,s,r="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}?branch=${r}`)).data,syncLogs:async e=>(await o().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,s,r,n,i)=>(await o().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:r,sourceEnv:n,sourceKey:i})).data,rotateSecret:async(e,t,s,r,n)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:r,parsedNewValue:n})).data,promoteSecret:async(e,t,s)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(e,t,s,r)=>{let n={format:e};return t&&(n.startDate=t),s&&(n.endDate=s),r&&(n.projectId=r),(await o().post("/audit/export",n,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,s,r)=>(await o().post("/access/request",{projectId:e,secretId:r,reason:t,duration:s})).data,approveAccess:async(e,t)=>(await o().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=h(),s=t?`&workspaceId=${t}`:"";return(await o().get(`/access/list?mode=${e}${s}`)).data},getAccessRequestStatus:async e=>(await o().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=h(),t=e?`/project?workspaceId=${e}`:"/project";return(await o().get(t)).data},getBranches:async e=>(await o().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,s)=>(await o().post("/branch",{projectId:e,name:t,description:s})).data,deleteBranch:async e=>(await o().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await o().put("/branch",{id:e,...t})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await o().get(`/admin/users${t}`)).data},setUserRole:async(e,t,s)=>(await o().put("/admin/users/role",{email:e,role:t,teamId:s})).data,getIntegrationStatus:async e=>(await o().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await o().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await o().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,t)=>{let s=new URLSearchParams(t).toString();return(await o().get(`/projects/${e}/kubernetes?${s}`)).data},getSecretHistory:async(e,t,s)=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}/history`)).data,rollbackSecret:async(e,t,s,r)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/history`,{version:r})).data,cloneEnvironment:async(e,t,s,r,n)=>(await o().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,overwrite:r,branch:n})).data,generateJitLink:async e=>(await o().post("/jit/generate",e)).data,claimJitLink:async e=>(await o().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await o().get(`/jit/${e}`)).data,getServiceAccounts:async e=>(await o().get(`/projects/${e}/service-accounts`)).data,createServiceAccount:async(e,t)=>(await o().post(`/projects/${e}/service-accounts`,t)).data,deleteServiceAccount:async(e,t)=>(await o().delete(`/projects/${e}/service-accounts/${t}`)).data,getServiceAccountKeys:async(e,t)=>(await o().get(`/projects/${e}/service-accounts/${t}/keys`)).data,createServiceAccountKey:async(e,t,s,r)=>(await o().post(`/projects/${e}/service-accounts/${t}/keys`,{label:s,expiresAt:r})).data,deleteServiceAccountKey:async(e,t,s)=>(await o().delete(`/projects/${e}/service-accounts/${t}/keys/${s}`)).data,post:async(e,t)=>(await o().post(e,t)).data}});var pe={};b(pe,{decrypt:()=>E,encrypt:()=>I,hash:()=>De});function ae(){let e=ne.get("masterKey");e||(e=S.default.randomBytes(32).toString("hex"),ne.set("masterKey",e));let t=(0,ce.machineIdSync)();return S.default.createHash("sha256").update(e+t).digest()}var S,oe,ce,ie,ne,I,E,De,N=$(()=>{S=p(require("crypto")),oe=p(require("conf")),ce=require("node-machine-id"),ie="aes-256-gcm",ne=new oe.default({projectName:"xtra-cli-crypto"});I=e=>{let t=S.default.randomBytes(16),s=ae(),r=S.default.createCipheriv(ie,s,t),n=r.update(e,"utf8","hex");n+=r.final("hex");let i=r.getAuthTag();return{iv:t.toString("hex"),content:n,tag:i.toString("hex")}},E=e=>{let t=ae(),s=Buffer.from(e.iv,"hex"),r=Buffer.from(e.tag,"hex"),n=S.default.createDecipheriv(ie,t,s);n.setAuthTag(r);let i=n.update(e.content,"hex","utf8");return i+=n.final("utf8"),i},De=e=>S.default.createHash("sha256").update(e).digest("hex")});var ue={};b(ue,{MANIFEST_DIR:()=>T,MANIFEST_FILE:()=>U,loadManifest:()=>ge,saveManifest:()=>de,updateManifest:()=>Fe});function ge(){if(!x.default.existsSync(U))return null;try{let e=x.default.readFileSync(U,"utf-8");return JSON.parse(e)}catch{return null}}function de(e){x.default.existsSync(T)||x.default.mkdirSync(T,{recursive:!0}),x.default.writeFileSync(U,JSON.stringify(e,null,2),"utf-8")}function Fe(e,t,s,r){let n=ge()||{projectId:e,environment:t,lastSyncedAt:new Date().toISOString(),secrets:{}};n.projectId=e,n.environment=t,n.lastSyncedAt=new Date().toISOString(),Object.entries(s).forEach(([i,y])=>{let l=r(y);n.secrets[i]={hash:l,updatedAt:new Date().toISOString()}}),de(n)}var x,V,T,U,le=$(()=>{x=p(require("fs")),V=p(require("path")),T=V.default.join(process.cwd(),".xtra"),U=V.default.join(T,"manifest.json")});var me={};b(me,{loadAuditLogs:()=>D,logAudit:()=>Pe,saveAuditLogs:()=>F,syncAuditLogs:()=>Me});function _e(e){if(!e||typeof e!="object")return e;let t={...e},s=["password","token","secret","value","apiKey","secretValue"];for(let r of Object.keys(t))s.some(n=>r.toLowerCase().includes(n))&&(t[r]="[REDACTED]");return t}async function ye(e){try{if(!h().token)return!1;let s={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:_e(e.details),timestamp:e.timestamp,projectId:e.projectId};return await L.post("/audit/cli-logs",{logs:[s]}),!0}catch(t){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",t),!1}}function Pe(e,t,s,r){let n={id:(0,fe.v4)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:s,details:r,synced:!1},i=D();i.push(n),F(i),ye(n).then(y=>{if(y){n.synced=!0;let l=D(),P=l.findIndex(u=>u.id===n.id);P!==-1&&(l[P].synced=!0,F(l))}}).catch(()=>{})}function D(){if(!j.default.existsSync(X))return[];try{let e=j.default.readFileSync(X,"utf-8"),t=JSON.parse(e),s=E(t);return JSON.parse(s)}catch{return[]}}function F(e){j.default.existsSync(z)||j.default.mkdirSync(z,{recursive:!0});let t=JSON.stringify(e),s=I(t);j.default.writeFileSync(X,JSON.stringify(s),"utf-8")}async function Me(){let e=D(),t=e.filter(r=>!r.synced);if(t.length===0)return 0;let s=0;for(let r of t)await ye(r)&&(r.synced=!0,s++);return s>0&&F(e),s}var j,W,fe,z,X,he=$(()=>{j=p(require("fs")),W=p(require("path")),fe=require("uuid");N();A();H();z=W.default.join(process.cwd(),".xtra"),X=W.default.join(z,"audit.enc")});var Je={};b(Je,{runCommand:()=>Be});module.exports=k(Je);var Se=require("commander");H();var ve=require("child_process"),d=p(require("chalk")),we=p(require("ora"));A();N();var _=p(require("fs")),xe=p(require("path")),je=p(require("dotenv")),Be=new Se.Command("run").description("Run a command with injected secrets").option("-p, --project <projectId>","Project ID").option("-e, --env <environment>","Environment (development, staging, production)","development").option("-b, --branch <branchName>","Branch Name").option("--shell","Enable shell mode (needed for npm run, shell built-ins on Windows)",!1).argument("<command>","Command to run").argument("[args...]","Command arguments").addHelpText("after",`
|
|
2
2
|
Examples:
|
|
3
3
|
$ xtra run npm start
|
|
4
4
|
$ xtra run -e production -- npm run build
|
|
5
5
|
$ xtra run -p proj_123 -b feature-branch -- python script.py
|
|
6
6
|
$ xtra run --shell "echo $SECRET_KEY"
|
|
7
|
-
`).action(async(e,t,s)=>{let{project:r,env:n,branch:
|
|
8
|
-
Error: Project '${r}' not found or your access has been revoked.`)):
|
|
7
|
+
`).action(async(e,t,s)=>{let{project:r,env:n,branch:i,shell:y}=s,l=K();i||(i=l.branch),n={dev:"development",stg:"staging",prod:"production"}[n]||n||l.env,r||(r=l.project),r||(console.error(d.default.red("Error: Project ID is required. Use -p <id> or checkout a branch.")),process.exit(1));let u=(0,we.default)(`Fetching secrets for ${n} (branch: ${i})...`).start(),a=null;if(R("localMode")===!0||process.env.XTRA_LOCAL_MODE==="true"){let c=xe.resolve(process.cwd(),".env.local");_.existsSync(c)||(u.fail("Local mode is ON but .env.local not found. Run 'xtra local sync' first."),process.exit(1)),a=je.default.parse(_.readFileSync(c,"utf8")),u.succeed(d.default.yellow(`\u{1F50C} Local mode: loaded ${Object.keys(a).length} secrets from .env.local`))}else try{if(a=await L.getSecrets(r,n,i),!a||Object.keys(a).length===0)u.warn(d.default.yellow("No secrets found for this environment."));else{u.succeed(`Loaded ${Object.keys(a).length} secrets (Online).`);try{let{hash:c}=(N(),k(pe)),{updateManifest:f}=(le(),k(ue));f(r,n,a,c)}catch{}try{let c=`cache.${r}.${n}.${i}`,f=I(JSON.stringify(a));J(c,f)}catch{console.error(d.default.yellow("Warning: Failed to cache secrets."))}}}catch(c){let f=`cache.${r}.${n}.${i}`;if(c.response&&[401,403,404].includes(c.response.status)){try{let{deleteConfig:w}=(A(),k(ee));w&&w(f)}catch{}u.fail("Access Denied."),c.response.status===404?console.error(d.default.red(`
|
|
8
|
+
Error: Project '${r}' not found or your access has been revoked.`)):c.response.status===401?console.error(d.default.red(`
|
|
9
9
|
Error: Unauthorized. Please run 'xtra login' again.`)):console.error(d.default.red(`
|
|
10
|
-
Error: ${
|
|
11
|
-
Details: ${
|
|
10
|
+
Error: ${c.response.data.error||"You do not have permission to access these secrets."}`)),process.exit(1)}let Y=R(f);if(Y)try{let w=E(Y);a=JSON.parse(w),u.warn(d.default.yellow(`Offline Mode: Loaded ${Object.keys(a).length} secrets from cache.`))}catch{u.fail("Failed to fetch secrets and cache is corrupt."),process.exit(1)}else u.fail("Failed to fetch secrets and no local cache available."),console.error(d.default.dim(`
|
|
11
|
+
Details: ${c?.response?.data?.error||"An unexpected error occurred"}`)),process.exit(1)}try{let{logAudit:c}=(he(),k(me));a&&Object.keys(a).length>0&&c("SECRET_ACCESS",r,n,{method:"run",keys:Object.keys(a),branch:i})}catch(c){console.error("Audit Error:",c)}let $e={...process.env,...a};if(!y&&/[;&|`$<>\\\n]/g.test(e)&&(console.error(d.default.red("Error: Command contains unsafe characters. Use --shell if intentional.")),process.exit(1)),n==="production"){let c=require("inquirer"),{confirm:f}=await c.prompt([{type:"confirm",name:"confirm",message:d.default.red(`\u26A0 You are about to run a command in PRODUCTION with ${Object.keys(a||{}).length} injected secrets. Continue?`),default:!1}]);if(!f){console.log(d.default.yellow("Aborted."));return}}console.log(d.default.gray(`> ${e} ${t.join(" ")}`));let be=process.platform==="win32",v=(0,ve.spawn)(e,t,{env:$e,stdio:"inherit",shell:y||be}),C=()=>{if(a)for(let c in a)a[c]="**********"};process.on("SIGINT",()=>{C(),v&&v.kill("SIGINT"),process.exit(0)}),process.on("SIGTERM",()=>{C(),v&&v.kill("SIGTERM"),process.exit(0)}),v.on("exit",c=>{C(),process.exit(c??0)}),v.on("error",c=>{console.error(d.default.red(`Failed to start command: ${c.message}`)),C(),process.exit(1)})});0&&(module.exports={runCommand});
|