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,184 +1,14 @@
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.profileCommand = void 0;
7
- const commander_1 = require("commander");
8
- const chalk_1 = __importDefault(require("chalk"));
9
- const table_1 = require("table");
10
- const inquirer_1 = __importDefault(require("inquirer"));
11
- const profiles_1 = require("../lib/profiles");
12
- // ─── Helper ───────────────────────────────────────────────────────────────────
13
- const safeError = (e) => e?.message || "Unknown error";
14
- // ─── xtra profile ─────────────────────────────────────────────────────────────
15
- exports.profileCommand = new commander_1.Command("profile")
16
- .description("Manage named configuration profiles (token, apiUrl, project per profile)")
17
- .addHelpText("after", `
18
- Examples:
19
- $ xtra profile list # Show all profiles
20
- $ xtra profile create work --url https://app.xtrasecurity.io/api
21
- $ xtra profile use work # Switch active profile
22
- $ xtra profile set work --project abc123 # Set a value in a profile
23
- $ xtra profile delete old-profile # Remove a profile
24
- $ xtra --profile work secrets list # Use profile for one command
25
- `);
26
- // ── LIST ──────────────────────────────────────────────────────────────────────
27
- exports.profileCommand
28
- .command("list")
29
- .alias("ls")
30
- .description("List all saved profiles")
31
- .action(() => {
32
- const profiles = (0, profiles_1.listProfiles)();
33
- const active = (0, profiles_1.getActiveProfileName)();
34
- if (Object.keys(profiles).length === 0) {
35
- console.log(chalk_1.default.yellow("No profiles found."));
36
- return;
37
- }
38
- const rows = [
39
- [chalk_1.default.bold("Profile"), chalk_1.default.bold("API URL"), chalk_1.default.bold("Project"), chalk_1.default.bold("Status")]
40
- ];
41
- for (const [name, data] of Object.entries(profiles)) {
42
- const isActive = name === active;
43
- rows.push([
44
- isActive ? chalk_1.default.green(`▶ ${name}`) : chalk_1.default.white(` ${name}`),
45
- chalk_1.default.gray(data.apiUrl || "(default)"),
46
- chalk_1.default.cyan(data.project || "(not set)"),
47
- isActive ? chalk_1.default.green("active") : chalk_1.default.gray("inactive"),
48
- ]);
49
- }
50
- console.log(chalk_1.default.bold("\nProfiles:\n"));
51
- console.log((0, table_1.table)(rows));
52
- console.log(chalk_1.default.gray(`Tip: Use XTRA_PROFILE=<name> to override per-command.\n`));
53
- });
54
- // ── CREATE ────────────────────────────────────────────────────────────────────
55
- exports.profileCommand
56
- .command("create <name>")
57
- .description("Create a new profile")
58
- .option("--url <apiUrl>", "XtraSecurity API URL for this profile")
59
- .option("--project <projectId>", "Default project ID for this profile")
60
- .option("--token <token>", "Auth token for this profile")
61
- .action(async (name, options) => {
62
- try {
63
- // If no options given, prompt interactively
64
- let { url, project, token } = options;
65
- if (!url && !project && !token) {
66
- const answers = await inquirer_1.default.prompt([
67
- {
68
- type: "input",
69
- name: "url",
70
- message: "API URL:",
71
- default: "https://www.xtrasecurity.in/api",
72
- },
73
- {
74
- type: "input",
75
- name: "project",
76
- message: "Default Project ID (optional):",
77
- default: "",
78
- },
79
- ]);
80
- url = answers.url;
81
- project = answers.project || undefined;
82
- }
83
- (0, profiles_1.createProfile)(name, { apiUrl: url, project: project || undefined, token: token || undefined });
84
- console.log(chalk_1.default.green(`✅ Profile '${name}' created!`));
85
- console.log(chalk_1.default.gray(` Activate it with: xtra profile use ${name}`));
86
- }
87
- catch (e) {
88
- console.error(chalk_1.default.red(safeError(e)));
89
- }
90
- });
91
- // ── USE ───────────────────────────────────────────────────────────────────────
92
- exports.profileCommand
93
- .command("use <name>")
94
- .description("Switch to a different profile (persists across sessions)")
95
- .action((name) => {
96
- try {
97
- (0, profiles_1.setActiveProfile)(name);
98
- console.log(chalk_1.default.green(`✅ Switched to profile '${name}'.`));
99
- console.log(chalk_1.default.gray(` All future commands will use this profile.`));
100
- }
101
- catch (e) {
102
- console.error(chalk_1.default.red(safeError(e)));
103
- }
104
- });
105
- // ── SET ───────────────────────────────────────────────────────────────────────
106
- exports.profileCommand
107
- .command("set <name>")
108
- .description("Update a value in an existing profile")
109
- .option("--url <apiUrl>", "Update the API URL")
110
- .option("--project <projectId>", "Update the default project ID")
111
- .option("--token <token>", "Update the auth token")
112
- .option("--env <environment>", "Update the default environment")
113
- .action((name, options) => {
114
- const fieldMap = {
115
- url: "apiUrl",
116
- project: "project",
117
- token: "token",
118
- env: "env",
119
- };
120
- const updated = [];
121
- try {
122
- for (const [flag, field] of Object.entries(fieldMap)) {
123
- if (options[flag]) {
124
- (0, profiles_1.setProfileValue)(name, field, options[flag]);
125
- updated.push(`${field} = ${field === "token" ? "****" : options[flag]}`);
126
- }
127
- }
128
- if (updated.length === 0) {
129
- console.log(chalk_1.default.yellow("No values provided. Use --url, --project, --token, or --env."));
130
- return;
131
- }
132
- console.log(chalk_1.default.green(`✅ Profile '${name}' updated:`));
133
- updated.forEach(u => console.log(chalk_1.default.gray(` ${u}`)));
134
- }
135
- catch (e) {
136
- console.error(chalk_1.default.red(safeError(e)));
137
- }
138
- });
139
- // ── CURRENT ───────────────────────────────────────────────────────────────────
140
- exports.profileCommand
141
- .command("current")
142
- .description("Show the currently active profile")
143
- .action(() => {
144
- const name = (0, profiles_1.getActiveProfileName)();
145
- const profiles = (0, profiles_1.listProfiles)();
146
- const data = profiles[name] || {};
147
- console.log(chalk_1.default.bold(`\nActive Profile: ${chalk_1.default.green(name)}\n`));
148
- const rows = [
149
- [chalk_1.default.bold("Key"), chalk_1.default.bold("Value")],
150
- ["API URL", chalk_1.default.cyan(data.apiUrl || "(default)")],
151
- ["Project", chalk_1.default.cyan(data.project || "(not set)")],
152
- ["Branch", chalk_1.default.cyan(data.branch || "(not set)")],
153
- ["Env", chalk_1.default.cyan(data.env || "(not set)")],
154
- ["Token", data.token ? chalk_1.default.green("Set ✓") : chalk_1.default.gray("Not set")],
155
- ];
156
- console.log((0, table_1.table)(rows));
157
- });
158
- // ── DELETE ────────────────────────────────────────────────────────────────────
159
- exports.profileCommand
160
- .command("delete <name>")
161
- .alias("rm")
162
- .description("Delete a profile")
163
- .option("-y, --yes", "Skip confirmation prompt")
164
- .action(async (name, options) => {
165
- try {
166
- if (!options.yes) {
167
- const { confirm } = await inquirer_1.default.prompt([{
168
- type: "confirm",
169
- name: "confirm",
170
- message: chalk_1.default.red(`Delete profile '${name}'? This cannot be undone.`),
171
- default: false,
172
- }]);
173
- if (!confirm) {
174
- console.log(chalk_1.default.gray("Cancelled."));
175
- return;
176
- }
177
- }
178
- (0, profiles_1.deleteProfile)(name);
179
- console.log(chalk_1.default.green(`✅ Profile '${name}' deleted.`));
180
- }
181
- catch (e) {
182
- console.error(chalk_1.default.red(safeError(e)));
183
- }
184
- });
1
+ var U=Object.create;var f=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var A=Object.getPrototypeOf,R=Object.prototype.hasOwnProperty;var b=(e,r)=>{for(var t in r)f(e,t,{get:r[t],enumerable:!0})},w=(e,r,t,i)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of $(r))!R.call(e,n)&&n!==t&&f(e,n,{get:()=>r[n],enumerable:!(i=j(r,n))||i.enumerable});return e};var u=(e,r,t)=>(t=e!=null?U(A(e)):{},w(r||!e||!e.__esModule?f(t,"default",{value:e,enumerable:!0}):t,e)),I=e=>w(f({},"__esModule",{value:!0}),e);var D={};b(D,{profileCommand:()=>c});module.exports=I(D);var k=require("commander"),o=u(require("chalk")),g=require("table"),P=u(require("inquirer"));var m=u(require("conf")),s=new m.default({projectName:"xtra-cli",defaults:{activeProfile:"default",profiles:{default:{apiUrl:process.env.XTRA_API_URL||"https://www.xtrasecurity.in/api"}}}});function a(){return s.get("profiles")||{}}function p(){return process.env.XTRA_PROFILE||s.get("activeProfile")||"default"}function h(e){if(!a()[e])throw new Error(`Profile '${e}' does not exist. Create it first with 'xtra profile create ${e}'.`);s.set("activeProfile",e)}function y(e,r={}){let t=a();if(t[e])throw new Error(`Profile '${e}' already exists. Use 'xtra profile set' to edit it.`);t[e]={apiUrl:process.env.XTRA_API_URL||"https://www.xtrasecurity.in/api",...r},s.set("profiles",t)}function v(e){if(e==="default")throw new Error("Cannot delete the 'default' profile.");let r=a();if(!r[e])throw new Error(`Profile '${e}' not found.`);delete r[e],s.set("profiles",r),p()===e&&s.set("activeProfile","default")}function x(e,r,t){let i=a();if(!i[e])throw new Error(`Profile '${e}' not found.`);i[e][r]=t,s.set("profiles",i)}var d=e=>e?.message||"Unknown error",c=new k.Command("profile").description("Manage named configuration profiles (token, apiUrl, project per profile)").addHelpText("after",`
2
+ Examples:
3
+ $ xtra profile list # Show all profiles
4
+ $ xtra profile create work --url https://app.xtrasecurity.io/api
5
+ $ xtra profile use work # Switch active profile
6
+ $ xtra profile set work --project abc123 # Set a value in a profile
7
+ $ xtra profile delete old-profile # Remove a profile
8
+ $ xtra --profile work secrets list # Use profile for one command
9
+ `);c.command("list").alias("ls").description("List all saved profiles").action(()=>{let e=a(),r=p();if(Object.keys(e).length===0){console.log(o.default.yellow("No profiles found."));return}let t=[[o.default.bold("Profile"),o.default.bold("API URL"),o.default.bold("Project"),o.default.bold("Status")]];for(let[i,n]of Object.entries(e)){let l=i===r;t.push([l?o.default.green(`\u25B6 ${i}`):o.default.white(` ${i}`),o.default.gray(n.apiUrl||"(default)"),o.default.cyan(n.project||"(not set)"),l?o.default.green("active"):o.default.gray("inactive")])}console.log(o.default.bold(`
10
+ Profiles:
11
+ `)),console.log((0,g.table)(t)),console.log(o.default.gray(`Tip: Use XTRA_PROFILE=<name> to override per-command.
12
+ `))});c.command("create <name>").description("Create a new profile").option("--url <apiUrl>","XtraSecurity API URL for this profile").option("--project <projectId>","Default project ID for this profile").option("--token <token>","Auth token for this profile").action(async(e,r)=>{try{let{url:t,project:i,token:n}=r;if(!t&&!i&&!n){let l=await P.default.prompt([{type:"input",name:"url",message:"API URL:",default:"https://www.xtrasecurity.in/api"},{type:"input",name:"project",message:"Default Project ID (optional):",default:""}]);t=l.url,i=l.project||void 0}y(e,{apiUrl:t,project:i||void 0,token:n||void 0}),console.log(o.default.green(`\u2705 Profile '${e}' created!`)),console.log(o.default.gray(` Activate it with: xtra profile use ${e}`))}catch(t){console.error(o.default.red(d(t)))}});c.command("use <name>").description("Switch to a different profile (persists across sessions)").action(e=>{try{h(e),console.log(o.default.green(`\u2705 Switched to profile '${e}'.`)),console.log(o.default.gray(" All future commands will use this profile."))}catch(r){console.error(o.default.red(d(r)))}});c.command("set <name>").description("Update a value in an existing profile").option("--url <apiUrl>","Update the API URL").option("--project <projectId>","Update the default project ID").option("--token <token>","Update the auth token").option("--env <environment>","Update the default environment").action((e,r)=>{let t={url:"apiUrl",project:"project",token:"token",env:"env"},i=[];try{for(let[n,l]of Object.entries(t))r[n]&&(x(e,l,r[n]),i.push(`${l} = ${l==="token"?"****":r[n]}`));if(i.length===0){console.log(o.default.yellow("No values provided. Use --url, --project, --token, or --env."));return}console.log(o.default.green(`\u2705 Profile '${e}' updated:`)),i.forEach(n=>console.log(o.default.gray(` ${n}`)))}catch(n){console.error(o.default.red(d(n)))}});c.command("current").description("Show the currently active profile").action(()=>{let e=p(),t=a()[e]||{};console.log(o.default.bold(`
13
+ Active Profile: ${o.default.green(e)}
14
+ `));let i=[[o.default.bold("Key"),o.default.bold("Value")],["API URL",o.default.cyan(t.apiUrl||"(default)")],["Project",o.default.cyan(t.project||"(not set)")],["Branch",o.default.cyan(t.branch||"(not set)")],["Env",o.default.cyan(t.env||"(not set)")],["Token",t.token?o.default.green("Set \u2713"):o.default.gray("Not set")]];console.log((0,g.table)(i))});c.command("delete <name>").alias("rm").description("Delete a profile").option("-y, --yes","Skip confirmation prompt").action(async(e,r)=>{try{if(!r.yes){let{confirm:t}=await P.default.prompt([{type:"confirm",name:"confirm",message:o.default.red(`Delete profile '${e}'? This cannot be undone.`),default:!1}]);if(!t){console.log(o.default.gray("Cancelled."));return}}v(e),console.log(o.default.green(`\u2705 Profile '${e}' deleted.`))}catch(t){console.error(o.default.red(d(t)))}});0&&(module.exports={profileCommand});
@@ -1,165 +1 @@
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.projectCommand = void 0;
40
- const commander_1 = require("commander");
41
- const chalk_1 = __importDefault(require("chalk"));
42
- const ora_1 = __importDefault(require("ora"));
43
- const inquirer_1 = __importDefault(require("inquirer"));
44
- const config_1 = require("../lib/config");
45
- const api_1 = require("../lib/api");
46
- const fs = __importStar(require("fs"));
47
- const path = __importStar(require("path"));
48
- exports.projectCommand = new commander_1.Command("project")
49
- .alias("projects")
50
- .description("Manage project context");
51
- const updateConfigs = (projectId, projectName) => {
52
- const oldProject = (0, config_1.getConfigValue)("project");
53
- // Always update global
54
- (0, config_1.setConfig)("project", projectId);
55
- // Clear branch if project changed
56
- if (oldProject !== projectId) {
57
- (0, config_1.setConfig)("branch", "main"); // Reset to main or clear? Projects have different branches.
58
- }
59
- // Update/Create local .xtrarc to make project context "sticky" to the directory
60
- const rcPath = path.join(process.cwd(), ".xtrarc");
61
- let rc = {};
62
- if (fs.existsSync(rcPath)) {
63
- try {
64
- rc = JSON.parse(fs.readFileSync(rcPath, "utf-8"));
65
- }
66
- catch (e) {
67
- console.error(chalk_1.default.yellow(` ⚠ Could not parse existing local .xtrarc: ${e instanceof Error ? e.message : 'Unknown error'}`));
68
- }
69
- }
70
- rc.project = projectId;
71
- if (oldProject !== projectId) {
72
- rc.branch = "main"; // Reset branch on project change
73
- }
74
- // Add other relevant defaults if it's a new file
75
- if (!rc.env)
76
- rc.env = "development";
77
- if (!rc.apiUrl)
78
- rc.apiUrl = (0, config_1.getConfigValue)("apiUrl") || "https://www.xtrasecurity.in/api";
79
- try {
80
- fs.writeFileSync(rcPath, JSON.stringify(rc, null, 2), "utf8");
81
- console.log(chalk_1.default.gray(` ✔ Updated local .xtrarc (Project context locked to this folder)`));
82
- }
83
- catch (e) {
84
- console.error(chalk_1.default.yellow(` ⚠ Could not write local .xtrarc: ${e instanceof Error ? e.message : 'Unknown error'}`));
85
- }
86
- console.log(chalk_1.default.green(`✔ Default project set to '${projectName}'`));
87
- const currentBranch = (0, config_1.getConfigValue)("branch");
88
- if (currentBranch) {
89
- console.log(chalk_1.default.gray(` Active branch: ${currentBranch}`));
90
- }
91
- };
92
- // SET
93
- exports.projectCommand
94
- .command("set")
95
- .description("Set the default project ID")
96
- .argument("[projectId]", "Project ID to set as default (optional - will show list if not provided)")
97
- .action(async (projectId) => {
98
- // If projectId is provided, set it directly
99
- if (projectId) {
100
- updateConfigs(projectId, projectId);
101
- return;
102
- }
103
- // Otherwise, fetch projects and show interactive selector
104
- const spinner = (0, ora_1.default)("Fetching your projects...").start();
105
- try {
106
- const projects = await api_1.api.getProjects();
107
- spinner.stop();
108
- if (!Array.isArray(projects) || projects.length === 0) {
109
- console.log(chalk_1.default.yellow("No projects found."));
110
- return;
111
- }
112
- const choices = projects.map((p) => ({
113
- name: `${p.name} (${p.id})`,
114
- value: p.id,
115
- short: p.name
116
- }));
117
- const { selectedProject } = await inquirer_1.default.prompt([{
118
- type: "list",
119
- name: "selectedProject",
120
- message: "Select a project:",
121
- choices
122
- }]);
123
- const selectedName = projects.find((p) => p.id === selectedProject)?.name || selectedProject;
124
- updateConfigs(selectedProject, selectedName);
125
- }
126
- catch (error) {
127
- spinner.fail("Failed to fetch projects");
128
- if (error.response?.data?.error) {
129
- console.error(chalk_1.default.red(`Error: ${error.response.data.error}`));
130
- }
131
- else {
132
- console.error(chalk_1.default.red(error.message));
133
- }
134
- }
135
- });
136
- // GET (show current)
137
- exports.projectCommand
138
- .command("current")
139
- .description("Show the current default project")
140
- .action(async () => {
141
- const projectId = (0, config_1.getConfigValue)("project");
142
- const branch = (0, config_1.getConfigValue)("branch");
143
- if (projectId) {
144
- // Try to fetch project name
145
- try {
146
- const projects = await api_1.api.getProjects();
147
- const project = projects.find((p) => p.id === projectId);
148
- if (project) {
149
- console.log(chalk_1.default.cyan(`Project: ${project.name} (${projectId})`));
150
- }
151
- else {
152
- console.log(chalk_1.default.cyan(`Project: ${projectId}`));
153
- }
154
- }
155
- catch {
156
- console.log(chalk_1.default.cyan(`Project: ${projectId}`));
157
- }
158
- }
159
- else {
160
- console.log(chalk_1.default.yellow("No default project set. Use 'xtra project set' to set one."));
161
- }
162
- if (branch) {
163
- console.log(chalk_1.default.cyan(`Branch: ${branch}`));
164
- }
165
- });
1
+ var L=Object.create;var u=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var O=(e,t)=>{for(var s in t)u(e,s,{get:t[s],enumerable:!0})},S=(e,t,s,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of _(t))!J.call(e,n)&&n!==s&&u(e,n,{get:()=>t[n],enumerable:!(r=N(t,n))||r.enumerable});return e};var p=(e,t,s)=>(s=e!=null?L(B(e)):{},S(t||!e||!e.__esModule?u(s,"default",{value:e,enumerable:!0}):s,e)),T=e=>S(u({},"__esModule",{value:!0}),e);var D={};O(D,{projectCommand:()=>$});module.exports=T(D);var P=require("commander"),a=p(require("chalk")),I=p(require("ora")),A=p(require("inquirer"));var x=p(require("conf")),f=p(require("fs"));var h="https://www.xtrasecurity.in/api",g=new x.default({projectName:"xtra-cli",defaults:{apiUrl:h}}),m=g.get("apiUrl");m&&!process.env.XTRA_API_URL&&(m.includes("localhost")||m.includes("xtra-security.vercel.app"))&&g.set("apiUrl",h);var y=()=>({...g.store,apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||h}),l=e=>g.get(e),w=(e,t)=>{if(g.set(e,t),e==="token"&&process.platform!=="win32"&&f.default.existsSync(g.path))try{f.default.chmodSync(g.path,384)}catch{}};var v=()=>g.get("token");var b=p(require("axios"));var k=p(require("fs")),U=p(require("path")),q=JSON.parse(k.readFileSync(U.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:e}=y(),t=v();return b.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":q.version,...t?{Authorization:`Bearer ${t}`}:{}}})},j={login:async(e,t,s)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,r,n="main")=>(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:r,branch:n})).data,getSecretDetails:async(e,t,s,r="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}?branch=${r}`)).data,syncLogs:async e=>(await o().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,s,r,n,i)=>(await o().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:r,sourceEnv:n,sourceKey:i})).data,rotateSecret:async(e,t,s,r,n)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:r,parsedNewValue:n})).data,promoteSecret:async(e,t,s)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(e,t,s,r)=>{let n={format:e};return t&&(n.startDate=t),s&&(n.endDate=s),r&&(n.projectId=r),(await o().post("/audit/export",n,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,s,r)=>(await o().post("/access/request",{projectId:e,secretId:r,reason:t,duration:s})).data,approveAccess:async(e,t)=>(await o().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=y(),s=t?`&workspaceId=${t}`:"";return(await o().get(`/access/list?mode=${e}${s}`)).data},getAccessRequestStatus:async e=>(await o().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=y(),t=e?`/project?workspaceId=${e}`:"/project";return(await o().get(t)).data},getBranches:async e=>(await o().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,s)=>(await o().post("/branch",{projectId:e,name:t,description:s})).data,deleteBranch:async e=>(await o().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await o().put("/branch",{id:e,...t})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await o().get(`/admin/users${t}`)).data},setUserRole:async(e,t,s)=>(await o().put("/admin/users/role",{email:e,role:t,teamId:s})).data,getIntegrationStatus:async e=>(await o().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await o().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await o().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,t)=>{let s=new URLSearchParams(t).toString();return(await o().get(`/projects/${e}/kubernetes?${s}`)).data},getSecretHistory:async(e,t,s)=>(await o().get(`/projects/${e}/envs/${t}/secrets/${s}/history`)).data,rollbackSecret:async(e,t,s,r)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${s}/history`,{version:r})).data,cloneEnvironment:async(e,t,s,r,n)=>(await o().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,overwrite:r,branch:n})).data,generateJitLink:async e=>(await o().post("/jit/generate",e)).data,claimJitLink:async e=>(await o().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await o().get(`/jit/${e}`)).data,post:async(e,t)=>(await o().post(e,t)).data};var d=p(require("fs")),R=p(require("path")),$=new P.Command("project").alias("projects").description("Manage project context"),C=(e,t)=>{let s=l("project");w("project",e),s!==e&&w("branch","main");let r=R.join(process.cwd(),".xtrarc"),n={};if(d.existsSync(r))try{n=JSON.parse(d.readFileSync(r,"utf-8"))}catch(c){console.error(a.default.yellow(` \u26A0 Could not parse existing local .xtrarc: ${c instanceof Error?c.message:"Unknown error"}`))}n.project=e,s!==e&&(n.branch="main"),n.env||(n.env="development"),n.apiUrl||(n.apiUrl=l("apiUrl")||"https://www.xtrasecurity.in/api");try{d.writeFileSync(r,JSON.stringify(n,null,2),"utf8"),console.log(a.default.gray(" \u2714 Updated local .xtrarc (Project context locked to this folder)"))}catch(c){console.error(a.default.yellow(` \u26A0 Could not write local .xtrarc: ${c instanceof Error?c.message:"Unknown error"}`))}console.log(a.default.green(`\u2714 Default project set to '${t}'`));let i=l("branch");i&&console.log(a.default.gray(` Active branch: ${i}`))};$.command("set").description("Set the default project ID").argument("[projectId]","Project ID to set as default (optional - will show list if not provided)").action(async e=>{if(e){C(e,e);return}let t=(0,I.default)("Fetching your projects...").start();try{let s=await j.getProjects();if(t.stop(),!Array.isArray(s)||s.length===0){console.log(a.default.yellow("No projects found."));return}let r=s.map(c=>({name:`${c.name} (${c.id})`,value:c.id,short:c.name})),{selectedProject:n}=await A.default.prompt([{type:"list",name:"selectedProject",message:"Select a project:",choices:r}]),i=s.find(c=>c.id===n)?.name||n;C(n,i)}catch(s){t.fail("Failed to fetch projects"),s.response?.data?.error?console.error(a.default.red(`Error: ${s.response.data.error}`)):console.error(a.default.red(s.message))}});$.command("current").description("Show the current default project").action(async()=>{let e=l("project"),t=l("branch");if(e)try{let r=(await j.getProjects()).find(n=>n.id===e);console.log(r?a.default.cyan(`Project: ${r.name} (${e})`):a.default.cyan(`Project: ${e}`))}catch{console.log(a.default.cyan(`Project: ${e}`))}else console.log(a.default.yellow("No default project set. Use 'xtra project set' to set one."));t&&console.log(a.default.cyan(`Branch: ${t}`))});0&&(module.exports={projectCommand});
@@ -1,95 +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.rollbackCommand = 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 inquirer_1 = __importDefault(require("inquirer"));
12
- const crypto_1 = require("../lib/crypto");
13
- const config_1 = require("../lib/config");
14
- exports.rollbackCommand = new commander_1.Command("rollback")
15
- .description("Rollback a secret to a previous version")
16
- .argument("<key>", "Secret Key to rollback")
17
- .option("-p, --project <projectId>", "Project ID")
18
- .option("-e, --env <environment>", "Environment (dev, stg, prod)", "dev")
19
- .action(async (key, options) => {
20
- let { project, env } = options;
21
- // Use config fallback
22
- if (!project)
23
- project = (0, config_1.getRcConfig)().project;
24
- if (!project) {
25
- console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
26
- process.exit(1);
27
- }
28
- // Normalize Env
29
- const envMap = { dev: "development", stg: "staging", prod: "production" };
30
- env = envMap[env] || env;
31
- const spinner = (0, ora_1.default)(`Fetching history for ${key}...`).start();
32
- try {
33
- const secret = await api_1.api.getSecretDetails(project, env, key);
34
- spinner.stop();
35
- if (!secret.history || !Array.isArray(secret.history) || secret.history.length === 0) {
36
- console.log(chalk_1.default.yellow(`No history found for ${key}. Cannot rollback.`));
37
- return;
38
- }
39
- // Prepare choices
40
- // Current version
41
- const choices = [];
42
- // History versions (reverse order to show latest first)
43
- const history = [...secret.history].reverse();
44
- history.forEach((h) => {
45
- let displayValue = "********";
46
- try {
47
- const enc = JSON.parse(h.value[0]);
48
- displayValue = (0, crypto_1.decrypt)(enc);
49
- }
50
- catch (e) {
51
- displayValue = h.value[0];
52
- }
53
- choices.push({
54
- name: `v${h.version} - ${new Date(h.updatedAt).toLocaleString()} (Value: ${displayValue.substring(0, 10)}...)`,
55
- value: h
56
- });
57
- });
58
- const { selectedVersion } = await inquirer_1.default.prompt([
59
- {
60
- type: "list",
61
- name: "selectedVersion",
62
- message: "Select version to restore:",
63
- choices: choices
64
- }
65
- ]);
66
- // Restore
67
- const confirmSpinner = (0, ora_1.default)(`Restoring version v${selectedVersion.version}...`).start();
68
- // We use setSecrets to update it to the old value.
69
- // This will create a NEW version in history (preserving the timeline).
70
- let restoredValue = selectedVersion.value[0];
71
- try {
72
- const enc = JSON.parse(restoredValue);
73
- restoredValue = (0, crypto_1.decrypt)(enc);
74
- }
75
- catch (e) { }
76
- const payload = { [key]: restoredValue };
77
- await api_1.api.setSecrets(project, env, payload);
78
- confirmSpinner.succeed(`Successfully rolled back ${key} to v${selectedVersion.version}`);
79
- // Log Audit
80
- try {
81
- const { logAudit } = require("../lib/audit");
82
- logAudit("SECRET_ROLLBACK", project, env, { key, version: selectedVersion.version });
83
- }
84
- catch (e) { }
85
- }
86
- catch (error) {
87
- spinner.fail("Failed to rollback.");
88
- if (error.response && error.response.status === 404) {
89
- console.error(chalk_1.default.red("Secret not found."));
90
- }
91
- else {
92
- console.error(chalk_1.default.red(error.message));
93
- }
94
- }
95
- });
1
+ var it=Object.create;var w=Object.defineProperty;var ct=Object.getOwnPropertyDescriptor;var pt=Object.getOwnPropertyNames;var gt=Object.getPrototypeOf,dt=Object.prototype.hasOwnProperty;var S=(t,e)=>()=>(t&&(e=t(t=0)),e);var P=(t,e)=>{for(var s in e)w(t,s,{get:e[s],enumerable:!0})},T=(t,e,s,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of pt(e))!dt.call(t,n)&&n!==s&&w(t,n,{get:()=>e[n],enumerable:!(r=ct(e,n))||r.enumerable});return t};var i=(t,e,s)=>(s=t!=null?it(gt(t)):{},T(e||!t||!t.__esModule?w(s,"default",{value:t,enumerable:!0}):s,t)),_=t=>T(w({},"__esModule",{value:!0}),t);var J,C,F,R,g,A,l,V,q,j=S(()=>{J=i(require("conf")),C=i(require("fs")),F=i(require("path")),R="https://www.xtrasecurity.in/api",g=new J.default({projectName:"xtra-cli",defaults:{apiUrl:R}}),A=g.get("apiUrl");A&&!process.env.XTRA_API_URL&&(A.includes("localhost")||A.includes("xtra-security.vercel.app"))&&g.set("apiUrl",R);l=()=>({...g.store,apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||R}),V=()=>g.get("token"),q=()=>{let t={};try{let e=F.default.join(process.cwd(),".xtrarc");C.default.existsSync(e)&&(t=JSON.parse(C.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 G,K,z,ut,o,m,L=S(()=>{G=i(require("axios"));j();K=i(require("fs")),z=i(require("path")),ut=JSON.parse(K.readFileSync(z.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:t}=l(),e=V();return G.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":ut.version,...e?{Authorization:`Bearer ${e}`}:{}}})},m={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,a)=>(await o().post(`/projects/${t}/envs/${e}/secrets/link`,{key:s,sourceProjectId:r,sourceEnv:n,sourceKey:a})).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}=l(),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}=l(),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 W(){let t=H.get("masterKey");t||(t=y.default.randomBytes(32).toString("hex"),H.set("masterKey",t));let e=(0,X.machineIdSync)();return y.default.createHash("sha256").update(t+e).digest()}var y,M,X,Q,H,Y,h,U=S(()=>{y=i(require("crypto")),M=i(require("conf")),X=require("node-machine-id"),Q="aes-256-gcm",H=new M.default({projectName:"xtra-cli-crypto"});Y=t=>{let e=y.default.randomBytes(16),s=W(),r=y.default.createCipheriv(Q,s,e),n=r.update(t,"utf8","hex");n+=r.final("hex");let a=r.getAuthTag();return{iv:e.toString("hex"),content:n,tag:a.toString("hex")}},h=t=>{let e=W(),s=Buffer.from(t.iv,"hex"),r=Buffer.from(t.tag,"hex"),n=y.default.createDecipheriv(Q,e,s);n.setAuthTag(r);let a=n.update(t.content,"hex","utf8");return a+=n.final("utf8"),a}});var et={};P(et,{loadAuditLogs:()=>x,logAudit:()=>yt,saveAuditLogs:()=>$,syncAuditLogs:()=>ft});function lt(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 tt(t){try{if(!l().token)return!1;let s={action:t.action,entity:"cli-project",entityId:t.projectId||"global",details:lt(t.details),timestamp:t.timestamp,projectId:t.projectId};return await m.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 yt(t,e,s,r){let n={id:(0,Z.v4)(),timestamp:new Date().toISOString(),action:t,projectId:e,environment:s,details:r,synced:!1},a=x();a.push(n),$(a),tt(n).then(c=>{if(c){n.synced=!0;let d=x(),b=d.findIndex(u=>u.id===n.id);b!==-1&&(d[b].synced=!0,$(d))}}).catch(()=>{})}function x(){if(!f.default.existsSync(B))return[];try{let t=f.default.readFileSync(B,"utf-8"),e=JSON.parse(t),s=h(e);return JSON.parse(s)}catch{return[]}}function $(t){f.default.existsSync(O)||f.default.mkdirSync(O,{recursive:!0});let e=JSON.stringify(t),s=Y(e);f.default.writeFileSync(B,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 tt(r)&&(r.synced=!0,s++);return s>0&&$(t),s}var f,D,Z,O,B,st=S(()=>{f=i(require("fs")),D=i(require("path")),Z=require("uuid");U();j();L();O=D.default.join(process.cwd(),".xtra"),B=D.default.join(O,"audit.enc")});var ht={};P(ht,{rollbackCommand:()=>mt});module.exports=_(ht);var rt=require("commander");L();var v=i(require("chalk")),E=i(require("ora")),nt=i(require("inquirer"));U();j();var mt=new rt.Command("rollback").description("Rollback a secret to a previous version").argument("<key>","Secret Key to rollback").option("-p, --project <projectId>","Project ID").option("-e, --env <environment>","Environment (dev, stg, prod)","dev").action(async(t,e)=>{let{project:s,env:r}=e;s||(s=q().project),s||(console.error(v.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first.")),process.exit(1)),r={dev:"development",stg:"staging",prod:"production"}[r]||r;let a=(0,E.default)(`Fetching history for ${t}...`).start();try{let c=await m.getSecretDetails(s,r,t);if(a.stop(),!c.history||!Array.isArray(c.history)||c.history.length===0){console.log(v.default.yellow(`No history found for ${t}. Cannot rollback.`));return}let d=[];[...c.history].reverse().forEach(p=>{let I="********";try{let N=JSON.parse(p.value[0]);I=h(N)}catch{I=p.value[0]}d.push({name:`v${p.version} - ${new Date(p.updatedAt).toLocaleString()} (Value: ${I.substring(0,10)}...)`,value:p})});let{selectedVersion:u}=await nt.default.prompt([{type:"list",name:"selectedVersion",message:"Select version to restore:",choices:d}]),ot=(0,E.default)(`Restoring version v${u.version}...`).start(),k=u.value[0];try{let p=JSON.parse(k);k=h(p)}catch{}let at={[t]:k};await m.setSecrets(s,r,at),ot.succeed(`Successfully rolled back ${t} to v${u.version}`);try{let{logAudit:p}=(st(),_(et));p("SECRET_ROLLBACK",s,r,{key:t,version:u.version})}catch{}}catch(c){a.fail("Failed to rollback."),c.response&&c.response.status===404?console.error(v.default.red("Secret not found.")):console.error(v.default.red(c.message))}});0&&(module.exports={rollbackCommand});
@@ -1,93 +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.rotateCommand = void 0;
7
- const commander_1 = require("commander");
8
- const api_1 = require("../lib/api");
9
- const config_1 = require("../lib/config");
10
- const chalk_1 = __importDefault(require("chalk"));
11
- const ora_1 = __importDefault(require("ora"));
12
- exports.rotateCommand = new commander_1.Command("rotate")
13
- .description("Rotate a secret (Zero-Downtime Shadow Mode)")
14
- .argument("<key>", "Key of the secret to rotate")
15
- .option("-p, --project <projectId>", "Project ID")
16
- .option("-e, --env <environment>", "Environment", "development")
17
- .option("--strategy <strategy>", "Rotation strategy", "shadow")
18
- .option("--promote", "Promote the shadow value to active", false)
19
- .option("--value <value>", "New value for the secret (optional)")
20
- .action(async (key, options) => {
21
- let { project, env, strategy, promote, value } = options;
22
- // Use config fallback
23
- if (!project)
24
- project = (0, config_1.getRcConfig)().project;
25
- // Normalize Env
26
- const envMap = { dev: "development", stg: "staging", prod: "production" };
27
- env = envMap[env] || env;
28
- if (!project) {
29
- console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or checkout a branch."));
30
- process.exit(1);
31
- }
32
- // Production confirmation gate
33
- if (env === "production") {
34
- const inquirer = require("inquirer");
35
- const { confirmProd } = await inquirer.prompt([{
36
- type: "confirm",
37
- name: "confirmProd",
38
- message: chalk_1.default.red(`⚠ You are about to rotate a secret in PRODUCTION (${key}). Proceed?`),
39
- default: false,
40
- }]);
41
- if (!confirmProd) {
42
- console.log(chalk_1.default.yellow("Aborted."));
43
- return;
44
- }
45
- }
46
- if (promote) {
47
- // PROMOTE FLOW
48
- const spinner = (0, ora_1.default)(`Promoting secret '${key}' in ${env}...`).start();
49
- try {
50
- const result = await api_1.api.promoteSecret(project, env, key);
51
- spinner.succeed(chalk_1.default.green(`Successfully promoted '${key}' to version ${result.version}`));
52
- try {
53
- const { logAudit } = require("../lib/audit");
54
- logAudit("SECRET_PROMOTE", project, env, { key, newVersion: result.version });
55
- }
56
- catch (e) { }
57
- }
58
- catch (error) {
59
- spinner.fail("Promotion failed");
60
- if (error.response && error.response.data && error.response.data.error) {
61
- console.error(chalk_1.default.red(`Server Error: ${error.response.data.error}`));
62
- }
63
- else {
64
- console.error(chalk_1.default.red(error.message));
65
- }
66
- }
67
- }
68
- else {
69
- // ROTATE FLOW
70
- const spinner = (0, ora_1.default)(`Starting rotation for '${key}' (Strategy: ${strategy})...`).start();
71
- try {
72
- const result = await api_1.api.rotateSecret(project, env, key, strategy, value);
73
- spinner.succeed(chalk_1.default.green(`Rotation initiated for '${key}'`));
74
- console.log(chalk_1.default.dim(`Shadow Value: ${result.shadowValue}`));
75
- console.log(chalk_1.default.dim(`Expires At: ${result.expiresAt}`));
76
- console.log(chalk_1.default.blue(`\nTo verify, run your app. To finalize, run:\nxtra rotate ${key} --promote -p ${project} -e ${env}`));
77
- try {
78
- const { logAudit } = require("../lib/audit");
79
- logAudit("SECRET_ROTATE", project, env, { key, strategy, expiresAt: result.expiresAt });
80
- }
81
- catch (e) { }
82
- }
83
- catch (error) {
84
- spinner.fail("Rotation failed");
85
- if (error.response && error.response.data && error.response.data.error) {
86
- console.error(chalk_1.default.red(`Server Error: ${error.response.data.error}`));
87
- }
88
- else {
89
- console.error(chalk_1.default.red(error.message));
90
- }
91
- }
92
- }
93
- });
1
+ var et=Object.create;var w=Object.defineProperty;var rt=Object.getOwnPropertyDescriptor;var st=Object.getOwnPropertyNames;var nt=Object.getPrototypeOf,ot=Object.prototype.hasOwnProperty;var S=(t,e)=>()=>(t&&(e=t(t=0)),e);var L=(t,e)=>{for(var r in e)w(t,r,{get:e[r],enumerable:!0})},D=(t,e,r,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of st(e))!ot.call(t,n)&&n!==r&&w(t,n,{get:()=>e[n],enumerable:!(s=rt(e,n))||s.enumerable});return t};var p=(t,e,r)=>(r=t!=null?et(nt(t)):{},D(e||!t||!t.__esModule?w(r,"default",{value:t,enumerable:!0}):r,t)),b=t=>D(w({},"__esModule",{value:!0}),t);var B,I,N,k,d,A,u,_,q,x=S(()=>{B=p(require("conf")),I=p(require("fs")),N=p(require("path")),k="https://www.xtrasecurity.in/api",d=new B.default({projectName:"xtra-cli",defaults:{apiUrl:k}}),A=d.get("apiUrl");A&&!process.env.XTRA_API_URL&&(A.includes("localhost")||A.includes("xtra-security.vercel.app"))&&d.set("apiUrl",k);u=()=>({...d.store,apiUrl:process.env.XTRA_API_URL||d.get("apiUrl")||k}),_=()=>d.get("token"),q=()=>{let t={};try{let e=N.default.join(process.cwd(),".xtrarc");I.default.existsSync(e)&&(t=JSON.parse(I.default.readFileSync(e,"utf-8")))}catch{}return{project:t.project||d.get("project")||"",env:t.env||d.get("env")||"development",branch:t.branch||d.get("branch")||"main"}}});var J,V,F,at,o,y,C=S(()=>{J=p(require("axios"));x();V=p(require("fs")),F=p(require("path")),at=JSON.parse(V.readFileSync(F.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:t}=u(),e=_();return J.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":at.version,...e?{Authorization:`Bearer ${e}`}:{}}})},y={login:async(t,e,r)=>(await o().post("/auth/cli-login",{email:t,password:e,apiKey:r})).data,getSecrets:async(t,e,r="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets?branch=${r}`)).data,getSecretVersions:async(t,e,r="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets?includeVersions=true&branch=${r}`)).data,setSecrets:async(t,e,r,s,n="main")=>(await o().post(`/projects/${t}/envs/${e}/secrets`,{secrets:r,expectedVersions:s,branch:n})).data,getSecretDetails:async(t,e,r,s="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets/${r}?branch=${s}`)).data,syncLogs:async t=>(await o().post("/audit/cli-logs",{logs:t})).data,linkSecret:async(t,e,r,s,n,i)=>(await o().post(`/projects/${t}/envs/${e}/secrets/link`,{key:r,sourceProjectId:s,sourceEnv:n,sourceKey:i})).data,rotateSecret:async(t,e,r,s,n)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${r}/rotate`,{strategy:s,parsedNewValue:n})).data,promoteSecret:async(t,e,r)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${r}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(t,e,r,s)=>{let n={format:t};return e&&(n.startDate=e),r&&(n.endDate=r),s&&(n.projectId=s),(await o().post("/audit/export",n,{responseType:t==="csv"?"text":"json"})).data},requestAccess:async(t,e,r,s)=>(await o().post("/access/request",{projectId:t,secretId:s,reason:e,duration:r})).data,approveAccess:async(t,e)=>(await o().post("/access/approve",{requestId:t,decision:e})).data,listAccessRequests:async t=>{let{workspace:e}=u(),r=e?`&workspaceId=${e}`:"";return(await o().get(`/access/list?mode=${t}${r}`)).data},getAccessRequestStatus:async t=>(await o().get(`/access/request?id=${t}`)).data,getProjects:async()=>{let{workspace:t}=u(),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,r)=>(await o().post("/branch",{projectId:t,name:e,description:r})).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,r)=>(await o().put("/admin/users/role",{email:t,role:e,teamId:r})).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 r=new URLSearchParams(e).toString();return(await o().get(`/projects/${t}/kubernetes?${r}`)).data},getSecretHistory:async(t,e,r)=>(await o().get(`/projects/${t}/envs/${e}/secrets/${r}/history`)).data,rollbackSecret:async(t,e,r,s)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${r}/history`,{version:s})).data,cloneEnvironment:async(t,e,r,s,n)=>(await o().post(`/projects/${t}/envs/clone`,{fromEnv:e,toEnv:r,overwrite:s,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,M.machineIdSync)();return l.default.createHash("sha256").update(t+e).digest()}var l,K,M,z,G,X,Y,Z=S(()=>{l=p(require("crypto")),K=p(require("conf")),M=require("node-machine-id"),z="aes-256-gcm",G=new K.default({projectName:"xtra-cli-crypto"});X=t=>{let e=l.default.randomBytes(16),r=H(),s=l.default.createCipheriv(z,r,e),n=s.update(t,"utf8","hex");n+=s.final("hex");let i=s.getAuthTag();return{iv:e.toString("hex"),content:n,tag:i.toString("hex")}},Y=t=>{let e=H(),r=Buffer.from(t.iv,"hex"),s=Buffer.from(t.tag,"hex"),n=l.default.createDecipheriv(z,e,r);n.setAuthTag(s);let i=n.update(t.content,"hex","utf8");return i+=n.final("utf8"),i}});var T={};L(T,{loadAuditLogs:()=>$,logAudit:()=>ct,saveAuditLogs:()=>j,syncAuditLogs:()=>pt});function it(t){if(!t||typeof t!="object")return t;let e={...t},r=["password","token","secret","value","apiKey","secretValue"];for(let s of Object.keys(e))r.some(n=>s.toLowerCase().includes(n))&&(e[s]="[REDACTED]");return e}async function W(t){try{if(!u().token)return!1;let r={action:t.action,entity:"cli-project",entityId:t.projectId||"global",details:it(t.details),timestamp:t.timestamp,projectId:t.projectId};return await y.post("/audit/cli-logs",{logs:[r]}),!0}catch(e){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",e),!1}}function ct(t,e,r,s){let n={id:(0,Q.v4)(),timestamp:new Date().toISOString(),action:t,projectId:e,environment:r,details:s,synced:!1},i=$();i.push(n),j(i),W(n).then(h=>{if(h){n.synced=!0;let v=$(),g=v.findIndex(a=>a.id===n.id);g!==-1&&(v[g].synced=!0,j(v))}}).catch(()=>{})}function $(){if(!f.default.existsSync(P))return[];try{let t=f.default.readFileSync(P,"utf-8"),e=JSON.parse(t),r=Y(e);return JSON.parse(r)}catch{return[]}}function j(t){f.default.existsSync(R)||f.default.mkdirSync(R,{recursive:!0});let e=JSON.stringify(t),r=X(e);f.default.writeFileSync(P,JSON.stringify(r),"utf-8")}async function pt(){let t=$(),e=t.filter(s=>!s.synced);if(e.length===0)return 0;let r=0;for(let s of e)await W(s)&&(s.synced=!0,r++);return r>0&&j(t),r}var f,E,Q,R,P,U=S(()=>{f=p(require("fs")),E=p(require("path")),Q=require("uuid");Z();x();C();R=E.default.join(process.cwd(),".xtra"),P=E.default.join(R,"audit.enc")});var dt={};L(dt,{rotateCommand:()=>gt});module.exports=b(dt);var tt=require("commander");C();x();var c=p(require("chalk")),O=p(require("ora")),gt=new tt.Command("rotate").description("Rotate a secret (Zero-Downtime Shadow Mode)").argument("<key>","Key of the secret to rotate").option("-p, --project <projectId>","Project ID").option("-e, --env <environment>","Environment","development").option("--strategy <strategy>","Rotation strategy","shadow").option("--promote","Promote the shadow value to active",!1).option("--value <value>","New value for the secret (optional)").action(async(t,e)=>{let{project:r,env:s,strategy:n,promote:i,value:h}=e;if(r||(r=q().project),s={dev:"development",stg:"staging",prod:"production"}[s]||s,r||(console.error(c.default.red("Error: Project ID is required. Use -p <id> or checkout a branch.")),process.exit(1)),s==="production"){let g=require("inquirer"),{confirmProd:a}=await g.prompt([{type:"confirm",name:"confirmProd",message:c.default.red(`\u26A0 You are about to rotate a secret in PRODUCTION (${t}). Proceed?`),default:!1}]);if(!a){console.log(c.default.yellow("Aborted."));return}}if(i){let g=(0,O.default)(`Promoting secret '${t}' in ${s}...`).start();try{let a=await y.promoteSecret(r,s,t);g.succeed(c.default.green(`Successfully promoted '${t}' to version ${a.version}`));try{let{logAudit:m}=(U(),b(T));m("SECRET_PROMOTE",r,s,{key:t,newVersion:a.version})}catch{}}catch(a){g.fail("Promotion failed"),a.response&&a.response.data&&a.response.data.error?console.error(c.default.red(`Server Error: ${a.response.data.error}`)):console.error(c.default.red(a.message))}}else{let g=(0,O.default)(`Starting rotation for '${t}' (Strategy: ${n})...`).start();try{let a=await y.rotateSecret(r,s,t,n,h);g.succeed(c.default.green(`Rotation initiated for '${t}'`)),console.log(c.default.dim(`Shadow Value: ${a.shadowValue}`)),console.log(c.default.dim(`Expires At: ${a.expiresAt}`)),console.log(c.default.blue(`
2
+ To verify, run your app. To finalize, run:
3
+ xtra rotate ${t} --promote -p ${r} -e ${s}`));try{let{logAudit:m}=(U(),b(T));m("SECRET_ROTATE",r,s,{key:t,strategy:n,expiresAt:a.expiresAt})}catch{}}catch(a){g.fail("Rotation failed"),a.response&&a.response.data&&a.response.data.error?console.error(c.default.red(`Server Error: ${a.response.data.error}`)):console.error(c.default.red(a.message))}}});0&&(module.exports={rotateCommand});