xtra-cli 1.0.3 → 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 +3 -137
  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 +7 -2
@@ -1,164 +1,2 @@
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.doctorCommand = void 0;
40
- /**
41
- * doctor.ts — Diagnose common xtra-cli setup issues
42
- */
43
- const commander_1 = require("commander");
44
- const chalk_1 = __importDefault(require("chalk"));
45
- const fs = __importStar(require("fs"));
46
- const path = __importStar(require("path"));
47
- const axios_1 = __importDefault(require("axios"));
48
- const config_1 = require("../lib/config");
49
- // ─── Box Drawing Helpers ─────────────────────────────────────────────────────
50
- const W = 65;
51
- const B = { tl: "╭", tr: "╮", bl: "╰", br: "╯", h: "─", v: "│" };
52
- function hline(w) { return B.h.repeat(w); }
53
- const PASS = chalk_1.default.green("✓ ");
54
- const FAIL = chalk_1.default.red("✗ ");
55
- const WARN = chalk_1.default.yellow("⚠ ");
56
- async function runChecks() {
57
- const checks = [];
58
- const config = (0, config_1.getConfig)();
59
- // 1. Node Version
60
- const nodeMajor = parseInt(process.versions.node.split(".")[0]);
61
- checks.push({
62
- name: "Node.js Version",
63
- status: nodeMajor >= 18 ? "pass" : "fail",
64
- message: `v${process.versions.node} ${nodeMajor >= 18 ? "(OK)" : "(requires >=18)"}`,
65
- });
66
- // 2. Auth Token
67
- const token = (0, config_1.getAuthToken)();
68
- checks.push({
69
- name: "Auth Token",
70
- status: token ? "pass" : "fail",
71
- message: token ? `Set (${token.substring(0, 8)}...)` : "Not set — run 'xtra login'",
72
- });
73
- // 3. API URL Configured
74
- const apiUrl = config.apiUrl || process.env.XTRA_API_URL || "https://www.xtrasecurity.in/api";
75
- checks.push({
76
- name: "API URL",
77
- status: config.apiUrl || process.env.XTRA_API_URL ? "pass" : "warn",
78
- message: apiUrl,
79
- });
80
- // 4. API Reachability
81
- try {
82
- const res = await axios_1.default.get(`${apiUrl}/health`, { timeout: 4000 });
83
- checks.push({
84
- name: "API Connectivity",
85
- status: res.status === 200 ? "pass" : "warn",
86
- message: `${res.status} ${res.statusText}`,
87
- });
88
- }
89
- catch (e) {
90
- const msg = e.code === "ECONNREFUSED" ? "Connection refused (offline?)"
91
- : e.code === "ETIMEDOUT" ? "Timed out (unreachable)"
92
- : e.response?.status === 404 ? "API reachable (health endpoint missing)"
93
- : e.message;
94
- // Special case: if it hits a 404 it means DNS and port work, but route is missing
95
- const status = e.response?.status === 404 ? "pass" : "fail";
96
- checks.push({ name: "API Connectivity", status, message: msg });
97
- }
98
- // 5. Active Project
99
- const project = (0, config_1.getRcConfig)().project;
100
- checks.push({
101
- name: "Active Project",
102
- status: project ? "pass" : "warn",
103
- message: project ? project : "Not set — run 'xtra project set <id>'",
104
- });
105
- // 6. Active Branch
106
- const branch = (0, config_1.getRcConfig)().branch || "main";
107
- checks.push({
108
- name: "Active Branch",
109
- status: "pass",
110
- message: branch,
111
- });
112
- // 7. Config files
113
- const rcPath = path.join(process.cwd(), ".xtrarc");
114
- const jsonPath = path.join(process.cwd(), "xtra.json");
115
- const hasConfig = fs.existsSync(rcPath) || fs.existsSync(jsonPath);
116
- checks.push({
117
- name: "Project Config",
118
- status: hasConfig ? "pass" : "warn",
119
- message: hasConfig ? (fs.existsSync(rcPath) ? ".xtrarc found" : "xtra.json found") : "Not found (run 'xtra init')",
120
- });
121
- return checks;
122
- }
123
- exports.doctorCommand = new commander_1.Command("doctor")
124
- .description("Diagnose CLI configuration and API connectivity")
125
- .option("--json", "Output results as JSON", false)
126
- .action(async (options) => {
127
- if (!options.json) {
128
- console.log();
129
- console.log(chalk_1.default.bold.cyan(" ⚕ XtraSecurity Diagnostics"));
130
- console.log(chalk_1.default.hex("#4a5568")(" " + B.tl + hline(W) + B.tr));
131
- }
132
- const checks = await runChecks();
133
- if (options.json) {
134
- process.stdout.write(JSON.stringify(checks, null, 2) + "\n");
135
- return;
136
- }
137
- let failures = 0, warnings = 0;
138
- for (const c of checks) {
139
- if (c.status === "fail")
140
- failures++;
141
- if (c.status === "warn")
142
- warnings++;
143
- const icon = c.status === "pass" ? PASS : c.status === "warn" ? WARN : FAIL;
144
- const name = chalk_1.default.bold(chalk_1.default.white(c.name.padEnd(20)));
145
- const msg = c.status === "pass" ? chalk_1.default.hex("#94a3b8")(c.message)
146
- : c.status === "warn" ? chalk_1.default.yellow(c.message)
147
- : chalk_1.default.red(c.message);
148
- console.log(chalk_1.default.hex("#4a5568")(" " + B.v) + ` ${icon}${name} ${msg}`.padEnd(W) + chalk_1.default.hex("#4a5568")(B.v));
149
- }
150
- console.log(chalk_1.default.hex("#4a5568")(" " + B.bl + hline(W) + B.br));
151
- console.log();
152
- if (failures === 0 && warnings === 0) {
153
- console.log(chalk_1.default.green(" ✓ All systems operational. The CLI is ready to use."));
154
- }
155
- else {
156
- const parts = [];
157
- if (failures > 0)
158
- parts.push(chalk_1.default.red(`${failures} error(s)`));
159
- if (warnings > 0)
160
- parts.push(chalk_1.default.yellow(`${warnings} warning(s)`));
161
- console.log(` Found ${parts.join(" and ")}.`);
162
- }
163
- console.log();
164
- });
1
+ var _=Object.create;var u=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var L=Object.getPrototypeOf,E=Object.prototype.hasOwnProperty;var G=(s,e)=>{for(var o in e)u(s,o,{get:e[o],enumerable:!0})},j=(s,e,o,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of O(e))!E.call(s,t)&&t!==o&&u(s,t,{get:()=>e[t],enumerable:!(r=$(e,t))||r.enumerable});return s};var i=(s,e,o)=>(o=s!=null?_(L(s)):{},j(e||!s||!s.__esModule?u(o,"default",{value:s,enumerable:!0}):o,s)),D=s=>j(u({},"__esModule",{value:!0}),s);var V={};G(V,{doctorCommand:()=>M});module.exports=D(V);var P=require("commander"),n=i(require("chalk")),f=i(require("fs")),C=i(require("path")),U=i(require("axios"));var A=i(require("conf")),d=i(require("fs")),v=i(require("path")),x="https://www.xtrasecurity.in/api",c=new A.default({projectName:"xtra-cli",defaults:{apiUrl:x}}),m=c.get("apiUrl");m&&!process.env.XTRA_API_URL&&(m.includes("localhost")||m.includes("xtra-security.vercel.app"))&&c.set("apiUrl",x);var b=()=>({...c.store,apiUrl:process.env.XTRA_API_URL||c.get("apiUrl")||x});var k=()=>c.get("token");var y=()=>{let s={};try{let e=v.default.join(process.cwd(),".xtrarc");d.default.existsSync(e)&&(s=JSON.parse(d.default.readFileSync(e,"utf-8")))}catch{}return{project:s.project||c.get("project")||"",env:s.env||c.get("env")||"development",branch:s.branch||c.get("branch")||"main"}};var w=65,p={tl:"\u256D",tr:"\u256E",bl:"\u2570",br:"\u256F",h:"\u2500",v:"\u2502"};function I(s){return p.h.repeat(s)}var F=n.default.green("\u2713 "),X=n.default.red("\u2717 "),B=n.default.yellow("\u26A0 ");async function J(){let s=[],e=b(),o=parseInt(process.versions.node.split(".")[0]);s.push({name:"Node.js Version",status:o>=18?"pass":"fail",message:`v${process.versions.node} ${o>=18?"(OK)":"(requires >=18)"}`});let r=k();s.push({name:"Auth Token",status:r?"pass":"fail",message:r?`Set (${r.substring(0,8)}...)`:"Not set \u2014 run 'xtra login'"});let t=e.apiUrl||process.env.XTRA_API_URL||"https://www.xtrasecurity.in/api";s.push({name:"API URL",status:e.apiUrl||process.env.XTRA_API_URL?"pass":"warn",message:t});try{let a=await U.default.get(`${t}/health`,{timeout:4e3});s.push({name:"API Connectivity",status:a.status===200?"pass":"warn",message:`${a.status} ${a.statusText}`})}catch(a){let N=a.code==="ECONNREFUSED"?"Connection refused (offline?)":a.code==="ETIMEDOUT"?"Timed out (unreachable)":a.response?.status===404?"API reachable (health endpoint missing)":a.message,T=a.response?.status===404?"pass":"fail";s.push({name:"API Connectivity",status:T,message:N})}let l=y().project;s.push({name:"Active Project",status:l?"pass":"warn",message:l||"Not set \u2014 run 'xtra project set <id>'"});let h=y().branch||"main";s.push({name:"Active Branch",status:"pass",message:h});let g=C.join(process.cwd(),".xtrarc"),R=C.join(process.cwd(),"xtra.json"),S=f.existsSync(g)||f.existsSync(R);return s.push({name:"Project Config",status:S?"pass":"warn",message:S?f.existsSync(g)?".xtrarc found":"xtra.json found":"Not found (run 'xtra init')"}),s}var M=new P.Command("doctor").description("Diagnose CLI configuration and API connectivity").option("--json","Output results as JSON",!1).action(async s=>{s.json||(console.log(),console.log(n.default.bold.cyan(" \u2695 XtraSecurity Diagnostics")),console.log(n.default.hex("#4a5568")(" "+p.tl+I(w)+p.tr)));let e=await J();if(s.json){process.stdout.write(JSON.stringify(e,null,2)+`
2
+ `);return}let o=0,r=0;for(let t of e){t.status==="fail"&&o++,t.status==="warn"&&r++;let l=t.status==="pass"?F:t.status==="warn"?B:X,h=n.default.bold(n.default.white(t.name.padEnd(20))),g=t.status==="pass"?n.default.hex("#94a3b8")(t.message):t.status==="warn"?n.default.yellow(t.message):n.default.red(t.message);console.log(n.default.hex("#4a5568")(" "+p.v)+` ${l}${h} ${g}`.padEnd(w)+n.default.hex("#4a5568")(p.v))}if(console.log(n.default.hex("#4a5568")(" "+p.bl+I(w)+p.br)),console.log(),o===0&&r===0)console.log(n.default.green(" \u2713 All systems operational. The CLI is ready to use."));else{let t=[];o>0&&t.push(n.default.red(`${o} error(s)`)),r>0&&t.push(n.default.yellow(`${r} warning(s)`)),console.log(` Found ${t.join(" and ")}.`)}console.log()});0&&(module.exports={doctorCommand});
@@ -1,70 +1,2 @@
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.envCommand = void 0;
7
- const commander_1 = require("commander");
8
- const chalk_1 = __importDefault(require("chalk"));
9
- const api_1 = require("../lib/api");
10
- const config_1 = require("../lib/config");
11
- const inquirer_1 = __importDefault(require("inquirer"));
12
- exports.envCommand = new commander_1.Command("env");
13
- exports.envCommand
14
- .command("clone")
15
- .description("Clone secrets from one environment to another")
16
- .requiredOption("--from <env>", "Source environment (e.g. production)")
17
- .requiredOption("--to <env>", "Destination environment (e.g. staging)")
18
- .option("-p, --project <id>", "Project ID")
19
- .option("-b, --branch <name>", "Branch Name")
20
- .option("--overwrite", "Overwrite existing secrets", false)
21
- .action(async (options) => {
22
- try {
23
- let projectId = options.project;
24
- const branch = options.branch || (0, config_1.getRcConfig)().branch || "main";
25
- if (!projectId) {
26
- projectId = (0, config_1.getRcConfig)().project;
27
- if (!projectId) {
28
- console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
29
- process.exit(1);
30
- }
31
- }
32
- const fromEnv = options.from.toLowerCase();
33
- const toEnv = options.to.toLowerCase();
34
- if (fromEnv === toEnv) {
35
- console.error(chalk_1.default.red("Source and destination must be different."));
36
- process.exit(1);
37
- }
38
- console.log(chalk_1.default.blue(`Cloning secrets from ${fromEnv} to ${toEnv} (branch: ${branch})...`));
39
- if (options.overwrite) {
40
- console.log(chalk_1.default.yellow("Warning: Existing secrets in destination will be overwritten!"));
41
- }
42
- const confirm = await inquirer_1.default.prompt([
43
- {
44
- type: "confirm",
45
- name: "proceed",
46
- message: "Are you sure you want to proceed?",
47
- default: false
48
- }
49
- ]);
50
- if (!confirm.proceed) {
51
- console.log("Operation cancelled.");
52
- return;
53
- }
54
- const result = await api_1.api.cloneEnvironment(projectId, fromEnv, toEnv, options.overwrite, branch);
55
- if (result.success) {
56
- console.log(chalk_1.default.green("\nClone successful!"));
57
- console.log(`Copied: ${result.summary.copied}`);
58
- console.log(`Updated: ${result.summary.updated} (overwrite: ${options.overwrite})`);
59
- console.log(`Skipped: ${result.summary.skipped}`);
60
- }
61
- }
62
- catch (error) {
63
- if (error.response && error.response.data && error.response.data.error) {
64
- console.error(chalk_1.default.red("Error cloning environment:"), error.response.data.error);
65
- }
66
- else {
67
- console.error(chalk_1.default.red("Error cloning environment:"), error.message || error);
68
- }
69
- }
70
- });
1
+ var U=Object.create;var d=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var L=Object.getPrototypeOf,P=Object.prototype.hasOwnProperty;var _=(e,s)=>{for(var t in s)d(e,t,{get:s[t],enumerable:!0})},w=(e,s,t,n)=>{if(s&&typeof s=="object"||typeof s=="function")for(let o of A(s))!P.call(e,o)&&o!==t&&d(e,o,{get:()=>s[o],enumerable:!(n=R(s,o))||n.enumerable});return e};var a=(e,s,t)=>(t=e!=null?U(L(e)):{},w(s||!e||!e.__esModule?d(t,"default",{value:e,enumerable:!0}):t,e)),q=e=>w(d({},"__esModule",{value:!0}),e);var B={};_(B,{envCommand:()=>I});module.exports=q(B);var k=require("commander"),c=a(require("chalk"));var j=a(require("axios"));var h=a(require("conf")),m=a(require("fs")),$=a(require("path")),y="https://www.xtrasecurity.in/api",i=new h.default({projectName:"xtra-cli",defaults:{apiUrl:y}}),u=i.get("apiUrl");u&&!process.env.XTRA_API_URL&&(u.includes("localhost")||u.includes("xtra-security.vercel.app"))&&i.set("apiUrl",y);var l=()=>({...i.store,apiUrl:process.env.XTRA_API_URL||i.get("apiUrl")||y});var v=()=>i.get("token");var f=()=>{let e={};try{let s=$.default.join(process.cwd(),".xtrarc");m.default.existsSync(s)&&(e=JSON.parse(m.default.readFileSync(s,"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 b=a(require("fs")),S=a(require("path")),O=JSON.parse(b.readFileSync(S.join(__dirname,"../../package.json"),"utf-8")),r=()=>{let{apiUrl:e}=l(),s=v();return j.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":O.version,...s?{Authorization:`Bearer ${s}`}:{}}})},x={login:async(e,s,t)=>(await r().post("/auth/cli-login",{email:e,password:s,apiKey:t})).data,getSecrets:async(e,s,t="main")=>(await r().get(`/projects/${e}/envs/${s}/secrets?branch=${t}`)).data,getSecretVersions:async(e,s,t="main")=>(await r().get(`/projects/${e}/envs/${s}/secrets?includeVersions=true&branch=${t}`)).data,setSecrets:async(e,s,t,n,o="main")=>(await r().post(`/projects/${e}/envs/${s}/secrets`,{secrets:t,expectedVersions:n,branch:o})).data,getSecretDetails:async(e,s,t,n="main")=>(await r().get(`/projects/${e}/envs/${s}/secrets/${t}?branch=${n}`)).data,syncLogs:async e=>(await r().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,s,t,n,o,p)=>(await r().post(`/projects/${e}/envs/${s}/secrets/link`,{key:t,sourceProjectId:n,sourceEnv:o,sourceKey:p})).data,rotateSecret:async(e,s,t,n,o)=>(await r().post(`/projects/${e}/envs/${s}/secrets/${t}/rotate`,{strategy:n,parsedNewValue:o})).data,promoteSecret:async(e,s,t)=>(await r().post(`/projects/${e}/envs/${s}/secrets/${t}/promote`,{})).data,verifyAuditLogs:async()=>(await r().get("/audit/verify")).data,exportAuditLogs:async(e,s,t,n)=>{let o={format:e};return s&&(o.startDate=s),t&&(o.endDate=t),n&&(o.projectId=n),(await r().post("/audit/export",o,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,s,t,n)=>(await r().post("/access/request",{projectId:e,secretId:n,reason:s,duration:t})).data,approveAccess:async(e,s)=>(await r().post("/access/approve",{requestId:e,decision:s})).data,listAccessRequests:async e=>{let{workspace:s}=l(),t=s?`&workspaceId=${s}`:"";return(await r().get(`/access/list?mode=${e}${t}`)).data},getAccessRequestStatus:async e=>(await r().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=l(),s=e?`/project?workspaceId=${e}`:"/project";return(await r().get(s)).data},getBranches:async e=>(await r().get(`/branch?projectId=${e}`)).data,createBranch:async(e,s,t)=>(await r().post("/branch",{projectId:e,name:s,description:t})).data,deleteBranch:async e=>(await r().delete(`/branch/${e}`)).data,updateBranch:async(e,s)=>(await r().put("/branch",{id:e,...s})).data,getRoles:async()=>(await r().get("/admin/roles")).data,getUsers:async e=>{let s=e?`?teamId=${e}`:"";return(await r().get(`/admin/users${s}`)).data},setUserRole:async(e,s,t)=>(await r().put("/admin/users/role",{email:e,role:s,teamId:t})).data,getIntegrationStatus:async e=>(await r().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await r().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await r().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,s)=>{let t=new URLSearchParams(s).toString();return(await r().get(`/projects/${e}/kubernetes?${t}`)).data},getSecretHistory:async(e,s,t)=>(await r().get(`/projects/${e}/envs/${s}/secrets/${t}/history`)).data,rollbackSecret:async(e,s,t,n)=>(await r().post(`/projects/${e}/envs/${s}/secrets/${t}/history`,{version:n})).data,cloneEnvironment:async(e,s,t,n,o)=>(await r().post(`/projects/${e}/envs/clone`,{fromEnv:s,toEnv:t,overwrite:n,branch:o})).data,generateJitLink:async e=>(await r().post("/jit/generate",e)).data,claimJitLink:async e=>(await r().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await r().get(`/jit/${e}`)).data,post:async(e,s)=>(await r().post(e,s)).data};var C=a(require("inquirer")),I=new k.Command("env");I.command("clone").description("Clone secrets from one environment to another").requiredOption("--from <env>","Source environment (e.g. production)").requiredOption("--to <env>","Destination environment (e.g. staging)").option("-p, --project <id>","Project ID").option("-b, --branch <name>","Branch Name").option("--overwrite","Overwrite existing secrets",!1).action(async e=>{try{let s=e.project,t=e.branch||f().branch||"main";s||(s=f().project,s||(console.error(c.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first.")),process.exit(1)));let n=e.from.toLowerCase(),o=e.to.toLowerCase();if(n===o&&(console.error(c.default.red("Source and destination must be different.")),process.exit(1)),console.log(c.default.blue(`Cloning secrets from ${n} to ${o} (branch: ${t})...`)),e.overwrite&&console.log(c.default.yellow("Warning: Existing secrets in destination will be overwritten!")),!(await C.default.prompt([{type:"confirm",name:"proceed",message:"Are you sure you want to proceed?",default:!1}])).proceed){console.log("Operation cancelled.");return}let g=await x.cloneEnvironment(s,n,o,e.overwrite,t);g.success&&(console.log(c.default.green(`
2
+ Clone successful!`)),console.log(`Copied: ${g.summary.copied}`),console.log(`Updated: ${g.summary.updated} (overwrite: ${e.overwrite})`),console.log(`Skipped: ${g.summary.skipped}`))}catch(s){s.response&&s.response.data&&s.response.data.error?console.error(c.default.red("Error cloning environment:"),s.response.data.error):console.error(c.default.red("Error cloning environment:"),s.message||s)}});0&&(module.exports={envCommand});
@@ -1,83 +1,2 @@
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.exportCommand = void 0;
7
- const commander_1 = require("commander");
8
- const api_1 = require("../lib/api");
9
- const chalk_1 = __importDefault(require("chalk"));
10
- const fs_1 = __importDefault(require("fs"));
11
- const path_1 = __importDefault(require("path"));
12
- const sync_1 = require("csv-stringify/sync");
13
- const config_1 = require("../lib/config");
14
- exports.exportCommand = new commander_1.Command("export")
15
- .description("Export secrets to a file (JSON, Dotenv, CSV)")
16
- .option("-p, --project <projectId>", "Project ID")
17
- .option("-e, --env <environment>", "Environment (development, staging, production)", "development")
18
- .option("-b, --branch <branchName>", "Branch Name")
19
- .option("-f, --format <format>", "Output format (json, dotenv, csv)", "json")
20
- .option("-o, --output <file>", "Output file path (default: stdout)")
21
- .action(async (options) => {
22
- let { project, env, branch, format, output } = options;
23
- // Use config fallback
24
- if (!project)
25
- project = (0, config_1.getRcConfig)().project;
26
- if (!branch) {
27
- branch = (0, config_1.getRcConfig)().branch || "main";
28
- }
29
- // Normalize Env
30
- const envMap = { dev: "development", stg: "staging", prod: "production" };
31
- env = envMap[env] || env;
32
- if (!project) {
33
- console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
34
- process.exit(1);
35
- }
36
- const spinner = require("ora")(`Fetching secrets for export (${env} @ ${branch})...`).start();
37
- try {
38
- const secrets = await api_1.api.getSecrets(project, env, branch);
39
- spinner.stop();
40
- if (!secrets || Object.keys(secrets).length === 0) {
41
- console.warn(chalk_1.default.yellow("No secrets found to export."));
42
- return;
43
- }
44
- let content = "";
45
- switch (format.toLowerCase()) {
46
- case "json":
47
- content = JSON.stringify(secrets, null, 2);
48
- break;
49
- case "dotenv":
50
- content = Object.entries(secrets)
51
- .map(([key, value]) => `${key}="${String(value).replace(/"/g, '\\"')}"`)
52
- .join("\n");
53
- break;
54
- case "csv":
55
- const records = Object.entries(secrets).map(([key, value]) => ({ key, value }));
56
- content = (0, sync_1.stringify)(records, { header: true });
57
- break;
58
- default:
59
- console.error(chalk_1.default.red(`Error: Unsupported format '${format}'. Use json, dotenv, or csv.`));
60
- process.exit(1);
61
- }
62
- if (output) {
63
- const outputPath = path_1.default.resolve(process.cwd(), output);
64
- fs_1.default.writeFileSync(outputPath, content, "utf-8");
65
- console.log(chalk_1.default.green(`✔ Secrets exported to ${outputPath}`));
66
- }
67
- else {
68
- console.log(content);
69
- }
70
- // Log Audit
71
- try {
72
- const { logAudit } = require("../lib/audit");
73
- logAudit("SECRET_EXPORT", project, env, { format, destination: output || "stdout", branch });
74
- }
75
- catch (e) { }
76
- }
77
- catch (error) {
78
- spinner.fail("Export failed.");
79
- const safeErr = error?.response?.data?.error || error.message || "Unknown error";
80
- console.error(chalk_1.default.red(safeErr));
81
- process.exit(1);
82
- }
83
- });
1
+ var ot=Object.create;var h=Object.defineProperty;var it=Object.getOwnPropertyDescriptor;var at=Object.getOwnPropertyNames;var ct=Object.getPrototypeOf,pt=Object.prototype.hasOwnProperty;var v=(t,e)=>()=>(t&&(e=t(t=0)),e);var N=(t,e)=>{for(var s in e)h(t,s,{get:e[s],enumerable:!0})},P=(t,e,s,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of at(e))!pt.call(t,n)&&n!==s&&h(t,n,{get:()=>e[n],enumerable:!(r=it(e,n))||r.enumerable});return t};var a=(t,e,s)=>(s=t!=null?ot(ct(t)):{},P(e||!t||!t.__esModule?h(s,"default",{value:t,enumerable:!0}):s,t)),B=t=>P(h({},"__esModule",{value:!0}),t);var T,A,_,C,g,I,f,D,U,w=v(()=>{T=a(require("conf")),A=a(require("fs")),_=a(require("path")),C="https://www.xtrasecurity.in/api",g=new T.default({projectName:"xtra-cli",defaults:{apiUrl:C}}),I=g.get("apiUrl");I&&!process.env.XTRA_API_URL&&(I.includes("localhost")||I.includes("xtra-security.vercel.app"))&&g.set("apiUrl",C);f=()=>({...g.store,apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||C}),D=()=>g.get("token"),U=()=>{let t={};try{let e=_.default.join(process.cwd(),".xtrarc");A.default.existsSync(e)&&(t=JSON.parse(A.default.readFileSync(e,"utf-8")))}catch{}return{project:t.project||g.get("project")||"",env:t.env||g.get("env")||"development",branch:t.branch||g.get("branch")||"main"}}});var J,F,q,gt,o,j,O=v(()=>{J=a(require("axios"));w();F=a(require("fs")),q=a(require("path")),gt=JSON.parse(F.readFileSync(q.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:t}=f(),e=D();return J.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":gt.version,...e?{Authorization:`Bearer ${e}`}:{}}})},j={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,r,n="main")=>(await o().post(`/projects/${t}/envs/${e}/secrets`,{secrets:s,expectedVersions:r,branch:n})).data,getSecretDetails:async(t,e,s,r="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets/${s}?branch=${r}`)).data,syncLogs:async t=>(await o().post("/audit/cli-logs",{logs:t})).data,linkSecret:async(t,e,s,r,n,i)=>(await o().post(`/projects/${t}/envs/${e}/secrets/link`,{key:s,sourceProjectId:r,sourceEnv:n,sourceKey:i})).data,rotateSecret:async(t,e,s,r,n)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/rotate`,{strategy:r,parsedNewValue:n})).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,r)=>{let n={format:t};return e&&(n.startDate=e),s&&(n.endDate=s),r&&(n.projectId=r),(await o().post("/audit/export",n,{responseType:t==="csv"?"text":"json"})).data},requestAccess:async(t,e,s,r)=>(await o().post("/access/request",{projectId:t,secretId:r,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,r)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/history`,{version:r})).data,cloneEnvironment:async(t,e,s,r,n)=>(await o().post(`/projects/${t}/envs/clone`,{fromEnv:e,toEnv:s,overwrite:r,branch:n})).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}});function H(){let t=G.get("masterKey");t||(t=l.default.randomBytes(32).toString("hex"),G.set("masterKey",t));let e=(0,K.machineIdSync)();return l.default.createHash("sha256").update(t+e).digest()}var l,V,K,z,G,M,X,Q=v(()=>{l=a(require("crypto")),V=a(require("conf")),K=require("node-machine-id"),z="aes-256-gcm",G=new V.default({projectName:"xtra-cli-crypto"});M=t=>{let e=l.default.randomBytes(16),s=H(),r=l.default.createCipheriv(z,s,e),n=r.update(t,"utf8","hex");n+=r.final("hex");let i=r.getAuthTag();return{iv:e.toString("hex"),content:n,tag:i.toString("hex")}},X=t=>{let e=H(),s=Buffer.from(t.iv,"hex"),r=Buffer.from(t.tag,"hex"),n=l.default.createDecipheriv(z,e,s);n.setAuthTag(r);let i=n.update(t.content,"hex","utf8");return i+=n.final("utf8"),i}});var Z={};N(Z,{loadAuditLogs:()=>x,logAudit:()=>ut,saveAuditLogs:()=>S,syncAuditLogs:()=>ft});function dt(t){if(!t||typeof t!="object")return t;let e={...t},s=["password","token","secret","value","apiKey","secretValue"];for(let r of Object.keys(e))s.some(n=>r.toLowerCase().includes(n))&&(e[r]="[REDACTED]");return e}async function Y(t){try{if(!f().token)return!1;let s={action:t.action,entity:"cli-project",entityId:t.projectId||"global",details:dt(t.details),timestamp:t.timestamp,projectId:t.projectId};return await j.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,r){let n={id:(0,W.v4)(),timestamp:new Date().toISOString(),action:t,projectId:e,environment:s,details:r,synced:!1},i=x();i.push(n),S(i),Y(n).then(b=>{if(b){n.synced=!0;let u=x(),c=u.findIndex(p=>p.id===n.id);c!==-1&&(u[c].synced=!0,S(u))}}).catch(()=>{})}function x(){if(!m.default.existsSync(E))return[];try{let t=m.default.readFileSync(E,"utf-8"),e=JSON.parse(t),s=X(e);return JSON.parse(s)}catch{return[]}}function S(t){m.default.existsSync(R)||m.default.mkdirSync(R,{recursive:!0});let e=JSON.stringify(t),s=M(e);m.default.writeFileSync(E,JSON.stringify(s),"utf-8")}async function ft(){let t=x(),e=t.filter(r=>!r.synced);if(e.length===0)return 0;let s=0;for(let r of e)await Y(r)&&(r.synced=!0,s++);return s>0&&S(t),s}var m,L,W,R,E,tt=v(()=>{m=a(require("fs")),L=a(require("path")),W=require("uuid");Q();w();O();R=L.default.join(process.cwd(),".xtra"),E=L.default.join(R,"audit.enc")});var mt={};N(mt,{exportCommand:()=>lt});module.exports=B(mt);var et=require("commander");O();var y=a(require("chalk")),st=a(require("fs")),rt=a(require("path")),nt=require("csv-stringify/sync");w();var lt=new et.Command("export").description("Export secrets to a file (JSON, Dotenv, CSV)").option("-p, --project <projectId>","Project ID").option("-e, --env <environment>","Environment (development, staging, production)","development").option("-b, --branch <branchName>","Branch Name").option("-f, --format <format>","Output format (json, dotenv, csv)","json").option("-o, --output <file>","Output file path (default: stdout)").action(async t=>{let{project:e,env:s,branch:r,format:n,output:i}=t;e||(e=U().project),r||(r=U().branch||"main"),s={dev:"development",stg:"staging",prod:"production"}[s]||s,e||(console.error(y.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first.")),process.exit(1));let u=require("ora")(`Fetching secrets for export (${s} @ ${r})...`).start();try{let c=await j.getSecrets(e,s,r);if(u.stop(),!c||Object.keys(c).length===0){console.warn(y.default.yellow("No secrets found to export."));return}let p="";switch(n.toLowerCase()){case"json":p=JSON.stringify(c,null,2);break;case"dotenv":p=Object.entries(c).map(([$,k])=>`${$}="${String(k).replace(/"/g,'\\"')}"`).join(`
2
+ `);break;case"csv":let d=Object.entries(c).map(([$,k])=>({key:$,value:k}));p=(0,nt.stringify)(d,{header:!0});break;default:console.error(y.default.red(`Error: Unsupported format '${n}'. Use json, dotenv, or csv.`)),process.exit(1)}if(i){let d=rt.default.resolve(process.cwd(),i);st.default.writeFileSync(d,p,"utf-8"),console.log(y.default.green(`\u2714 Secrets exported to ${d}`))}else console.log(p);try{let{logAudit:d}=(tt(),B(Z));d("SECRET_EXPORT",e,s,{format:n,destination:i||"stdout",branch:r})}catch{}}catch(c){u.fail("Export failed.");let p=c?.response?.data?.error||c.message||"Unknown error";console.error(y.default.red(p)),process.exit(1)}});0&&(module.exports={exportCommand});
@@ -1,179 +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.generateCommand = void 0;
7
- const commander_1 = require("commander");
8
- const api_1 = require("../lib/api");
9
- const chalk_1 = __importDefault(require("chalk"));
10
- const ora_1 = __importDefault(require("ora"));
11
- const fs_1 = __importDefault(require("fs"));
12
- const path_1 = __importDefault(require("path"));
13
- const yaml_1 = __importDefault(require("yaml"));
14
- const config_1 = require("../lib/config");
15
- // Helper: Parse .env file into key-value pairs
16
- function parseEnvFile(content) {
17
- const result = {};
18
- const lines = content.split(/\r?\n/);
19
- for (const line of lines) {
20
- const trimmed = line.trim();
21
- // Skip empty lines and comments
22
- if (!trimmed || trimmed.startsWith('#'))
23
- continue;
24
- const idx = trimmed.indexOf('=');
25
- if (idx === -1)
26
- continue;
27
- const key = trimmed.substring(0, idx).trim();
28
- let value = trimmed.substring(idx + 1).trim();
29
- // Remove surrounding quotes if present
30
- if ((value.startsWith('"') && value.endsWith('"')) ||
31
- (value.startsWith("'") && value.endsWith("'"))) {
32
- value = value.slice(1, -1);
33
- }
34
- result[key] = value;
35
- }
36
- return result;
37
- }
38
- // Helper: Merge secrets into existing file content, preserving comments and order
39
- function mergeEnvContent(existingContent, newSecrets) {
40
- const lines = existingContent.split(/\r?\n/);
41
- const existingKeys = new Set();
42
- const added = [];
43
- const updated = [];
44
- // First pass: update existing keys
45
- const updatedLines = lines.map(line => {
46
- const trimmed = line.trim();
47
- if (!trimmed || trimmed.startsWith('#'))
48
- return line;
49
- const idx = trimmed.indexOf('=');
50
- if (idx === -1)
51
- return line;
52
- const key = trimmed.substring(0, idx).trim();
53
- existingKeys.add(key);
54
- if (key in newSecrets) {
55
- const oldValue = parseEnvFile(line)[key];
56
- if (oldValue !== newSecrets[key]) {
57
- updated.push(key);
58
- }
59
- return `${key}="${newSecrets[key]}"`;
60
- }
61
- return line;
62
- });
63
- // Second pass: add new keys
64
- for (const [key, value] of Object.entries(newSecrets)) {
65
- if (!existingKeys.has(key)) {
66
- updatedLines.push(`${key}="${value}"`);
67
- added.push(key);
68
- }
69
- }
70
- return { content: updatedLines.join('\n'), added, updated };
71
- }
72
- exports.generateCommand = new commander_1.Command("generate")
73
- .description("Generate local configuration files from secrets")
74
- .option("-p, --project <projectId>", "Project ID")
75
- .option("-e, --env <environment>", "Environment (dev, stg, prod)", "dev")
76
- .option("-b, --branch <branchName>", "Branch Name")
77
- .option("-o, --output <path>", "Output file path (forces complete overwrite)")
78
- .option("-f, --format <format>", "Output format (env, json, yaml)", "env")
79
- .option("--force", "Skip confirmation prompts", false)
80
- .action(async (options) => {
81
- let { project, env, branch, output, format, force } = options;
82
- // Use config fallback
83
- if (!project)
84
- project = (0, config_1.getRcConfig)().project;
85
- if (!branch) {
86
- branch = (0, config_1.getRcConfig)().branch || "main";
87
- }
88
- // Normalize Env
89
- const envMap = { dev: "development", stg: "staging", prod: "production" };
90
- env = envMap[env] || env;
91
- if (!project) {
92
- console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
93
- process.exit(1);
94
- }
95
- // Determine if we should merge or overwrite
96
- const shouldMerge = !output && format === "env";
97
- // Determine output filename
98
- let outputPath = output;
99
- if (!outputPath) {
100
- switch (format) {
101
- case "json":
102
- outputPath = "secrets.json";
103
- break;
104
- case "yaml":
105
- outputPath = "secrets.yaml";
106
- break;
107
- default:
108
- outputPath = ".env";
109
- break;
110
- }
111
- }
112
- const fullPath = path_1.default.resolve(process.cwd(), outputPath);
113
- const fileExists = fs_1.default.existsSync(fullPath);
114
- const spinner = (0, ora_1.default)(`Fetching secrets for ${env} (branch: ${branch})...`).start();
115
- try {
116
- const secrets = await api_1.api.getSecrets(project, env, branch);
117
- if (!secrets || Object.keys(secrets).length === 0) {
118
- spinner.warn(chalk_1.default.yellow("No secrets found. File not modified."));
119
- return;
120
- }
121
- let content = "";
122
- let added = [];
123
- let updated = [];
124
- // Handle merge for .env format when no -o flag
125
- if (shouldMerge && fileExists) {
126
- spinner.text = "Merging with existing .env file...";
127
- const existingContent = fs_1.default.readFileSync(fullPath, 'utf-8');
128
- const mergeResult = mergeEnvContent(existingContent, secrets);
129
- content = mergeResult.content;
130
- added = mergeResult.added;
131
- updated = mergeResult.updated;
132
- if (added.length === 0 && updated.length === 0) {
133
- spinner.succeed(chalk_1.default.green("No changes needed - .env is already up to date."));
134
- return;
135
- }
136
- }
137
- else {
138
- // Full overwrite mode
139
- switch (format.toLowerCase()) {
140
- case "json":
141
- content = JSON.stringify(secrets, null, 2);
142
- break;
143
- case "yaml":
144
- content = yaml_1.default.stringify(secrets);
145
- break;
146
- case "env":
147
- default:
148
- content = Object.entries(secrets)
149
- .map(([key, value]) => `${key}="${value}"`)
150
- .join("\n");
151
- break;
152
- }
153
- }
154
- // Write file
155
- fs_1.default.writeFileSync(fullPath, content, "utf-8");
156
- // Update manifest
157
- const { hash } = require("../lib/crypto");
158
- const { updateManifest } = require("../lib/manifest");
159
- updateManifest(project, env, secrets, hash);
160
- // Show result
161
- if (shouldMerge && fileExists) {
162
- spinner.succeed(chalk_1.default.green(`Updated ${outputPath}`));
163
- if (added.length > 0) {
164
- console.log(chalk_1.default.cyan(` + Added: ${added.join(', ')}`));
165
- }
166
- if (updated.length > 0) {
167
- console.log(chalk_1.default.yellow(` ~ Updated: ${updated.join(', ')}`));
168
- }
169
- }
170
- else {
171
- spinner.succeed(`Generated ${outputPath} (${Object.keys(secrets).length} secrets)`);
172
- }
173
- }
174
- catch (error) {
175
- spinner.fail("Failed to generate file.");
176
- console.error(chalk_1.default.red(error.message));
177
- process.exit(1);
178
- }
179
- });
1
+ var pt=Object.create;var $=Object.defineProperty;var gt=Object.getOwnPropertyDescriptor;var dt=Object.getOwnPropertyNames;var ut=Object.getPrototypeOf,ft=Object.prototype.hasOwnProperty;var F=(t,e)=>()=>(t&&(e=t(t=0)),e);var O=(t,e)=>{for(var s in e)$(t,s,{get:e[s],enumerable:!0})},_=(t,e,s,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of dt(e))!ft.call(t,r)&&r!==s&&$(t,r,{get:()=>e[r],enumerable:!(n=gt(e,r))||n.enumerable});return t};var c=(t,e,s)=>(s=t!=null?pt(ut(t)):{},_(e||!t||!t.__esModule?$(s,"default",{value:t,enumerable:!0}):s,t)),U=t=>_($({},"__esModule",{value:!0}),t);var Y={};O(Y,{decrypt:()=>yt,encrypt:()=>mt,hash:()=>ht});function z(){let t=W.get("masterKey");t||(t=y.default.randomBytes(32).toString("hex"),W.set("masterKey",t));let e=(0,H.machineIdSync)();return y.default.createHash("sha256").update(t+e).digest()}var y,K,H,X,W,mt,yt,ht,Q=F(()=>{y=c(require("crypto")),K=c(require("conf")),H=require("node-machine-id"),X="aes-256-gcm",W=new K.default({projectName:"xtra-cli-crypto"});mt=t=>{let e=y.default.randomBytes(16),s=z(),n=y.default.createCipheriv(X,s,e),r=n.update(t,"utf8","hex");r+=n.final("hex");let i=n.getAuthTag();return{iv:e.toString("hex"),content:r,tag:i.toString("hex")}},yt=t=>{let e=z(),s=Buffer.from(t.iv,"hex"),n=Buffer.from(t.tag,"hex"),r=y.default.createDecipheriv(X,e,s);r.setAuthTag(n);let i=r.update(t.content,"hex","utf8");return i+=r.final("utf8"),i},ht=t=>y.default.createHash("sha256").update(t).digest("hex")});var et={};O(et,{MANIFEST_DIR:()=>k,MANIFEST_FILE:()=>I,loadManifest:()=>Z,saveManifest:()=>tt,updateManifest:()=>vt});function Z(){if(!v.default.existsSync(I))return null;try{let t=v.default.readFileSync(I,"utf-8");return JSON.parse(t)}catch{return null}}function tt(t){v.default.existsSync(k)||v.default.mkdirSync(k,{recursive:!0}),v.default.writeFileSync(I,JSON.stringify(t,null,2),"utf-8")}function vt(t,e,s,n){let r=Z()||{projectId:t,environment:e,lastSyncedAt:new Date().toISOString(),secrets:{}};r.projectId=t,r.environment=e,r.lastSyncedAt=new Date().toISOString(),Object.entries(s).forEach(([i,f])=>{let a=n(f);r.secrets[i]={hash:a,updatedAt:new Date().toISOString()}}),tt(r)}var v,B,k,I,st=F(()=>{v=c(require("fs")),B=c(require("path")),k=B.default.join(process.cwd(),".xtra"),I=B.default.join(k,"manifest.json")});var St={};O(St,{generateCommand:()=>xt});module.exports=U(St);var nt=require("commander");var q=c(require("axios"));var T=c(require("conf")),M=c(require("fs")),E=c(require("path")),N="https://www.xtrasecurity.in/api",l=new T.default({projectName:"xtra-cli",defaults:{apiUrl:N}}),P=l.get("apiUrl");P&&!process.env.XTRA_API_URL&&(P.includes("localhost")||P.includes("xtra-security.vercel.app"))&&l.set("apiUrl",N);var b=()=>({...l.store,apiUrl:process.env.XTRA_API_URL||l.get("apiUrl")||N});var D=()=>l.get("token");var L=()=>{let t={};try{let e=E.default.join(process.cwd(),".xtrarc");M.default.existsSync(e)&&(t=JSON.parse(M.default.readFileSync(e,"utf-8")))}catch{}return{project:t.project||l.get("project")||"",env:t.env||l.get("env")||"development",branch:t.branch||l.get("branch")||"main"}};var G=c(require("fs")),J=c(require("path")),lt=JSON.parse(G.readFileSync(J.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:t}=b(),e=D();return q.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":lt.version,...e?{Authorization:`Bearer ${e}`}:{}}})},V={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,i)=>(await o().post(`/projects/${t}/envs/${e}/secrets/link`,{key:s,sourceProjectId:n,sourceEnv:r,sourceKey:i})).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}=b(),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}=b(),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 m=c(require("chalk")),rt=c(require("ora")),A=c(require("fs")),ot=c(require("path")),it=c(require("yaml"));function wt(t){let e={},s=t.split(/\r?\n/);for(let n of s){let r=n.trim();if(!r||r.startsWith("#"))continue;let i=r.indexOf("=");if(i===-1)continue;let f=r.substring(0,i).trim(),a=r.substring(i+1).trim();(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),e[f]=a}return e}function jt(t,e){let s=t.split(/\r?\n/),n=new Set,r=[],i=[],f=s.map(a=>{let u=a.trim();if(!u||u.startsWith("#"))return a;let g=u.indexOf("=");if(g===-1)return a;let p=u.substring(0,g).trim();return n.add(p),p in e?(wt(a)[p]!==e[p]&&i.push(p),`${p}="${e[p]}"`):a});for(let[a,u]of Object.entries(e))n.has(a)||(f.push(`${a}="${u}"`),r.push(a));return{content:f.join(`
2
+ `),added:r,updated:i}}var xt=new nt.Command("generate").description("Generate local configuration files from secrets").option("-p, --project <projectId>","Project ID").option("-e, --env <environment>","Environment (dev, stg, prod)","dev").option("-b, --branch <branchName>","Branch Name").option("-o, --output <path>","Output file path (forces complete overwrite)").option("-f, --format <format>","Output format (env, json, yaml)","env").option("--force","Skip confirmation prompts",!1).action(async t=>{let{project:e,env:s,branch:n,output:r,format:i,force:f}=t;e||(e=L().project),n||(n=L().branch||"main"),s={dev:"development",stg:"staging",prod:"production"}[s]||s,e||(console.error(m.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first.")),process.exit(1));let u=!r&&i==="env",g=r;if(!g)switch(i){case"json":g="secrets.json";break;case"yaml":g="secrets.yaml";break;default:g=".env";break}let p=ot.default.resolve(process.cwd(),g),C=A.default.existsSync(p),h=(0,rt.default)(`Fetching secrets for ${s} (branch: ${n})...`).start();try{let d=await V.getSecrets(e,s,n);if(!d||Object.keys(d).length===0){h.warn(m.default.yellow("No secrets found. File not modified."));return}let w="",x=[],S=[];if(u&&C){h.text="Merging with existing .env file...";let R=A.default.readFileSync(p,"utf-8"),j=jt(R,d);if(w=j.content,x=j.added,S=j.updated,x.length===0&&S.length===0){h.succeed(m.default.green("No changes needed - .env is already up to date."));return}}else switch(i.toLowerCase()){case"json":w=JSON.stringify(d,null,2);break;case"yaml":w=it.default.stringify(d);break;default:w=Object.entries(d).map(([R,j])=>`${R}="${j}"`).join(`
3
+ `);break}A.default.writeFileSync(p,w,"utf-8");let{hash:at}=(Q(),U(Y)),{updateManifest:ct}=(st(),U(et));ct(e,s,d,at),u&&C?(h.succeed(m.default.green(`Updated ${g}`)),x.length>0&&console.log(m.default.cyan(` + Added: ${x.join(", ")}`)),S.length>0&&console.log(m.default.yellow(` ~ Updated: ${S.join(", ")}`))):h.succeed(`Generated ${g} (${Object.keys(d).length} secrets)`)}catch(d){h.fail("Failed to generate file."),console.error(m.default.red(d.message)),process.exit(1)}});0&&(module.exports={generateCommand});