xtra-cli 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/bin/xtra.js +2 -294
  2. package/dist/commands/access.js +1 -184
  3. package/dist/commands/admin.js +5 -118
  4. package/dist/commands/audit.js +1 -67
  5. package/dist/commands/branch.js +1 -212
  6. package/dist/commands/checkout.js +1 -80
  7. package/dist/commands/ci.js +31 -341
  8. package/dist/commands/completion.js +85 -224
  9. package/dist/commands/diff.js +6 -162
  10. package/dist/commands/doctor.js +2 -164
  11. package/dist/commands/env.js +2 -70
  12. package/dist/commands/export.js +2 -83
  13. package/dist/commands/generate.js +3 -179
  14. package/dist/commands/history.js +4 -77
  15. package/dist/commands/import.js +1 -121
  16. package/dist/commands/init.js +7 -205
  17. package/dist/commands/integration.js +11 -188
  18. package/dist/commands/jit-run.js +5 -0
  19. package/dist/commands/local.js +16 -198
  20. package/dist/commands/login.js +16 -198
  21. package/dist/commands/login.test.js +16 -51
  22. package/dist/commands/logout.js +1 -0
  23. package/dist/commands/logs.js +3 -121
  24. package/dist/commands/profile.js +14 -184
  25. package/dist/commands/project.js +1 -165
  26. package/dist/commands/rollback.js +1 -95
  27. package/dist/commands/rotate.js +3 -93
  28. package/dist/commands/run.js +11 -215
  29. package/dist/commands/scan.js +25 -127
  30. package/dist/commands/secrets.js +14 -305
  31. package/dist/commands/simulate.js +6 -109
  32. package/dist/commands/status.js +2 -93
  33. package/dist/commands/template.js +22 -276
  34. package/dist/commands/ui.js +2 -289
  35. package/dist/commands/watch.js +17 -123
  36. package/dist/lib/api.js +1 -187
  37. package/dist/lib/api.test.js +1 -89
  38. package/dist/lib/audit.js +1 -136
  39. package/dist/lib/config.js +1 -72
  40. package/dist/lib/config.test.js +1 -47
  41. package/dist/lib/crypto.js +1 -50
  42. package/dist/lib/manifest.js +1 -52
  43. package/dist/lib/profiles.js +1 -103
  44. package/package.json +2 -2
