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,123 +1,17 @@
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.watchCommand = void 0;
7
- /**
8
- * watch.ts — Live reload secrets in dev mode
9
- *
10
- * Polls XtraSecurity Cloud for secret changes at a configurable interval.
11
- * When a change is detected, restarts the child process with fresh secrets.
12
- *
13
- * Usage:
14
- * xtra watch -p proj123 -e dev node app.js
15
- * xtra watch -p proj123 -e dev --interval 10 npm run dev --shell
16
- */
17
- const commander_1 = require("commander");
18
- const api_1 = require("../lib/api");
19
- const config_1 = require("../lib/config");
20
- const chalk_1 = __importDefault(require("chalk"));
21
- const child_process_1 = require("child_process");
22
- let child = null;
23
- let lastHash = "";
24
- function hashSecrets(secrets) {
25
- return JSON.stringify(Object.keys(secrets).sort().map(k => `${k}=${secrets[k]}`));
26
- }
27
- async function startProcess(command, args, secrets, useShell) {
28
- if (child) {
29
- process.stdout.write(chalk_1.default.cyan("\n [watch] ") + chalk_1.default.yellow("Secret change detected — restarting...\n"));
30
- child.kill("SIGTERM");
31
- // Give it 500ms to terminate gracefully
32
- await new Promise(r => setTimeout(r, 500));
33
- }
34
- const envVars = { ...process.env, ...secrets };
35
- process.stdout.write(chalk_1.default.cyan(" [watch] ") + chalk_1.default.green(`Starting: ${command} ${args.join(" ")}\n`));
36
- child = (0, child_process_1.spawn)(command, args, {
37
- env: envVars,
38
- stdio: "inherit",
39
- shell: useShell,
40
- });
41
- child.on("exit", (code) => {
42
- if (code !== null && code !== 0) {
43
- process.stdout.write(chalk_1.default.cyan(" [watch] ") + chalk_1.default.red(`Process exited with code ${code}\n`));
44
- }
45
- child = null;
46
- });
47
- child.on("error", (err) => {
48
- process.stdout.write(chalk_1.default.cyan(" [watch] ") + chalk_1.default.red(`Failed to start: ${err.message}\n`));
49
- child = null;
50
- });
51
- }
52
- exports.watchCommand = new commander_1.Command("watch")
53
- .description("Live reload — auto-restart process when secrets change in cloud")
54
- .option("-p, --project <id>", "Project ID")
55
- .option("-e, --env <environment>", "Environment", "development")
56
- .option("-b, --branch <branch>", "Branch", "main")
57
- .option("--interval <seconds>", "Poll interval in seconds", "5")
58
- .option("--shell", "Use shell mode for the child process (for npm run etc.)", false)
59
- .argument("<command>", "Command to run")
60
- .argument("[args...]", "Command arguments")
61
- .addHelpText("after", `
62
- Examples:
63
- $ xtra watch -p proj123 -e dev node app.js
64
- $ xtra watch -p proj123 -e dev --interval 10 --shell npm run dev
65
- $ xtra watch -p proj123 -e dev -- node -r dotenv/config server.js
66
- `)
67
- .action(async (command, args, options) => {
68
- let { project, env, branch, interval, shell: useShell } = options;
69
- const envMap = { dev: "development", stg: "staging", prod: "production" };
70
- env = envMap[env] || env;
71
- if (!project)
72
- project = (0, config_1.getRcConfig)().project;
73
- if (!project) {
74
- console.error(chalk_1.default.red("Error: Project ID required. Use -p <id> or run 'xtra project set'."));
75
- process.exit(1);
76
- }
77
- // Block production watch — too dangerous
78
- if (env === "production") {
79
- console.error(chalk_1.default.red("⚠ xtra watch is not allowed in PRODUCTION for safety reasons."));
80
- console.error(chalk_1.default.gray(" Use 'xtra run' for one-shot production injection."));
81
- process.exit(1);
82
- }
83
- const pollMs = Math.max(3, parseInt(interval)) * 1000;
84
- const isWindows = process.platform === "win32";
85
- const finalShell = useShell || isWindows;
86
- console.log(chalk_1.default.bold.cyan("\n● xtra watch") + chalk_1.default.bold(` — watching ${env}/${branch} (every ${interval}s)\n`));
87
- console.log(chalk_1.default.gray(` Press Ctrl+C to stop.\n`));
88
- // Graceful shutdown
89
- process.on("SIGINT", () => {
90
- if (child)
91
- child.kill("SIGTERM");
92
- console.log(chalk_1.default.cyan("\n [watch] ") + chalk_1.default.gray("Stopped."));
93
- process.exit(0);
94
- });
95
- // Initial fetch & start
96
- try {
97
- const secrets = await api_1.api.getSecrets(project, env, branch);
98
- lastHash = hashSecrets(secrets);
99
- await startProcess(command, args, secrets, finalShell);
100
- }
101
- catch (e) {
102
- console.error(chalk_1.default.red("Failed to fetch secrets: " + (e?.response?.data?.error || e.message)));
103
- process.exit(1);
104
- }
105
- // Poll loop
106
- setInterval(async () => {
107
- try {
108
- const secrets = await api_1.api.getSecrets(project, env, branch);
109
- const hash = hashSecrets(secrets);
110
- if (hash !== lastHash) {
111
- lastHash = hash;
112
- await startProcess(command, args, secrets, finalShell);
113
- }
114
- else {
115
- process.stdout.write(chalk_1.default.cyan(" [watch] ") + chalk_1.default.gray(`${new Date().toLocaleTimeString()} — no changes \r`));
116
- }
117
- }
118
- catch (e) {
119
- process.stdout.write(chalk_1.default.cyan("\n [watch] ") + chalk_1.default.yellow(`Poll failed: ${e.message}\n`));
120
- // Don't exit — keep trying
121
- }
122
- }, pollMs);
123
- });
1
+ var N=Object.create;var d=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var q=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var E=(e,t)=>{for(var s in t)d(e,s,{get:t[s],enumerable:!0})},S=(e,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of D(t))!J.call(e,o)&&o!==s&&d(e,o,{get:()=>t[o],enumerable:!(n=B(t,o))||n.enumerable});return e};var l=(e,t,s)=>(s=e!=null?N(q(e)):{},S(t||!e||!e.__esModule?d(s,"default",{value:e,enumerable:!0}):s,e)),M=e=>S(d({},"__esModule",{value:!0}),e);var H={};E(H,{watchCommand:()=>F});module.exports=M(H);var T=require("commander");var C=l(require("axios"));var x=l(require("conf")),m=l(require("fs")),k=l(require("path")),w="https://www.xtrasecurity.in/api",g=new x.default({projectName:"xtra-cli",defaults:{apiUrl:w}}),h=g.get("apiUrl");h&&!process.env.XTRA_API_URL&&(h.includes("localhost")||h.includes("xtra-security.vercel.app"))&&g.set("apiUrl",w);var u=()=>({...g.store,apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||w});var b=()=>g.get("token");var I=()=>{let e={};try{let t=k.default.join(process.cwd(),".xtrarc");m.default.existsSync(t)&&(e=JSON.parse(m.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||g.get("project")||"",env:e.env||g.get("env")||"development",branch:e.branch||g.get("branch")||"main"}};var P=l(require("fs")),R=l(require("path")),V=JSON.parse(P.readFileSync(R.join(__dirname,"../../package.json"),"utf-8")),r=()=>{let{apiUrl:e}=u(),t=b();return C.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":V.version,...t?{Authorization:`Bearer ${t}`}:{}}})},f={login:async(e,t,s)=>(await r().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await r().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await r().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,n,o="main")=>(await r().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:n,branch:o})).data,getSecretDetails:async(e,t,s,n="main")=>(await r().get(`/projects/${e}/envs/${t}/secrets/${s}?branch=${n}`)).data,syncLogs:async e=>(await r().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,s,n,o,i)=>(await r().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:n,sourceEnv:o,sourceKey:i})).data,rotateSecret:async(e,t,s,n,o)=>(await r().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:n,parsedNewValue:o})).data,promoteSecret:async(e,t,s)=>(await r().post(`/projects/${e}/envs/${t}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await r().get("/audit/verify")).data,exportAuditLogs:async(e,t,s,n)=>{let o={format:e};return t&&(o.startDate=t),s&&(o.endDate=s),n&&(o.projectId=n),(await r().post("/audit/export",o,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,s,n)=>(await r().post("/access/request",{projectId:e,secretId:n,reason:t,duration:s})).data,approveAccess:async(e,t)=>(await r().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=u(),s=t?`&workspaceId=${t}`:"";return(await r().get(`/access/list?mode=${e}${s}`)).data},getAccessRequestStatus:async e=>(await r().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=u(),t=e?`/project?workspaceId=${e}`:"/project";return(await r().get(t)).data},getBranches:async e=>(await r().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,s)=>(await r().post("/branch",{projectId:e,name:t,description:s})).data,deleteBranch:async e=>(await r().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await r().put("/branch",{id:e,...t})).data,getRoles:async()=>(await r().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await r().get(`/admin/users${t}`)).data},setUserRole:async(e,t,s)=>(await r().put("/admin/users/role",{email:e,role:t,teamId:s})).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,t)=>{let s=new URLSearchParams(t).toString();return(await r().get(`/projects/${e}/kubernetes?${s}`)).data},getSecretHistory:async(e,t,s)=>(await r().get(`/projects/${e}/envs/${t}/secrets/${s}/history`)).data,rollbackSecret:async(e,t,s,n)=>(await r().post(`/projects/${e}/envs/${t}/secrets/${s}/history`,{version:n})).data,cloneEnvironment:async(e,t,s,n,o)=>(await r().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,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,t)=>(await r().post(e,t)).data};var a=l(require("chalk")),L=require("child_process"),p=null,v="";function U(e){return JSON.stringify(Object.keys(e).sort().map(t=>`${t}=${e[t]}`))}async function A(e,t,s,n){p&&(process.stdout.write(a.default.cyan(`
2
+ [watch] `)+a.default.yellow(`Secret change detected \u2014 restarting...
3
+ `)),p.kill("SIGTERM"),await new Promise(i=>setTimeout(i,500)));let o={...process.env,...s};process.stdout.write(a.default.cyan(" [watch] ")+a.default.green(`Starting: ${e} ${t.join(" ")}
4
+ `)),p=(0,L.spawn)(e,t,{env:o,stdio:"inherit",shell:n}),p.on("exit",i=>{i!==null&&i!==0&&process.stdout.write(a.default.cyan(" [watch] ")+a.default.red(`Process exited with code ${i}
5
+ `)),p=null}),p.on("error",i=>{process.stdout.write(a.default.cyan(" [watch] ")+a.default.red(`Failed to start: ${i.message}
6
+ `)),p=null})}var F=new T.Command("watch").description("Live reload \u2014 auto-restart process when secrets change in cloud").option("-p, --project <id>","Project ID").option("-e, --env <environment>","Environment","development").option("-b, --branch <branch>","Branch","main").option("--interval <seconds>","Poll interval in seconds","5").option("--shell","Use shell mode for the child process (for npm run etc.)",!1).argument("<command>","Command to run").argument("[args...]","Command arguments").addHelpText("after",`
7
+ Examples:
8
+ $ xtra watch -p proj123 -e dev node app.js
9
+ $ xtra watch -p proj123 -e dev --interval 10 --shell npm run dev
10
+ $ xtra watch -p proj123 -e dev -- node -r dotenv/config server.js
11
+ `).action(async(e,t,s)=>{let{project:n,env:o,branch:i,interval:y,shell:_}=s;o={dev:"development",stg:"staging",prod:"production"}[o]||o,n||(n=I().project),n||(console.error(a.default.red("Error: Project ID required. Use -p <id> or run 'xtra project set'.")),process.exit(1)),o==="production"&&(console.error(a.default.red("\u26A0 xtra watch is not allowed in PRODUCTION for safety reasons.")),console.error(a.default.gray(" Use 'xtra run' for one-shot production injection.")),process.exit(1));let G=Math.max(3,parseInt(y))*1e3,O=process.platform==="win32",$=_||O;console.log(a.default.bold.cyan(`
12
+ \u25CF xtra watch`)+a.default.bold(` \u2014 watching ${o}/${i} (every ${y}s)
13
+ `)),console.log(a.default.gray(` Press Ctrl+C to stop.
14
+ `)),process.on("SIGINT",()=>{p&&p.kill("SIGTERM"),console.log(a.default.cyan(`
15
+ [watch] `)+a.default.gray("Stopped.")),process.exit(0)});try{let c=await f.getSecrets(n,o,i);v=U(c),await A(e,t,c,$)}catch(c){console.error(a.default.red("Failed to fetch secrets: "+(c?.response?.data?.error||c.message))),process.exit(1)}setInterval(async()=>{try{let c=await f.getSecrets(n,o,i),j=U(c);j!==v?(v=j,await A(e,t,c,$)):process.stdout.write(a.default.cyan(" [watch] ")+a.default.gray(`${new Date().toLocaleTimeString()} \u2014 no changes \r`))}catch(c){process.stdout.write(a.default.cyan(`
16
+ [watch] `)+a.default.yellow(`Poll failed: ${c.message}
17
+ `))}},G)});0&&(module.exports={watchCommand});
package/dist/lib/api.js CHANGED
@@ -1,187 +1 @@
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.api = void 0;
7
- const axios_1 = __importDefault(require("axios"));
8
- const config_1 = require("./config");
9
- const getClient = () => {
10
- const { apiUrl } = (0, config_1.getConfig)();
11
- const token = (0, config_1.getAuthToken)();
12
- const client = axios_1.default.create({
13
- baseURL: apiUrl,
14
- headers: {
15
- "Content-Type": "application/json",
16
- ...(token ? { Authorization: `Bearer ${token}` } : {}),
17
- },
18
- });
19
- return client;
20
- };
21
- exports.api = {
22
- login: async (email, password, apiKey) => {
23
- const response = await getClient().post("/auth/cli-login", {
24
- email,
25
- password,
26
- apiKey,
27
- });
28
- return response.data;
29
- },
30
- // Placeholders for future methods
31
- getSecrets: async (projectId, env, branch = "main") => {
32
- // Fixed path to match Next.js dynamic route folder structure
33
- const response = await getClient().get(`/projects/${projectId}/envs/${env}/secrets?branch=${branch}`);
34
- return response.data;
35
- },
36
- getSecretVersions: async (projectId, env, branch = "main") => {
37
- const response = await getClient().get(`/projects/${projectId}/envs/${env}/secrets?includeVersions=true&branch=${branch}`);
38
- return response.data;
39
- },
40
- setSecrets: async (projectId, env, secrets, expectedVersions, branch = "main") => {
41
- const response = await getClient().post(`/projects/${projectId}/envs/${env}/secrets`, { secrets, expectedVersions, branch });
42
- return response.data;
43
- },
44
- getSecretDetails: async (projectId, env, key, branch = "main") => {
45
- const response = await getClient().get(`/projects/${projectId}/envs/${env}/secrets/${key}?branch=${branch}`);
46
- return response.data;
47
- },
48
- syncLogs: async (logs) => {
49
- const response = await getClient().post("/audit/cli-logs", { logs });
50
- return response.data;
51
- },
52
- linkSecret: async (projectId, env, key, sourceProjectId, sourceEnv, sourceKey) => {
53
- const response = await getClient().post(`/projects/${projectId}/envs/${env}/secrets/link`, {
54
- key,
55
- sourceProjectId,
56
- sourceEnv,
57
- sourceKey
58
- });
59
- return response.data;
60
- },
61
- rotateSecret: async (projectId, env, key, strategy, parsedNewValue) => {
62
- const response = await getClient().post(`/projects/${projectId}/envs/${env}/secrets/${key}/rotate`, {
63
- strategy,
64
- parsedNewValue
65
- });
66
- return response.data;
67
- },
68
- promoteSecret: async (projectId, env, key) => {
69
- const response = await getClient().post(`/projects/${projectId}/envs/${env}/secrets/${key}/promote`, {});
70
- return response.data;
71
- },
72
- verifyAuditLogs: async () => {
73
- const response = await getClient().get("/audit/verify");
74
- return response.data;
75
- },
76
- exportAuditLogs: async (format, start, end, projectId) => {
77
- const body = { format };
78
- if (start)
79
- body.startDate = start;
80
- if (end)
81
- body.endDate = end;
82
- if (projectId)
83
- body.projectId = projectId;
84
- const response = await getClient().post("/audit/export", body, { responseType: format === "csv" ? "text" : "json" });
85
- return response.data;
86
- },
87
- // JIT Access
88
- requestAccess: async (projectId, reason, duration, secretId) => {
89
- const response = await getClient().post("/access/request", { projectId, secretId, reason, duration });
90
- return response.data;
91
- },
92
- approveAccess: async (requestId, decision) => {
93
- const response = await getClient().post("/access/approve", { requestId, decision });
94
- return response.data;
95
- },
96
- listAccessRequests: async (mode) => {
97
- const response = await getClient().get(`/access/list?mode=${mode}`);
98
- return response.data;
99
- },
100
- // Project Management
101
- getProjects: async () => {
102
- const { workspace } = (0, config_1.getConfig)();
103
- const url = workspace ? `/project?workspaceId=${workspace}` : "/project";
104
- const response = await getClient().get(url);
105
- return response.data;
106
- },
107
- // Branch Management
108
- getBranches: async (projectId) => {
109
- const response = await getClient().get(`/branch?projectId=${projectId}`);
110
- return response.data;
111
- },
112
- createBranch: async (projectId, name, description) => {
113
- const response = await getClient().post("/branch", { projectId, name, description });
114
- return response.data;
115
- },
116
- deleteBranch: async (branchId) => {
117
- const response = await getClient().delete(`/branch/${branchId}`);
118
- return response.data;
119
- },
120
- updateBranch: async (branchId, updates) => {
121
- const response = await getClient().put("/branch", { id: branchId, ...updates });
122
- return response.data;
123
- },
124
- // Admin - Role Management
125
- getRoles: async () => {
126
- const response = await getClient().get("/admin/roles");
127
- return response.data;
128
- },
129
- getUsers: async (teamId) => {
130
- const params = teamId ? `?teamId=${teamId}` : "";
131
- const response = await getClient().get(`/admin/users${params}`);
132
- return response.data;
133
- },
134
- setUserRole: async (email, role, teamId) => {
135
- const response = await getClient().put("/admin/users/role", { email, role, teamId });
136
- return response.data;
137
- },
138
- // Integrations
139
- getIntegrationStatus: async (provider) => {
140
- const response = await getClient().get(`/integrations/${provider}`);
141
- return response.data;
142
- },
143
- getIntegrationRepos: async (provider) => {
144
- const response = await getClient().get(`/integrations/${provider}/sync`);
145
- return response.data.repos;
146
- },
147
- syncSecretsToGithub: async (data) => {
148
- const response = await getClient().post("/integrations/github/sync", data);
149
- return response.data;
150
- },
151
- exportKubernetesSecret: async (projectId, params) => {
152
- const query = new URLSearchParams(params).toString();
153
- const response = await getClient().get(`/projects/${projectId}/kubernetes?${query}`);
154
- return response.data; // This returns the YAML string directly
155
- },
156
- // Advanced Features
157
- getSecretHistory: async (projectId, env, key) => {
158
- const response = await getClient().get(`/projects/${projectId}/envs/${env}/secrets/${key}/history`);
159
- return response.data;
160
- },
161
- rollbackSecret: async (projectId, env, key, version) => {
162
- const response = await getClient().post(`/projects/${projectId}/envs/${env}/secrets/${key}/history`, { version });
163
- return response.data;
164
- },
165
- cloneEnvironment: async (projectId, fromEnv, toEnv, overwrite, branch) => {
166
- const response = await getClient().post(`/projects/${projectId}/envs/clone`, { fromEnv, toEnv, overwrite, branch });
167
- return response.data;
168
- },
169
- // JIT Link Management
170
- generateJitLink: async (opts) => {
171
- const response = await getClient().post("/jit/generate", opts);
172
- return response.data;
173
- },
174
- claimJitLink: async (token) => {
175
- const response = await getClient().post("/jit/claim", { token });
176
- return response.data;
177
- },
178
- getJitInfo: async (token) => {
179
- const response = await getClient().get(`/jit/${token}`);
180
- return response.data;
181
- },
182
- // Generic POST method for audit logging and other uses
183
- post: async (endpoint, data) => {
184
- const response = await getClient().post(endpoint, data);
185
- return response.data;
186
- }
187
- };
1
+ var $=Object.create;var c=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var v=Object.getPrototypeOf,b=Object.prototype.hasOwnProperty;var k=(s,e)=>{for(var t in e)c(s,t,{get:e[t],enumerable:!0})},l=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of S(e))!b.call(s,a)&&a!==t&&c(s,a,{get:()=>e[a],enumerable:!(r=j(e,a))||r.enumerable});return s};var p=(s,e,t)=>(t=s!=null?$(v(s)):{},l(e||!s||!s.__esModule?c(t,"default",{value:s,enumerable:!0}):t,s)),x=s=>l(c({},"__esModule",{value:!0}),s);var C={};k(C,{api:()=>U});module.exports=x(C);var w=p(require("axios"));var y=p(require("conf"));var d="https://www.xtrasecurity.in/api",i=new y.default({projectName:"xtra-cli",defaults:{apiUrl:d}}),u=i.get("apiUrl");u&&!process.env.XTRA_API_URL&&(u.includes("localhost")||u.includes("xtra-security.vercel.app"))&&i.set("apiUrl",d);var g=()=>({...i.store,apiUrl:process.env.XTRA_API_URL||i.get("apiUrl")||d});var m=()=>i.get("token");var f=p(require("fs")),h=p(require("path")),I=JSON.parse(f.readFileSync(h.join(__dirname,"../../package.json"),"utf-8")),n=()=>{let{apiUrl:s}=g(),e=m();return w.default.create({baseURL:s,headers:{"Content-Type":"application/json","X-CLI-Version":I.version,...e?{Authorization:`Bearer ${e}`}:{}}})},U={login:async(s,e,t)=>(await n().post("/auth/cli-login",{email:s,password:e,apiKey:t})).data,getSecrets:async(s,e,t="main")=>(await n().get(`/projects/${s}/envs/${e}/secrets?branch=${t}`)).data,getSecretVersions:async(s,e,t="main")=>(await n().get(`/projects/${s}/envs/${e}/secrets?includeVersions=true&branch=${t}`)).data,setSecrets:async(s,e,t,r,a="main")=>(await n().post(`/projects/${s}/envs/${e}/secrets`,{secrets:t,expectedVersions:r,branch:a})).data,getSecretDetails:async(s,e,t,r="main")=>(await n().get(`/projects/${s}/envs/${e}/secrets/${t}?branch=${r}`)).data,syncLogs:async s=>(await n().post("/audit/cli-logs",{logs:s})).data,linkSecret:async(s,e,t,r,a,o)=>(await n().post(`/projects/${s}/envs/${e}/secrets/link`,{key:t,sourceProjectId:r,sourceEnv:a,sourceKey:o})).data,rotateSecret:async(s,e,t,r,a)=>(await n().post(`/projects/${s}/envs/${e}/secrets/${t}/rotate`,{strategy:r,parsedNewValue:a})).data,promoteSecret:async(s,e,t)=>(await n().post(`/projects/${s}/envs/${e}/secrets/${t}/promote`,{})).data,verifyAuditLogs:async()=>(await n().get("/audit/verify")).data,exportAuditLogs:async(s,e,t,r)=>{let a={format:s};return e&&(a.startDate=e),t&&(a.endDate=t),r&&(a.projectId=r),(await n().post("/audit/export",a,{responseType:s==="csv"?"text":"json"})).data},requestAccess:async(s,e,t,r)=>(await n().post("/access/request",{projectId:s,secretId:r,reason:e,duration:t})).data,approveAccess:async(s,e)=>(await n().post("/access/approve",{requestId:s,decision:e})).data,listAccessRequests:async s=>{let{workspace:e}=g(),t=e?`&workspaceId=${e}`:"";return(await n().get(`/access/list?mode=${s}${t}`)).data},getAccessRequestStatus:async s=>(await n().get(`/access/request?id=${s}`)).data,getProjects:async()=>{let{workspace:s}=g(),e=s?`/project?workspaceId=${s}`:"/project";return(await n().get(e)).data},getBranches:async s=>(await n().get(`/branch?projectId=${s}`)).data,createBranch:async(s,e,t)=>(await n().post("/branch",{projectId:s,name:e,description:t})).data,deleteBranch:async s=>(await n().delete(`/branch/${s}`)).data,updateBranch:async(s,e)=>(await n().put("/branch",{id:s,...e})).data,getRoles:async()=>(await n().get("/admin/roles")).data,getUsers:async s=>{let e=s?`?teamId=${s}`:"";return(await n().get(`/admin/users${e}`)).data},setUserRole:async(s,e,t)=>(await n().put("/admin/users/role",{email:s,role:e,teamId:t})).data,getIntegrationStatus:async s=>(await n().get(`/integrations/${s}`)).data,getIntegrationRepos:async s=>(await n().get(`/integrations/${s}/sync`)).data.repos,syncSecretsToGithub:async s=>(await n().post("/integrations/github/sync",s)).data,exportKubernetesSecret:async(s,e)=>{let t=new URLSearchParams(e).toString();return(await n().get(`/projects/${s}/kubernetes?${t}`)).data},getSecretHistory:async(s,e,t)=>(await n().get(`/projects/${s}/envs/${e}/secrets/${t}/history`)).data,rollbackSecret:async(s,e,t,r)=>(await n().post(`/projects/${s}/envs/${e}/secrets/${t}/history`,{version:r})).data,cloneEnvironment:async(s,e,t,r,a)=>(await n().post(`/projects/${s}/envs/clone`,{fromEnv:e,toEnv:t,overwrite:r,branch:a})).data,generateJitLink:async s=>(await n().post("/jit/generate",s)).data,claimJitLink:async s=>(await n().post("/jit/claim",{token:s})).data,getJitInfo:async s=>(await n().get(`/jit/${s}`)).data,post:async(s,e)=>(await n().post(s,e)).data};0&&(module.exports={api});
@@ -1,89 +1 @@
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 api_1 = require("./api");
7
- const axios_1 = __importDefault(require("axios"));
8
- const config_1 = require("./config");
9
- // Mock axios and config
10
- jest.mock('axios');
11
- jest.mock('./config');
12
- const mockAxios = axios_1.default;
13
- describe('API Client', () => {
14
- const mockCreate = jest.fn();
15
- const mockGet = jest.fn();
16
- const mockPost = jest.fn();
17
- beforeAll(() => {
18
- mockAxios.create = mockCreate;
19
- config_1.getConfig.mockReturnValue({ apiUrl: 'http://localhost:3000/api' });
20
- config_1.getAuthToken.mockReturnValue('test-token-123');
21
- mockCreate.mockReturnValue({
22
- get: mockGet,
23
- post: mockPost,
24
- });
25
- });
26
- beforeEach(() => {
27
- jest.clearAllMocks();
28
- });
29
- describe('login', () => {
30
- it('should send login request with email and password', async () => {
31
- mockPost.mockResolvedValue({ data: { token: 'new-token' } });
32
- const result = await api_1.api.login('user@example.com', 'password123');
33
- expect(mockPost).toHaveBeenCalledWith('/auth/cli-login', {
34
- email: 'user@example.com',
35
- password: 'password123',
36
- apiKey: undefined
37
- });
38
- expect(result).toEqual({ token: 'new-token' });
39
- });
40
- it('should send login request with API key', async () => {
41
- mockPost.mockResolvedValue({ data: { token: 'api-key-token' } });
42
- const result = await api_1.api.login(undefined, undefined, 'xtra_key_abc123');
43
- expect(mockPost).toHaveBeenCalledWith('/auth/cli-login', {
44
- email: undefined,
45
- password: undefined,
46
- apiKey: 'xtra_key_abc123'
47
- });
48
- expect(result).toEqual({ token: 'api-key-token' });
49
- });
50
- });
51
- describe('getSecrets', () => {
52
- it('should fetch secrets for project and environment', async () => {
53
- const mockSecrets = { secrets: [{ key: 'DB_URL', value: 'postgres://...' }] };
54
- mockGet.mockResolvedValue({ data: mockSecrets });
55
- const result = await api_1.api.getSecrets('proj-123', 'production', 'main');
56
- expect(mockGet).toHaveBeenCalledWith('/projects/proj-123/envs/production/secrets?branch=main');
57
- expect(result).toEqual(mockSecrets);
58
- });
59
- it('should use default branch if not specified', async () => {
60
- mockGet.mockResolvedValue({ data: { secrets: [] } });
61
- await api_1.api.getSecrets('proj-123', 'dev');
62
- expect(mockGet).toHaveBeenCalledWith('/projects/proj-123/envs/dev/secrets?branch=main');
63
- });
64
- });
65
- describe('setSecrets', () => {
66
- it('should post secrets to API', async () => {
67
- const secrets = { DB_URL: 'postgres://new', API_KEY: 'key123' };
68
- mockPost.mockResolvedValue({ data: { success: true } });
69
- const result = await api_1.api.setSecrets('proj-123', 'staging', secrets);
70
- expect(mockPost).toHaveBeenCalledWith('/projects/proj-123/envs/staging/secrets', {
71
- secrets,
72
- expectedVersions: undefined,
73
- branch: 'main'
74
- });
75
- expect(result).toEqual({ success: true });
76
- });
77
- });
78
- describe('rotateSecret', () => {
79
- it('should rotate secret with strategy', async () => {
80
- mockPost.mockResolvedValue({ data: { newValue: 'rotated-value' } });
81
- const result = await api_1.api.rotateSecret('proj-123', 'prod', 'API_KEY', 'regenerate');
82
- expect(mockPost).toHaveBeenCalledWith('/projects/proj-123/envs/prod/secrets/API_KEY/rotate', {
83
- strategy: 'regenerate',
84
- parsedNewValue: undefined
85
- });
86
- expect(result).toEqual({ newValue: 'rotated-value' });
87
- });
88
- });
89
- });
1
+ var j=Object.create;var y=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var b=Object.getPrototypeOf,S=Object.prototype.hasOwnProperty;var $=(e,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of x(t))!S.call(e,o)&&o!==s&&y(e,o,{get:()=>t[o],enumerable:!(n=v(t,o))||n.enumerable});return e};var p=(e,t,s)=>(s=e!=null?j(b(e)):{},$(t||!e||!e.__esModule?y(s,"default",{value:e,enumerable:!0}):s,e));var h=p(require("axios"));var m=p(require("conf"));var u="https://www.xtrasecurity.in/api",g=new m.default({projectName:"xtra-cli",defaults:{apiUrl:u}}),l=g.get("apiUrl");l&&!process.env.XTRA_API_URL&&(l.includes("localhost")||l.includes("xtra-security.vercel.app"))&&g.set("apiUrl",u);var c=()=>({...g.store,apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||u});var d=()=>g.get("token");var w=p(require("fs")),f=p(require("path")),R=JSON.parse(w.readFileSync(f.join(__dirname,"../../package.json"),"utf-8")),r=()=>{let{apiUrl:e}=c(),t=d();return h.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":R.version,...t?{Authorization:`Bearer ${t}`}:{}}})},a={login:async(e,t,s)=>(await r().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await r().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await r().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,n,o="main")=>(await r().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:n,branch:o})).data,getSecretDetails:async(e,t,s,n="main")=>(await r().get(`/projects/${e}/envs/${t}/secrets/${s}?branch=${n}`)).data,syncLogs:async e=>(await r().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,s,n,o,i)=>(await r().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:n,sourceEnv:o,sourceKey:i})).data,rotateSecret:async(e,t,s,n,o)=>(await r().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:n,parsedNewValue:o})).data,promoteSecret:async(e,t,s)=>(await r().post(`/projects/${e}/envs/${t}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await r().get("/audit/verify")).data,exportAuditLogs:async(e,t,s,n)=>{let o={format:e};return t&&(o.startDate=t),s&&(o.endDate=s),n&&(o.projectId=n),(await r().post("/audit/export",o,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,s,n)=>(await r().post("/access/request",{projectId:e,secretId:n,reason:t,duration:s})).data,approveAccess:async(e,t)=>(await r().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=c(),s=t?`&workspaceId=${t}`:"";return(await r().get(`/access/list?mode=${e}${s}`)).data},getAccessRequestStatus:async e=>(await r().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=c(),t=e?`/project?workspaceId=${e}`:"/project";return(await r().get(t)).data},getBranches:async e=>(await r().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,s)=>(await r().post("/branch",{projectId:e,name:t,description:s})).data,deleteBranch:async e=>(await r().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await r().put("/branch",{id:e,...t})).data,getRoles:async()=>(await r().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await r().get(`/admin/users${t}`)).data},setUserRole:async(e,t,s)=>(await r().put("/admin/users/role",{email:e,role:t,teamId:s})).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,t)=>{let s=new URLSearchParams(t).toString();return(await r().get(`/projects/${e}/kubernetes?${s}`)).data},getSecretHistory:async(e,t,s)=>(await r().get(`/projects/${e}/envs/${t}/secrets/${s}/history`)).data,rollbackSecret:async(e,t,s,n)=>(await r().post(`/projects/${e}/envs/${t}/secrets/${s}/history`,{version:n})).data,cloneEnvironment:async(e,t,s,n,o)=>(await r().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,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,t)=>(await r().post(e,t)).data};var k=p(require("axios"));jest.mock("axios");jest.mock("./config");var I=k.default;describe("API Client",()=>{let e=jest.fn(),t=jest.fn(),s=jest.fn();beforeAll(()=>{I.create=e,c.mockReturnValue({apiUrl:"http://localhost:3000/api"}),d.mockReturnValue("test-token-123"),e.mockReturnValue({get:t,post:s})}),beforeEach(()=>{jest.clearAllMocks()}),describe("login",()=>{it("should send login request with email and password",async()=>{s.mockResolvedValue({data:{token:"new-token"}});let n=await a.login("user@example.com","password123");expect(s).toHaveBeenCalledWith("/auth/cli-login",{email:"user@example.com",password:"password123",apiKey:void 0}),expect(n).toEqual({token:"new-token"})}),it("should send login request with API key",async()=>{s.mockResolvedValue({data:{token:"api-key-token"}});let n=await a.login(void 0,void 0,"xtra_key_abc123");expect(s).toHaveBeenCalledWith("/auth/cli-login",{email:void 0,password:void 0,apiKey:"xtra_key_abc123"}),expect(n).toEqual({token:"api-key-token"})})}),describe("getSecrets",()=>{it("should fetch secrets for project and environment",async()=>{let n={secrets:[{key:"DB_URL",value:"postgres://..."}]};t.mockResolvedValue({data:n});let o=await a.getSecrets("proj-123","production","main");expect(t).toHaveBeenCalledWith("/projects/proj-123/envs/production/secrets?branch=main"),expect(o).toEqual(n)}),it("should use default branch if not specified",async()=>{t.mockResolvedValue({data:{secrets:[]}}),await a.getSecrets("proj-123","dev"),expect(t).toHaveBeenCalledWith("/projects/proj-123/envs/dev/secrets?branch=main")})}),describe("setSecrets",()=>{it("should post secrets to API",async()=>{let n={DB_URL:"postgres://new",API_KEY:"key123"};s.mockResolvedValue({data:{success:!0}});let o=await a.setSecrets("proj-123","staging",n);expect(s).toHaveBeenCalledWith("/projects/proj-123/envs/staging/secrets",{secrets:n,expectedVersions:void 0,branch:"main"}),expect(o).toEqual({success:!0})})}),describe("rotateSecret",()=>{it("should rotate secret with strategy",async()=>{s.mockResolvedValue({data:{newValue:"rotated-value"}});let n=await a.rotateSecret("proj-123","prod","API_KEY","regenerate");expect(s).toHaveBeenCalledWith("/projects/proj-123/envs/prod/secrets/API_KEY/rotate",{strategy:"regenerate",parsedNewValue:void 0}),expect(n).toEqual({newValue:"rotated-value"})})})});
package/dist/lib/audit.js CHANGED
@@ -1,136 +1 @@
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.logAudit = logAudit;
7
- exports.loadAuditLogs = loadAuditLogs;
8
- exports.saveAuditLogs = saveAuditLogs;
9
- exports.syncAuditLogs = syncAuditLogs;
10
- const fs_1 = __importDefault(require("fs"));
11
- const path_1 = __importDefault(require("path"));
12
- const uuid_1 = require("uuid");
13
- const crypto_1 = require("./crypto");
14
- const config_1 = require("./config");
15
- const api_1 = require("./api");
16
- const MANIFEST_DIR = path_1.default.join(process.cwd(), ".xtra");
17
- const AUDIT_FILE = path_1.default.join(MANIFEST_DIR, "audit.enc");
18
- /**
19
- * Sanitize sensitive data from details
20
- */
21
- function sanitizeDetails(details) {
22
- if (!details || typeof details !== 'object')
23
- return details;
24
- const sanitized = { ...details };
25
- const sensitiveKeys = ['password', 'token', 'secret', 'value', 'apiKey', 'secretValue'];
26
- for (const key of Object.keys(sanitized)) {
27
- if (sensitiveKeys.some(sk => key.toLowerCase().includes(sk))) {
28
- sanitized[key] = '[REDACTED]';
29
- }
30
- }
31
- return sanitized;
32
- }
33
- /**
34
- * Send audit log to backend API
35
- */
36
- async function sendToBackend(entry) {
37
- try {
38
- const config = (0, config_1.getConfig)();
39
- // Skip if not authenticated
40
- if (!config.token) {
41
- return false;
42
- }
43
- const payload = {
44
- action: entry.action,
45
- entity: 'cli-project',
46
- entityId: entry.projectId || 'global',
47
- details: sanitizeDetails(entry.details),
48
- timestamp: entry.timestamp,
49
- projectId: entry.projectId,
50
- };
51
- await api_1.api.post('/audit/cli-logs', { logs: [payload] });
52
- return true;
53
- }
54
- catch (error) {
55
- // Silently fail - don't disrupt CLI operations
56
- if (process.env.DEBUG) {
57
- console.error('Failed to send audit log to backend:', error);
58
- }
59
- return false;
60
- }
61
- }
62
- function logAudit(action, projectId, environment, details) {
63
- const entry = {
64
- id: (0, uuid_1.v4)(),
65
- timestamp: new Date().toISOString(),
66
- action,
67
- projectId,
68
- environment,
69
- details,
70
- synced: false
71
- };
72
- // Save locally
73
- const logs = loadAuditLogs();
74
- logs.push(entry);
75
- saveAuditLogs(logs);
76
- // Send to backend (non-blocking)
77
- sendToBackend(entry).then((synced) => {
78
- if (synced) {
79
- // Mark as synced in local logs
80
- entry.synced = true;
81
- const updatedLogs = loadAuditLogs();
82
- const index = updatedLogs.findIndex(l => l.id === entry.id);
83
- if (index !== -1) {
84
- updatedLogs[index].synced = true;
85
- saveAuditLogs(updatedLogs);
86
- }
87
- }
88
- }).catch(() => {
89
- // Ignore errors
90
- });
91
- }
92
- function loadAuditLogs() {
93
- if (!fs_1.default.existsSync(AUDIT_FILE)) {
94
- return [];
95
- }
96
- try {
97
- const encryptedStr = fs_1.default.readFileSync(AUDIT_FILE, "utf-8");
98
- const encryptedObj = JSON.parse(encryptedStr);
99
- const decrypted = (0, crypto_1.decrypt)(encryptedObj);
100
- return JSON.parse(decrypted);
101
- }
102
- catch (error) {
103
- // console.error("Failed to load audit logs", error);
104
- return [];
105
- }
106
- }
107
- function saveAuditLogs(logs) {
108
- if (!fs_1.default.existsSync(MANIFEST_DIR)) {
109
- fs_1.default.mkdirSync(MANIFEST_DIR, { recursive: true });
110
- }
111
- const serialized = JSON.stringify(logs);
112
- const encryptedObj = (0, crypto_1.encrypt)(serialized);
113
- fs_1.default.writeFileSync(AUDIT_FILE, JSON.stringify(encryptedObj), "utf-8");
114
- }
115
- /**
116
- * Sync unsynced audit logs to backend
117
- */
118
- async function syncAuditLogs() {
119
- const logs = loadAuditLogs();
120
- const unsynced = logs.filter(l => !l.synced);
121
- if (unsynced.length === 0) {
122
- return 0;
123
- }
124
- let syncedCount = 0;
125
- for (const entry of unsynced) {
126
- const success = await sendToBackend(entry);
127
- if (success) {
128
- entry.synced = true;
129
- syncedCount++;
130
- }
131
- }
132
- if (syncedCount > 0) {
133
- saveAuditLogs(logs);
134
- }
135
- return syncedCount;
136
- }
1
+ var J=Object.create;var u=Object.defineProperty;var F=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var q=Object.getPrototypeOf,K=Object.prototype.hasOwnProperty;var V=(t,e)=>{for(var s in e)u(t,s,{get:e[s],enumerable:!0})},$=(t,e,s,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of G(e))!K.call(t,r)&&r!==s&&u(t,r,{get:()=>e[r],enumerable:!(n=F(e,r))||n.enumerable});return t};var i=(t,e,s)=>(s=t!=null?J(q(t)):{},$(e||!t||!t.__esModule?u(s,"default",{value:t,enumerable:!0}):s,t)),z=t=>$(u({},"__esModule",{value:!0}),t);var W={};V(W,{loadAuditLogs:()=>y,logAudit:()=>M,saveAuditLogs:()=>f,syncAuditLogs:()=>Q});module.exports=z(W);var g=i(require("fs")),x=i(require("path")),D=require("uuid");var c=i(require("crypto")),k=i(require("conf")),I=require("node-machine-id"),A="aes-256-gcm",b=new k.default({projectName:"xtra-cli-crypto"});function C(){let t=b.get("masterKey");t||(t=c.default.randomBytes(32).toString("hex"),b.set("masterKey",t));let e=(0,I.machineIdSync)();return c.default.createHash("sha256").update(t+e).digest()}var U=t=>{let e=c.default.randomBytes(16),s=C(),n=c.default.createCipheriv(A,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")}},R=t=>{let e=C(),s=Buffer.from(t.iv,"hex"),n=Buffer.from(t.tag,"hex"),r=c.default.createDecipheriv(A,e,s);r.setAuthTag(n);let a=r.update(t.content,"hex","utf8");return a+=r.final("utf8"),a};var L=i(require("conf"));var h="https://www.xtrasecurity.in/api",d=new L.default({projectName:"xtra-cli",defaults:{apiUrl:h}}),m=d.get("apiUrl");m&&!process.env.XTRA_API_URL&&(m.includes("localhost")||m.includes("xtra-security.vercel.app"))&&d.set("apiUrl",h);var p=()=>({...d.store,apiUrl:process.env.XTRA_API_URL||d.get("apiUrl")||h});var B=()=>d.get("token");var O=i(require("axios"));var T=i(require("fs")),P=i(require("path")),H=JSON.parse(T.readFileSync(P.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:t}=p(),e=B();return O.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":H.version,...e?{Authorization:`Bearer ${e}`}:{}}})},_={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}=p(),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}=p(),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 w=x.default.join(process.cwd(),".xtra"),S=x.default.join(w,"audit.enc");function X(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 N(t){try{if(!p().token)return!1;let s={action:t.action,entity:"cli-project",entityId:t.projectId||"global",details:X(t.details),timestamp:t.timestamp,projectId:t.projectId};return await _.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 M(t,e,s,n){let r={id:(0,D.v4)(),timestamp:new Date().toISOString(),action:t,projectId:e,environment:s,details:n,synced:!1},a=y();a.push(r),f(a),N(r).then(v=>{if(v){r.synced=!0;let l=y(),j=l.findIndex(E=>E.id===r.id);j!==-1&&(l[j].synced=!0,f(l))}}).catch(()=>{})}function y(){if(!g.default.existsSync(S))return[];try{let t=g.default.readFileSync(S,"utf-8"),e=JSON.parse(t),s=R(e);return JSON.parse(s)}catch{return[]}}function f(t){g.default.existsSync(w)||g.default.mkdirSync(w,{recursive:!0});let e=JSON.stringify(t),s=U(e);g.default.writeFileSync(S,JSON.stringify(s),"utf-8")}async function Q(){let t=y(),e=t.filter(n=>!n.synced);if(e.length===0)return 0;let s=0;for(let n of e)await N(n)&&(n.synced=!0,s++);return s>0&&f(t),s}0&&(module.exports={loadAuditLogs,logAudit,saveAuditLogs,syncAuditLogs});