xtra-cli 1.0.7 → 1.0.9
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/agent.js +4 -0
- 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 +2 -2
- package/dist/commands/env.js +2 -2
- package/dist/commands/export.js +3 -2
- package/dist/commands/generate.js +3 -3
- package/dist/commands/history.js +4 -4
- package/dist/commands/import.js +1 -1
- package/dist/commands/init.js +4 -4
- package/dist/commands/integration.js +9 -9
- package/dist/commands/jit-run.js +5 -5
- package/dist/commands/local.js +5 -5
- package/dist/commands/login.js +6 -6
- package/dist/commands/logout.js +1 -1
- package/dist/commands/logs.js +3 -3
- package/dist/commands/oidc-link.js +6 -0
- 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 +8 -6
- package/dist/commands/scan.js +13 -18
- package/dist/commands/secrets.js +6 -5
- package/dist/commands/service-account.js +5 -5
- package/dist/commands/simulate.js +5 -5
- package/dist/commands/status.js +2 -2
- package/dist/commands/template.js +9 -9
- package/dist/commands/ui.js +2 -2
- package/dist/commands/watch.js +13 -13
- package/dist/lib/api.js +1 -1
- package/dist/lib/audit.js +1 -1
- package/dist/lib/config.js +1 -1
- package/dist/lib/crypto.js +1 -1
- package/package.json +3 -3
- package/dist/commands/login.test.js +0 -16
- package/dist/lib/api.test.js +0 -1
- package/dist/lib/config.test.js +0 -1
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 I=(t,e)=>{for(var s in e)$(t,s,{get:e[s],enumerable:!0})},P=(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)):{},P(e||!t||!t.__esModule?$(s,"default",{value:t,enumerable:!0}):s,t)),C=t=>P($({},"__esModule",{value:!0}),t);function K(){let t=B.get("masterKey");t||(t=y.default.randomBytes(32).toString("hex"),B.set("masterKey",t));let e=(0,F.machineIdSync)();return y.default.createHash("sha256").update(t+e).digest()}var y,_,F,J,B,q,G,V=b(()=>{y=u(require("crypto")),_=u(require("conf")),F=require("node-machine-id"),J="aes-256-gcm",B=new _.default({projectName:"xtra-cli-crypto"});q=t=>{let e=y.default.randomBytes(16),s=K(),n=y.default.createCipheriv(J,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")}},G=t=>{let e=K(),s=Buffer.from(t.iv,"hex"),n=Buffer.from(t.tag,"hex"),r=y.default.createDecipheriv(J,e,s);r.setAuthTag(n);let a=r.update(t.content,"hex","utf8");return a+=r.final("utf8"),a}});var z,L,j,H,f,M,U=b(()=>{z=u(require("conf")),L="https://www.xtrasecurity.in/api",j=new z.default({projectName:"xtra-cli",defaults:{apiUrl:L}}),H=j.get("apiUrl");H&&!process.env.XTRA_API_URL&&H.includes("xtra-security.vercel.app")&&j.set("apiUrl",L);f=()=>({...j.store,apiUrl:process.env.XTRA_API_URL||j.get("apiUrl")||L}),M=()=>j.get("token")});var Y={};I(Y,{api:()=>R});var X,Q,W,dt,o,R,T=b(()=>{X=u(require("axios"));U();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}`}:{}}})},R={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 R.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(O))return[];try{let t=m.default.readFileSync(O,"utf-8"),e=JSON.parse(t),s=G(e);return JSON.parse(s)}catch{return[]}}function x(t){m.default.existsSync(D)||m.default.mkdirSync(D,{recursive:!0});let e=JSON.stringify(t),s=q(e);m.default.writeFileSync(O,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,E,Z,D,O,N=b(()=>{m=u(require("fs")),E=u(require("path")),Z=require("uuid");V();U();T();D=E.default.join(process.cwd(),".xtra"),O=E.default.join(D,"audit.enc")});var mt={};I(mt,{logsCommand:()=>ft});module.exports=C(mt);var st=require("commander");N();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}=(T(),C(Y)),{saveAuditLogs:k}=(N(),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
|
|
3
|
-
Local Audit Logs${
|
|
1
|
+
var me=Object.create;var C=Object.defineProperty;var he=Object.getOwnPropertyDescriptor;var ve=Object.getOwnPropertyNames;var Se=Object.getPrototypeOf,we=Object.prototype.hasOwnProperty;var B=(e,t)=>()=>(e&&(t=e(e=0)),t);var P=(e,t)=>{for(var r in t)C(e,r,{get:t[r],enumerable:!0})},Y=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of ve(t))!we.call(e,n)&&n!==r&&C(e,n,{get:()=>t[n],enumerable:!(s=he(t,n))||s.enumerable});return e};var v=(e,t,r)=>(r=e!=null?me(Se(e)):{},Y(t||!e||!e.__esModule?C(r,"default",{value:e,enumerable:!0}):r,e)),b=e=>Y(C({},"__esModule",{value:!0}),e);var ee={};P(ee,{clearConfig:()=>$e,deleteConfig:()=>be,getAuthToken:()=>K,getBreakGlassSession:()=>ke,getConfig:()=>j,getConfigValue:()=>xe,getProjectConfig:()=>Te,getRcConfig:()=>Pe,setBreakGlassSession:()=>Ae,setConfig:()=>je});var Q,x,J,F,d,Z,j,xe,je,$e,be,K,ke,Ae,Te,Pe,L=B(()=>{Q=v(require("conf")),x=v(require("fs")),J=v(require("path"));E();F="https://www.xtrasecurity.in/api",d=new Q.default({projectName:"xtra-cli",defaults:{apiUrl:F}}),Z=d.get("apiUrl");Z&&!process.env.XTRA_API_URL&&Z.includes("xtra-security.vercel.app")&&d.set("apiUrl",F);j=()=>({...d.store,token:K(),apiUrl:process.env.XTRA_API_URL||d.get("apiUrl")||F}),xe=e=>e==="token"?K():d.get(e),je=(e,t)=>{if(e==="token"&&t&&I("token",t),d.set(e,t),e==="token"&&process.platform!=="win32"&&x.default.existsSync(d.path))try{x.default.chmodSync(d.path,384)}catch{}},$e=()=>d.clear(),be=e=>d.delete(e),K=()=>R("token")||d.get("token"),ke=()=>d.get("breakGlassSessionId"),Ae=e=>{e?d.set("breakGlassSessionId",e):d.delete("breakGlassSessionId")},Te=async()=>{try{let e=J.default.join(process.cwd(),"xtra.json");if(x.default.existsSync(e)){let t=x.default.readFileSync(e,"utf-8");return JSON.parse(t)}return null}catch{return null}},Pe=()=>{let e={};try{let t=J.default.join(process.cwd(),".xtrarc");x.default.existsSync(t)&&(e=JSON.parse(x.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 q={};P(q,{createWorkloadKeyEnvelope:()=>Ce,decrypt:()=>V,decryptSecretValue:()=>Ee,decryptWorkloadKeyEnvelope:()=>Be,deriveProjectKey:()=>Ie,encrypt:()=>D,encryptSecretValue:()=>Re,hash:()=>Ke,resolveVaultPassphrase:()=>oe,saveVaultPassphrase:()=>_e,secureRead:()=>R,secureSave:()=>I});function ne(){if(O)return O;let e=U.get("masterKey");e||(e=p.default.randomBytes(32).toString("hex"),U.set("masterKey",e));let t="";try{t=(0,re.machineIdSync)()||""}catch{t=p.default.createHash("sha256").update(w.default.hostname()+(w.default.userInfo?.()?.username||"root")).digest("hex")}let r=w.default.platform(),s=w.default.userInfo?.()?.username||"default_user",n=`${r}:${s}:${t}:${e}`;return O=p.default.createHash("sha256").update(n).digest(),O}function Ie(e,t){t||(t=oe(void 0,e));let r=Buffer.from(`project_salt_${e}`),s=Buffer.from("xtra-e2ee-project-key-v2"),n=p.default.hkdfSync("sha256",Buffer.from(t),r,s,32);return Buffer.from(n).toString("hex")}function Re(e,t){let r=p.default.randomBytes(12),s=Buffer.from(t.slice(0,64).padEnd(64,"0"),"hex"),n=p.default.createCipheriv("aes-256-gcm",s,r),i=n.update(e,"utf8","hex");i+=n.final("hex");let f=n.getAuthTag().toString("hex");return{ciphertext:i,iv:r.toString("hex"),authTag:f}}function Ee(e,t){let r=Buffer.from(t.slice(0,64).padEnd(64,"0"),"hex"),s=Buffer.from(e.iv,"hex"),n=Buffer.from(e.authTag,"hex"),i=p.default.createDecipheriv("aes-256-gcm",r,s);i.setAuthTag(n);let f=i.update(e.ciphertext,"hex","utf8");return f+=i.final("utf8"),f}function oe(e,t){if(e&&e.trim())return e.trim();if(process.env.XTRA_VAULT_PASSPHRASE&&process.env.XTRA_VAULT_PASSPHRASE.trim())return process.env.XTRA_VAULT_PASSPHRASE.trim();if(process.env.XTRA_MASTER_SECRET&&process.env.XTRA_MASTER_SECRET.trim())return process.env.XTRA_MASTER_SECRET.trim();try{if(t){let s=R(`vault_${t}`);if(s)return s}let r=R("vault_passphrase");if(r)return r}catch{}try{let{getRcConfig:r}=(L(),b(ee)),s=r();if(s&&s.passphrase)return s.passphrase}catch{}throw new Error("Vault Passphrase or Master Secret is required for Zero-Knowledge E2EE encryption/decryption.")}function _e(e,t){t&&I(`vault_${t}`,e),I("vault_passphrase",e)}function Ce(e,t){let{publicKey:r,privateKey:s}=p.default.generateKeyPairSync("x25519"),n=r.export({type:"spki",format:"pem"}).toString(),i=p.default.createPublicKey(t),f=p.default.diffieHellman({privateKey:s,publicKey:i}),c=Buffer.from(p.default.hkdfSync("sha256",f,Buffer.alloc(0),Buffer.from("xtra-workload-envelope"),32)),u=p.default.randomBytes(12),y=p.default.createCipheriv("aes-256-gcm",c,u),h=y.update(e,"utf8","hex");h+=y.final("hex");let $=y.getAuthTag().toString("hex");return{targetPublicKey:t,ephemeralPublicKey:n,encryptedProjectKey:h,iv:u.toString("hex"),authTag:$}}function Be(e,t){let r=p.default.createPrivateKey(t),s=p.default.createPublicKey(e.ephemeralPublicKey),n=p.default.diffieHellman({privateKey:r,publicKey:s}),i=Buffer.from(p.default.hkdfSync("sha256",n,Buffer.alloc(0),Buffer.from("xtra-workload-envelope"),32)),f=Buffer.from(e.iv,"hex"),c=Buffer.from(e.authTag,"hex"),u=p.default.createDecipheriv("aes-256-gcm",i,f);u.setAuthTag(c);let y=u.update(e.encryptedProjectKey,"hex","utf8");return y+=u.final("utf8"),y}var p,w,te,re,_,se,U,O,D,V,Ke,I,R,E=B(()=>{p=v(require("crypto")),w=v(require("os")),te=v(require("conf")),re=require("node-machine-id"),_=require("child_process"),se="aes-256-gcm",U=new te.default({projectName:"xtra-cli-crypto"}),O=null;D=e=>{let t=p.default.randomBytes(12),r=ne(),s=p.default.createCipheriv(se,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")}},V=e=>{let t=ne(),r=Buffer.from(e.iv,"hex"),s=Buffer.from(e.tag,"hex"),n=p.default.createDecipheriv(se,t,r);n.setAuthTag(s);let i=n.update(e.content,"hex","utf8");return i+=n.final("utf8"),i},Ke=e=>p.default.createHash("sha256").update(e).digest("hex"),I=(e,t)=>{try{let s="XtraSecurityCLI",n=e;if(w.default.platform()==="darwin"){(0,_.execFileSync)("security",["add-generic-password","-s",s,"-a",n,"-w",t,"-U"],{stdio:"ignore"});return}else if(w.default.platform()!=="win32"){if(w.default.platform()==="linux")try{(0,_.execFileSync)("secret-tool",["store","--label",s,"service",s,"account",n],{input:t,stdio:["pipe","ignore","ignore"]});return}catch{}}}catch{}let r=D(t);U.set(`secure_${e}`,JSON.stringify(r))},R=e=>{try{let t="XtraSecurityCLI",r=e;if(w.default.platform()==="darwin")return(0,_.execFileSync)("security",["find-generic-password","-s",t,"-a",r,"-w"],{stdio:["ignore","pipe","ignore"]}).toString().trim();if(w.default.platform()!=="win32"){if(w.default.platform()==="linux")try{return(0,_.execFileSync)("secret-tool",["lookup","service",t,"account",r],{stdio:["ignore","pipe","ignore"]}).toString().trim()}catch{}}}catch{}try{let t=U.get(`secure_${e}`);if(!t)return null;let r=JSON.parse(t);return V(r)}catch{return null}}});var pe={};P(pe,{api:()=>H});var ie,ae,ce,Le,o,H,X=B(()=>{ie=v(require("axios"));L();ae=v(require("fs")),ce=v(require("path")),Le=JSON.parse(ae.readFileSync(ce.join(__dirname,"../../package.json"),"utf-8")),o=e=>{let{apiUrl:t}=j(),r=e||K();return ie.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":Le.version,...r?{Authorization:`Bearer ${r}`}:{}}})},H={login:async(e,t,r)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:r})).data,exchangeOidcToken:async(e,t)=>{let r=await o().post("/v2/auth/oidc/token",{provider:e,token:t});return{accessToken:r.data.access_token,envelope:r.data.envelope}},spawnAgentContext:async e=>(await o().post("/agents/ephemeral-context",e)).data,getSecrets:async(e,t,r="main",s,n,i)=>{let c=(await o(n).get(`/projects/${e}/envs/${t}/secrets?branch=${r}`)).data;if(c&&typeof c=="object"){let u=null,{deriveProjectKey:y,decryptSecretValue:h,resolveVaultPassphrase:$,decryptWorkloadKeyEnvelope:a}=(E(),b(q));for(let[g,m]of Object.entries(c))if(typeof m=="string"&&m.startsWith("{"))try{let S=JSON.parse(m);if(S.ciphertext&&S.iv){if(!u)if(i&&process.env.XTRA_WORKLOAD_PRIVATE_KEY)u=a(i,process.env.XTRA_WORKLOAD_PRIVATE_KEY);else{let T=$(s,e);u=y(e,T)}c[g]=h(S,u)}}catch(S){if(S.message&&S.message.includes("Zero-Knowledge"))throw S}}return c},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")=>{let{deriveProjectKey:i,encryptSecretValue:f,resolveVaultPassphrase:c}=(E(),b(q)),u=c(void 0,e),y=i(e,u),h={};for(let[a,g]of Object.entries(r))if(typeof g=="string"&&g.startsWith("{")&&g.includes("ciphertext"))h[a]=g;else{let m=f(g,y);h[a]=JSON.stringify(m)}return(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:h,expectedVersions:s,branch:n})).data},getSecretDetails:async(e,t,r,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${r}?branch=${s}`)).data,getSecretsV2:async(e,t)=>{let r=t?`&branchId=${t}`:"";return(await o().get(`/v2/secret?projectId=${e}${r}`)).data},createSecretV2:async e=>(await o().post("/v2/secret",e)).data,updateSecretV2:async e=>(await o().put(`/v2/secret?id=${e.id}`,e)).data,deleteSecretV2:async e=>(await o().delete(`/v2/secret?id=${e}`)).data,bulkImportV2:async e=>(await o().post("/v2/secret/bulk",e)).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}=j(),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}=j(),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}});var de={};P(de,{loadAuditLogs:()=>A,logAudit:()=>Ue,saveAuditLogs:()=>N,syncAuditLogs:()=>De});function Oe(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 ue(e){try{if(!j().token)return!1;let r={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:Oe(e.details),timestamp:e.timestamp,projectId:e.projectId};return await H.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 Ue(e,t,r,s){let n={id:(0,ge.randomUUID)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:r,details:s,synced:!1},i=A();i.push(n),N(i),ue(n).then(f=>{if(f){n.synced=!0;let c=A(),u=c.findIndex(y=>y.id===n.id);u!==-1&&(c[u].synced=!0,N(c))}}).catch(()=>{})}function A(){if(!k.default.existsSync(G))return[];try{let e=k.default.readFileSync(G,"utf-8"),t=JSON.parse(e),r=V(t);return JSON.parse(r)}catch{return[]}}function N(e){k.default.existsSync(W)||k.default.mkdirSync(W,{recursive:!0});let t=JSON.stringify(e),r=D(t);k.default.writeFileSync(G,JSON.stringify(r),"utf-8")}async function De(){let e=A(),t=e.filter(s=>!s.synced);if(t.length===0)return 0;let r=0;for(let s of t)await ue(s)&&(s.synced=!0,r++);return r>0&&N(e),r}var k,M,ge,W,G,z=B(()=>{k=v(require("fs")),M=v(require("path")),ge=require("crypto");E();L();X();W=M.default.join(process.cwd(),".xtra"),G=M.default.join(W,"audit.enc")});var Ne={};P(Ne,{logsCommand:()=>Ve});module.exports=b(Ne);var le=require("commander");z();var l=v(require("chalk")),fe=require("table"),Ve=new le.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 e=>{let{limit:t,sync:r,event:s,project:n,since:i,json:f}=e;try{let c=A();if(r){let a=c.filter(m=>!m.synced);if(a.length===0){console.log(l.default.green("All logs are already synced."));return}let g=require("ora")(`Syncing ${a.length} logs to cloud...`).start();try{let{api:m}=(X(),b(pe)),{saveAuditLogs:S}=(z(),b(de));await m.syncLogs(a),a.forEach(T=>T.synced=!0),S(c),g.succeed(`Successfully synced ${a.length} logs.`)}catch(m){g.fail("Sync failed."),console.error(l.default.red(m.message))}return}if(c.length===0){console.log(l.default.yellow("No local audit logs found."));return}if(s){let a=s.toUpperCase();c=c.filter(g=>g.action?.toUpperCase().includes(a))}if(n&&(c=c.filter(a=>a.projectId===n)),i){let a=i.match(/^(\d+)(h|d|m)$/i);a||(console.error(l.default.red(`Invalid --since format: '${i}'. Use e.g. 1h, 24h, 7d, 30d`)),process.exit(1));let g=parseInt(a[1]),m=a[2].toLowerCase(),S={h:36e5,d:864e5,m:6e4},T=new Date(Date.now()-g*S[m]);c=c.filter(ye=>new Date(ye.timestamp)>=T)}c.sort((a,g)=>new Date(g.timestamp).getTime()-new Date(a.timestamp).getTime());let u=c.slice(0,parseInt(t));if(u.length===0){console.log(l.default.yellow("No logs matched your filters."));return}if(f){process.stdout.write(JSON.stringify(u,null,2)+`
|
|
2
|
+
`);return}let y=[[l.default.bold("Timestamp"),l.default.bold("Action"),l.default.bold("Project"),l.default.bold("Sync"),l.default.bold("Details")]];u.forEach(a=>{let g="";a.details&&(a.details.keys?g=`Keys: ${a.details.keys.join(", ")}`:a.details.key?g=`Key: ${a.details.key}`:g=JSON.stringify(a.details));let m=a.projectId?a.projectId.substring(0,8)+"...":"-";y.push([new Date(a.timestamp).toLocaleString(),a.action,m,a.synced?l.default.green("\u2714"):l.default.yellow("\u2716"),g.substring(0,50)+(g.length>50?"...":"")])});let h=[];s&&h.push(`event: ${s.toUpperCase()}`),n&&h.push(`project: ${n}`),i&&h.push(`since: ${i}`);let $=h.length>0?l.default.gray(` [${h.join(" | ")}]`):"";console.log(l.default.bold(`
|
|
3
|
+
Local Audit Logs${$}`)),console.log((0,fe.table)(y)),console.log(l.default.gray(` Showing ${u.length} of ${c.length} total logs.`))}catch(c){console.error(l.default.red("Failed to load logs: "+c?.response?.data?.error||"An unexpected error occurred"))}});0&&(module.exports={logsCommand});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
var Y=Object.create;var x=Object.defineProperty;var z=Object.getOwnPropertyDescriptor;var Q=Object.getOwnPropertyNames;var ee=Object.getPrototypeOf,te=Object.prototype.hasOwnProperty;var j=(e,t)=>()=>(e&&(t=e(e=0)),t);var R=(e,t)=>{for(var r in t)x(e,r,{get:t[r],enumerable:!0})},B=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Q(t))!te.call(e,n)&&n!==r&&x(e,n,{get:()=>t[n],enumerable:!(o=z(t,n))||o.enumerable});return e};var l=(e,t,r)=>(r=e!=null?Y(ee(e)):{},B(t||!e||!e.__esModule?x(r,"default",{value:e,enumerable:!0}):r,e)),I=e=>B(x({},"__esModule",{value:!0}),e);function X(){if(S)return S;let e=k.get("masterKey");e||(e=i.default.randomBytes(32).toString("hex"),k.set("masterKey",e));let t="";try{t=(0,D.machineIdSync)()||""}catch{t=i.default.createHash("sha256").update(a.default.hostname()+(a.default.userInfo?.()?.username||"root")).digest("hex")}let r=a.default.platform(),o=a.default.userInfo?.()?.username||"default_user",n=`${r}:${o}:${t}:${e}`;return S=i.default.createHash("sha256").update(n).digest(),S}function W(e,t){t||(t=b(void 0,e));let r=Buffer.from(`project_salt_${e}`),o=Buffer.from("xtra-e2ee-project-key-v2"),n=i.default.hkdfSync("sha256",Buffer.from(t),r,o,32);return Buffer.from(n).toString("hex")}function b(e,t){if(e&&e.trim())return e.trim();if(process.env.XTRA_VAULT_PASSPHRASE&&process.env.XTRA_VAULT_PASSPHRASE.trim())return process.env.XTRA_VAULT_PASSPHRASE.trim();if(process.env.XTRA_MASTER_SECRET&&process.env.XTRA_MASTER_SECRET.trim())return process.env.XTRA_MASTER_SECRET.trim();try{if(t){let o=P(`vault_${t}`);if(o)return o}let r=P("vault_passphrase");if(r)return r}catch{}try{let{getRcConfig:r}=(w(),I($)),o=r();if(o&&o.passphrase)return o.passphrase}catch{}throw new Error("Vault Passphrase or Master Secret is required for Zero-Knowledge E2EE encryption/decryption.")}function H(e,t){let{publicKey:r,privateKey:o}=i.default.generateKeyPairSync("x25519"),n=r.export({type:"spki",format:"pem"}).toString(),c=i.default.createPublicKey(t),u=i.default.diffieHellman({privateKey:o,publicKey:c}),g=Buffer.from(i.default.hkdfSync("sha256",u,Buffer.alloc(0),Buffer.from("xtra-workload-envelope"),32)),m=i.default.randomBytes(12),d=i.default.createCipheriv("aes-256-gcm",g,m),v=d.update(e,"utf8","hex");v+=d.final("hex");let T=d.getAuthTag().toString("hex");return{targetPublicKey:t,ephemeralPublicKey:n,encryptedProjectKey:v,iv:m.toString("hex"),authTag:T}}var i,a,U,D,h,O,k,S,re,oe,V,P,E=j(()=>{i=l(require("crypto")),a=l(require("os")),U=l(require("conf")),D=require("node-machine-id"),h=require("child_process"),O="aes-256-gcm",k=new U.default({projectName:"xtra-cli-crypto"}),S=null;re=e=>{let t=i.default.randomBytes(12),r=X(),o=i.default.createCipheriv(O,r,t),n=o.update(e,"utf8","hex");n+=o.final("hex");let c=o.getAuthTag();return{iv:t.toString("hex"),content:n,tag:c.toString("hex")}},oe=e=>{let t=X(),r=Buffer.from(e.iv,"hex"),o=Buffer.from(e.tag,"hex"),n=i.default.createDecipheriv(O,t,r);n.setAuthTag(o);let c=n.update(e.content,"hex","utf8");return c+=n.final("utf8"),c},V=(e,t)=>{try{let o="XtraSecurityCLI",n=e;if(a.default.platform()==="darwin"){(0,h.execFileSync)("security",["add-generic-password","-s",o,"-a",n,"-w",t,"-U"],{stdio:"ignore"});return}else if(a.default.platform()!=="win32"){if(a.default.platform()==="linux")try{(0,h.execFileSync)("secret-tool",["store","--label",o,"service",o,"account",n],{input:t,stdio:["pipe","ignore","ignore"]});return}catch{}}}catch{}let r=re(t);k.set(`secure_${e}`,JSON.stringify(r))},P=e=>{try{let t="XtraSecurityCLI",r=e;if(a.default.platform()==="darwin")return(0,h.execFileSync)("security",["find-generic-password","-s",t,"-a",r,"-w"],{stdio:["ignore","pipe","ignore"]}).toString().trim();if(a.default.platform()!=="win32"){if(a.default.platform()==="linux")try{return(0,h.execFileSync)("secret-tool",["lookup","service",t,"account",r],{stdio:["ignore","pipe","ignore"]}).toString().trim()}catch{}}}catch{}try{let t=k.get(`secure_${e}`);if(!t)return null;let r=JSON.parse(t);return oe(r)}catch{return null}}});var $={};R($,{clearConfig:()=>ie,deleteConfig:()=>ce,getAuthToken:()=>y,getBreakGlassSession:()=>ae,getConfig:()=>K,getConfigValue:()=>ne,getProjectConfig:()=>le,getRcConfig:()=>ue,setBreakGlassSession:()=>pe,setConfig:()=>se});var N,f,C,_,s,L,K,ne,se,ie,ce,y,ae,pe,le,ue,w=j(()=>{N=l(require("conf")),f=l(require("fs")),C=l(require("path"));E();_="https://www.xtrasecurity.in/api",s=new N.default({projectName:"xtra-cli",defaults:{apiUrl:_}}),L=s.get("apiUrl");L&&!process.env.XTRA_API_URL&&L.includes("xtra-security.vercel.app")&&s.set("apiUrl",_);K=()=>({...s.store,token:y(),apiUrl:process.env.XTRA_API_URL||s.get("apiUrl")||_}),ne=e=>e==="token"?y():s.get(e),se=(e,t)=>{if(e==="token"&&t&&V("token",t),s.set(e,t),e==="token"&&process.platform!=="win32"&&f.default.existsSync(s.path))try{f.default.chmodSync(s.path,384)}catch{}},ie=()=>s.clear(),ce=e=>s.delete(e),y=()=>P("token")||s.get("token"),ae=()=>s.get("breakGlassSessionId"),pe=e=>{e?s.set("breakGlassSessionId",e):s.delete("breakGlassSessionId")},le=async()=>{try{let e=C.default.join(process.cwd(),"xtra.json");if(f.default.existsSync(e)){let t=f.default.readFileSync(e,"utf-8");return JSON.parse(t)}return null}catch{return null}},ue=()=>{let e={};try{let t=C.default.join(process.cwd(),".xtrarc");f.default.existsSync(t)&&(e=JSON.parse(f.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||s.get("project")||"",env:e.env||s.get("env")||"development",branch:e.branch||s.get("branch")||"main"}}});var ge={};R(ge,{oidcLinkCommand:()=>fe});module.exports=I(ge);var G=require("commander");w();var p=l(require("chalk")),F=l(require("ora"));E();var M=l(require("crypto")),q=l(require("axios")),fe=new G.Command("oidc-link").description("Link a CI/CD workload via OIDC and generate a Workload Key Envelope (Phase 3 E2EE)").option("-p, --project <projectId>","Project ID").option("--provider <provider>","OIDC Provider (e.g., github)","github").option("--subject <subject>","Workload subject (e.g., XtraFusion/MyFrontendApp)").option("--env <environment>","Environment to grant access to","production").option("--passphrase <passphrase>","Vault passphrase for Level 3 Zero-Knowledge encryption").action(async e=>{let{project:t,provider:r,subject:o,env:n}=e;t||(t=K().project),t||(console.error(p.default.red("Error: Project ID is required.")),process.exit(1)),o||(console.error(p.default.red("Error: Workload subject is required (e.g. --subject XtraFusion/MyFrontendApp).")),process.exit(1));let c=y();c||(console.error(p.default.red("Error: You must be logged in to configure OIDC links.")),process.exit(1));let u=(0,F.default)("Configuring Zero-Knowledge Workload Identity...").start();try{u.text="Generating Workload X25519 Keypair...";let{publicKey:g,privateKey:m}=M.generateKeyPairSync("x25519"),d=g.export({type:"spki",format:"pem"}).toString(),v=m.export({type:"pkcs8",format:"pem"}).toString();u.text="Deriving local Project AES Key...";let T=b(e.passphrase,t),J=W(t,T);u.text="Creating Workload Key Envelope...";let A=H(J,d);u.text="Registering Trust Policy & Envelope with server...";let{apiUrl:Z}=K();await q.default.post(`${Z}/projects/${t}/oidc`,{provider:r,subject:o,environmentType:n,branchName:"main",workloadPublicKey:d,encryptedProjectKey:A.encryptedProjectKey,envelopeIv:A.iv,envelopeAuthTag:A.authTag},{headers:{"Content-Type":"application/json",Authorization:`Bearer ${c}`}}),u.succeed(p.default.green("OIDC Workload Trust Policy created successfully.")),console.log(p.default.bold.blue(`
|
|
2
|
+
================ IMPORTANT: SAVE THIS KEY ================`)),console.log("To maintain Zero-Knowledge E2EE, you MUST provide the following Private Key"),console.log("to your CI/CD pipeline. XtraSecurity does NOT have a copy of this key."),console.log(p.default.yellow(`
|
|
3
|
+
Add this to your GitHub Repository Secrets:
|
|
4
|
+
`)),console.log(p.default.cyan("Secret Name: XTRA_WORKLOAD_PRIVATE_KEY")),console.log(p.default.cyan(`Secret Value:
|
|
5
|
+
${v}`)),console.log(p.default.bold.blue(`==========================================================
|
|
6
|
+
`))}catch(g){u.fail("Failed to configure OIDC link"),console.error(p.default.red(g.response?.data?.error||g.message)),process.exit(1)}});0&&(module.exports={oidcLinkCommand});
|
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})},$=(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)):{},$(t||!e||!e.__esModule?u(s,"default",{value:e,enumerable:!0}):s,e)),T=e=>$(u({},"__esModule",{value:!0}),e);var D={};O(D,{projectCommand:()=>h});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")),m=p(require("fs"));var f="https://www.xtrasecurity.in/api",g=new S.default({projectName:"xtra-cli",defaults:{apiUrl:f}}),v=g.get("apiUrl");v&&!process.env.XTRA_API_URL&&v.includes("xtra-security.vercel.app")&&g.set("apiUrl",f);var y=()=>({...g.store,apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||f}),l=e=>g.get(e),w=(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{}};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}`}:{}}})},j={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")),h=new C.Command("project").alias("projects").description("Manage project context"),U=(e,t)=>{let s=l("project");w("project",e),s!==e&&w("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}`))};h.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 j.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"))}});h.command("current").description("Show the current default project").action(async()=>{let e=l("project"),t=l("branch");if(e)try{let r=(await j.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
|
+
var ge=Object.create;var C=Object.defineProperty;var ue=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var de=Object.getPrototypeOf,fe=Object.prototype.hasOwnProperty;var H=(e,t)=>()=>(e&&(t=e(e=0)),t);var L=(e,t)=>{for(var r in t)C(e,r,{get:t[r],enumerable:!0})},J=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of le(t))!fe.call(e,n)&&n!==r&&C(e,n,{get:()=>t[n],enumerable:!(s=ue(t,n))||s.enumerable});return e};var d=(e,t,r)=>(r=e!=null?ge(de(e)):{},J(t||!e||!e.__esModule?C(r,"default",{value:e,enumerable:!0}):r,e)),x=e=>J(C({},"__esModule",{value:!0}),e);var T={};L(T,{createWorkloadKeyEnvelope:()=>Se,decrypt:()=>Z,decryptSecretValue:()=>ve,decryptWorkloadKeyEnvelope:()=>xe,deriveProjectKey:()=>he,encrypt:()=>Y,encryptSecretValue:()=>me,hash:()=>ye,resolveVaultPassphrase:()=>z,saveVaultPassphrase:()=>we,secureRead:()=>A,secureSave:()=>b});function M(){if(E)return E;let e=U.get("masterKey");e||(e=i.default.randomBytes(32).toString("hex"),U.set("masterKey",e));let t="";try{t=(0,F.machineIdSync)()||""}catch{t=i.default.createHash("sha256").update(f.default.hostname()+(f.default.userInfo?.()?.username||"root")).digest("hex")}let r=f.default.platform(),s=f.default.userInfo?.()?.username||"default_user",n=`${r}:${s}:${t}:${e}`;return E=i.default.createHash("sha256").update(n).digest(),E}function he(e,t){t||(t=z(void 0,e));let r=Buffer.from(`project_salt_${e}`),s=Buffer.from("xtra-e2ee-project-key-v2"),n=i.default.hkdfSync("sha256",Buffer.from(t),r,s,32);return Buffer.from(n).toString("hex")}function me(e,t){let r=i.default.randomBytes(12),s=Buffer.from(t.slice(0,64).padEnd(64,"0"),"hex"),n=i.default.createCipheriv("aes-256-gcm",s,r),a=n.update(e,"utf8","hex");a+=n.final("hex");let p=n.getAuthTag().toString("hex");return{ciphertext:a,iv:r.toString("hex"),authTag:p}}function ve(e,t){let r=Buffer.from(t.slice(0,64).padEnd(64,"0"),"hex"),s=Buffer.from(e.iv,"hex"),n=Buffer.from(e.authTag,"hex"),a=i.default.createDecipheriv("aes-256-gcm",r,s);a.setAuthTag(n);let p=a.update(e.ciphertext,"hex","utf8");return p+=a.final("utf8"),p}function z(e,t){if(e&&e.trim())return e.trim();if(process.env.XTRA_VAULT_PASSPHRASE&&process.env.XTRA_VAULT_PASSPHRASE.trim())return process.env.XTRA_VAULT_PASSPHRASE.trim();if(process.env.XTRA_MASTER_SECRET&&process.env.XTRA_MASTER_SECRET.trim())return process.env.XTRA_MASTER_SECRET.trim();try{if(t){let s=A(`vault_${t}`);if(s)return s}let r=A("vault_passphrase");if(r)return r}catch{}try{let{getRcConfig:r}=(V(),x(Q)),s=r();if(s&&s.passphrase)return s.passphrase}catch{}throw new Error("Vault Passphrase or Master Secret is required for Zero-Knowledge E2EE encryption/decryption.")}function we(e,t){t&&b(`vault_${t}`,e),b("vault_passphrase",e)}function Se(e,t){let{publicKey:r,privateKey:s}=i.default.generateKeyPairSync("x25519"),n=r.export({type:"spki",format:"pem"}).toString(),a=i.default.createPublicKey(t),p=i.default.diffieHellman({privateKey:s,publicKey:a}),u=Buffer.from(i.default.hkdfSync("sha256",p,Buffer.alloc(0),Buffer.from("xtra-workload-envelope"),32)),c=i.default.randomBytes(12),y=i.default.createCipheriv("aes-256-gcm",u,c),h=y.update(e,"utf8","hex");h+=y.final("hex");let _=y.getAuthTag().toString("hex");return{targetPublicKey:t,ephemeralPublicKey:n,encryptedProjectKey:h,iv:c.toString("hex"),authTag:_}}function xe(e,t){let r=i.default.createPrivateKey(t),s=i.default.createPublicKey(e.ephemeralPublicKey),n=i.default.diffieHellman({privateKey:r,publicKey:s}),a=Buffer.from(i.default.hkdfSync("sha256",n,Buffer.alloc(0),Buffer.from("xtra-workload-envelope"),32)),p=Buffer.from(e.iv,"hex"),u=Buffer.from(e.authTag,"hex"),c=i.default.createDecipheriv("aes-256-gcm",a,p);c.setAuthTag(u);let y=c.update(e.encryptedProjectKey,"hex","utf8");return y+=c.final("utf8"),y}var i,f,W,F,P,G,U,E,Y,Z,ye,b,A,j=H(()=>{i=d(require("crypto")),f=d(require("os")),W=d(require("conf")),F=require("node-machine-id"),P=require("child_process"),G="aes-256-gcm",U=new W.default({projectName:"xtra-cli-crypto"}),E=null;Y=e=>{let t=i.default.randomBytes(12),r=M(),s=i.default.createCipheriv(G,r,t),n=s.update(e,"utf8","hex");n+=s.final("hex");let a=s.getAuthTag();return{iv:t.toString("hex"),content:n,tag:a.toString("hex")}},Z=e=>{let t=M(),r=Buffer.from(e.iv,"hex"),s=Buffer.from(e.tag,"hex"),n=i.default.createDecipheriv(G,t,r);n.setAuthTag(s);let a=n.update(e.content,"hex","utf8");return a+=n.final("utf8"),a},ye=e=>i.default.createHash("sha256").update(e).digest("hex"),b=(e,t)=>{try{let s="XtraSecurityCLI",n=e;if(f.default.platform()==="darwin"){(0,P.execFileSync)("security",["add-generic-password","-s",s,"-a",n,"-w",t,"-U"],{stdio:"ignore"});return}else if(f.default.platform()!=="win32"){if(f.default.platform()==="linux")try{(0,P.execFileSync)("secret-tool",["store","--label",s,"service",s,"account",n],{input:t,stdio:["pipe","ignore","ignore"]});return}catch{}}}catch{}let r=Y(t);U.set(`secure_${e}`,JSON.stringify(r))},A=e=>{try{let t="XtraSecurityCLI",r=e;if(f.default.platform()==="darwin")return(0,P.execFileSync)("security",["find-generic-password","-s",t,"-a",r,"-w"],{stdio:["ignore","pipe","ignore"]}).toString().trim();if(f.default.platform()!=="win32"){if(f.default.platform()==="linux")try{return(0,P.execFileSync)("secret-tool",["lookup","service",t,"account",r],{stdio:["ignore","pipe","ignore"]}).toString().trim()}catch{}}}catch{}try{let t=U.get(`secure_${e}`);if(!t)return null;let r=JSON.parse(t);return Z(r)}catch{return null}}});var Q={};L(Q,{clearConfig:()=>je,deleteConfig:()=>$e,getAuthToken:()=>R,getBreakGlassSession:()=>ke,getConfig:()=>K,getConfigValue:()=>S,getProjectConfig:()=>be,getRcConfig:()=>Ae,setBreakGlassSession:()=>Pe,setConfig:()=>I});var te,w,N,D,g,ee,K,S,I,je,$e,R,ke,Pe,be,Ae,V=H(()=>{te=d(require("conf")),w=d(require("fs")),N=d(require("path"));j();D="https://www.xtrasecurity.in/api",g=new te.default({projectName:"xtra-cli",defaults:{apiUrl:D}}),ee=g.get("apiUrl");ee&&!process.env.XTRA_API_URL&&ee.includes("xtra-security.vercel.app")&&g.set("apiUrl",D);K=()=>({...g.store,token:R(),apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||D}),S=e=>e==="token"?R():g.get(e),I=(e,t)=>{if(e==="token"&&t&&b("token",t),g.set(e,t),e==="token"&&process.platform!=="win32"&&w.default.existsSync(g.path))try{w.default.chmodSync(g.path,384)}catch{}},je=()=>g.clear(),$e=e=>g.delete(e),R=()=>A("token")||g.get("token"),ke=()=>g.get("breakGlassSessionId"),Pe=e=>{e?g.set("breakGlassSessionId",e):g.delete("breakGlassSessionId")},be=async()=>{try{let e=N.default.join(process.cwd(),"xtra.json");if(w.default.existsSync(e)){let t=w.default.readFileSync(e,"utf-8");return JSON.parse(t)}return null}catch{return null}},Ae=()=>{let e={};try{let t=N.default.join(process.cwd(),".xtrarc");w.default.existsSync(t)&&(e=JSON.parse(w.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 Ke={};L(Ke,{projectCommand:()=>X});module.exports=x(Ke);var ae=require("commander"),l=d(require("chalk")),ce=d(require("ora")),O=d(require("inquirer"));V();var re=d(require("axios"));V();var se=d(require("fs")),ne=d(require("path")),Te=JSON.parse(se.readFileSync(ne.join(__dirname,"../../package.json"),"utf-8")),o=e=>{let{apiUrl:t}=K(),r=e||R();return re.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":Te.version,...r?{Authorization:`Bearer ${r}`}:{}}})},q={login:async(e,t,r)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:r})).data,exchangeOidcToken:async(e,t)=>{let r=await o().post("/v2/auth/oidc/token",{provider:e,token:t});return{accessToken:r.data.access_token,envelope:r.data.envelope}},spawnAgentContext:async e=>(await o().post("/agents/ephemeral-context",e)).data,getSecrets:async(e,t,r="main",s,n,a)=>{let u=(await o(n).get(`/projects/${e}/envs/${t}/secrets?branch=${r}`)).data;if(u&&typeof u=="object"){let c=null,{deriveProjectKey:y,decryptSecretValue:h,resolveVaultPassphrase:_,decryptWorkloadKeyEnvelope:B}=(j(),x(T));for(let[m,k]of Object.entries(u))if(typeof k=="string"&&k.startsWith("{"))try{let v=JSON.parse(k);if(v.ciphertext&&v.iv){if(!c)if(a&&process.env.XTRA_WORKLOAD_PRIVATE_KEY)c=B(a,process.env.XTRA_WORKLOAD_PRIVATE_KEY);else{let pe=_(s,e);c=y(e,pe)}u[m]=h(v,c)}}catch(v){if(v.message&&v.message.includes("Zero-Knowledge"))throw v}}return u},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")=>{let{deriveProjectKey:a,encryptSecretValue:p,resolveVaultPassphrase:u}=(j(),x(T)),c=u(void 0,e),y=a(e,c),h={};for(let[B,m]of Object.entries(r))if(typeof m=="string"&&m.startsWith("{")&&m.includes("ciphertext"))h[B]=m;else{let k=p(m,y);h[B]=JSON.stringify(k)}return(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:h,expectedVersions:s,branch:n})).data},getSecretDetails:async(e,t,r,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${r}?branch=${s}`)).data,getSecretsV2:async(e,t)=>{let r=t?`&branchId=${t}`:"";return(await o().get(`/v2/secret?projectId=${e}${r}`)).data},createSecretV2:async e=>(await o().post("/v2/secret",e)).data,updateSecretV2:async e=>(await o().put(`/v2/secret?id=${e.id}`,e)).data,deleteSecretV2:async e=>(await o().delete(`/v2/secret?id=${e}`)).data,bulkImportV2:async e=>(await o().post("/v2/secret/bulk",e)).data,syncLogs:async e=>(await o().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,r,s,n,a)=>(await o().post(`/projects/${e}/envs/${t}/secrets/link`,{key:r,sourceProjectId:s,sourceEnv:n,sourceKey:a})).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}=K(),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}=K(),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};var $=d(require("fs")),ie=d(require("path")),X=new ae.Command("project").alias("projects").description("Manage project context"),oe=(e,t)=>{let r=S("project");I("project",e),r!==e&&I("branch","main");let s=ie.join(process.cwd(),".xtrarc"),n={};if($.existsSync(s))try{n=JSON.parse($.readFileSync(s,"utf-8"))}catch(p){console.error(l.default.yellow(` \u26A0 Could not parse existing local .xtrarc: ${p?.response?.data?.error||p?.message||"Unknown error"}`))}n.project=e,r!==e&&(n.branch="main"),n.env||(n.env="development"),n.apiUrl||(n.apiUrl=S("apiUrl")||"https://www.xtrasecurity.in/api");try{$.writeFileSync(s,JSON.stringify(n,null,2),"utf8"),console.log(l.default.gray(" \u2714 Updated local .xtrarc (Project context locked to this folder)"))}catch(p){console.error(l.default.yellow(` \u26A0 Could not write local .xtrarc: ${p?.response?.data?.error||p?.message||"Unknown error"}`))}console.log(l.default.green(`\u2714 Default project set to '${t}'`));let a=S("branch");a&&console.log(l.default.gray(` Active branch: ${a}`))};X.command("set").description("Set the default project ID").argument("[projectId]","Project ID to set as default (optional - will show list if not provided)").option("--passphrase <passphrase>","Save vault passphrase to hardware keyring for this project").action(async(e,t)=>{if(e){oe(e,e);let s=t.passphrase;if(!s&&process.stdout.isTTY&&(s=(await O.default.prompt([{type:"password",name:"passphrase",message:`Enter the Master Passphrase for project '${e}' to enable Zero-Knowledge Decryption:`}])).passphrase),s){let{saveVaultPassphrase:n}=(j(),x(T));n(s,e),console.log(l.default.green("\u2714 Vault passphrase saved securely to local hardware keyring."))}return}let r=(0,ce.default)("Fetching your projects...").start();try{let s=await q.getProjects();if(r.stop(),!Array.isArray(s)||s.length===0){console.log(l.default.yellow("No projects found."));return}let n=s.map(c=>({name:`${c.name} (${c.id})`,value:c.id,short:c.name})),{selectedProject:a}=await O.default.prompt([{type:"list",name:"selectedProject",message:"Select a project:",choices:n}]),p=s.find(c=>c.id===a)?.name||a;oe(a,p);let u=t.passphrase;if(!u&&process.stdout.isTTY&&(u=(await O.default.prompt([{type:"password",name:"passphrase",message:`Enter the Master Passphrase for '${p}' to enable Zero-Knowledge Decryption:`}])).passphrase),u){let{saveVaultPassphrase:c}=(j(),x(T));c(u,a),console.log(l.default.green("\u2714 Vault passphrase saved securely to local hardware keyring."))}}catch(s){r.fail("Failed to fetch projects"),s.response?.data?.error?console.error(l.default.red(`Error: ${s.response.data.error}`)):console.error(l.default.red(s?.response?.data?.error||"An unexpected error occurred"))}});X.command("current").description("Show the current default project").action(async()=>{let e=S("project"),t=S("branch");if(e)try{let s=(await q.getProjects()).find(n=>n.id===e);console.log(s?l.default.cyan(`Project: ${s.name} (${e})`):l.default.cyan(`Project: ${e}`))}catch{console.log(l.default.cyan(`Project: ${e}`))}else console.log(l.default.yellow("No default project set. Use 'xtra project set' to set one."));t&&console.log(l.default.cyan(`Branch: ${t}`))});0&&(module.exports={projectCommand});
|
|
@@ -1 +1 @@
|
|
|
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 N=(e,t)=>{for(var s in t)w(e,s,{get:t[s],enumerable:!0})},P=(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)):{},P(t||!e||!e.__esModule?w(s,"default",{value:e,enumerable:!0}):s,e)),T=e=>P(w({},"__esModule",{value:!0}),e);var J,I,V,C,g,_,l,K,F,j=S(()=>{J=i(require("conf")),I=i(require("fs")),V=i(require("path")),C="https://www.xtrasecurity.in/api",g=new J.default({projectName:"xtra-cli",defaults:{apiUrl:C}}),_=g.get("apiUrl");_&&!process.env.XTRA_API_URL&&_.includes("xtra-security.vercel.app")&&g.set("apiUrl",C);l=()=>({...g.store,apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||C}),K=()=>g.get("token"),F=()=>{let e={};try{let t=V.default.join(process.cwd(),".xtrarc");I.default.existsSync(t)&&(e=JSON.parse(I.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,R=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,v,L=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")}},v=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={};N(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(O))return[];try{let e=f.default.readFileSync(O,"utf-8"),t=JSON.parse(e),s=v(t);return JSON.parse(s)}catch{return[]}}function x(e){f.default.existsSync(U)||f.default.mkdirSync(U,{recursive:!0});let t=JSON.stringify(e),s=Y(t);f.default.writeFileSync(O,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,B,Z,U,O,se=S(()=>{f=i(require("fs")),B=i(require("path")),Z=require("uuid");L();j();R();U=B.default.join(process.cwd(),".xtra"),O=B.default.join(U,"audit.enc")});var ve={};N(ve,{rollbackCommand:()=>me});module.exports=T(ve);var re=require("commander");R();var h=i(require("chalk")),D=i(require("ora")),ne=i(require("inquirer"));L();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(h.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,D.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(h.default.yellow(`No history found for ${e}. Cannot rollback.`));return}let d=[];[...c.history].reverse().forEach(p=>{let A="********";try{let E=JSON.parse(p.value[0]);A=v(E)}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,D.default)(`Restoring version v${u.version}...`).start(),k=u.value[0];try{let p=JSON.parse(k);k=v(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(),T(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(h.default.red("Secret not found.")):console.error(h.default.red(c?.response?.data?.error||"An unexpected error occurred"))}});0&&(module.exports={rollbackCommand});
|
|
1
|
+
var Se=Object.create;var C=Object.defineProperty;var xe=Object.getOwnPropertyDescriptor;var we=Object.getOwnPropertyNames;var je=Object.getPrototypeOf,$e=Object.prototype.hasOwnProperty;var B=(e,t)=>()=>(e&&(t=e(e=0)),t);var V=(e,t)=>{for(var r in t)C(e,r,{get:t[r],enumerable:!0})},te=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of we(t))!$e.call(e,n)&&n!==r&&C(e,n,{get:()=>t[n],enumerable:!(s=xe(t,n))||s.enumerable});return e};var l=(e,t,r)=>(r=e!=null?Se(je(e)):{},te(t||!e||!e.__esModule?C(r,"default",{value:e,enumerable:!0}):r,e)),k=e=>te(C({},"__esModule",{value:!0}),e);var N={};V(N,{createWorkloadKeyEnvelope:()=>Ke,decrypt:()=>D,decryptSecretValue:()=>Pe,decryptWorkloadKeyEnvelope:()=>Re,deriveProjectKey:()=>be,encrypt:()=>U,encryptSecretValue:()=>Ae,hash:()=>ke,resolveVaultPassphrase:()=>ie,saveVaultPassphrase:()=>Te,secureRead:()=>K,secureSave:()=>T});function oe(){if(O)return O;let e=L.get("masterKey");e||(e=c.default.randomBytes(32).toString("hex"),L.set("masterKey",e));let t="";try{t=(0,se.machineIdSync)()||""}catch{t=c.default.createHash("sha256").update(h.default.hostname()+(h.default.userInfo?.()?.username||"root")).digest("hex")}let r=h.default.platform(),s=h.default.userInfo?.()?.username||"default_user",n=`${r}:${s}:${t}:${e}`;return O=c.default.createHash("sha256").update(n).digest(),O}function be(e,t){t||(t=ie(void 0,e));let r=Buffer.from(`project_salt_${e}`),s=Buffer.from("xtra-e2ee-project-key-v2"),n=c.default.hkdfSync("sha256",Buffer.from(t),r,s,32);return Buffer.from(n).toString("hex")}function Ae(e,t){let r=c.default.randomBytes(12),s=Buffer.from(t.slice(0,64).padEnd(64,"0"),"hex"),n=c.default.createCipheriv("aes-256-gcm",s,r),i=n.update(e,"utf8","hex");i+=n.final("hex");let a=n.getAuthTag().toString("hex");return{ciphertext:i,iv:r.toString("hex"),authTag:a}}function Pe(e,t){let r=Buffer.from(t.slice(0,64).padEnd(64,"0"),"hex"),s=Buffer.from(e.iv,"hex"),n=Buffer.from(e.authTag,"hex"),i=c.default.createDecipheriv("aes-256-gcm",r,s);i.setAuthTag(n);let a=i.update(e.ciphertext,"hex","utf8");return a+=i.final("utf8"),a}function ie(e,t){if(e&&e.trim())return e.trim();if(process.env.XTRA_VAULT_PASSPHRASE&&process.env.XTRA_VAULT_PASSPHRASE.trim())return process.env.XTRA_VAULT_PASSPHRASE.trim();if(process.env.XTRA_MASTER_SECRET&&process.env.XTRA_MASTER_SECRET.trim())return process.env.XTRA_MASTER_SECRET.trim();try{if(t){let s=K(`vault_${t}`);if(s)return s}let r=K("vault_passphrase");if(r)return r}catch{}try{let{getRcConfig:r}=(R(),k(ae)),s=r();if(s&&s.passphrase)return s.passphrase}catch{}throw new Error("Vault Passphrase or Master Secret is required for Zero-Knowledge E2EE encryption/decryption.")}function Te(e,t){t&&T(`vault_${t}`,e),T("vault_passphrase",e)}function Ke(e,t){let{publicKey:r,privateKey:s}=c.default.generateKeyPairSync("x25519"),n=r.export({type:"spki",format:"pem"}).toString(),i=c.default.createPublicKey(t),a=c.default.diffieHellman({privateKey:s,publicKey:i}),p=Buffer.from(c.default.hkdfSync("sha256",a,Buffer.alloc(0),Buffer.from("xtra-workload-envelope"),32)),g=c.default.randomBytes(12),d=c.default.createCipheriv("aes-256-gcm",p,g),v=d.update(e,"utf8","hex");v+=d.final("hex");let $=d.getAuthTag().toString("hex");return{targetPublicKey:t,ephemeralPublicKey:n,encryptedProjectKey:v,iv:g.toString("hex"),authTag:$}}function Re(e,t){let r=c.default.createPrivateKey(t),s=c.default.createPublicKey(e.ephemeralPublicKey),n=c.default.diffieHellman({privateKey:r,publicKey:s}),i=Buffer.from(c.default.hkdfSync("sha256",n,Buffer.alloc(0),Buffer.from("xtra-workload-envelope"),32)),a=Buffer.from(e.iv,"hex"),p=Buffer.from(e.authTag,"hex"),g=c.default.createDecipheriv("aes-256-gcm",i,a);g.setAuthTag(p);let d=g.update(e.encryptedProjectKey,"hex","utf8");return d+=g.final("utf8"),d}var c,h,re,se,P,ne,L,O,U,D,ke,T,K,b=B(()=>{c=l(require("crypto")),h=l(require("os")),re=l(require("conf")),se=require("node-machine-id"),P=require("child_process"),ne="aes-256-gcm",L=new re.default({projectName:"xtra-cli-crypto"}),O=null;U=e=>{let t=c.default.randomBytes(12),r=oe(),s=c.default.createCipheriv(ne,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")}},D=e=>{let t=oe(),r=Buffer.from(e.iv,"hex"),s=Buffer.from(e.tag,"hex"),n=c.default.createDecipheriv(ne,t,r);n.setAuthTag(s);let i=n.update(e.content,"hex","utf8");return i+=n.final("utf8"),i},ke=e=>c.default.createHash("sha256").update(e).digest("hex"),T=(e,t)=>{try{let s="XtraSecurityCLI",n=e;if(h.default.platform()==="darwin"){(0,P.execFileSync)("security",["add-generic-password","-s",s,"-a",n,"-w",t,"-U"],{stdio:"ignore"});return}else if(h.default.platform()!=="win32"){if(h.default.platform()==="linux")try{(0,P.execFileSync)("secret-tool",["store","--label",s,"service",s,"account",n],{input:t,stdio:["pipe","ignore","ignore"]});return}catch{}}}catch{}let r=U(t);L.set(`secure_${e}`,JSON.stringify(r))},K=e=>{try{let t="XtraSecurityCLI",r=e;if(h.default.platform()==="darwin")return(0,P.execFileSync)("security",["find-generic-password","-s",t,"-a",r,"-w"],{stdio:["ignore","pipe","ignore"]}).toString().trim();if(h.default.platform()!=="win32"){if(h.default.platform()==="linux")try{return(0,P.execFileSync)("secret-tool",["lookup","service",t,"account",r],{stdio:["ignore","pipe","ignore"]}).toString().trim()}catch{}}}catch{}try{let t=L.get(`secure_${e}`);if(!t)return null;let r=JSON.parse(t);return D(r)}catch{return null}}});var ae={};V(ae,{clearConfig:()=>Ie,deleteConfig:()=>Ce,getAuthToken:()=>_,getBreakGlassSession:()=>Be,getConfig:()=>j,getConfigValue:()=>_e,getProjectConfig:()=>Oe,getRcConfig:()=>G,setBreakGlassSession:()=>Ve,setConfig:()=>Ee});var pe,w,F,W,u,ce,j,_e,Ee,Ie,Ce,_,Be,Ve,Oe,G,R=B(()=>{pe=l(require("conf")),w=l(require("fs")),F=l(require("path"));b();W="https://www.xtrasecurity.in/api",u=new pe.default({projectName:"xtra-cli",defaults:{apiUrl:W}}),ce=u.get("apiUrl");ce&&!process.env.XTRA_API_URL&&ce.includes("xtra-security.vercel.app")&&u.set("apiUrl",W);j=()=>({...u.store,token:_(),apiUrl:process.env.XTRA_API_URL||u.get("apiUrl")||W}),_e=e=>e==="token"?_():u.get(e),Ee=(e,t)=>{if(e==="token"&&t&&T("token",t),u.set(e,t),e==="token"&&process.platform!=="win32"&&w.default.existsSync(u.path))try{w.default.chmodSync(u.path,384)}catch{}},Ie=()=>u.clear(),Ce=e=>u.delete(e),_=()=>K("token")||u.get("token"),Be=()=>u.get("breakGlassSessionId"),Ve=e=>{e?u.set("breakGlassSessionId",e):u.delete("breakGlassSessionId")},Oe=async()=>{try{let e=F.default.join(process.cwd(),"xtra.json");if(w.default.existsSync(e)){let t=w.default.readFileSync(e,"utf-8");return JSON.parse(t)}return null}catch{return null}},G=()=>{let e={};try{let t=F.default.join(process.cwd(),".xtrarc");w.default.existsSync(t)&&(e=JSON.parse(w.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||u.get("project")||"",env:e.env||u.get("env")||"development",branch:e.branch||u.get("branch")||"main"}}});var ge,ue,de,Le,o,E,M=B(()=>{ge=l(require("axios"));R();ue=l(require("fs")),de=l(require("path")),Le=JSON.parse(ue.readFileSync(de.join(__dirname,"../../package.json"),"utf-8")),o=e=>{let{apiUrl:t}=j(),r=e||_();return ge.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":Le.version,...r?{Authorization:`Bearer ${r}`}:{}}})},E={login:async(e,t,r)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:r})).data,exchangeOidcToken:async(e,t)=>{let r=await o().post("/v2/auth/oidc/token",{provider:e,token:t});return{accessToken:r.data.access_token,envelope:r.data.envelope}},spawnAgentContext:async e=>(await o().post("/agents/ephemeral-context",e)).data,getSecrets:async(e,t,r="main",s,n,i)=>{let p=(await o(n).get(`/projects/${e}/envs/${t}/secrets?branch=${r}`)).data;if(p&&typeof p=="object"){let g=null,{deriveProjectKey:d,decryptSecretValue:v,resolveVaultPassphrase:$,decryptWorkloadKeyEnvelope:S}=(b(),k(N));for(let[f,x]of Object.entries(p))if(typeof x=="string"&&x.startsWith("{"))try{let y=JSON.parse(x);if(y.ciphertext&&y.iv){if(!g)if(i&&process.env.XTRA_WORKLOAD_PRIVATE_KEY)g=S(i,process.env.XTRA_WORKLOAD_PRIVATE_KEY);else{let X=$(s,e);g=d(e,X)}p[f]=v(y,g)}}catch(y){if(y.message&&y.message.includes("Zero-Knowledge"))throw y}}return p},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")=>{let{deriveProjectKey:i,encryptSecretValue:a,resolveVaultPassphrase:p}=(b(),k(N)),g=p(void 0,e),d=i(e,g),v={};for(let[S,f]of Object.entries(r))if(typeof f=="string"&&f.startsWith("{")&&f.includes("ciphertext"))v[S]=f;else{let x=a(f,d);v[S]=JSON.stringify(x)}return(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:v,expectedVersions:s,branch:n})).data},getSecretDetails:async(e,t,r,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${r}?branch=${s}`)).data,getSecretsV2:async(e,t)=>{let r=t?`&branchId=${t}`:"";return(await o().get(`/v2/secret?projectId=${e}${r}`)).data},createSecretV2:async e=>(await o().post("/v2/secret",e)).data,updateSecretV2:async e=>(await o().put(`/v2/secret?id=${e.id}`,e)).data,deleteSecretV2:async e=>(await o().delete(`/v2/secret?id=${e}`)).data,bulkImportV2:async e=>(await o().post("/v2/secret/bulk",e)).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}=j(),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}=j(),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}});var ye={};V(ye,{loadAuditLogs:()=>J,logAudit:()=>De,saveAuditLogs:()=>q,syncAuditLogs:()=>Ne});function Ue(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 fe(e){try{if(!j().token)return!1;let r={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:Ue(e.details),timestamp:e.timestamp,projectId:e.projectId};return await E.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 De(e,t,r,s){let n={id:(0,le.randomUUID)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:r,details:s,synced:!1},i=J();i.push(n),q(i),fe(n).then(a=>{if(a){n.synced=!0;let p=J(),g=p.findIndex(d=>d.id===n.id);g!==-1&&(p[g].synced=!0,q(p))}}).catch(()=>{})}function J(){if(!A.default.existsSync(Y))return[];try{let e=A.default.readFileSync(Y,"utf-8"),t=JSON.parse(e),r=D(t);return JSON.parse(r)}catch{return[]}}function q(e){A.default.existsSync(z)||A.default.mkdirSync(z,{recursive:!0});let t=JSON.stringify(e),r=U(t);A.default.writeFileSync(Y,JSON.stringify(r),"utf-8")}async function Ne(){let e=J(),t=e.filter(s=>!s.synced);if(t.length===0)return 0;let r=0;for(let s of t)await fe(s)&&(s.synced=!0,r++);return r>0&&q(e),r}var A,Z,le,z,Y,me=B(()=>{A=l(require("fs")),Z=l(require("path")),le=require("crypto");b();R();M();z=Z.default.join(process.cwd(),".xtra"),Y=Z.default.join(z,"audit.enc")});var qe={};V(qe,{rollbackCommand:()=>Je});module.exports=k(qe);var he=require("commander");M();var I=l(require("chalk")),Q=l(require("ora")),ve=l(require("inquirer"));R();var Je=new he.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:r,env:s}=t;r||(r=G().project),r||(console.error(I.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first.")),process.exit(1)),s={dev:"development",stg:"staging",prod:"production"}[s]||s;let i=(0,Q.default)(`Fetching history for ${e}...`).start();try{let a=await E.getSecretDetails(r,s,e);if(i.stop(),!a.history||!Array.isArray(a.history)||a.history.length===0){console.log(I.default.yellow(`No history found for ${e}. Cannot rollback.`));return}let p=[],{deriveProjectKey:g,decryptSecretValue:d,resolveVaultPassphrase:v}=(b(),k(N)),$=v(void 0,r),S=g(r,$);a.history.forEach(m=>{let H="********";try{let ee=JSON.parse(m.value[0]);H=d(ee,S)}catch{H=m.value[0]}p.push({name:`v${m.version} - ${new Date(m.updatedAt).toLocaleString()} (Value: ${H.substring(0,10)}...)`,value:m})});let{selectedVersion:f}=await ve.default.prompt([{type:"list",name:"selectedVersion",message:"Select version to restore:",choices:p}]),x=(0,Q.default)(`Restoring version v${f.version}...`).start(),y=f.value[0];try{let m=JSON.parse(y);y=d(m,S)}catch{}let X={[e]:y};await E.setSecrets(r,s,X),x.succeed(`Successfully rolled back ${e} to v${f.version}`);try{let{logAudit:m}=(me(),k(ye));m("SECRET_ROLLBACK",r,s,{key:e,version:f.version})}catch{}}catch(a){i.fail("Failed to rollback."),a.response&&a.response.status===404?console.error(I.default.red("Secret not found.")):console.error(I.default.red(a?.response?.data?.error||"An unexpected error occurred"))}});0&&(module.exports={rollbackCommand});
|
package/dist/commands/rotate.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
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 O=(e,t)=>{for(var r in t)w(e,r,{get:t[r],enumerable:!0})},L=(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)):{},L(t||!e||!e.__esModule?w(r,"default",{value:e,enumerable:!0}):r,e)),A=e=>L(w({},"__esModule",{value:!0}),e);var B,b,N,I,d,D,u,_,q,$=S(()=>{B=p(require("conf")),b=p(require("fs")),N=p(require("path")),I="https://www.xtrasecurity.in/api",d=new B.default({projectName:"xtra-cli",defaults:{apiUrl:I}}),D=d.get("apiUrl");D&&!process.env.XTRA_API_URL&&D.includes("xtra-security.vercel.app")&&d.set("apiUrl",I);u=()=>({...d.store,apiUrl:process.env.XTRA_API_URL||d.get("apiUrl")||I}),_=()=>d.get("token"),q=()=>{let e={};try{let t=N.default.join(process.cwd(),".xtrarc");b.default.existsSync(t)&&(e=JSON.parse(b.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,k=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 E={};O(E,{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(R))return[];try{let e=y.default.readFileSync(R,"utf-8"),t=JSON.parse(e),r=Y(t);return JSON.parse(r)}catch{return[]}}function x(e){y.default.existsSync(C)||y.default.mkdirSync(C,{recursive:!0});let t=JSON.stringify(e),r=X(t);y.default.writeFileSync(R,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,P,Q,C,R,T=S(()=>{y=p(require("fs")),P=p(require("path")),Q=require("uuid");Z();$();k();C=P.default.join(process.cwd(),".xtra"),R=P.default.join(C,"audit.enc")});var de={};O(de,{rotateCommand:()=>ge});module.exports=A(de);var ee=require("commander");k();$();var c=p(require("chalk")),U=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,U.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}=(T(),A(E));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,U.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(`
|
|
1
|
+
var ye=Object.create;var I=Object.defineProperty;var me=Object.getOwnPropertyDescriptor;var he=Object.getOwnPropertyNames;var ve=Object.getPrototypeOf,Se=Object.prototype.hasOwnProperty;var C=(e,t)=>()=>(e&&(t=e(e=0)),t);var B=(e,t)=>{for(var r in t)I(e,r,{get:t[r],enumerable:!0})},Q=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of he(t))!Se.call(e,n)&&n!==r&&I(e,n,{get:()=>t[n],enumerable:!(s=me(t,n))||s.enumerable});return e};var f=(e,t,r)=>(r=e!=null?ye(ve(e)):{},Q(t||!e||!e.__esModule?I(r,"default",{value:e,enumerable:!0}):r,e)),w=e=>Q(I({},"__esModule",{value:!0}),e);var q={};B(q,{createWorkloadKeyEnvelope:()=>be,decrypt:()=>L,decryptSecretValue:()=>Ae,decryptWorkloadKeyEnvelope:()=>ke,deriveProjectKey:()=>we,encrypt:()=>U,encryptSecretValue:()=>$e,hash:()=>xe,resolveVaultPassphrase:()=>ne,saveVaultPassphrase:()=>je,secureRead:()=>k,secureSave:()=>b});function se(){if(O)return O;let e=V.get("masterKey");e||(e=p.default.randomBytes(32).toString("hex"),V.set("masterKey",e));let t="";try{t=(0,te.machineIdSync)()||""}catch{t=p.default.createHash("sha256").update(m.default.hostname()+(m.default.userInfo?.()?.username||"root")).digest("hex")}let r=m.default.platform(),s=m.default.userInfo?.()?.username||"default_user",n=`${r}:${s}:${t}:${e}`;return O=p.default.createHash("sha256").update(n).digest(),O}function we(e,t){t||(t=ne(void 0,e));let r=Buffer.from(`project_salt_${e}`),s=Buffer.from("xtra-e2ee-project-key-v2"),n=p.default.hkdfSync("sha256",Buffer.from(t),r,s,32);return Buffer.from(n).toString("hex")}function $e(e,t){let r=p.default.randomBytes(12),s=Buffer.from(t.slice(0,64).padEnd(64,"0"),"hex"),n=p.default.createCipheriv("aes-256-gcm",s,r),a=n.update(e,"utf8","hex");a+=n.final("hex");let u=n.getAuthTag().toString("hex");return{ciphertext:a,iv:r.toString("hex"),authTag:u}}function Ae(e,t){let r=Buffer.from(t.slice(0,64).padEnd(64,"0"),"hex"),s=Buffer.from(e.iv,"hex"),n=Buffer.from(e.authTag,"hex"),a=p.default.createDecipheriv("aes-256-gcm",r,s);a.setAuthTag(n);let u=a.update(e.ciphertext,"hex","utf8");return u+=a.final("utf8"),u}function ne(e,t){if(e&&e.trim())return e.trim();if(process.env.XTRA_VAULT_PASSPHRASE&&process.env.XTRA_VAULT_PASSPHRASE.trim())return process.env.XTRA_VAULT_PASSPHRASE.trim();if(process.env.XTRA_MASTER_SECRET&&process.env.XTRA_MASTER_SECRET.trim())return process.env.XTRA_MASTER_SECRET.trim();try{if(t){let s=k(`vault_${t}`);if(s)return s}let r=k("vault_passphrase");if(r)return r}catch{}try{let{getRcConfig:r}=(P(),w(oe)),s=r();if(s&&s.passphrase)return s.passphrase}catch{}throw new Error("Vault Passphrase or Master Secret is required for Zero-Knowledge E2EE encryption/decryption.")}function je(e,t){t&&b(`vault_${t}`,e),b("vault_passphrase",e)}function be(e,t){let{publicKey:r,privateKey:s}=p.default.generateKeyPairSync("x25519"),n=r.export({type:"spki",format:"pem"}).toString(),a=p.default.createPublicKey(t),u=p.default.diffieHellman({privateKey:s,publicKey:a}),d=Buffer.from(p.default.hkdfSync("sha256",u,Buffer.alloc(0),Buffer.from("xtra-workload-envelope"),32)),c=p.default.randomBytes(12),i=p.default.createCipheriv("aes-256-gcm",d,c),l=i.update(e,"utf8","hex");l+=i.final("hex");let K=i.getAuthTag().toString("hex");return{targetPublicKey:t,ephemeralPublicKey:n,encryptedProjectKey:l,iv:c.toString("hex"),authTag:K}}function ke(e,t){let r=p.default.createPrivateKey(t),s=p.default.createPublicKey(e.ephemeralPublicKey),n=p.default.diffieHellman({privateKey:r,publicKey:s}),a=Buffer.from(p.default.hkdfSync("sha256",n,Buffer.alloc(0),Buffer.from("xtra-workload-envelope"),32)),u=Buffer.from(e.iv,"hex"),d=Buffer.from(e.authTag,"hex"),c=p.default.createDecipheriv("aes-256-gcm",a,u);c.setAuthTag(d);let i=c.update(e.encryptedProjectKey,"hex","utf8");return i+=c.final("utf8"),i}var p,m,ee,te,j,re,V,O,U,L,xe,b,k,T=C(()=>{p=f(require("crypto")),m=f(require("os")),ee=f(require("conf")),te=require("node-machine-id"),j=require("child_process"),re="aes-256-gcm",V=new ee.default({projectName:"xtra-cli-crypto"}),O=null;U=e=>{let t=p.default.randomBytes(12),r=se(),s=p.default.createCipheriv(re,r,t),n=s.update(e,"utf8","hex");n+=s.final("hex");let a=s.getAuthTag();return{iv:t.toString("hex"),content:n,tag:a.toString("hex")}},L=e=>{let t=se(),r=Buffer.from(e.iv,"hex"),s=Buffer.from(e.tag,"hex"),n=p.default.createDecipheriv(re,t,r);n.setAuthTag(s);let a=n.update(e.content,"hex","utf8");return a+=n.final("utf8"),a},xe=e=>p.default.createHash("sha256").update(e).digest("hex"),b=(e,t)=>{try{let s="XtraSecurityCLI",n=e;if(m.default.platform()==="darwin"){(0,j.execFileSync)("security",["add-generic-password","-s",s,"-a",n,"-w",t,"-U"],{stdio:"ignore"});return}else if(m.default.platform()!=="win32"){if(m.default.platform()==="linux")try{(0,j.execFileSync)("secret-tool",["store","--label",s,"service",s,"account",n],{input:t,stdio:["pipe","ignore","ignore"]});return}catch{}}}catch{}let r=U(t);V.set(`secure_${e}`,JSON.stringify(r))},k=e=>{try{let t="XtraSecurityCLI",r=e;if(m.default.platform()==="darwin")return(0,j.execFileSync)("security",["find-generic-password","-s",t,"-a",r,"-w"],{stdio:["ignore","pipe","ignore"]}).toString().trim();if(m.default.platform()!=="win32"){if(m.default.platform()==="linux")try{return(0,j.execFileSync)("secret-tool",["lookup","service",t,"account",r],{stdio:["ignore","pipe","ignore"]}).toString().trim()}catch{}}}catch{}try{let t=V.get(`secure_${e}`);if(!t)return null;let r=JSON.parse(t);return L(r)}catch{return null}}});var oe={};B(oe,{clearConfig:()=>Re,deleteConfig:()=>Ee,getAuthToken:()=>R,getBreakGlassSession:()=>Ke,getConfig:()=>x,getConfigValue:()=>Te,getProjectConfig:()=>Ie,getRcConfig:()=>H,setBreakGlassSession:()=>_e,setConfig:()=>Pe});var ae,S,J,X,g,ie,x,Te,Pe,Re,Ee,R,Ke,_e,Ie,H,P=C(()=>{ae=f(require("conf")),S=f(require("fs")),J=f(require("path"));T();X="https://www.xtrasecurity.in/api",g=new ae.default({projectName:"xtra-cli",defaults:{apiUrl:X}}),ie=g.get("apiUrl");ie&&!process.env.XTRA_API_URL&&ie.includes("xtra-security.vercel.app")&&g.set("apiUrl",X);x=()=>({...g.store,token:R(),apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||X}),Te=e=>e==="token"?R():g.get(e),Pe=(e,t)=>{if(e==="token"&&t&&b("token",t),g.set(e,t),e==="token"&&process.platform!=="win32"&&S.default.existsSync(g.path))try{S.default.chmodSync(g.path,384)}catch{}},Re=()=>g.clear(),Ee=e=>g.delete(e),R=()=>k("token")||g.get("token"),Ke=()=>g.get("breakGlassSessionId"),_e=e=>{e?g.set("breakGlassSessionId",e):g.delete("breakGlassSessionId")},Ie=async()=>{try{let e=J.default.join(process.cwd(),"xtra.json");if(S.default.existsSync(e)){let t=S.default.readFileSync(e,"utf-8");return JSON.parse(t)}return null}catch{return null}},H=()=>{let e={};try{let t=J.default.join(process.cwd(),".xtrarc");S.default.existsSync(t)&&(e=JSON.parse(S.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 ce,pe,ge,Ce,o,E,M=C(()=>{ce=f(require("axios"));P();pe=f(require("fs")),ge=f(require("path")),Ce=JSON.parse(pe.readFileSync(ge.join(__dirname,"../../package.json"),"utf-8")),o=e=>{let{apiUrl:t}=x(),r=e||R();return ce.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":Ce.version,...r?{Authorization:`Bearer ${r}`}:{}}})},E={login:async(e,t,r)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:r})).data,exchangeOidcToken:async(e,t)=>{let r=await o().post("/v2/auth/oidc/token",{provider:e,token:t});return{accessToken:r.data.access_token,envelope:r.data.envelope}},spawnAgentContext:async e=>(await o().post("/agents/ephemeral-context",e)).data,getSecrets:async(e,t,r="main",s,n,a)=>{let d=(await o(n).get(`/projects/${e}/envs/${t}/secrets?branch=${r}`)).data;if(d&&typeof d=="object"){let c=null,{deriveProjectKey:i,decryptSecretValue:l,resolveVaultPassphrase:K,decryptWorkloadKeyEnvelope:_}=(T(),w(q));for(let[h,A]of Object.entries(d))if(typeof A=="string"&&A.startsWith("{"))try{let v=JSON.parse(A);if(v.ciphertext&&v.iv){if(!c)if(a&&process.env.XTRA_WORKLOAD_PRIVATE_KEY)c=_(a,process.env.XTRA_WORKLOAD_PRIVATE_KEY);else{let fe=K(s,e);c=i(e,fe)}d[h]=l(v,c)}}catch(v){if(v.message&&v.message.includes("Zero-Knowledge"))throw v}}return d},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")=>{let{deriveProjectKey:a,encryptSecretValue:u,resolveVaultPassphrase:d}=(T(),w(q)),c=d(void 0,e),i=a(e,c),l={};for(let[_,h]of Object.entries(r))if(typeof h=="string"&&h.startsWith("{")&&h.includes("ciphertext"))l[_]=h;else{let A=u(h,i);l[_]=JSON.stringify(A)}return(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:l,expectedVersions:s,branch:n})).data},getSecretDetails:async(e,t,r,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${r}?branch=${s}`)).data,getSecretsV2:async(e,t)=>{let r=t?`&branchId=${t}`:"";return(await o().get(`/v2/secret?projectId=${e}${r}`)).data},createSecretV2:async e=>(await o().post("/v2/secret",e)).data,updateSecretV2:async e=>(await o().put(`/v2/secret?id=${e.id}`,e)).data,deleteSecretV2:async e=>(await o().delete(`/v2/secret?id=${e}`)).data,bulkImportV2:async e=>(await o().post("/v2/secret/bulk",e)).data,syncLogs:async e=>(await o().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,r,s,n,a)=>(await o().post(`/projects/${e}/envs/${t}/secrets/link`,{key:r,sourceProjectId:s,sourceEnv:n,sourceKey:a})).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}=x(),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}=x(),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}});var z={};B(z,{loadAuditLogs:()=>D,logAudit:()=>Oe,saveAuditLogs:()=>N,syncAuditLogs:()=>Ve});function Be(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 de(e){try{if(!x().token)return!1;let r={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:Be(e.details),timestamp:e.timestamp,projectId:e.projectId};return await E.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 Oe(e,t,r,s){let n={id:(0,ue.randomUUID)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:r,details:s,synced:!1},a=D();a.push(n),N(a),de(n).then(u=>{if(u){n.synced=!0;let d=D(),c=d.findIndex(i=>i.id===n.id);c!==-1&&(d[c].synced=!0,N(d))}}).catch(()=>{})}function D(){if(!$.default.existsSync(F))return[];try{let e=$.default.readFileSync(F,"utf-8"),t=JSON.parse(e),r=L(t);return JSON.parse(r)}catch{return[]}}function N(e){$.default.existsSync(W)||$.default.mkdirSync(W,{recursive:!0});let t=JSON.stringify(e),r=U(t);$.default.writeFileSync(F,JSON.stringify(r),"utf-8")}async function Ve(){let e=D(),t=e.filter(s=>!s.synced);if(t.length===0)return 0;let r=0;for(let s of t)await de(s)&&(s.synced=!0,r++);return r>0&&N(e),r}var $,G,ue,W,F,Y=C(()=>{$=f(require("fs")),G=f(require("path")),ue=require("crypto");T();P();M();W=G.default.join(process.cwd(),".xtra"),F=G.default.join(W,"audit.enc")});var Le={};B(Le,{rotateCommand:()=>Ue});module.exports=w(Le);var le=require("commander");M();P();var y=f(require("chalk")),Z=f(require("ora")),Ue=new le.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:a,value:u}=t;if(r||(r=H().project),s={dev:"development",stg:"staging",prod:"production"}[s]||s,r||(console.error(y.default.red("Error: Project ID is required. Use -p <id> or checkout a branch.")),process.exit(1)),s==="production"){let c=require("inquirer"),{confirmProd:i}=await c.prompt([{type:"confirm",name:"confirmProd",message:y.default.red(`\u26A0 You are about to rotate a secret in PRODUCTION (${e}). Proceed?`),default:!1}]);if(!i){console.log(y.default.yellow("Aborted."));return}}if(a){let c=(0,Z.default)(`Promoting secret '${e}' in ${s}...`).start();try{let i=await E.promoteSecret(r,s,e);c.succeed(y.default.green(`Successfully promoted '${e}' to version ${i.version}`));try{let{logAudit:l}=(Y(),w(z));l("SECRET_PROMOTE",r,s,{key:e,newVersion:i.version})}catch{}}catch(i){c.fail("Promotion failed"),i.response&&i.response.data&&i.response.data.error?console.error(y.default.red(`Server Error: ${i.response.data.error}`)):console.error(y.default.red(i?.response?.data?.error||"An unexpected error occurred"))}}else{let c=(0,Z.default)(`Starting rotation for '${e}' (Strategy: ${n})...`).start();try{let i=await E.rotateSecret(r,s,e,n,u);c.succeed(y.default.green(`Rotation initiated for '${e}'`)),console.log(y.default.dim(`Shadow Value: ${i.shadowValue}`)),console.log(y.default.dim(`Expires At: ${i.expiresAt}`)),console.log(y.default.blue(`
|
|
2
2
|
To verify, run your app. To finalize, run:
|
|
3
|
-
xtra rotate ${e} --promote -p ${r} -e ${s}`));try{let{logAudit:
|
|
3
|
+
xtra rotate ${e} --promote -p ${r} -e ${s}`));try{let{logAudit:l}=(Y(),w(z));l("SECRET_ROTATE",r,s,{key:e,strategy:n,expiresAt:i.expiresAt})}catch{}}catch(i){c.fail("Rotation failed"),i.response&&i.response.data&&i.response.data.error?console.error(y.default.red(`Server Error: ${i.response.data.error}`)):console.error(y.default.red(i?.response?.data?.error||"An unexpected error occurred"))}}});0&&(module.exports={rotateCommand});
|
package/dist/commands/run.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
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})},Y=(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)):{},Y(t||!e||!e.__esModule?O(s,"default",{value:e,enumerable:!0}):s,e)),k=e=>Y(O({},"__esModule",{value:!0}),e);var ee={};b(ee,{clearConfig:()=>Oe,deleteConfig:()=>Re,getAuthToken:()=>J,getBreakGlassSession:()=>Le,getConfig:()=>h,getConfigValue:()=>R,getProjectConfig:()=>Te,getRcConfig:()=>G,setBreakGlassSession:()=>Ne,setConfig:()=>B});var Z,m,q,M,g,Q,h,R,B,Oe,Re,J,Le,Ne,Te,G,A=$(()=>{Z=p(require("conf")),m=p(require("fs")),q=p(require("path")),M="https://www.xtrasecurity.in/api",g=new Z.default({projectName:"xtra-cli",defaults:{apiUrl:M}}),Q=g.get("apiUrl");Q&&!process.env.XTRA_API_URL&&Q.includes("xtra-security.vercel.app")&&g.set("apiUrl",M);h=()=>({...g.store,apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||M}),R=e=>g.get(e),B=(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),J=()=>g.get("token"),Le=()=>g.get("breakGlassSessionId"),Ne=e=>{e?g.set("breakGlassSessionId",e):g.delete("breakGlassSessionId")},Te=async()=>{try{let e=q.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}},G=()=>{let e={};try{let t=q.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,K=$(()=>{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=J();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,H,T,U,le=$(()=>{x=p(require("fs")),H=p(require("path")),T=H.default.join(process.cwd(),".xtra"),U=H.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(z))return[];try{let e=j.default.readFileSync(z,"utf-8"),t=JSON.parse(e),s=E(t);return JSON.parse(s)}catch{return[]}}function F(e){j.default.existsSync(V)||j.default.mkdirSync(V,{recursive:!0});let t=JSON.stringify(e),s=I(t);j.default.writeFileSync(z,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,X,fe,V,z,he=$(()=>{j=p(require("fs")),X=p(require("path")),fe=require("uuid");N();A();K();V=X.default.join(process.cwd(),".xtra"),z=X.default.join(V,"audit.enc")});var Je={};b(Je,{runCommand:()=>Be});module.exports=k(Je);var Se=require("commander");K();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",`
|
|
1
|
+
var Be=Object.create;var H=Object.defineProperty;var De=Object.getOwnPropertyDescriptor;var Ne=Object.getOwnPropertyNames;var Ue=Object.getPrototypeOf,Ve=Object.prototype.hasOwnProperty;var B=(e,t)=>()=>(e&&(t=e(e=0)),t);var D=(e,t)=>{for(var r in t)H(e,r,{get:t[r],enumerable:!0})},de=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Ne(t))!Ve.call(e,n)&&n!==r&&H(e,n,{get:()=>t[n],enumerable:!(s=De(t,n))||s.enumerable});return e};var l=(e,t,r)=>(r=e!=null?Be(Ue(e)):{},de(t||!e||!e.__esModule?H(r,"default",{value:e,enumerable:!0}):r,e)),w=e=>de(H({},"__esModule",{value:!0}),e);var F={};D(F,{createWorkloadKeyEnvelope:()=>We,decrypt:()=>K,decryptSecretValue:()=>qe,decryptWorkloadKeyEnvelope:()=>Xe,deriveProjectKey:()=>Me,encrypt:()=>R,encryptSecretValue:()=>Je,hash:()=>Fe,resolveVaultPassphrase:()=>me,saveVaultPassphrase:()=>He,secureRead:()=>V,secureSave:()=>U});function he(){if(W)return W;let e=X.get("masterKey");e||(e=g.default.randomBytes(32).toString("hex"),X.set("masterKey",e));let t="";try{t=(0,fe.machineIdSync)()||""}catch{t=g.default.createHash("sha256").update(S.default.hostname()+(S.default.userInfo?.()?.username||"root")).digest("hex")}let r=S.default.platform(),s=S.default.userInfo?.()?.username||"default_user",n=`${r}:${s}:${t}:${e}`;return W=g.default.createHash("sha256").update(n).digest(),W}function Me(e,t){t||(t=me(void 0,e));let r=Buffer.from(`project_salt_${e}`),s=Buffer.from("xtra-e2ee-project-key-v2"),n=g.default.hkdfSync("sha256",Buffer.from(t),r,s,32);return Buffer.from(n).toString("hex")}function Je(e,t){let r=g.default.randomBytes(12),s=Buffer.from(t.slice(0,64).padEnd(64,"0"),"hex"),n=g.default.createCipheriv("aes-256-gcm",s,r),i=n.update(e,"utf8","hex");i+=n.final("hex");let d=n.getAuthTag().toString("hex");return{ciphertext:i,iv:r.toString("hex"),authTag:d}}function qe(e,t){let r=Buffer.from(t.slice(0,64).padEnd(64,"0"),"hex"),s=Buffer.from(e.iv,"hex"),n=Buffer.from(e.authTag,"hex"),i=g.default.createDecipheriv("aes-256-gcm",r,s);i.setAuthTag(n);let d=i.update(e.ciphertext,"hex","utf8");return d+=i.final("utf8"),d}function me(e,t){if(e&&e.trim())return e.trim();if(process.env.XTRA_VAULT_PASSPHRASE&&process.env.XTRA_VAULT_PASSPHRASE.trim())return process.env.XTRA_VAULT_PASSPHRASE.trim();if(process.env.XTRA_MASTER_SECRET&&process.env.XTRA_MASTER_SECRET.trim())return process.env.XTRA_MASTER_SECRET.trim();try{if(t){let s=V(`vault_${t}`);if(s)return s}let r=V("vault_passphrase");if(r)return r}catch{}try{let{getRcConfig:r}=(_(),w(re)),s=r();if(s&&s.passphrase)return s.passphrase}catch{}throw new Error("Vault Passphrase or Master Secret is required for Zero-Knowledge E2EE encryption/decryption.")}function He(e,t){t&&U(`vault_${t}`,e),U("vault_passphrase",e)}function We(e,t){let{publicKey:r,privateKey:s}=g.default.generateKeyPairSync("x25519"),n=r.export({type:"spki",format:"pem"}).toString(),i=g.default.createPublicKey(t),d=g.default.diffieHellman({privateKey:s,publicKey:i}),u=Buffer.from(g.default.hkdfSync("sha256",d,Buffer.alloc(0),Buffer.from("xtra-workload-envelope"),32)),y=g.default.randomBytes(12),p=g.default.createCipheriv("aes-256-gcm",u,y),c=p.update(e,"utf8","hex");c+=p.final("hex");let L=p.getAuthTag().toString("hex");return{targetPublicKey:t,ephemeralPublicKey:n,encryptedProjectKey:c,iv:y.toString("hex"),authTag:L}}function Xe(e,t){let r=g.default.createPrivateKey(t),s=g.default.createPublicKey(e.ephemeralPublicKey),n=g.default.diffieHellman({privateKey:r,publicKey:s}),i=Buffer.from(g.default.hkdfSync("sha256",n,Buffer.alloc(0),Buffer.from("xtra-workload-envelope"),32)),d=Buffer.from(e.iv,"hex"),u=Buffer.from(e.authTag,"hex"),y=g.default.createDecipheriv("aes-256-gcm",i,d);y.setAuthTag(u);let p=y.update(e.encryptedProjectKey,"hex","utf8");return p+=y.final("utf8"),p}var g,S,le,fe,N,ye,X,W,R,K,Fe,U,V,b=B(()=>{g=l(require("crypto")),S=l(require("os")),le=l(require("conf")),fe=require("node-machine-id"),N=require("child_process"),ye="aes-256-gcm",X=new le.default({projectName:"xtra-cli-crypto"}),W=null;R=e=>{let t=g.default.randomBytes(12),r=he(),s=g.default.createCipheriv(ye,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")}},K=e=>{let t=he(),r=Buffer.from(e.iv,"hex"),s=Buffer.from(e.tag,"hex"),n=g.default.createDecipheriv(ye,t,r);n.setAuthTag(s);let i=n.update(e.content,"hex","utf8");return i+=n.final("utf8"),i},Fe=e=>g.default.createHash("sha256").update(e).digest("hex"),U=(e,t)=>{try{let s="XtraSecurityCLI",n=e;if(S.default.platform()==="darwin"){(0,N.execFileSync)("security",["add-generic-password","-s",s,"-a",n,"-w",t,"-U"],{stdio:"ignore"});return}else if(S.default.platform()!=="win32"){if(S.default.platform()==="linux")try{(0,N.execFileSync)("secret-tool",["store","--label",s,"service",s,"account",n],{input:t,stdio:["pipe","ignore","ignore"]});return}catch{}}}catch{}let r=R(t);X.set(`secure_${e}`,JSON.stringify(r))},V=e=>{try{let t="XtraSecurityCLI",r=e;if(S.default.platform()==="darwin")return(0,N.execFileSync)("security",["find-generic-password","-s",t,"-a",r,"-w"],{stdio:["ignore","pipe","ignore"]}).toString().trim();if(S.default.platform()!=="win32"){if(S.default.platform()==="linux")try{return(0,N.execFileSync)("secret-tool",["lookup","service",t,"account",r],{stdio:["ignore","pipe","ignore"]}).toString().trim()}catch{}}}catch{}try{let t=X.get(`secure_${e}`);if(!t)return null;let r=JSON.parse(t);return K(r)}catch{return null}}});var re={};D(re,{clearConfig:()=>Ge,deleteConfig:()=>ze,getAuthToken:()=>M,getBreakGlassSession:()=>Ye,getConfig:()=>T,getConfigValue:()=>G,getProjectConfig:()=>Qe,getRcConfig:()=>ie,setBreakGlassSession:()=>Ze,setConfig:()=>oe});var Se,A,se,ne,h,ve,T,G,oe,Ge,ze,M,Ye,Ze,Qe,ie,_=B(()=>{Se=l(require("conf")),A=l(require("fs")),se=l(require("path"));b();ne="https://www.xtrasecurity.in/api",h=new Se.default({projectName:"xtra-cli",defaults:{apiUrl:ne}}),ve=h.get("apiUrl");ve&&!process.env.XTRA_API_URL&&ve.includes("xtra-security.vercel.app")&&h.set("apiUrl",ne);T=()=>({...h.store,token:M(),apiUrl:process.env.XTRA_API_URL||h.get("apiUrl")||ne}),G=e=>e==="token"?M():h.get(e),oe=(e,t)=>{if(e==="token"&&t&&U("token",t),h.set(e,t),e==="token"&&process.platform!=="win32"&&A.default.existsSync(h.path))try{A.default.chmodSync(h.path,384)}catch{}},Ge=()=>h.clear(),ze=e=>h.delete(e),M=()=>V("token")||h.get("token"),Ye=()=>h.get("breakGlassSessionId"),Ze=e=>{e?h.set("breakGlassSessionId",e):h.delete("breakGlassSessionId")},Qe=async()=>{try{let e=se.default.join(process.cwd(),"xtra.json");if(A.default.existsSync(e)){let t=A.default.readFileSync(e,"utf-8");return JSON.parse(t)}return null}catch{return null}},ie=()=>{let e={};try{let t=se.default.join(process.cwd(),".xtrarc");A.default.existsSync(t)&&(e=JSON.parse(A.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||h.get("project")||"",env:e.env||h.get("env")||"development",branch:e.branch||h.get("branch")||"main"}}});var xe,we,je,et,o,J,ce=B(()=>{xe=l(require("axios"));_();we=l(require("fs")),je=l(require("path")),et=JSON.parse(we.readFileSync(je.join(__dirname,"../../package.json"),"utf-8")),o=e=>{let{apiUrl:t}=T(),r=e||M();return xe.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":et.version,...r?{Authorization:`Bearer ${r}`}:{}}})},J={login:async(e,t,r)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:r})).data,exchangeOidcToken:async(e,t)=>{let r=await o().post("/v2/auth/oidc/token",{provider:e,token:t});return{accessToken:r.data.access_token,envelope:r.data.envelope}},spawnAgentContext:async e=>(await o().post("/agents/ephemeral-context",e)).data,getSecrets:async(e,t,r="main",s,n,i)=>{let u=(await o(n).get(`/projects/${e}/envs/${t}/secrets?branch=${r}`)).data;if(u&&typeof u=="object"){let y=null,{deriveProjectKey:p,decryptSecretValue:c,resolveVaultPassphrase:L,decryptWorkloadKeyEnvelope:E}=(b(),w(F));for(let[j,P]of Object.entries(u))if(typeof P=="string"&&P.startsWith("{"))try{let m=JSON.parse(P);if(m.ciphertext&&m.iv){if(!y)if(i&&process.env.XTRA_WORKLOAD_PRIVATE_KEY)y=E(i,process.env.XTRA_WORKLOAD_PRIVATE_KEY);else{let I=L(s,e);y=p(e,I)}u[j]=c(m,y)}}catch(m){if(m.message&&m.message.includes("Zero-Knowledge"))throw m}}return u},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")=>{let{deriveProjectKey:i,encryptSecretValue:d,resolveVaultPassphrase:u}=(b(),w(F)),y=u(void 0,e),p=i(e,y),c={};for(let[E,j]of Object.entries(r))if(typeof j=="string"&&j.startsWith("{")&&j.includes("ciphertext"))c[E]=j;else{let P=d(j,p);c[E]=JSON.stringify(P)}return(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:c,expectedVersions:s,branch:n})).data},getSecretDetails:async(e,t,r,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${r}?branch=${s}`)).data,getSecretsV2:async(e,t)=>{let r=t?`&branchId=${t}`:"";return(await o().get(`/v2/secret?projectId=${e}${r}`)).data},createSecretV2:async e=>(await o().post("/v2/secret",e)).data,updateSecretV2:async e=>(await o().put(`/v2/secret?id=${e.id}`,e)).data,deleteSecretV2:async e=>(await o().delete(`/v2/secret?id=${e}`)).data,bulkImportV2:async e=>(await o().post("/v2/secret/bulk",e)).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}=T(),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}=T(),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}});var be={};D(be,{MANIFEST_DIR:()=>z,MANIFEST_FILE:()=>Y,loadManifest:()=>$e,saveManifest:()=>ke,updateManifest:()=>tt});function $e(){if(!O.default.existsSync(Y))return null;try{let e=O.default.readFileSync(Y,"utf-8");return JSON.parse(e)}catch{return null}}function ke(e){O.default.existsSync(z)||O.default.mkdirSync(z,{recursive:!0}),O.default.writeFileSync(Y,JSON.stringify(e,null,2),"utf-8")}function tt(e,t,r,s){let n=$e()||{projectId:e,environment:t,lastSyncedAt:new Date().toISOString(),secrets:{}};n.projectId=e,n.environment=t,n.lastSyncedAt=new Date().toISOString(),Object.entries(r).forEach(([i,d])=>{let u=s(d);n.secrets[i]={hash:u,updatedAt:new Date().toISOString()}}),ke(n)}var O,ae,z,Y,Ae=B(()=>{O=l(require("fs")),ae=l(require("path")),z=ae.default.join(process.cwd(),".xtra"),Y=ae.default.join(z,"manifest.json")});var Pe={};D(Pe,{loadAuditLogs:()=>Z,logAudit:()=>st,saveAuditLogs:()=>Q,syncAuditLogs:()=>nt});function rt(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 Ee(e){try{if(!T().token)return!1;let r={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:rt(e.details),timestamp:e.timestamp,projectId:e.projectId};return await J.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 st(e,t,r,s){let n={id:(0,Te.randomUUID)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:r,details:s,synced:!1},i=Z();i.push(n),Q(i),Ee(n).then(d=>{if(d){n.synced=!0;let u=Z(),y=u.findIndex(p=>p.id===n.id);y!==-1&&(u[y].synced=!0,Q(u))}}).catch(()=>{})}function Z(){if(!C.default.existsSync(ge))return[];try{let e=C.default.readFileSync(ge,"utf-8"),t=JSON.parse(e),r=K(t);return JSON.parse(r)}catch{return[]}}function Q(e){C.default.existsSync(pe)||C.default.mkdirSync(pe,{recursive:!0});let t=JSON.stringify(e),r=R(t);C.default.writeFileSync(ge,JSON.stringify(r),"utf-8")}async function nt(){let e=Z(),t=e.filter(s=>!s.synced);if(t.length===0)return 0;let r=0;for(let s of t)await Ee(s)&&(s.synced=!0,r++);return r>0&&Q(e),r}var C,ue,Te,pe,ge,Ie=B(()=>{C=l(require("fs")),ue=l(require("path")),Te=require("crypto");b();_();ce();pe=ue.default.join(process.cwd(),".xtra"),ge=ue.default.join(pe,"audit.enc")});var it={};D(it,{runCommand:()=>ot});module.exports=w(it);var Re=require("commander");ce();var Ke=require("child_process"),f=l(require("chalk")),_e=l(require("ora"));_();b();var ee=l(require("fs")),Oe=l(require("path")),Ce=l(require("dotenv")),ot=new Re.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).option("--passphrase <passphrase>","Vault passphrase for Level 3 Zero-Knowledge decryption").option("--oidc-provider <provider>","OIDC Provider (e.g., github, gitlab)").option("--oidc-token <token>","OIDC JWT Token").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
|
+
$ xtra run --oidc-provider github --oidc-token $JWT_TOKEN -- npm start
|
|
5
6
|
$ xtra run -p proj_123 -b feature-branch -- python script.py
|
|
6
7
|
$ xtra run --shell "echo $SECRET_KEY"
|
|
7
|
-
`).action(async(e,t,
|
|
8
|
-
Error
|
|
9
|
-
Error:
|
|
10
|
-
Error:
|
|
11
|
-
|
|
8
|
+
`).action(async(e,t,r)=>{let{project:s,env:n,branch:i,shell:d}=r,u=ie();i||(i=u.branch),n={dev:"development",stg:"staging",prod:"production"}[n]||n||u.env,s||(s=u.project),s||(console.error(f.default.red("Error: Project ID is required. Use -p <id> or checkout a branch.")),process.exit(1));let p=(0,_e.default)(`Fetching secrets for ${n} (branch: ${i})...`).start(),c=null;if(G("localMode")===!0||process.env.XTRA_LOCAL_MODE==="true"){let a=Oe.resolve(process.cwd(),".env.local");ee.existsSync(a)||(p.fail("Local mode is ON but .env.local not found. Run 'xtra local sync' first."),process.exit(1)),c=Ce.default.parse(ee.readFileSync(a,"utf8")),p.succeed(f.default.yellow(`\u{1F50C} Local mode: loaded ${Object.keys(c).length} secrets from .env.local`))}else try{let a=null,x=null;if(r.oidcProvider&&r.oidcToken){p.text=`Exchanging OIDC Token via ${r.oidcProvider}...`;let v=await J.exchangeOidcToken(r.oidcProvider,r.oidcToken);a=v.accessToken,x=v.envelope,p.succeed(f.default.green("OIDC Ephemeral Token issued.")),p.start(`Fetching secrets for ${n} (branch: ${i})...`)}if(c=await J.getSecrets(s,n,i,r.passphrase,a,x),!c||Object.keys(c).length===0)p.warn(f.default.yellow("No secrets found for this environment."));else{p.succeed(`Loaded ${Object.keys(c).length} secrets (Online).`);try{let{hash:v}=(b(),w(F)),{updateManifest:$}=(Ae(),w(be));$(s,n,c,v)}catch{}try{let v=`cache.${s}.${n}.${i}`,$=R(JSON.stringify(c));oe(v,$)}catch{console.error(f.default.yellow("Warning: Failed to cache secrets."))}}}catch(a){let x=`cache.${s}.${n}.${i}`,v=a.response&&[401,403,404].includes(a.response.status);if(a.message&&a.message.includes("Zero-Knowledge")&&(p.fail("Decryption Failed."),console.error(f.default.red(`
|
|
9
|
+
[Decryption Error] ${a.message}`)),console.log(f.default.yellow("Hint: Use 'xtra project set' to save your passphrase, or pass it using --passphrase")),process.exit(1)),v){try{let{deleteConfig:k}=(_(),w(re));k&&k(x)}catch{}p.fail("Access Denied."),a.response.status===404?console.error(f.default.red(`
|
|
10
|
+
Error: Project '${s}' not found or your access has been revoked.`)):a.response.status===401?console.error(f.default.red(`
|
|
11
|
+
Error: Unauthorized. Please run 'xtra login' again.`)):console.error(f.default.red(`
|
|
12
|
+
Error: ${a.response.data.error||"You do not have permission to access these secrets."}`)),process.exit(1)}let $=G(x);if($)try{let k=K($);c=JSON.parse(k),p.warn(f.default.yellow(`Offline Mode: Loaded ${Object.keys(c).length} secrets from cache.`))}catch{p.fail("Failed to fetch secrets and cache is corrupt."),process.exit(1)}else p.fail("Failed to fetch secrets and no local cache available."),console.error(f.default.dim(`
|
|
13
|
+
Details: ${a?.response?.data?.error||"An unexpected error occurred"}`)),process.exit(1)}try{let{logAudit:a}=(Ie(),w(Pe));c&&Object.keys(c).length>0&&a("SECRET_ACCESS",s,n,{method:"run",keys:Object.keys(c),branch:i})}catch(a){console.error("Audit Error:",a)}if(c&&typeof c=="object")try{let{deriveProjectKey:a,decryptSecretValue:x,resolveVaultPassphrase:v}=(b(),w(F)),$=v(r.passphrase,s),k=a(s,$);for(let[Le,te]of Object.entries(c))if(typeof te=="string"&&te.startsWith("{"))try{let q=JSON.parse(te);q.ciphertext&&q.iv&&(c[Le]=x(q,k))}catch{}}catch{}let E={...process.env,...c};if(!d&&/[;&|`$<>\\\n]/g.test(e)&&(console.error(f.default.red("Error: Command contains unsafe characters. Use --shell if intentional.")),process.exit(1)),n==="production"){let a=require("inquirer"),{confirm:x}=await a.prompt([{type:"confirm",name:"confirm",message:f.default.red(`\u26A0 You are about to run a command in PRODUCTION with ${Object.keys(c||{}).length} injected secrets. Continue?`),default:!1}]);if(!x){console.log(f.default.yellow("Aborted."));return}}console.log(f.default.gray(`> ${e} ${t.join(" ")}`));let P=process.platform==="win32",m=(0,Ke.spawn)(e,t,{env:E,stdio:"inherit",shell:d}),I=()=>{if(c)for(let a in c)c[a]="**********"};process.on("SIGINT",()=>{I(),m&&m.kill("SIGINT"),process.exit(0)}),process.on("SIGTERM",()=>{I(),m&&m.kill("SIGTERM"),process.exit(0)}),m.on("exit",a=>{I(),process.exit(a??0)}),m.on("error",a=>{console.error(f.default.red(`Failed to start command: ${a.message}`)),I(),process.exit(1)})});0&&(module.exports={runCommand});
|
package/dist/commands/scan.js
CHANGED
|
@@ -1,25 +1,20 @@
|
|
|
1
|
-
var
|
|
2
|
-
|
|
3
|
-
\u2714
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
var R=Object.create;var g=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var w=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty;var F=(e,t)=>{for(var n in t)g(e,n,{get:t[n],enumerable:!0})},x=(e,t,n,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of $(t))!C.call(e,r)&&r!==n&&g(e,r,{get:()=>t[r],enumerable:!(i=I(t,r))||i.enumerable});return e};var h=(e,t,n)=>(n=e!=null?R(w(e)):{},x(t||!e||!e.__esModule?g(n,"default",{value:e,enumerable:!0}):n,e)),T=e=>x(g({},"__esModule",{value:!0}),e);var G={};F(G,{SCAN_PATTERNS:()=>k,installGitHooks:()=>A,scanCommand:()=>j});module.exports=T(G);var y=require("commander"),s=h(require("chalk")),c=h(require("fs")),l=h(require("path")),u=require("child_process"),k=[{name:"Xtra API Key",regex:/xs_[a-zA-Z0-9]{16,}/},{name:"AWS Access Key ID",regex:/AKIA[0-9A-Z]{16}/},{name:"Stripe Secret Key",regex:/sk_live_[a-zA-Z0-9]{24,}/},{name:"OpenAI Secret Key",regex:/sk-proj-[a-zA-Z0-9_-]{20,}/},{name:"Slack Token",regex:/xox[bapro]-[0-9a-zA-Z]{10,}/},{name:"Private RSA/SSH Key",regex:/-----BEGIN (?:RSA|OPENSSH|EC|DSA|PGP)?\s*PRIVATE KEY-----/},{name:"Generic Hardcoded Secret",regex:/(?:key|secret|password|token|api_key|access_key)\s*[:=]\s*["']([^"']{12,})["']/i}],j=new y.Command("scan").description("Scan project for secrets, hardcoded credentials, and git leaks").option("--staged","Scan only staged files (for pre-commit hooks)",!1).option("--install-hook","Install pre-commit & pre-push git security hooks").option("--auto-fix","Automatically migrate detected secrets to process.env and .env.local",!1).action(async e=>{let{staged:t,installHook:n,autoFix:i}=e;if(n){A();return}console.log(s.default.bold("\u{1F6E1}\uFE0F XtraSecurity Pre-Commit & Leak Scanner"));let r=0;b()&&(console.error(s.default.red("CRITICAL: .env file is tracked in git repository!")),r++),(t?K():D()).forEach(o=>{try{if(!c.default.existsSync(o)||c.default.statSync(o).isDirectory()||o.endsWith(".png")||o.endsWith(".jpg")||o.endsWith(".lock")||o.includes("dist/")||o.includes(".git/"))return;let d=c.default.readFileSync(o,"utf-8"),S=!1;if(k.forEach(a=>{let P=a.regex.flags.includes("g")?a.regex.flags:a.regex.flags+"g",E=new RegExp(a.regex.source,P),m;for(;(m=E.exec(d))!==null;){r++;let p=m[0];if(console.error(s.default.red(`[${o}] Detected ${a.name}: ${p.substring(0,8)}...`)),i){let _=m[1]||p,f=`XTRA_MIGRATED_SECRET_${Math.floor(Math.random()*1e4)}`;d=d.replace(p,`process.env.${f}`),S=!0;let v=l.default.join(process.cwd(),".env.local");c.default.appendFileSync(v,`
|
|
2
|
+
${f}="${_}"
|
|
3
|
+
`,"utf-8"),console.log(s.default.green(` \u2714 Auto-Fixed: Replaced in ${o} with process.env.${f} and added to .env.local`))}}}),S&&(c.default.writeFileSync(o,d,"utf-8"),t))try{(0,u.execSync)(`git add "${o}" "${l.default.join(process.cwd(),".env.local")}"`,{stdio:"ignore"})}catch{}}catch{}}),r>0&&!i?(console.error(s.default.red(`
|
|
4
|
+
\u2716 Scan failed! Found ${r} secret leak(s). Run 'xtra scan --auto-fix' to remediate.`)),process.exit(1)):console.log(s.default.green(`
|
|
5
|
+
\u2714 Scan complete. No unhandled secret leaks found.`))});function A(){let e=l.default.join(process.cwd(),".git","hooks");if(!c.default.existsSync(e)){console.error(s.default.red("Error: .git directory not found. Is this a git repository?"));return}let t=l.default.join(e,"pre-commit"),n=l.default.join(e,"pre-push"),i=`#!/bin/sh
|
|
6
|
+
# XtraSecurity Automated Pre-Commit / Pre-Push Guard
|
|
7
|
+
echo "\u{1F6E1}\uFE0F Running XtraSecurity Leak Scan..."
|
|
6
8
|
|
|
7
|
-
# Check if 'xtra' is globally installed or use local script
|
|
8
9
|
if command -v xtra >/dev/null 2>&1; then
|
|
9
10
|
xtra scan --staged
|
|
10
11
|
elif [ -f "./node_modules/.bin/xtra" ]; then
|
|
11
12
|
./node_modules/.bin/xtra scan --staged
|
|
13
|
+
elif [ -f "./dist/bin/xtra.js" ]; then
|
|
14
|
+
node ./dist/bin/xtra.js scan --staged
|
|
12
15
|
else
|
|
13
|
-
|
|
14
|
-
# For dev testing:
|
|
15
|
-
if [ -f "./dist/bin/xtra.js" ]; then
|
|
16
|
-
node ./dist/bin/xtra.js scan --staged
|
|
17
|
-
else
|
|
18
|
-
echo "Warning: XtraSync CLI not found. Skipping scan."
|
|
19
|
-
fi
|
|
16
|
+
echo "Warning: XtraSecurity CLI not found. Skipping scan."
|
|
20
17
|
fi
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
`).filter(t=>t.trim().length>0)}catch{return[]}}function X(){try{return(0,a.execSync)("git ls-files",{encoding:"utf-8"}).split(`
|
|
25
|
-
`).filter(t=>t.trim().length>0)}catch{return[]}}0&&(module.exports={scanCommand});
|
|
18
|
+
`;c.default.writeFileSync(t,i,{mode:493}),c.default.writeFileSync(n,i,{mode:493}),console.log(s.default.green("\u2714 Pre-commit and pre-push hooks installed successfully in .git/hooks/"))}function b(){try{return(0,u.execSync)("git ls-files --error-unmatch .env",{stdio:"ignore"}),!0}catch{return!1}}function K(){try{return(0,u.execSync)("git diff --cached --name-only",{encoding:"utf-8"}).split(`
|
|
19
|
+
`).filter(t=>t.trim().length>0)}catch{return[]}}function D(){try{return(0,u.execSync)("git ls-files",{encoding:"utf-8"}).split(`
|
|
20
|
+
`).filter(t=>t.trim().length>0)}catch{return[]}}0&&(module.exports={SCAN_PATTERNS,installGitHooks,scanCommand});
|