@@ -1,198 +1,16 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.loginCommand = void 0;
40
- const commander_1 = require("commander");
41
- const inquirer_1 = __importDefault(require("inquirer"));
42
- const api_1 = require("../lib/api");
43
- const config_1 = require("../lib/config");
44
- const chalk_1 = __importDefault(require("chalk"));
45
- const ora_1 = __importDefault(require("ora"));
46
- exports.loginCommand = new commander_1.Command("login")
47
- .description("Authenticate with XtraSecurity")
48
- .option("-k, --key <key>", "Login using an Access Key")
49
- .option("-e, --email <email>", "Login using Email")
50
- .option("--sso", "Login via Web (SSO)")
51
- .action(async (options) => {
52
- try {
53
- // Interactive Login Choice
54
- if (!options.key && !options.email && !options.sso) {
55
- const { method } = await inquirer_1.default.prompt([
56
- {
57
- type: "list",
58
- name: "method",
59
- message: "How would you like to login?",
60
- choices: [
61
- { name: "Browser Login (SSO)", value: "sso" },
62
- { name: "Access Key", value: "key" },
63
- { name: "Email & Password", value: "email" }
64
- ],
65
- },
66
- ]);
67
- if (method === "sso") {
68
- await handleSSOLogin();
69
- return;
70
- }
71
- else if (method === "key") {
72
- const { key } = await inquirer_1.default.prompt([{ type: "password", name: "key", message: "Enter Access Key:" }]);
73
- await handleKeyLogin(key);
74
- return;
75
- }
76
- // Fall through to Email
77
- }
78
- if (options.sso) {
79
- await handleSSOLogin();
80
- }
81
- else if (options.key) {
82
- await handleKeyLogin(options.key);
83
- }
84
- else {
85
- // Abstract Email Login
86
- let { email } = options;
87
- if (!email) {
88
- const answers = await inquirer_1.default.prompt([
89
- { type: "input", name: "email", message: "Email:" },
90
- ]);
91
- email = answers.email;
92
- }
93
- const answers = await inquirer_1.default.prompt([
94
- { type: "password", name: "password", message: "Password:" },
95
- ]);
96
- const password = answers.password;
97
- const spinner = (0, ora_1.default)("Authenticating...").start();
98
- const data = await api_1.api.login(email, password);
99
- (0, config_1.setConfig)("token", data.token);
100
- spinner.succeed("Logged in successfully!");
101
- // Audit Log
102
- try {
103
- const { logAudit } = await Promise.resolve().then(() => __importStar(require("../lib/audit")));
104
- logAudit("USER_LOGIN", null, null, { method: "email", email });
105
- }
106
- catch (e) { }
107
- }
108
- }
109
- catch (error) {
110
- if (error.response) {
111
- console.error(chalk_1.default.red(`\nError: ${error.response.data.error || 'Login failed'}`));
112
- }
113
- else {
114
- console.error(chalk_1.default.red(`\nError: ${error.message}`));
115
- }
116
- process.exit(1);
117
- }
118
- });
119
- async function handleKeyLogin(key) {
120
- const spinner = (0, ora_1.default)("Authenticating with Access Key...").start();
121
- const data = await api_1.api.login(undefined, undefined, key);
122
- (0, config_1.setConfig)("token", data.token);
123
- if (data.user) {
124
- console.log(chalk_1.default.green(`\nLogged in as ${data.user.email}`));
125
- }
126
- spinner.succeed("Logged in successfully!");
127
- // Audit Log
128
- try {
129
- const { logAudit } = await Promise.resolve().then(() => __importStar(require("../lib/audit")));
130
- logAudit("USER_LOGIN", null, null, { method: "api_key", email: data.user?.email });
131
- }
132
- catch (e) { }
133
- }
134
- async function handleSSOLogin() {
135
- const http = require("http");
136
- // 'open' is strictly ESM, so we must use dynamic import
137
- const { default: open } = await Promise.resolve().then(() => __importStar(require("open")));
138
- return new Promise((resolve) => {
139
- const server = http.createServer(async (req, res) => {
140
- const url = new URL(req.url, `http://${req.headers.host}`);
141
- const token = url.searchParams.get("token");
142
- const email = url.searchParams.get("email");
143
- const workspaceId = url.searchParams.get("workspaceId");
144
- const workspaceName = url.searchParams.get("workspaceName");
145
- if (token) {
146
- (0, config_1.setConfig)("token", token);
147
- if (workspaceId)
148
- (0, config_1.setConfig)("workspace", workspaceId);
149
- res.writeHead(200, { "Content-Type": "text/html" });
150
- res.end(`
151
- <html>
152
- <body style="background:#111;color:#eee;font-family:sans-serif;text-align:center;padding:50px;">
153
- <h1>Login Successful</h1>
154
- <p>You have successfully logged in to XtraSync.</p>
155
- <p>You can now close this tab and return to your terminal.</p>
156
- <script>
157
- setTimeout(function() { window.close(); }, 1000);
158
- </script>
159
- </body>
160
- </html>
161
- `);
162
- console.log(chalk_1.default.green(`\n✔ SS0 Login Successful! Logged in as ${email}`));
163
- if (workspaceId) {
164
- console.log(chalk_1.default.dim(`Selected Workspace: ${workspaceName} (${workspaceId})`));
165
- }
166
- // Audit Log
167
- try {
168
- const { logAudit } = await Promise.resolve().then(() => __importStar(require("../lib/audit")));
169
- logAudit("USER_LOGIN", null, null, { method: "sso", email, workspaceId, workspaceName });
170
- }
171
- catch (e) { }
172
- res.end(() => {
173
- server.close();
174
- setTimeout(() => {
175
- process.exit(0);
176
- }, 1000);
177
- });
178
- }
179
- else {
180
- res.writeHead(400);
181
- res.end("Missing token");
182
- }
183
- });
184
- server.listen(0, async () => {
185
- const address = server.address();
186
- const port = typeof address === 'string' ? 0 : address?.port;
187
- const callbackUrl = `http://localhost:${port}`;
188
- let { apiUrl } = require("../lib/config").getConfig();
189
- // Hard fallback if getConfig somehow returned the old cached localhost
190
- if (apiUrl.includes("localhost")) {
191
- apiUrl = "https://www.xtrasecurity.in/api";
192
- }
193
- const ssoUrl = `${apiUrl}/auth/cli/sso?callbackUrl=${encodeURIComponent(callbackUrl)}`;
194
- console.log(chalk_1.default.blue(`Waiting for browser login... (Opening ${ssoUrl})`));
195
- await open(ssoUrl);
196
- });
197
- });
198
- }
1
+ var ae=Object.create;var x=Object.defineProperty;var ie=Object.getOwnPropertyDescriptor;var ce=Object.getOwnPropertyNames;var pe=Object.getPrototypeOf,ge=Object.prototype.hasOwnProperty;var $=(e,t)=>()=>(e&&(t=e(e=0)),t);var L=(e,t)=>{for(var s in t)x(e,s,{get:t[s],enumerable:!0})},G=(e,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of ce(t))!ge.call(e,r)&&r!==s&&x(e,r,{get:()=>t[r],enumerable:!(n=ie(t,r))||n.enumerable});return e};var c=(e,t,s)=>(s=e!=null?ae(pe(e)):{},G(t||!e||!e.__esModule?x(s,"default",{value:e,enumerable:!0}):s,e)),K=e=>G(x({},"__esModule",{value:!0}),e);var q={};L(q,{clearConfig:()=>le,deleteConfig:()=>ue,getAuthToken:()=>R,getBreakGlassSession:()=>me,getConfig:()=>m,getConfigValue:()=>de,getProjectConfig:()=>fe,getRcConfig:()=>he,setBreakGlassSession:()=>ye,setConfig:()=>f});var J,u,O,U,i,C,m,de,f,le,ue,R,me,ye,fe,he,S=$(()=>{J=c(require("conf")),u=c(require("fs")),O=c(require("path")),U="https://www.xtrasecurity.in/api",i=new J.default({projectName:"xtra-cli",defaults:{apiUrl:U}}),C=i.get("apiUrl");C&&!process.env.XTRA_API_URL&&(C.includes("localhost")||C.includes("xtra-security.vercel.app"))&&i.set("apiUrl",U);m=()=>({...i.store,apiUrl:process.env.XTRA_API_URL||i.get("apiUrl")||U}),de=e=>i.get(e),f=(e,t)=>{if(i.set(e,t),e==="token"&&process.platform!=="win32"&&u.default.existsSync(i.path))try{u.default.chmodSync(i.path,384)}catch{}},le=()=>i.clear(),ue=e=>i.delete(e),R=()=>i.get("token"),me=()=>i.get("breakGlassSessionId"),ye=e=>{e?i.set("breakGlassSessionId",e):i.delete("breakGlassSessionId")},fe=async()=>{try{let e=O.default.join(process.cwd(),"xtra.json");if(u.default.existsSync(e)){let t=u.default.readFileSync(e,"utf-8");return JSON.parse(t)}return null}catch{return null}},he=()=>{let e={};try{let t=O.default.join(process.cwd(),".xtrarc");u.default.existsSync(t)&&(e=JSON.parse(u.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||i.get("project")||"",env:e.env||i.get("env")||"development",branch:e.branch||i.get("branch")||"main"}}});var F,H,V,we,o,k,E=$(()=>{F=c(require("axios"));S();H=c(require("fs")),V=c(require("path")),we=JSON.parse(H.readFileSync(V.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:e}=m(),t=R();return F.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":we.version,...t?{Authorization:`Bearer ${t}`}:{}}})},k={login:async(e,t,s)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,n,r="main")=>(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:n,branch:r})).data,getSecretDetails:async(e,t,s,n="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}?branch=${n}`)).data,syncLogs:async e=>(await o().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,s,n,r,a)=>(await o().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:n,sourceEnv:r,sourceKey:a})).data,rotateSecret:async(e,t,s,n,r)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:n,parsedNewValue:r})).data,promoteSecret:async(e,t,s)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(e,t,s,n)=>{let r={format:e};return t&&(r.startDate=t),s&&(r.endDate=s),n&&(r.projectId=n),(await o().post("/audit/export",r,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,s,n)=>(await o().post("/access/request",{projectId:e,secretId:n,reason:t,duration:s})).data,approveAccess:async(e,t)=>(await o().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=m(),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}=m(),t=e?`/project?workspaceId=${e}`:"/project";return(await o().get(t)).data},getBranches:async e=>(await o().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,s)=>(await o().post("/branch",{projectId:e,name:t,description:s})).data,deleteBranch:async e=>(await o().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await o().put("/branch",{id:e,...t})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await o().get(`/admin/users${t}`)).data},setUserRole:async(e,t,s)=>(await o().put("/admin/users/role",{email:e,role:t,teamId:s})).data,getIntegrationStatus:async e=>(await o().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await o().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await o().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,t)=>{let s=new URLSearchParams(t).toString();return(await o().get(`/projects/${e}/kubernetes?${s}`)).data},getSecretHistory:async(e,t,s)=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}/history`)).data,rollbackSecret:async(e,t,s,n)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/history`,{version:n})).data,cloneEnvironment:async(e,t,s,n,r)=>(await o().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,overwrite:n,branch:r})).data,generateJitLink:async e=>(await o().post("/jit/generate",e)).data,claimJitLink:async e=>(await o().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await o().get(`/jit/${e}`)).data,post:async(e,t)=>(await o().post(e,t)).data}});function Y(){let e=X.get("masterKey");e||(e=h.default.randomBytes(32).toString("hex"),X.set("masterKey",e));let t=(0,M.machineIdSync)();return h.default.createHash("sha256").update(e+t).digest()}var h,z,M,W,X,Q,Z,ee=$(()=>{h=c(require("crypto")),z=c(require("conf")),M=require("node-machine-id"),W="aes-256-gcm",X=new z.default({projectName:"xtra-cli-crypto"});Q=e=>{let t=h.default.randomBytes(16),s=Y(),n=h.default.createCipheriv(W,s,t),r=n.update(e,"utf8","hex");r+=n.final("hex");let a=n.getAuthTag();return{iv:t.toString("hex"),content:r,tag:a.toString("hex")}},Z=e=>{let t=Y(),s=Buffer.from(e.iv,"hex"),n=Buffer.from(e.tag,"hex"),r=h.default.createDecipheriv(W,t,s);r.setAuthTag(n);let a=r.update(e.content,"hex","utf8");return a+=r.final("utf8"),a}});var A={};L(A,{loadAuditLogs:()=>b,logAudit:()=>ke,saveAuditLogs:()=>j,syncAuditLogs:()=>ve});function Se(e){if(!e||typeof e!="object")return e;let t={...e},s=["password","token","secret","value","apiKey","secretValue"];for(let n of Object.keys(t))s.some(r=>n.toLowerCase().includes(r))&&(t[n]="[REDACTED]");return t}async function se(e){try{if(!m().token)return!1;let s={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:Se(e.details),timestamp:e.timestamp,projectId:e.projectId};return await k.post("/audit/cli-logs",{logs:[s]}),!0}catch(t){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",t),!1}}function ke(e,t,s,n){let r={id:(0,te.v4)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:s,details:n,synced:!1},a=b();a.push(r),j(a),se(r).then(p=>{if(p){r.synced=!0;let g=b(),d=g.findIndex(l=>l.id===r.id);d!==-1&&(g[d].synced=!0,j(g))}}).catch(()=>{})}function b(){if(!w.default.existsSync(N))return[];try{let e=w.default.readFileSync(N,"utf-8"),t=JSON.parse(e),s=Z(t);return JSON.parse(s)}catch{return[]}}function j(e){w.default.existsSync(P)||w.default.mkdirSync(P,{recursive:!0});let t=JSON.stringify(e),s=Q(t);w.default.writeFileSync(N,JSON.stringify(s),"utf-8")}async function ve(){let e=b(),t=e.filter(n=>!n.synced);if(t.length===0)return 0;let s=0;for(let n of t)await se(n)&&(n.synced=!0,s++);return s>0&&j(e),s}var w,T,te,P,N,I=$(()=>{w=c(require("fs")),T=c(require("path")),te=require("uuid");ee();S();E();P=T.default.join(process.cwd(),".xtra"),N=T.default.join(P,"audit.enc")});var $e={};L($e,{loginCommand:()=>xe});module.exports=K($e);var oe=require("commander"),v=c(require("inquirer"));E();S();var y=c(require("chalk")),_=c(require("ora")),xe=new oe.Command("login").description("Authenticate with XtraSecurity").option("-k, --key <key>","Login using an Access Key").option("-e, --email <email>","Login using Email").option("--sso","Login via Web (SSO)").action(async e=>{try{if(!e.key&&!e.email&&!e.sso){let{method:t}=await v.default.prompt([{type:"list",name:"method",message:"How would you like to login?",choices:[{name:"Browser Login (SSO)",value:"sso"},{name:"Access Key",value:"key"},{name:"Email & Password",value:"email"}]}]);if(t==="sso"){await re();return}else if(t==="key"){let{key:s}=await v.default.prompt([{type:"password",name:"key",message:"Enter Access Key:"}]);await ne(s);return}}if(e.sso)await re();else if(e.key)await ne(e.key);else{let{email:t}=e;t||(t=(await v.default.prompt([{type:"input",name:"email",message:"Email:"}])).email);let n=(await v.default.prompt([{type:"password",name:"password",message:"Password:"}])).password,r=(0,_.default)("Authenticating...").start(),a=await k.login(t,n);f("token",a.token),r.succeed("Logged in successfully!");try{let{logAudit:p}=await Promise.resolve().then(()=>(I(),A));p("USER_LOGIN",null,null,{method:"email",email:t})}catch{}}}catch(t){t.response?console.error(y.default.red(`
2
+ Error: ${t.response.data.error||"Login failed"}`)):console.error(y.default.red(`
3
+ Error: ${t.message}`)),process.exit(1)}});async function ne(e){let t=(0,_.default)("Authenticating with Access Key...").start(),s=await k.login(void 0,void 0,e);f("token",s.token),s.user&&console.log(y.default.green(`
4
+ Logged in as ${s.user.email}`)),t.succeed("Logged in successfully!");try{let{logAudit:n}=await Promise.resolve().then(()=>(I(),A));n("USER_LOGIN",null,null,{method:"api_key",email:s.user?.email})}catch{}}async function re(){let e=require("http"),{default:t}=await import("open");return new Promise(s=>{let n=e.createServer(async(r,a)=>{let p=new URL(r.url,`http://${r.headers.host}`),g=p.searchParams.get("token"),d=p.searchParams.get("email"),l=p.searchParams.get("workspaceId"),B=p.searchParams.get("workspaceName");if(g){f("token",g),l&&f("workspace",l),a.writeHead(200,{"Content-Type":"text/html"}),a.end(`
5
+ <html>
6
+ <body style="background:#111;color:#eee;font-family:sans-serif;text-align:center;padding:50px;">
7
+ <h1>Login Successful</h1>
8
+ <p>You have successfully logged in to XtraSync.</p>
9
+ <p>You can now close this tab and return to your terminal.</p>
10
+ <script>
11
+ setTimeout(function() { window.close(); }, 1000);
12
+ </script>
13
+ </body>
14
+ </html>
15
+ `),console.log(y.default.green(`
16
+ \u2714 SS0 Login Successful! Logged in as ${d}`)),l&&console.log(y.default.dim(`Selected Workspace: ${B} (${l})`));try{let{logAudit:D}=await Promise.resolve().then(()=>(I(),A));D("USER_LOGIN",null,null,{method:"sso",email:d,workspaceId:l,workspaceName:B})}catch{}a.end(()=>{n.close(),setTimeout(()=>{process.exit(0)},1e3)})}else a.writeHead(400),a.end("Missing token")});n.listen(0,async()=>{let r=n.address(),p=`http://localhost:${typeof r=="string"?0:r?.port}`,{apiUrl:g}=(S(),K(q)).getConfig();g.includes("localhost")&&(g="https://www.xtrasecurity.in/api");let d=`${g}/auth/cli/sso?callbackUrl=${encodeURIComponent(p)}`;console.log(y.default.blue(`Waiting for browser login... (Opening ${d})`)),await t(d)})})}0&&(module.exports={loginCommand});
@@ -1,51 +1,16 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const login_1 = require("./login");
7
- const api_1 = require("../lib/api");
8
- const config_1 = require("../lib/config");
9
- const inquirer_1 = __importDefault(require("inquirer"));
10
- // Mock dependencies
11
- jest.mock('../lib/api');
12
- jest.mock('../lib/config');
13
- jest.mock('inquirer');
14
- jest.mock('ora', () => {
15
- return jest.fn(() => ({
16
- start: jest.fn().mockReturnThis(),
17
- succeed: jest.fn().mockReturnThis(),
18
- fail: jest.fn().mockReturnThis(),
19
- }));
20
- });
21
- describe('Login Command', () => {
22
- const mockApi = api_1.api;
23
- const mockInquirer = inquirer_1.default;
24
- beforeEach(() => {
25
- jest.clearAllMocks();
26
- });
27
- it('should login with API key option', async () => {
28
- mockApi.login.mockResolvedValue({ token: 'test-token-from-key' });
29
- // Simulate command execution with --key option
30
- const mockOptions = { key: 'xtra_key_abc123' };
31
- // Execute the action handler directly
32
- await login_1.loginCommand._actionHandler(mockOptions);
33
- expect(mockApi.login).toHaveBeenCalledWith(undefined, undefined, 'xtra_key_abc123');
34
- expect(config_1.setConfig).toHaveBeenCalledWith('token', 'test-token-from-key');
35
- });
36
- it('should prompt for email and password if no options provided', async () => {
37
- mockInquirer.prompt
38
- .mockResolvedValueOnce({ method: 'email' })
39
- .mockResolvedValueOnce({ email: 'test@example.com' })
40
- .mockResolvedValueOnce({ password: 'password123' });
41
- mockApi.login.mockResolvedValue({ token: 'email-token' });
42
- await login_1.loginCommand._actionHandler({});
43
- expect(mockInquirer.prompt).toHaveBeenCalledTimes(3);
44
- expect(mockApi.login).toHaveBeenCalledWith('test@example.com', 'password123', undefined);
45
- });
46
- it('should handle login failure gracefully', async () => {
47
- mockApi.login.mockRejectedValue(new Error('Invalid credentials'));
48
- const mockOptions = { key: 'bad-key' };
49
- await expect(login_1.loginCommand._actionHandler(mockOptions)).rejects.toThrow('Invalid credentials');
50
- });
51
- });
1
+ var ie=Object.create;var x=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var ge=Object.getPrototypeOf,le=Object.prototype.hasOwnProperty;var j=(e,t)=>()=>(e&&(t=e(e=0)),t);var q=(e,t)=>{for(var s in t)x(e,s,{get:t[s],enumerable:!0})},D=(e,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of pe(t))!le.call(e,r)&&r!==s&&x(e,r,{get:()=>t[r],enumerable:!(n=ce(t,r))||n.enumerable});return e};var c=(e,t,s)=>(s=e!=null?ie(ge(e)):{},D(t||!e||!e.__esModule?x(s,"default",{value:e,enumerable:!0}):s,e)),de=e=>D(x({},"__esModule",{value:!0}),e);var K={};q(K,{clearConfig:()=>me,deleteConfig:()=>ye,getAuthToken:()=>O,getBreakGlassSession:()=>fe,getConfig:()=>y,getConfigValue:()=>ue,getProjectConfig:()=>we,getRcConfig:()=>ke,setBreakGlassSession:()=>he,setConfig:()=>d});var G,m,_,U,i,R,y,ue,d,me,ye,O,fe,he,we,ke,w=j(()=>{G=c(require("conf")),m=c(require("fs")),_=c(require("path")),U="https://www.xtrasecurity.in/api",i=new G.default({projectName:"xtra-cli",defaults:{apiUrl:U}}),R=i.get("apiUrl");R&&!process.env.XTRA_API_URL&&(R.includes("localhost")||R.includes("xtra-security.vercel.app"))&&i.set("apiUrl",U);y=()=>({...i.store,apiUrl:process.env.XTRA_API_URL||i.get("apiUrl")||U}),ue=e=>i.get(e),d=(e,t)=>{if(i.set(e,t),e==="token"&&process.platform!=="win32"&&m.default.existsSync(i.path))try{m.default.chmodSync(i.path,384)}catch{}},me=()=>i.clear(),ye=e=>i.delete(e),O=()=>i.get("token"),fe=()=>i.get("breakGlassSessionId"),he=e=>{e?i.set("breakGlassSessionId",e):i.delete("breakGlassSessionId")},we=async()=>{try{let e=_.default.join(process.cwd(),"xtra.json");if(m.default.existsSync(e)){let t=m.default.readFileSync(e,"utf-8");return JSON.parse(t)}return null}catch{return null}},ke=()=>{let e={};try{let t=_.default.join(process.cwd(),".xtrarc");m.default.existsSync(t)&&(e=JSON.parse(m.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||i.get("project")||"",env:e.env||i.get("env")||"development",branch:e.branch||i.get("branch")||"main"}}});var V,J,F,ve,o,f,b=j(()=>{V=c(require("axios"));w();J=c(require("fs")),F=c(require("path")),ve=JSON.parse(J.readFileSync(F.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:e}=y(),t=O();return V.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":ve.version,...t?{Authorization:`Bearer ${t}`}:{}}})},f={login:async(e,t,s)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,n,r="main")=>(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:n,branch:r})).data,getSecretDetails:async(e,t,s,n="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}?branch=${n}`)).data,syncLogs:async e=>(await o().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,s,n,r,a)=>(await o().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:n,sourceEnv:r,sourceKey:a})).data,rotateSecret:async(e,t,s,n,r)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:n,parsedNewValue:r})).data,promoteSecret:async(e,t,s)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(e,t,s,n)=>{let r={format:e};return t&&(r.startDate=t),s&&(r.endDate=s),n&&(r.projectId=n),(await o().post("/audit/export",r,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,s,n)=>(await o().post("/access/request",{projectId:e,secretId:n,reason:t,duration:s})).data,approveAccess:async(e,t)=>(await o().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=y(),s=t?`&workspaceId=${t}`:"";return(await o().get(`/access/list?mode=${e}${s}`)).data},getAccessRequestStatus:async e=>(await o().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=y(),t=e?`/project?workspaceId=${e}`:"/project";return(await o().get(t)).data},getBranches:async e=>(await o().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,s)=>(await o().post("/branch",{projectId:e,name:t,description:s})).data,deleteBranch:async e=>(await o().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await o().put("/branch",{id:e,...t})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await o().get(`/admin/users${t}`)).data},setUserRole:async(e,t,s)=>(await o().put("/admin/users/role",{email:e,role:t,teamId:s})).data,getIntegrationStatus:async e=>(await o().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await o().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await o().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,t)=>{let s=new URLSearchParams(t).toString();return(await o().get(`/projects/${e}/kubernetes?${s}`)).data},getSecretHistory:async(e,t,s)=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}/history`)).data,rollbackSecret:async(e,t,s,n)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/history`,{version:n})).data,cloneEnvironment:async(e,t,s,n,r)=>(await o().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,overwrite:n,branch:r})).data,generateJitLink:async e=>(await o().post("/jit/generate",e)).data,claimJitLink:async e=>(await o().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await o().get(`/jit/${e}`)).data,post:async(e,t)=>(await o().post(e,t)).data}});function Y(){let e=M.get("masterKey");e||(e=k.default.randomBytes(32).toString("hex"),M.set("masterKey",e));let t=(0,X.machineIdSync)();return k.default.createHash("sha256").update(e+t).digest()}var k,W,X,z,M,Q,Z,ee=j(()=>{k=c(require("crypto")),W=c(require("conf")),X=require("node-machine-id"),z="aes-256-gcm",M=new W.default({projectName:"xtra-cli-crypto"});Q=e=>{let t=k.default.randomBytes(16),s=Y(),n=k.default.createCipheriv(z,s,t),r=n.update(e,"utf8","hex");r+=n.final("hex");let a=n.getAuthTag();return{iv:t.toString("hex"),content:r,tag:a.toString("hex")}},Z=e=>{let t=Y(),s=Buffer.from(e.iv,"hex"),n=Buffer.from(e.tag,"hex"),r=k.default.createDecipheriv(z,t,s);r.setAuthTag(n);let a=r.update(e.content,"hex","utf8");return a+=r.final("utf8"),a}});var A={};q(A,{loadAuditLogs:()=>$,logAudit:()=>xe,saveAuditLogs:()=>I,syncAuditLogs:()=>je});function Se(e){if(!e||typeof e!="object")return e;let t={...e},s=["password","token","secret","value","apiKey","secretValue"];for(let n of Object.keys(t))s.some(r=>n.toLowerCase().includes(r))&&(t[n]="[REDACTED]");return t}async function se(e){try{if(!y().token)return!1;let s={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:Se(e.details),timestamp:e.timestamp,projectId:e.projectId};return await f.post("/audit/cli-logs",{logs:[s]}),!0}catch(t){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",t),!1}}function xe(e,t,s,n){let r={id:(0,te.v4)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:s,details:n,synced:!1},a=$();a.push(r),I(a),se(r).then(p=>{if(p){r.synced=!0;let g=$(),l=g.findIndex(u=>u.id===r.id);l!==-1&&(g[l].synced=!0,I(g))}}).catch(()=>{})}function $(){if(!v.default.existsSync(T))return[];try{let e=v.default.readFileSync(T,"utf-8"),t=JSON.parse(e),s=Z(t);return JSON.parse(s)}catch{return[]}}function I(e){v.default.existsSync(E)||v.default.mkdirSync(E,{recursive:!0});let t=JSON.stringify(e),s=Q(t);v.default.writeFileSync(T,JSON.stringify(s),"utf-8")}async function je(){let e=$(),t=e.filter(n=>!n.synced);if(t.length===0)return 0;let s=0;for(let n of t)await se(n)&&(n.synced=!0,s++);return s>0&&I(e),s}var v,P,te,E,T,C=j(()=>{v=c(require("fs")),P=c(require("path")),te=require("uuid");ee();w();b();E=P.default.join(process.cwd(),".xtra"),T=P.default.join(E,"audit.enc")});var oe=require("commander"),S=c(require("inquirer"));b();w();var h=c(require("chalk")),B=c(require("ora")),L=new oe.Command("login").description("Authenticate with XtraSecurity").option("-k, --key <key>","Login using an Access Key").option("-e, --email <email>","Login using Email").option("--sso","Login via Web (SSO)").action(async e=>{try{if(!e.key&&!e.email&&!e.sso){let{method:t}=await S.default.prompt([{type:"list",name:"method",message:"How would you like to login?",choices:[{name:"Browser Login (SSO)",value:"sso"},{name:"Access Key",value:"key"},{name:"Email & Password",value:"email"}]}]);if(t==="sso"){await re();return}else if(t==="key"){let{key:s}=await S.default.prompt([{type:"password",name:"key",message:"Enter Access Key:"}]);await ne(s);return}}if(e.sso)await re();else if(e.key)await ne(e.key);else{let{email:t}=e;t||(t=(await S.default.prompt([{type:"input",name:"email",message:"Email:"}])).email);let n=(await S.default.prompt([{type:"password",name:"password",message:"Password:"}])).password,r=(0,B.default)("Authenticating...").start(),a=await f.login(t,n);d("token",a.token),r.succeed("Logged in successfully!");try{let{logAudit:p}=await Promise.resolve().then(()=>(C(),A));p("USER_LOGIN",null,null,{method:"email",email:t})}catch{}}}catch(t){t.response?console.error(h.default.red(`
2
+ Error: ${t.response.data.error||"Login failed"}`)):console.error(h.default.red(`
3
+ Error: ${t.message}`)),process.exit(1)}});async function ne(e){let t=(0,B.default)("Authenticating with Access Key...").start(),s=await f.login(void 0,void 0,e);d("token",s.token),s.user&&console.log(h.default.green(`
4
+ Logged in as ${s.user.email}`)),t.succeed("Logged in successfully!");try{let{logAudit:n}=await Promise.resolve().then(()=>(C(),A));n("USER_LOGIN",null,null,{method:"api_key",email:s.user?.email})}catch{}}async function re(){let e=require("http"),{default:t}=await import("open");return new Promise(s=>{let n=e.createServer(async(r,a)=>{let p=new URL(r.url,`http://${r.headers.host}`),g=p.searchParams.get("token"),l=p.searchParams.get("email"),u=p.searchParams.get("workspaceId"),N=p.searchParams.get("workspaceName");if(g){d("token",g),u&&d("workspace",u),a.writeHead(200,{"Content-Type":"text/html"}),a.end(`
5
+ <html>
6
+ <body style="background:#111;color:#eee;font-family:sans-serif;text-align:center;padding:50px;">
7
+ <h1>Login Successful</h1>
8
+ <p>You have successfully logged in to XtraSync.</p>
9
+ <p>You can now close this tab and return to your terminal.</p>
10
+ <script>
11
+ setTimeout(function() { window.close(); }, 1000);
12
+ </script>
13
+ </body>
14
+ </html>
15
+ `),console.log(h.default.green(`
16
+ \u2714 SS0 Login Successful! Logged in as ${l}`)),u&&console.log(h.default.dim(`Selected Workspace: ${N} (${u})`));try{let{logAudit:H}=await Promise.resolve().then(()=>(C(),A));H("USER_LOGIN",null,null,{method:"sso",email:l,workspaceId:u,workspaceName:N})}catch{}a.end(()=>{n.close(),setTimeout(()=>{process.exit(0)},1e3)})}else a.writeHead(400),a.end("Missing token")});n.listen(0,async()=>{let r=n.address(),p=`http://localhost:${typeof r=="string"?0:r?.port}`,{apiUrl:g}=(w(),de(K)).getConfig();g.includes("localhost")&&(g="https://www.xtrasecurity.in/api");let l=`${g}/auth/cli/sso?callbackUrl=${encodeURIComponent(p)}`;console.log(h.default.blue(`Waiting for browser login... (Opening ${l})`)),await t(l)})})}b();w();var ae=c(require("inquirer"));jest.mock("../lib/api");jest.mock("../lib/config");jest.mock("inquirer");jest.mock("ora",()=>jest.fn(()=>({start:jest.fn().mockReturnThis(),succeed:jest.fn().mockReturnThis(),fail:jest.fn().mockReturnThis()})));describe("Login Command",()=>{let e=f,t=ae.default;beforeEach(()=>{jest.clearAllMocks()}),it("should login with API key option",async()=>{e.login.mockResolvedValue({token:"test-token-from-key"});let s={key:"xtra_key_abc123"};await L._actionHandler(s),expect(e.login).toHaveBeenCalledWith(void 0,void 0,"xtra_key_abc123"),expect(d).toHaveBeenCalledWith("token","test-token-from-key")}),it("should prompt for email and password if no options provided",async()=>{t.prompt.mockResolvedValueOnce({method:"email"}).mockResolvedValueOnce({email:"test@example.com"}).mockResolvedValueOnce({password:"password123"}),e.login.mockResolvedValue({token:"email-token"}),await L._actionHandler({}),expect(t.prompt).toHaveBeenCalledTimes(3),expect(e.login).toHaveBeenCalledWith("test@example.com","password123",void 0)}),it("should handle login failure gracefully",async()=>{e.login.mockRejectedValue(new Error("Invalid credentials"));let s={key:"bad-key"};await expect(L._actionHandler(s)).rejects.toThrow("Invalid credentials")})});
@@ -0,0 +1 @@
1
+ var y=Object.create;var c=Object.defineProperty;var x=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var S=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty;var b=(e,t)=>{for(var o in t)c(e,o,{get:t[o],enumerable:!0})},f=(e,t,o,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of k(t))!C.call(e,n)&&n!==o&&c(e,n,{get:()=>t[n],enumerable:!(s=x(t,n))||s.enumerable});return e};var i=(e,t,o)=>(o=e!=null?y(S(e)):{},f(t||!e||!e.__esModule?c(o,"default",{value:e,enumerable:!0}):o,e)),j=e=>f(c({},"__esModule",{value:!0}),e);var v={};b(v,{logoutCommand:()=>U});module.exports=j(v);var u=require("commander"),a=i(require("chalk")),m=i(require("ora"));var h=i(require("conf"));var g="https://www.xtrasecurity.in/api",r=new h.default({projectName:"xtra-cli",defaults:{apiUrl:g}}),l=r.get("apiUrl");l&&!process.env.XTRA_API_URL&&(l.includes("localhost")||l.includes("xtra-security.vercel.app"))&&r.set("apiUrl",g);var d=()=>({...r.store,apiUrl:process.env.XTRA_API_URL||r.get("apiUrl")||g});var p=e=>r.delete(e);var U=new u.Command("logout").description("Logout and clear all local credentials and caches").action(async()=>{let e=(0,m.default)("Logging out...").start();try{p("token");let t=d(),s=Object.keys(t).filter(n=>n.startsWith("cache."));for(let n of s)p(n);e.succeed(a.default.green("\u2714 Successfully logged out.")),console.log(a.default.gray("Local authentication token and secret caches have been purged."))}catch(t){e.fail(a.default.red(`Logout failed: ${t.message}`))}});0&&(module.exports={logoutCommand});
@@ -1,121 +1,3 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.logsCommand = void 0;
7
- const commander_1 = require("commander");
8
- const audit_1 = require("../lib/audit");
9
- const chalk_1 = __importDefault(require("chalk"));
10
- const table_1 = require("table");
11
- exports.logsCommand = new commander_1.Command("logs")
12
- .description("View local audit logs")
13
- .option("-n, --limit <number>", "Number of logs to show", "20")
14
- .option("--sync", "Sync logs to cloud", false)
15
- .option("--event <type>", "Filter by event type (e.g. SECRET_UPDATE, SECRET_ROTATE)")
16
- .option("--project <projectId>", "Filter by project ID")
17
- .option("--since <duration>", "Show logs since (e.g. 1h, 24h, 7d, 30d)", "")
18
- .option("--json", "Output raw JSON instead of table", false)
19
- .action(async (options) => {
20
- const { limit, sync, event: eventFilter, project: projectFilter, since, json: jsonOut } = options;
21
- try {
22
- let logs = (0, audit_1.loadAuditLogs)();
23
- if (sync) {
24
- const unsynced = logs.filter(l => !l.synced);
25
- if (unsynced.length === 0) {
26
- console.log(chalk_1.default.green("All logs are already synced."));
27
- return;
28
- }
29
- const spinner = require("ora")(`Syncing ${unsynced.length} logs to cloud...`).start();
30
- try {
31
- const { api } = require("../lib/api");
32
- const { saveAuditLogs } = require("../lib/audit");
33
- await api.syncLogs(unsynced);
34
- unsynced.forEach(l => l.synced = true);
35
- saveAuditLogs(logs);
36
- spinner.succeed(`Successfully synced ${unsynced.length} logs.`);
37
- }
38
- catch (err) {
39
- spinner.fail("Sync failed.");
40
- console.error(chalk_1.default.red(err.message));
41
- }
42
- return;
43
- }
44
- if (logs.length === 0) {
45
- console.log(chalk_1.default.yellow("No local audit logs found."));
46
- return;
47
- }
48
- // ── Filtering ─────────────────────────────────────────────────────────
49
- // Filter by event type
50
- if (eventFilter) {
51
- const upper = eventFilter.toUpperCase();
52
- logs = logs.filter(l => l.action?.toUpperCase().includes(upper));
53
- }
54
- // Filter by project
55
- if (projectFilter) {
56
- logs = logs.filter(l => l.projectId === projectFilter);
57
- }
58
- // Filter by --since duration (1h, 6h, 24h, 7d, 30d)
59
- if (since) {
60
- const match = since.match(/^(\d+)(h|d|m)$/i);
61
- if (!match) {
62
- console.error(chalk_1.default.red(`Invalid --since format: '${since}'. Use e.g. 1h, 24h, 7d, 30d`));
63
- process.exit(1);
64
- }
65
- const amount = parseInt(match[1]);
66
- const unit = match[2].toLowerCase();
67
- const msMap = { h: 3600000, d: 86400000, m: 60000 };
68
- const cutoff = new Date(Date.now() - amount * msMap[unit]);
69
- logs = logs.filter(l => new Date(l.timestamp) >= cutoff);
70
- }
71
- // Sort newest first
72
- logs.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
73
- const limitedLogs = logs.slice(0, parseInt(limit));
74
- if (limitedLogs.length === 0) {
75
- console.log(chalk_1.default.yellow("No logs matched your filters."));
76
- return;
77
- }
78
- // ── Output ────────────────────────────────────────────────────────────
79
- if (jsonOut) {
80
- process.stdout.write(JSON.stringify(limitedLogs, null, 2) + "\n");
81
- return;
82
- }
83
- const data = [
84
- [chalk_1.default.bold("Timestamp"), chalk_1.default.bold("Action"), chalk_1.default.bold("Project"), chalk_1.default.bold("Sync"), chalk_1.default.bold("Details")]
85
- ];
86
- limitedLogs.forEach(l => {
87
- let details = "";
88
- if (l.details) {
89
- if (l.details.keys)
90
- details = `Keys: ${l.details.keys.join(", ")}`;
91
- else if (l.details.key)
92
- details = `Key: ${l.details.key}`;
93
- else
94
- details = JSON.stringify(l.details);
95
- }
96
- const proj = l.projectId ? l.projectId.substring(0, 8) + "..." : "-";
97
- data.push([
98
- new Date(l.timestamp).toLocaleString(),
99
- l.action,
100
- proj,
101
- l.synced ? chalk_1.default.green("✔") : chalk_1.default.yellow("✖"),
102
- details.substring(0, 50) + (details.length > 50 ? "..." : "")
103
- ]);
104
- });
105
- // Show active filters in header
106
- const filterParts = [];
107
- if (eventFilter)
108
- filterParts.push(`event: ${eventFilter.toUpperCase()}`);
109
- if (projectFilter)
110
- filterParts.push(`project: ${projectFilter}`);
111
- if (since)
112
- filterParts.push(`since: ${since}`);
113
- const filterHint = filterParts.length > 0 ? chalk_1.default.gray(` [${filterParts.join(" | ")}]`) : "";
114
- console.log(chalk_1.default.bold(`\nLocal Audit Logs${filterHint}`));
115
- console.log((0, table_1.table)(data));
116
- console.log(chalk_1.default.gray(` Showing ${limitedLogs.length} of ${logs.length} total logs.`));
117
- }
118
- catch (error) {
119
- console.error(chalk_1.default.red("Failed to load logs: " + error.message));
120
- }
121
- });
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 A=(t,e)=>{for(var s in e)$(t,s,{get:e[s],enumerable:!0})},B=(t,e,s,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of ct(e))!gt.call(t,r)&&r!==s&&$(t,r,{get:()=>e[r],enumerable:!(n=at(e,r))||n.enumerable});return t};var l=(t,e,s)=>(s=t!=null?it(pt(t)):{},B(e||!t||!t.__esModule?$(s,"default",{value:t,enumerable:!0}):s,t)),C=t=>B($({},"__esModule",{value:!0}),t);function G(){let t=_.get("masterKey");t||(t=y.default.randomBytes(32).toString("hex"),_.set("masterKey",t));let e=(0,J.machineIdSync)();return y.default.createHash("sha256").update(t+e).digest()}var y,F,J,q,_,K,V,H=b(()=>{y=l(require("crypto")),F=l(require("conf")),J=require("node-machine-id"),q="aes-256-gcm",_=new F.default({projectName:"xtra-cli-crypto"});K=t=>{let e=y.default.randomBytes(16),s=G(),n=y.default.createCipheriv(q,s,e),r=n.update(t,"utf8","hex");r+=n.final("hex");let a=n.getAuthTag();return{iv:e.toString("hex"),content:r,tag:a.toString("hex")}},V=t=>{let e=G(),s=Buffer.from(t.iv,"hex"),n=Buffer.from(t.tag,"hex"),r=y.default.createDecipheriv(q,e,s);r.setAuthTag(n);let a=r.update(t.content,"hex","utf8");return a+=r.final("utf8"),a}});var z,U,j,L,f,M,R=b(()=>{z=l(require("conf")),U="https://www.xtrasecurity.in/api",j=new z.default({projectName:"xtra-cli",defaults:{apiUrl:U}}),L=j.get("apiUrl");L&&!process.env.XTRA_API_URL&&(L.includes("localhost")||L.includes("xtra-security.vercel.app"))&&j.set("apiUrl",U);f=()=>({...j.store,apiUrl:process.env.XTRA_API_URL||j.get("apiUrl")||U}),M=()=>j.get("token")});var Y={};A(Y,{api:()=>T});var X,Q,W,dt,o,T,D=b(()=>{X=l(require("axios"));R();Q=l(require("fs")),W=l(require("path")),dt=JSON.parse(Q.readFileSync(W.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:t}=f(),e=M();return X.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":dt.version,...e?{Authorization:`Bearer ${e}`}:{}}})},T={login:async(t,e,s)=>(await o().post("/auth/cli-login",{email:t,password:e,apiKey:s})).data,getSecrets:async(t,e,s="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets?branch=${s}`)).data,getSecretVersions:async(t,e,s="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(t,e,s,n,r="main")=>(await o().post(`/projects/${t}/envs/${e}/secrets`,{secrets:s,expectedVersions:n,branch:r})).data,getSecretDetails:async(t,e,s,n="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets/${s}?branch=${n}`)).data,syncLogs:async t=>(await o().post("/audit/cli-logs",{logs:t})).data,linkSecret:async(t,e,s,n,r,a)=>(await o().post(`/projects/${t}/envs/${e}/secrets/link`,{key:s,sourceProjectId:n,sourceEnv:r,sourceKey:a})).data,rotateSecret:async(t,e,s,n,r)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/rotate`,{strategy:n,parsedNewValue:r})).data,promoteSecret:async(t,e,s)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(t,e,s,n)=>{let r={format:t};return e&&(r.startDate=e),s&&(r.endDate=s),n&&(r.projectId=n),(await o().post("/audit/export",r,{responseType:t==="csv"?"text":"json"})).data},requestAccess:async(t,e,s,n)=>(await o().post("/access/request",{projectId:t,secretId:n,reason:e,duration:s})).data,approveAccess:async(t,e)=>(await o().post("/access/approve",{requestId:t,decision:e})).data,listAccessRequests:async t=>{let{workspace:e}=f(),s=e?`&workspaceId=${e}`:"";return(await o().get(`/access/list?mode=${t}${s}`)).data},getAccessRequestStatus:async t=>(await o().get(`/access/request?id=${t}`)).data,getProjects:async()=>{let{workspace:t}=f(),e=t?`/project?workspaceId=${t}`:"/project";return(await o().get(e)).data},getBranches:async t=>(await o().get(`/branch?projectId=${t}`)).data,createBranch:async(t,e,s)=>(await o().post("/branch",{projectId:t,name:e,description:s})).data,deleteBranch:async t=>(await o().delete(`/branch/${t}`)).data,updateBranch:async(t,e)=>(await o().put("/branch",{id:t,...e})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async t=>{let e=t?`?teamId=${t}`:"";return(await o().get(`/admin/users${e}`)).data},setUserRole:async(t,e,s)=>(await o().put("/admin/users/role",{email:t,role:e,teamId:s})).data,getIntegrationStatus:async t=>(await o().get(`/integrations/${t}`)).data,getIntegrationRepos:async t=>(await o().get(`/integrations/${t}/sync`)).data.repos,syncSecretsToGithub:async t=>(await o().post("/integrations/github/sync",t)).data,exportKubernetesSecret:async(t,e)=>{let s=new URLSearchParams(e).toString();return(await o().get(`/projects/${t}/kubernetes?${s}`)).data},getSecretHistory:async(t,e,s)=>(await o().get(`/projects/${t}/envs/${e}/secrets/${s}/history`)).data,rollbackSecret:async(t,e,s,n)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/history`,{version:n})).data,cloneEnvironment:async(t,e,s,n,r)=>(await o().post(`/projects/${t}/envs/clone`,{fromEnv:e,toEnv:s,overwrite:n,branch:r})).data,generateJitLink:async t=>(await o().post("/jit/generate",t)).data,claimJitLink:async t=>(await o().post("/jit/claim",{token:t})).data,getJitInfo:async t=>(await o().get(`/jit/${t}`)).data,post:async(t,e)=>(await o().post(t,e)).data}});var et={};A(et,{loadAuditLogs:()=>h,logAudit:()=>ut,saveAuditLogs:()=>x,syncAuditLogs:()=>yt});function lt(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:lt(t.details),timestamp:t.timestamp,projectId:t.projectId};return await T.post("/audit/cli-logs",{logs:[s]}),!0}catch(e){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",e),!1}}function ut(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(),u=c.findIndex(v=>v.id===r.id);u!==-1&&(c[u].synced=!0,x(c))}}).catch(()=>{})}function h(){if(!m.default.existsSync(E))return[];try{let t=m.default.readFileSync(E,"utf-8"),e=JSON.parse(t),s=V(e);return JSON.parse(s)}catch{return[]}}function x(t){m.default.existsSync(O)||m.default.mkdirSync(O,{recursive:!0});let e=JSON.stringify(t),s=K(e);m.default.writeFileSync(E,JSON.stringify(s),"utf-8")}async function yt(){let t=h(),e=t.filter(n=>!n.synced);if(e.length===0)return 0;let s=0;for(let n of e)await tt(n)&&(n.synced=!0,s++);return s>0&&x(t),s}var m,N,Z,O,E,P=b(()=>{m=l(require("fs")),N=l(require("path")),Z=require("uuid");H();R();D();O=N.default.join(process.cwd(),".xtra"),E=N.default.join(O,"audit.enc")});var mt={};A(mt,{logsCommand:()=>ft});module.exports=C(mt);var st=require("commander");P();var p=l(require("chalk")),nt=require("table"),ft=new st.Command("logs").description("View local audit logs").option("-n, --limit <number>","Number of logs to show","20").option("--sync","Sync logs to cloud",!1).option("--event <type>","Filter by event type (e.g. SECRET_UPDATE, SECRET_ROTATE)").option("--project <projectId>","Filter by project ID").option("--since <duration>","Show logs since (e.g. 1h, 24h, 7d, 30d)","").option("--json","Output raw JSON instead of table",!1).action(async t=>{let{limit:e,sync:s,event:n,project:r,since:a,json:S}=t;try{let c=h();if(s){let i=c.filter(d=>!d.synced);if(i.length===0){console.log(p.default.green("All logs are already synced."));return}let g=require("ora")(`Syncing ${i.length} logs to cloud...`).start();try{let{api:d}=(D(),C(Y)),{saveAuditLogs:k}=(P(),C(et));await d.syncLogs(i),i.forEach(I=>I.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},I=new Date(Date.now()-g*k[d]);c=c.filter(ot=>new Date(ot.timestamp)>=I)}c.sort((i,g)=>new Date(g.timestamp).getTime()-new Date(i.timestamp).getTime());let u=c.slice(0,parseInt(e));if(u.length===0){console.log(p.default.yellow("No logs matched your filters."));return}if(S){process.stdout.write(JSON.stringify(u,null,2)+`
2
+ `);return}let v=[[p.default.bold("Timestamp"),p.default.bold("Action"),p.default.bold("Project"),p.default.bold("Sync"),p.default.bold("Details")]];u.forEach(i=>{let g="";i.details&&(i.details.keys?g=`Keys: ${i.details.keys.join(", ")}`:i.details.key?g=`Key: ${i.details.key}`:g=JSON.stringify(i.details));let d=i.projectId?i.projectId.substring(0,8)+"...":"-";v.push([new Date(i.timestamp).toLocaleString(),i.action,d,i.synced?p.default.green("\u2714"):p.default.yellow("\u2716"),g.substring(0,50)+(g.length>50?"...":"")])});let w=[];n&&w.push(`event: ${n.toUpperCase()}`),r&&w.push(`project: ${r}`),a&&w.push(`since: ${a}`);let rt=w.length>0?p.default.gray(` [${w.join(" | ")}]`):"";console.log(p.default.bold(`
3
+ Local Audit Logs${rt}`)),console.log((0,nt.table)(v)),console.log(p.default.gray(` Showing ${u.length} of ${c.length} total logs.`))}catch(c){console.error(p.default.red("Failed to load logs: "+c.message))}});0&&(module.exports={logsCommand});