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,305 +1,14 @@
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.secretsCommand = void 0;
40
- const commander_1 = require("commander");
41
- const api_1 = require("../lib/api");
42
- const chalk_1 = __importDefault(require("chalk"));
43
- const ora_1 = __importDefault(require("ora"));
44
- const table_1 = require("table");
45
- const config_1 = require("../lib/config");
46
- exports.secretsCommand = new commander_1.Command("secrets")
47
- .description("Manage secrets (List, Set, Delete)")
48
- .option("-p, --project <projectId>", "Project ID")
49
- .option("-e, --env <environment>", "Environment (development, staging, production)", "development")
50
- .option("-b, --branch <branchName>", "Branch Name");
51
- // LIST
52
- exports.secretsCommand
53
- .command("list")
54
- .description("List all secrets for a project/environment")
55
- .option("--show", "Reveal secret values", false)
56
- .addHelpText("after", `
57
- Examples:
58
- $ xtra secrets list
59
- $ xtra secrets list -e production --show
60
- `)
61
- .action(async (options) => {
62
- const parentOpts = exports.secretsCommand.opts();
63
- let { project, env, branch } = parentOpts;
64
- // Load .xtrarc from CWD (local project config has priority over global conf store)
65
- const rc = (0, config_1.getRcConfig)();
66
- if (!project)
67
- project = rc.project;
68
- if (!branch)
69
- branch = rc.branch;
70
- if (!env || env === "development")
71
- env = rc.env; // only override if still at default
72
- // Normalize Env
73
- const envMap = { dev: "development", stg: "staging", prod: "production" };
74
- env = envMap[env] || env;
75
- const { show } = options;
76
- if (!project) {
77
- console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run `xtra init` first."));
78
- process.exit(1);
79
- }
80
- const spinner = (0, ora_1.default)(`Fetching secrets for ${env} (branch: ${branch})...`).start();
81
- try {
82
- const secrets = await api_1.api.getSecrets(project, env, branch);
83
- spinner.stop();
84
- if (!secrets || Object.keys(secrets).length === 0) {
85
- console.log(chalk_1.default.yellow("No secrets found."));
86
- return;
87
- }
88
- if (show) {
89
- console.log(chalk_1.default.red("⚠ Warning: Secret values will be visible in your terminal and shell history!"));
90
- }
91
- const data = [
92
- [chalk_1.default.bold("Key"), chalk_1.default.bold("Value"), chalk_1.default.bold("Env")]
93
- ];
94
- Object.entries(secrets).forEach(([key, value]) => {
95
- data.push([
96
- key,
97
- show ? value : "********",
98
- env
99
- ]);
100
- });
101
- console.log((0, table_1.table)(data));
102
- // Audit Log
103
- try {
104
- const { logAudit } = await Promise.resolve().then(() => __importStar(require("../lib/audit")));
105
- logAudit("SECRET_LIST", project, env, { branch, count: Object.keys(secrets).length });
106
- }
107
- catch (e) { }
108
- }
109
- catch (error) {
110
- spinner.fail("Failed to fetch secrets");
111
- console.error(chalk_1.default.red(error.message));
112
- }
113
- });
114
- // SET
115
- exports.secretsCommand
116
- .command("set")
117
- .description("Set one or more secrets (KEY=VALUE)")
118
- .argument("<secrets...>", "Secrets to set (format: KEY=VALUE)")
119
- .option("-f, --force", "Force update (overwrite remote changes without warning)", false)
120
- .addHelpText("after", `
121
- Examples:
122
- $ xtra secrets set API_KEY=xyz
123
- $ xtra secrets set DB_USER=admin DB_PASS=secret -e staging
124
- `)
125
- .action(async (args, options) => {
126
- const parentOpts = exports.secretsCommand.opts();
127
- let { project, env, branch } = parentOpts;
128
- // Use active branch from config if not specified
129
- if (!branch) {
130
- branch = (0, config_1.getConfigValue)("branch") || "main";
131
- }
132
- // Normalize Env
133
- const envMap = { dev: "development", stg: "staging", prod: "production" };
134
- env = envMap[env] || env;
135
- if (!project) {
136
- project = (0, config_1.getConfigValue)("project");
137
- }
138
- if (!project) {
139
- console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
140
- process.exit(1);
141
- }
142
- // Parse key=value pairs
143
- const payload = {};
144
- args.forEach((arg) => {
145
- const idx = arg.indexOf("=");
146
- if (idx === -1) {
147
- console.warn(chalk_1.default.yellow(`Skipping invalid format: ${arg} (expected KEY=VALUE)`));
148
- return;
149
- }
150
- const key = arg.substring(0, idx);
151
- const value = arg.substring(idx + 1);
152
- payload[key] = value;
153
- });
154
- if (Object.keys(payload).length === 0) {
155
- console.error(chalk_1.default.red("No valid secrets provided."));
156
- return;
157
- }
158
- // 🔒 Production gate: require explicit confirmation before writing to production
159
- if (env === "production" && !options.force) {
160
- const inquirer = require("inquirer");
161
- const { confirm } = await inquirer.prompt([{
162
- type: "confirm",
163
- name: "confirm",
164
- message: chalk_1.default.red(`⚠ You are about to SET ${Object.keys(payload).length} secret(s) in PRODUCTION. Are you sure?`),
165
- default: false,
166
- }]);
167
- if (!confirm) {
168
- console.log(chalk_1.default.yellow("Aborted."));
169
- return;
170
- }
171
- }
172
- const spinner = (0, ora_1.default)(`Setting ${Object.keys(payload).length} secrets for ${env} (branch: ${branch})...`);
173
- if (options.force) {
174
- spinner.start();
175
- }
176
- try {
177
- let expectedVersions = undefined;
178
- if (!options.force) {
179
- // Fetch current versions for optimistic locking
180
- spinner.text = "Fetching current versions...";
181
- spinner.start();
182
- try {
183
- const remoteSecrets = await api_1.api.getSecretVersions(project, env, branch);
184
- expectedVersions = {};
185
- spinner.stop();
186
- // Populate expected versions for keys we are updating
187
- Object.keys(payload).forEach(key => {
188
- if (remoteSecrets[key]) {
189
- expectedVersions[key] = remoteSecrets[key].version;
190
- }
191
- });
192
- }
193
- catch (verErr) {
194
- spinner.warn(chalk_1.default.yellow("Could not fetch remote versions. Conflict detection disabled."));
195
- }
196
- }
197
- spinner.start(`Updating secrets...`);
198
- await api_1.api.setSecrets(project, env, payload, expectedVersions, branch);
199
- spinner.succeed("Secrets updated successfully.");
200
- // Log Audit
201
- try {
202
- const { logAudit } = require("../lib/audit");
203
- logAudit("SECRET_UPDATE", project, env, { keys: Object.keys(payload), branch });
204
- }
205
- catch (e) { }
206
- }
207
- catch (error) {
208
- spinner.stop();
209
- if (error.response && error.response.status === 409) {
210
- // Conflict Detected
211
- const conflicts = error.response.data.conflicts || [];
212
- console.log(chalk_1.default.red("\n⚠ Conflict Detected! The following secrets have changed remotely:\n"));
213
- const conflictTable = [[chalk_1.default.bold("Key"), chalk_1.default.bold("Remote Version"), chalk_1.default.bold("Remote Value")]];
214
- conflicts.forEach((c) => {
215
- conflictTable.push([c.key, c.actual, c.remoteValue]);
216
- });
217
- console.log((0, table_1.table)(conflictTable));
218
- const inquirer = require("inquirer");
219
- const { confirm } = await inquirer.prompt([{
220
- type: "confirm",
221
- name: "confirm",
222
- message: "Do you want to overwrite these changes exactly as you specified?",
223
- default: false
224
- }]);
225
- if (confirm) {
226
- const retrySpinner = (0, ora_1.default)("Overwriting secrets...").start();
227
- try {
228
- // Start retry with Force (no expectedVersions)
229
- await api_1.api.setSecrets(project, env, payload, undefined, branch);
230
- retrySpinner.succeed("Secrets overwritten successfully.");
231
- // Log Audit Force
232
- try {
233
- const { logAudit } = require("../lib/audit");
234
- logAudit("SECRET_UPDATE_FORCE", project, env, { keys: Object.keys(payload), branch });
235
- }
236
- catch (e) { }
237
- }
238
- catch (retryErr) {
239
- retrySpinner.fail("Failed to overwrite secrets.");
240
- console.error(chalk_1.default.red(retryErr.message));
241
- }
242
- }
243
- else {
244
- console.log(chalk_1.default.yellow("Update cancelled."));
245
- }
246
- return; // Handled
247
- }
248
- if (spinner.isSpinning)
249
- spinner.fail("Failed to update secrets");
250
- if (error.response && error.response.data && error.response.data.error) {
251
- console.error(chalk_1.default.red(`Server Error: ${error.response.data.error}`));
252
- }
253
- else {
254
- console.error(chalk_1.default.red(error.message));
255
- }
256
- }
257
- });
258
- // LINK
259
- exports.secretsCommand
260
- .command("link")
261
- .description("Link a secret to another secret (Reference)")
262
- .argument("<key>", "Key of the secret to create (e.g. DB_URL)")
263
- .requiredOption("--source <source>", "Source path (format: project/env/key)")
264
- .addHelpText("after", `
265
- Examples:
266
- $ xtra secrets link SHARED_DB_URL --source shared-proj/production/DB_URL
267
- `)
268
- .action(async (key, options) => {
269
- const parentOpts = exports.secretsCommand.opts();
270
- let { project, env } = parentOpts;
271
- // Normalize Env
272
- const envMap = { dev: "development", stg: "staging", prod: "production" };
273
- env = envMap[env] || env;
274
- const { source } = options;
275
- if (!project) {
276
- project = (0, config_1.getConfigValue)("project");
277
- }
278
- if (!project) {
279
- console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
280
- process.exit(1);
281
- }
282
- // Parse Source: "proj-123/prod/DATABASE_URL"
283
- const parts = source.split("/");
284
- if (parts.length !== 3) {
285
- console.error(chalk_1.default.red("Error: Source must be in format 'projectId/env/key'"));
286
- return;
287
- }
288
- const [sourceProjectId, sourceEnv, sourceKey] = parts;
289
- const spinner = (0, ora_1.default)(`Linking ${key} to ${source}...`).start();
290
- try {
291
- await api_1.api.linkSecret(project, env, key, sourceProjectId, sourceEnv, sourceKey);
292
- spinner.succeed(chalk_1.default.green(`Secret '${key}' successfully linked to '${sourceKey}'`));
293
- // Audit log
294
- try {
295
- const { logAudit } = require("../lib/audit");
296
- logAudit("SECRET_LINKED", project, env, { key, source });
297
- }
298
- catch (e) { }
299
- }
300
- catch (error) {
301
- spinner.fail("Failed to link secret");
302
- const safeErr = error?.response?.data?.error || error.message || "Unknown error";
303
- console.error(chalk_1.default.red(`Server Error: ${safeErr}`));
304
- }
305
- });
1
+ var pe=Object.create;var I=Object.defineProperty;var ge=Object.getOwnPropertyDescriptor;var de=Object.getOwnPropertyNames;var le=Object.getPrototypeOf,ue=Object.prototype.hasOwnProperty;var A=(e,t)=>()=>(e&&(t=e(e=0)),t);var V=(e,t)=>{for(var r in t)I(e,r,{get:t[r],enumerable:!0})},J=(e,t,r,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of de(t))!ue.call(e,n)&&n!==r&&I(e,n,{get:()=>t[n],enumerable:!(s=ge(t,n))||s.enumerable});return e};var u=(e,t,r)=>(r=e!=null?pe(le(e)):{},J(t||!e||!e.__esModule?I(r,"default",{value:e,enumerable:!0}):r,e)),R=e=>J(I({},"__esModule",{value:!0}),e);var M,_,H,P,y,T,S,C,G,z,U=A(()=>{M=u(require("conf")),_=u(require("fs")),H=u(require("path")),P="https://www.xtrasecurity.in/api",y=new M.default({projectName:"xtra-cli",defaults:{apiUrl:P}}),T=y.get("apiUrl");T&&!process.env.XTRA_API_URL&&(T.includes("localhost")||T.includes("xtra-security.vercel.app"))&&y.set("apiUrl",P);S=()=>({...y.store,apiUrl:process.env.XTRA_API_URL||y.get("apiUrl")||P}),C=e=>y.get(e),G=()=>y.get("token"),z=()=>{let e={};try{let t=H.default.join(process.cwd(),".xtrarc");_.default.existsSync(t)&&(e=JSON.parse(_.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||y.get("project")||"",env:e.env||y.get("env")||"development",branch:e.branch||y.get("branch")||"main"}}});var Y,X,W,fe,o,h,B=A(()=>{Y=u(require("axios"));U();X=u(require("fs")),W=u(require("path")),fe=JSON.parse(X.readFileSync(W.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:e}=S(),t=G();return Y.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":fe.version,...t?{Authorization:`Bearer ${t}`}:{}}})},h={login:async(e,t,r)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:r})).data,getSecrets:async(e,t,r="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?branch=${r}`)).data,getSecretVersions:async(e,t,r="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${r}`)).data,setSecrets:async(e,t,r,s,n="main")=>(await o().post(`/projects/${e}/envs/${t}/secrets`,{secrets:r,expectedVersions:s,branch:n})).data,getSecretDetails:async(e,t,r,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets/${r}?branch=${s}`)).data,syncLogs:async e=>(await o().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,r,s,n,c)=>(await o().post(`/projects/${e}/envs/${t}/secrets/link`,{key:r,sourceProjectId:s,sourceEnv:n,sourceKey:c})).data,rotateSecret:async(e,t,r,s,n)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${r}/rotate`,{strategy:s,parsedNewValue:n})).data,promoteSecret:async(e,t,r)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${r}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(e,t,r,s)=>{let n={format:e};return t&&(n.startDate=t),r&&(n.endDate=r),s&&(n.projectId=s),(await o().post("/audit/export",n,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,r,s)=>(await o().post("/access/request",{projectId:e,secretId:s,reason:t,duration:r})).data,approveAccess:async(e,t)=>(await o().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=S(),r=t?`&workspaceId=${t}`:"";return(await o().get(`/access/list?mode=${e}${r}`)).data},getAccessRequestStatus:async e=>(await o().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=S(),t=e?`/project?workspaceId=${e}`:"/project";return(await o().get(t)).data},getBranches:async e=>(await o().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,r)=>(await o().post("/branch",{projectId:e,name:t,description:r})).data,deleteBranch:async e=>(await o().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await o().put("/branch",{id:e,...t})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await o().get(`/admin/users${t}`)).data},setUserRole:async(e,t,r)=>(await o().put("/admin/users/role",{email:e,role:t,teamId:r})).data,getIntegrationStatus:async e=>(await o().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await o().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await o().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,t)=>{let r=new URLSearchParams(t).toString();return(await o().get(`/projects/${e}/kubernetes?${r}`)).data},getSecretHistory:async(e,t,r)=>(await o().get(`/projects/${e}/envs/${t}/secrets/${r}/history`)).data,rollbackSecret:async(e,t,r,s)=>(await o().post(`/projects/${e}/envs/${t}/secrets/${r}/history`,{version:s})).data,cloneEnvironment:async(e,t,r,s,n)=>(await o().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:r,overwrite:s,branch:n})).data,generateJitLink:async e=>(await o().post("/jit/generate",e)).data,claimJitLink:async e=>(await o().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await o().get(`/jit/${e}`)).data,post:async(e,t)=>(await o().post(e,t)).data}});function re(){let e=Q.get("masterKey");e||(e=j.default.randomBytes(32).toString("hex"),Q.set("masterKey",e));let t=(0,ee.machineIdSync)();return j.default.createHash("sha256").update(e+t).digest()}var j,Z,ee,te,Q,se,ne,oe=A(()=>{j=u(require("crypto")),Z=u(require("conf")),ee=require("node-machine-id"),te="aes-256-gcm",Q=new Z.default({projectName:"xtra-cli-crypto"});se=e=>{let t=j.default.randomBytes(16),r=re(),s=j.default.createCipheriv(te,r,t),n=s.update(e,"utf8","hex");n+=s.final("hex");let c=s.getAuthTag();return{iv:t.toString("hex"),content:n,tag:c.toString("hex")}},ne=e=>{let t=re(),r=Buffer.from(e.iv,"hex"),s=Buffer.from(e.tag,"hex"),n=j.default.createDecipheriv(te,t,r);n.setAuthTag(s);let c=n.update(e.content,"hex","utf8");return c+=n.final("utf8"),c}});var b={};V(b,{loadAuditLogs:()=>O,logAudit:()=>me,saveAuditLogs:()=>D,syncAuditLogs:()=>he});function ye(e){if(!e||typeof e!="object")return e;let t={...e},r=["password","token","secret","value","apiKey","secretValue"];for(let s of Object.keys(t))r.some(n=>s.toLowerCase().includes(n))&&(t[s]="[REDACTED]");return t}async function ce(e){try{if(!S().token)return!1;let r={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:ye(e.details),timestamp:e.timestamp,projectId:e.projectId};return await h.post("/audit/cli-logs",{logs:[r]}),!0}catch(t){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",t),!1}}function me(e,t,r,s){let n={id:(0,ie.v4)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:r,details:s,synced:!1},c=O();c.push(n),D(c),ce(n).then(m=>{if(m){n.synced=!0;let g=O(),d=g.findIndex(i=>i.id===n.id);d!==-1&&(g[d].synced=!0,D(g))}}).catch(()=>{})}function O(){if(!x.default.existsSync(q))return[];try{let e=x.default.readFileSync(q,"utf-8"),t=JSON.parse(e),r=ne(t);return JSON.parse(r)}catch{return[]}}function D(e){x.default.existsSync(N)||x.default.mkdirSync(N,{recursive:!0});let t=JSON.stringify(e),r=se(t);x.default.writeFileSync(q,JSON.stringify(r),"utf-8")}async function he(){let e=O(),t=e.filter(s=>!s.synced);if(t.length===0)return 0;let r=0;for(let s of t)await ce(s)&&(s.synced=!0,r++);return r>0&&D(e),r}var x,F,ie,N,q,$=A(()=>{x=u(require("fs")),F=u(require("path")),ie=require("uuid");oe();U();B();N=F.default.join(process.cwd(),".xtra"),q=F.default.join(N,"audit.enc")});var ve={};V(ve,{secretsCommand:()=>v});module.exports=R(ve);var ae=require("commander");B();var a=u(require("chalk")),k=u(require("ora")),K=require("table");U();var v=new ae.Command("secrets").description("Manage secrets (List, Set, Delete)").option("-p, --project <projectId>","Project ID").option("-e, --env <environment>","Environment (development, staging, production)","development").option("-b, --branch <branchName>","Branch Name");v.command("list").description("List all secrets for a project/environment").option("--show","Reveal secret values",!1).addHelpText("after",`
2
+ Examples:
3
+ $ xtra secrets list
4
+ $ xtra secrets list -e production --show
5
+ `).action(async e=>{let t=v.opts(),{project:r,env:s,branch:n}=t,c=z();r||(r=c.project),n||(n=c.branch),(!s||s==="development")&&(s=c.env),s={dev:"development",stg:"staging",prod:"production"}[s]||s;let{show:g}=e;r||(console.error(a.default.red("Error: Project ID is required. Use -p <id> or run `xtra init` first.")),process.exit(1));let d=(0,k.default)(`Fetching secrets for ${s} (branch: ${n})...`).start();try{let i=await h.getSecrets(r,s,n);if(d.stop(),!i||Object.keys(i).length===0){console.log(a.default.yellow("No secrets found."));return}g&&console.log(a.default.red("\u26A0 Warning: Secret values will be visible in your terminal and shell history!"));let p=[[a.default.bold("Key"),a.default.bold("Value"),a.default.bold("Env")]];Object.entries(i).forEach(([l,f])=>{p.push([l,g?f:"********",s])}),console.log((0,K.table)(p));try{let{logAudit:l}=await Promise.resolve().then(()=>($(),b));l("SECRET_LIST",r,s,{branch:n,count:Object.keys(i).length})}catch{}}catch(i){d.fail("Failed to fetch secrets"),console.error(a.default.red(i.message))}});v.command("set").description("Set one or more secrets (KEY=VALUE)").argument("<secrets...>","Secrets to set (format: KEY=VALUE)").option("-f, --force","Force update (overwrite remote changes without warning)",!1).addHelpText("after",`
6
+ Examples:
7
+ $ xtra secrets set API_KEY=xyz
8
+ $ xtra secrets set DB_USER=admin DB_PASS=secret -e staging
9
+ `).action(async(e,t)=>{let r=v.opts(),{project:s,env:n,branch:c}=r;c||(c=C("branch")||"main"),n={dev:"development",stg:"staging",prod:"production"}[n]||n,s||(s=C("project")),s||(console.error(a.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first.")),process.exit(1));let g={};if(e.forEach(i=>{let p=i.indexOf("=");if(p===-1){console.warn(a.default.yellow(`Skipping invalid format: ${i} (expected KEY=VALUE)`));return}let l=i.substring(0,p),f=i.substring(p+1);g[l]=f}),Object.keys(g).length===0){console.error(a.default.red("No valid secrets provided."));return}if(n==="production"&&!t.force){let i=require("inquirer"),{confirm:p}=await i.prompt([{type:"confirm",name:"confirm",message:a.default.red(`\u26A0 You are about to SET ${Object.keys(g).length} secret(s) in PRODUCTION. Are you sure?`),default:!1}]);if(!p){console.log(a.default.yellow("Aborted."));return}}let d=(0,k.default)(`Setting ${Object.keys(g).length} secrets for ${n} (branch: ${c})...`);t.force&&d.start();try{let i;if(!t.force){d.text="Fetching current versions...",d.start();try{let p=await h.getSecretVersions(s,n,c);i={},d.stop(),Object.keys(g).forEach(l=>{p[l]&&(i[l]=p[l].version)})}catch{d.warn(a.default.yellow("Could not fetch remote versions. Conflict detection disabled."))}}d.start("Updating secrets..."),await h.setSecrets(s,n,g,i,c),d.succeed("Secrets updated successfully.");try{let{logAudit:p}=($(),R(b));p("SECRET_UPDATE",s,n,{keys:Object.keys(g),branch:c})}catch{}}catch(i){if(d.stop(),i.response&&i.response.status===409){let p=i.response.data.conflicts||[];console.log(a.default.red(`
10
+ \u26A0 Conflict Detected! The following secrets have changed remotely:
11
+ `));let l=[[a.default.bold("Key"),a.default.bold("Remote Version"),a.default.bold("Remote Value")]];p.forEach(w=>{l.push([w.key,w.actual,w.remoteValue])}),console.log((0,K.table)(l));let f=require("inquirer"),{confirm:L}=await f.prompt([{type:"confirm",name:"confirm",message:"Do you want to overwrite these changes exactly as you specified?",default:!1}]);if(L){let w=(0,k.default)("Overwriting secrets...").start();try{await h.setSecrets(s,n,g,void 0,c),w.succeed("Secrets overwritten successfully.");try{let{logAudit:E}=($(),R(b));E("SECRET_UPDATE_FORCE",s,n,{keys:Object.keys(g),branch:c})}catch{}}catch(E){w.fail("Failed to overwrite secrets."),console.error(a.default.red(E.message))}}else console.log(a.default.yellow("Update cancelled."));return}d.isSpinning&&d.fail("Failed to update secrets"),i.response&&i.response.data&&i.response.data.error?console.error(a.default.red(`Server Error: ${i.response.data.error}`)):console.error(a.default.red(i.message))}});v.command("link").description("Link a secret to another secret (Reference)").argument("<key>","Key of the secret to create (e.g. DB_URL)").requiredOption("--source <source>","Source path (format: project/env/key)").addHelpText("after",`
12
+ Examples:
13
+ $ xtra secrets link SHARED_DB_URL --source shared-proj/production/DB_URL
14
+ `).action(async(e,t)=>{let r=v.opts(),{project:s,env:n}=r;n={dev:"development",stg:"staging",prod:"production"}[n]||n;let{source:m}=t;s||(s=C("project")),s||(console.error(a.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first.")),process.exit(1));let g=m.split("/");if(g.length!==3){console.error(a.default.red("Error: Source must be in format 'projectId/env/key'"));return}let[d,i,p]=g,l=(0,k.default)(`Linking ${e} to ${m}...`).start();try{await h.linkSecret(s,n,e,d,i,p),l.succeed(a.default.green(`Secret '${e}' successfully linked to '${p}'`));try{let{logAudit:f}=($(),R(b));f("SECRET_LINKED",s,n,{key:e,source:m})}catch{}}catch(f){l.fail("Failed to link secret");let L=f?.response?.data?.error||f.message||"Unknown error";console.error(a.default.red(`Server Error: ${L}`))}});0&&(module.exports={secretsCommand});
@@ -1,109 +1,6 @@
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.simulateCommand = void 0;
7
- /**
8
- * simulate.ts — Dry-run mode for xtra run
9
- *
10
- * Fetches secrets and shows exactly what `xtra run` would inject into
11
- * the process environment — without actually executing the command.
12
- * Safe to use in any environment.
13
- */
14
- const commander_1 = require("commander");
15
- const api_1 = require("../lib/api");
16
- const config_1 = require("../lib/config");
17
- const chalk_1 = __importDefault(require("chalk"));
18
- const ora_1 = __importDefault(require("ora"));
19
- const table_1 = require("table");
20
- exports.simulateCommand = new commander_1.Command("simulate")
21
- .description("Dry-run: show what 'xtra run' would inject without executing the command")
22
- .option("-p, --project <id>", "Project ID")
23
- .option("-e, --env <environment>", "Environment", "development")
24
- .option("-b, --branch <branch>", "Branch", "main")
25
- .argument("[command]", "Command that would be executed (display only)")
26
- .option("--show-values", "Reveal secret values in output (default: masked)", false)
27
- .option("--diff", "Highlight secrets that differ from local .env / process.env", false)
28
- .action(async (command, options) => {
29
- let { project, env, branch, showValues, diff: showDiff } = options;
30
- const envMap = { dev: "development", stg: "staging", prod: "production" };
31
- env = envMap[env] || env;
32
- if (!project)
33
- project = (0, config_1.getRcConfig)().project;
34
- if (!project) {
35
- console.error(chalk_1.default.red("Error: Project ID required. Use -p <id> or run 'xtra project set'."));
36
- process.exit(1);
37
- }
38
- const spinner = (0, ora_1.default)(`Fetching secrets to simulate injection (${env}/${branch})...`).start();
39
- let secrets;
40
- try {
41
- secrets = await api_1.api.getSecrets(project, env, branch);
42
- spinner.stop();
43
- }
44
- catch (e) {
45
- spinner.fail("Failed to fetch secrets.");
46
- console.error(chalk_1.default.red(e?.response?.data?.error || e.message));
47
- process.exit(1);
48
- }
49
- const count = Object.keys(secrets).length;
50
- const termWidth = process.stdout.columns || 100;
51
- const keyWidth = Math.floor(termWidth * 0.25);
52
- const valWidth = Math.floor(termWidth * 0.4);
53
- const localWidth = Math.floor(termWidth * 0.15);
54
- console.log(chalk_1.default.bold.cyan("\n● Simulation") + chalk_1.default.bold(` — xtra run ${command ? chalk_1.default.cyan(command) : "(no command specified)"}\n`));
55
- console.log(chalk_1.default.gray(` Project : ${chalk_1.default.white(project)}`));
56
- console.log(chalk_1.default.gray(` Env : ${chalk_1.default.white(env)}`));
57
- console.log(chalk_1.default.gray(` Branch : ${chalk_1.default.white(branch)}`));
58
- console.log(chalk_1.default.gray(` Secrets : ${chalk_1.default.white(count)} would be injected\n`));
59
- if (count === 0) {
60
- console.log(chalk_1.default.yellow(" No secrets found for this environment/branch."));
61
- return;
62
- }
63
- const rows = [
64
- [chalk_1.default.bold("Key"), chalk_1.default.bold("Injected Value"), chalk_1.default.bold("Local .env"), chalk_1.default.bold("Status")]
65
- ];
66
- for (const [key, value] of Object.entries(secrets)) {
67
- const localVal = process.env[key];
68
- const displayVal = showValues ? chalk_1.default.cyan(value) : chalk_1.default.gray("••••••••");
69
- let status = chalk_1.default.green("Injected");
70
- let localDisplay = "-";
71
- if (showDiff && localVal !== undefined) {
72
- localDisplay = showValues ? chalk_1.default.yellow(localVal) : chalk_1.default.gray("••••••••");
73
- if (localVal === value) {
74
- status = chalk_1.default.gray("Same");
75
- }
76
- else {
77
- status = chalk_1.default.yellow("⚡ Override");
78
- }
79
- }
80
- else if (showDiff) {
81
- status = chalk_1.default.blue("New");
82
- localDisplay = chalk_1.default.gray("(not set)");
83
- }
84
- rows.push([chalk_1.default.white(key), displayVal, showDiff ? localDisplay : "-", status]);
85
- }
86
- console.log((0, table_1.table)(rows, {
87
- columns: [
88
- { width: keyWidth, wrapWord: true },
89
- { width: valWidth, wrapWord: true },
90
- { width: localWidth, wrapWord: true },
91
- { width: 10 }
92
- ],
93
- border: {
94
- topBody: `─`, topJoin: `┬`, topLeft: `┌`, topRight: `┐`,
95
- bottomBody: `─`, bottomJoin: `┴`, bottomLeft: `└`, bottomRight: `┘`,
96
- bodyLeft: `│`, bodyRight: `│`, bodyJoin: `│`,
97
- joinBody: `─`, joinLeft: `├`, joinRight: `┤`, joinJoin: `┼`
98
- }
99
- }));
100
- // Summary
101
- if (!showValues) {
102
- console.log(chalk_1.default.gray(" Tip: use --show-values to reveal actual secret values"));
103
- }
104
- if (!showDiff) {
105
- console.log(chalk_1.default.gray(" Tip: use --diff to compare against your local process.env"));
106
- }
107
- console.log(chalk_1.default.bold.green(`\n ✔ Simulation complete.`) + chalk_1.default.bold(` ${count} secret(s) would be injected.`));
108
- console.log(chalk_1.default.gray(" Run without 'simulate' to actually execute the command.\n"));
109
- });
1
+ var G=Object.create;var u=Object.defineProperty;var W=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var M=Object.getPrototypeOf,E=Object.prototype.hasOwnProperty;var H=(e,t)=>{for(var s in t)u(e,s,{get:t[s],enumerable:!0})},R=(e,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of F(t))!E.call(e,a)&&a!==s&&u(e,a,{get:()=>t[a],enumerable:!(n=W(t,a))||n.enumerable});return e};var c=(e,t,s)=>(s=e!=null?G(M(e)):{},R(t||!e||!e.__esModule?u(s,"default",{value:e,enumerable:!0}):s,e)),X=e=>R(u({},"__esModule",{value:!0}),e);var Q={};H(Q,{simulateCommand:()=>z});module.exports=X(Q);var J=require("commander");var A=c(require("axios"));var I=c(require("conf")),j=c(require("fs")),U=c(require("path")),$="https://www.xtrasecurity.in/api",p=new I.default({projectName:"xtra-cli",defaults:{apiUrl:$}}),v=p.get("apiUrl");v&&!process.env.XTRA_API_URL&&(v.includes("localhost")||v.includes("xtra-security.vercel.app"))&&p.set("apiUrl",$);var y=()=>({...p.store,apiUrl:process.env.XTRA_API_URL||p.get("apiUrl")||$});var C=()=>p.get("token");var L=()=>{let e={};try{let t=U.default.join(process.cwd(),".xtrarc");j.default.existsSync(t)&&(e=JSON.parse(j.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||p.get("project")||"",env:e.env||p.get("env")||"development",branch:e.branch||p.get("branch")||"main"}};var P=c(require("fs")),B=c(require("path")),K=JSON.parse(P.readFileSync(B.join(__dirname,"../../package.json"),"utf-8")),r=()=>{let{apiUrl:e}=y(),t=C();return A.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":K.version,...t?{Authorization:`Bearer ${t}`}:{}}})},_={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,a="main")=>(await r().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:n,branch:a})).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,a,i)=>(await r().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:n,sourceEnv:a,sourceKey:i})).data,rotateSecret:async(e,t,s,n,a)=>(await r().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:n,parsedNewValue:a})).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 a={format:e};return t&&(a.startDate=t),s&&(a.endDate=s),n&&(a.projectId=n),(await r().post("/audit/export",a,{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}=y(),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}=y(),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,a)=>(await r().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,overwrite:n,branch:a})).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 o=c(require("chalk")),T=c(require("ora")),D=require("table"),z=new J.Command("simulate").description("Dry-run: show what 'xtra run' would inject without executing the command").option("-p, --project <id>","Project ID").option("-e, --env <environment>","Environment","development").option("-b, --branch <branch>","Branch","main").argument("[command]","Command that would be executed (display only)").option("--show-values","Reveal secret values in output (default: masked)",!1).option("--diff","Highlight secrets that differ from local .env / process.env",!1).action(async(e,t)=>{let{project:s,env:n,branch:a,showValues:i,diff:g}=t;n={dev:"development",stg:"staging",prod:"production"}[n]||n,s||(s=L().project),s||(console.error(o.default.red("Error: Project ID required. Use -p <id> or run 'xtra project set'.")),process.exit(1));let S=(0,T.default)(`Fetching secrets to simulate injection (${n}/${a})...`).start(),m;try{m=await _.getSecrets(s,n,a),S.stop()}catch(l){S.fail("Failed to fetch secrets."),console.error(o.default.red(l?.response?.data?.error||l.message)),process.exit(1)}let f=Object.keys(m).length,h=process.stdout.columns||100,O=Math.floor(h*.25),V=Math.floor(h*.4),N=Math.floor(h*.15);if(console.log(o.default.bold.cyan(`
2
+ \u25CF Simulation`)+o.default.bold(` \u2014 xtra run ${e?o.default.cyan(e):"(no command specified)"}
3
+ `)),console.log(o.default.gray(` Project : ${o.default.white(s)}`)),console.log(o.default.gray(` Env : ${o.default.white(n)}`)),console.log(o.default.gray(` Branch : ${o.default.white(a)}`)),console.log(o.default.gray(` Secrets : ${o.default.white(f)} would be injected
4
+ `)),f===0){console.log(o.default.yellow(" No secrets found for this environment/branch."));return}let x=[[o.default.bold("Key"),o.default.bold("Injected Value"),o.default.bold("Local .env"),o.default.bold("Status")]];for(let[l,k]of Object.entries(m)){let w=process.env[l],q=i?o.default.cyan(k):o.default.gray("\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"),d=o.default.green("Injected"),b="-";g&&w!==void 0?(b=i?o.default.yellow(w):o.default.gray("\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"),w===k?d=o.default.gray("Same"):d=o.default.yellow("\u26A1 Override")):g&&(d=o.default.blue("New"),b=o.default.gray("(not set)")),x.push([o.default.white(l),q,g?b:"-",d])}console.log((0,D.table)(x,{columns:[{width:O,wrapWord:!0},{width:V,wrapWord:!0},{width:N,wrapWord:!0},{width:10}],border:{topBody:"\u2500",topJoin:"\u252C",topLeft:"\u250C",topRight:"\u2510",bottomBody:"\u2500",bottomJoin:"\u2534",bottomLeft:"\u2514",bottomRight:"\u2518",bodyLeft:"\u2502",bodyRight:"\u2502",bodyJoin:"\u2502",joinBody:"\u2500",joinLeft:"\u251C",joinRight:"\u2524",joinJoin:"\u253C"}})),i||console.log(o.default.gray(" Tip: use --show-values to reveal actual secret values")),g||console.log(o.default.gray(" Tip: use --diff to compare against your local process.env")),console.log(o.default.bold.green(`
5
+ \u2714 Simulation complete.`)+o.default.bold(` ${f} secret(s) would be injected.`)),console.log(o.default.gray(` Run without 'simulate' to actually execute the command.
6
+ `))});0&&(module.exports={simulateCommand});
@@ -1,93 +1,2 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.statusCommand = 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 table_1 = require("table");
12
- const manifest_1 = require("../lib/manifest");
13
- const crypto_1 = require("../lib/crypto");
14
- const config_1 = require("../lib/config");
15
- exports.statusCommand = new commander_1.Command("status")
16
- .description("Check synchronization status with XtraSync platform")
17
- .option("-p, --project <projectId>", "Project ID")
18
- .option("-e, --env <environment>", "Environment (dev, stg, prod)", "dev")
19
- .option("-b, --branch <branchName>", "Branch Name")
20
- .action(async (options) => {
21
- let { project, env, branch } = options;
22
- // Use config fallback
23
- if (!project)
24
- project = (0, config_1.getRcConfig)().project;
25
- if (!branch) {
26
- branch = (0, config_1.getRcConfig)().branch || "main";
27
- }
28
- if (!project) {
29
- console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
30
- process.exit(1);
31
- }
32
- // Normalize Env
33
- const envMap = { dev: "development", stg: "staging", prod: "production" };
34
- env = envMap[env] || env;
35
- // Load Manifest
36
- const manifest = (0, manifest_1.loadManifest)();
37
- if (!manifest) {
38
- console.log(chalk_1.default.yellow("No local manifest found. Run 'xtra run' or 'xtra generate' first."));
39
- return;
40
- }
41
- if (manifest.projectId !== project || manifest.environment !== env) {
42
- console.log(chalk_1.default.yellow(`Manifest found for DIFFERENT project/env (${manifest.projectId}/${manifest.environment}).`));
43
- console.log("Checking status against requested target anyway...");
44
- }
45
- const spinner = (0, ora_1.default)(`Fetching remote state for ${env} (branch: ${branch})...`).start();
46
- try {
47
- const secrets = await api_1.api.getSecrets(project, env, branch);
48
- spinner.stop();
49
- // Compare
50
- const rows = [[chalk_1.default.bold("Secret Key"), chalk_1.default.bold("Status"), chalk_1.default.bold("Local Last Updated")]];
51
- let diffCount = 0;
52
- // Check Remote vs Local
53
- Object.entries(secrets).forEach(([key, value]) => {
54
- const remoteHash = (0, crypto_1.hash)(value);
55
- const localEntry = manifest.secrets[key];
56
- if (!localEntry) {
57
- rows.push([key, chalk_1.default.green("NEW (Remote)"), "-"]);
58
- diffCount++;
59
- }
60
- else if (localEntry.hash !== remoteHash) {
61
- rows.push([key, chalk_1.default.yellow("MODIFIED"), localEntry.updatedAt]);
62
- diffCount++;
63
- }
64
- else {
65
- rows.push([key, chalk_1.default.cyan("Synced"), localEntry.updatedAt]);
66
- }
67
- });
68
- // Check Local vs Remote (Deleted keys)
69
- Object.keys(manifest.secrets).forEach(key => {
70
- if (!secrets[key]) {
71
- rows.push([key, chalk_1.default.red("DELETED (Remote)"), manifest.secrets[key].updatedAt]);
72
- diffCount++;
73
- }
74
- });
75
- console.log("");
76
- console.log((0, table_1.table)(rows));
77
- if (diffCount === 0) {
78
- console.log(chalk_1.default.green("✔ Everything is in sync."));
79
- }
80
- else {
81
- console.log(chalk_1.default.yellow(`⚠ Found ${diffCount} difference(s).\n`));
82
- console.log(chalk_1.default.bold(" Next steps:"));
83
- console.log(chalk_1.default.gray(" xtra generate ") + chalk_1.default.white("# pull cloud secrets → .env (merge)"));
84
- console.log(chalk_1.default.gray(" xtra generate -f json ") + chalk_1.default.white("# pull cloud secrets → secrets.json"));
85
- console.log(chalk_1.default.gray(" xtra run node app.js ") + chalk_1.default.white("# inject secrets at runtime (no file)"));
86
- console.log(chalk_1.default.gray(" xtra local sync ") + chalk_1.default.white("# pull cloud secrets → .env.local (offline mode)"));
87
- }
88
- }
89
- catch (error) {
90
- spinner.fail("Failed to fetch remote secrets.");
91
- console.error(chalk_1.default.red(error.message));
92
- }
93
- });
1
+ var q=Object.create;var m=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var H=Object.getPrototypeOf,K=Object.prototype.hasOwnProperty;var V=(t,e)=>{for(var s in e)m(t,s,{get:e[s],enumerable:!0})},b=(t,e,s,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of G(e))!K.call(t,a)&&a!==s&&m(t,a,{get:()=>e[a],enumerable:!(n=J(e,a))||n.enumerable});return t};var c=(t,e,s)=>(s=t!=null?q(H(t)):{},b(e||!t||!t.__esModule?m(s,"default",{value:t,enumerable:!0}):s,t)),X=t=>b(m({},"__esModule",{value:!0}),t);var Z={};V(Z,{statusCommand:()=>Y});module.exports=X(Z);var O=require("commander");var C=c(require("axios"));var I=c(require("conf")),v=c(require("fs")),A=c(require("path")),S="https://www.xtrasecurity.in/api",g=new I.default({projectName:"xtra-cli",defaults:{apiUrl:S}}),w=g.get("apiUrl");w&&!process.env.XTRA_API_URL&&(w.includes("localhost")||w.includes("xtra-security.vercel.app"))&&g.set("apiUrl",S);var y=()=>({...g.store,apiUrl:process.env.XTRA_API_URL||g.get("apiUrl")||S});var k=()=>g.get("token");var j=()=>{let t={};try{let e=A.default.join(process.cwd(),".xtrarc");v.default.existsSync(e)&&(t=JSON.parse(v.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 R=c(require("fs")),U=c(require("path")),z=JSON.parse(R.readFileSync(U.join(__dirname,"../../package.json"),"utf-8")),r=()=>{let{apiUrl:t}=y(),e=k();return C.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":z.version,...e?{Authorization:`Bearer ${e}`}:{}}})},E={login:async(t,e,s)=>(await r().post("/auth/cli-login",{email:t,password:e,apiKey:s})).data,getSecrets:async(t,e,s="main")=>(await r().get(`/projects/${t}/envs/${e}/secrets?branch=${s}`)).data,getSecretVersions:async(t,e,s="main")=>(await r().get(`/projects/${t}/envs/${e}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(t,e,s,n,a="main")=>(await r().post(`/projects/${t}/envs/${e}/secrets`,{secrets:s,expectedVersions:n,branch:a})).data,getSecretDetails:async(t,e,s,n="main")=>(await r().get(`/projects/${t}/envs/${e}/secrets/${s}?branch=${n}`)).data,syncLogs:async t=>(await r().post("/audit/cli-logs",{logs:t})).data,linkSecret:async(t,e,s,n,a,i)=>(await r().post(`/projects/${t}/envs/${e}/secrets/link`,{key:s,sourceProjectId:n,sourceEnv:a,sourceKey:i})).data,rotateSecret:async(t,e,s,n,a)=>(await r().post(`/projects/${t}/envs/${e}/secrets/${s}/rotate`,{strategy:n,parsedNewValue:a})).data,promoteSecret:async(t,e,s)=>(await r().post(`/projects/${t}/envs/${e}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await r().get("/audit/verify")).data,exportAuditLogs:async(t,e,s,n)=>{let a={format:t};return e&&(a.startDate=e),s&&(a.endDate=s),n&&(a.projectId=n),(await r().post("/audit/export",a,{responseType:t==="csv"?"text":"json"})).data},requestAccess:async(t,e,s,n)=>(await r().post("/access/request",{projectId:t,secretId:n,reason:e,duration:s})).data,approveAccess:async(t,e)=>(await r().post("/access/approve",{requestId:t,decision:e})).data,listAccessRequests:async t=>{let{workspace:e}=y(),s=e?`&workspaceId=${e}`:"";return(await r().get(`/access/list?mode=${t}${s}`)).data},getAccessRequestStatus:async t=>(await r().get(`/access/request?id=${t}`)).data,getProjects:async()=>{let{workspace:t}=y(),e=t?`/project?workspaceId=${t}`:"/project";return(await r().get(e)).data},getBranches:async t=>(await r().get(`/branch?projectId=${t}`)).data,createBranch:async(t,e,s)=>(await r().post("/branch",{projectId:t,name:e,description:s})).data,deleteBranch:async t=>(await r().delete(`/branch/${t}`)).data,updateBranch:async(t,e)=>(await r().put("/branch",{id:t,...e})).data,getRoles:async()=>(await r().get("/admin/roles")).data,getUsers:async t=>{let e=t?`?teamId=${t}`:"";return(await r().get(`/admin/users${e}`)).data},setUserRole:async(t,e,s)=>(await r().put("/admin/users/role",{email:t,role:e,teamId:s})).data,getIntegrationStatus:async t=>(await r().get(`/integrations/${t}`)).data,getIntegrationRepos:async t=>(await r().get(`/integrations/${t}/sync`)).data.repos,syncSecretsToGithub:async t=>(await r().post("/integrations/github/sync",t)).data,exportKubernetesSecret:async(t,e)=>{let s=new URLSearchParams(e).toString();return(await r().get(`/projects/${t}/kubernetes?${s}`)).data},getSecretHistory:async(t,e,s)=>(await r().get(`/projects/${t}/envs/${e}/secrets/${s}/history`)).data,rollbackSecret:async(t,e,s,n)=>(await r().post(`/projects/${t}/envs/${e}/secrets/${s}/history`,{version:n})).data,cloneEnvironment:async(t,e,s,n,a)=>(await r().post(`/projects/${t}/envs/clone`,{fromEnv:e,toEnv:s,overwrite:n,branch:a})).data,generateJitLink:async t=>(await r().post("/jit/generate",t)).data,claimJitLink:async t=>(await r().post("/jit/claim",{token:t})).data,getJitInfo:async t=>(await r().get(`/jit/${t}`)).data,post:async(t,e)=>(await r().post(t,e)).data};var o=c(require("chalk")),B=c(require("ora")),F=require("table");var x=c(require("fs")),$=c(require("path")),W=$.default.join(process.cwd(),".xtra"),N=$.default.join(W,"manifest.json");function D(){if(!x.default.existsSync(N))return null;try{let t=x.default.readFileSync(N,"utf-8");return JSON.parse(t)}catch{return null}}var M=c(require("crypto")),P=c(require("conf")),Q=require("node-machine-id");var ot=new P.default({projectName:"xtra-cli-crypto"});var L=t=>M.default.createHash("sha256").update(t).digest("hex");var Y=new O.Command("status").description("Check synchronization status with XtraSync platform").option("-p, --project <projectId>","Project ID").option("-e, --env <environment>","Environment (dev, stg, prod)","dev").option("-b, --branch <branchName>","Branch Name").action(async t=>{let{project:e,env:s,branch:n}=t;e||(e=j().project),n||(n=j().branch||"main"),e||(console.error(o.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first.")),process.exit(1)),s={dev:"development",stg:"staging",prod:"production"}[s]||s;let i=D();if(!i){console.log(o.default.yellow("No local manifest found. Run 'xtra run' or 'xtra generate' first."));return}(i.projectId!==e||i.environment!==s)&&(console.log(o.default.yellow(`Manifest found for DIFFERENT project/env (${i.projectId}/${i.environment}).`)),console.log("Checking status against requested target anyway..."));let h=(0,B.default)(`Fetching remote state for ${s} (branch: ${n})...`).start();try{let u=await E.getSecrets(e,s,n);h.stop();let l=[[o.default.bold("Secret Key"),o.default.bold("Status"),o.default.bold("Local Last Updated")]],d=0;Object.entries(u).forEach(([p,T])=>{let _=L(T),f=i.secrets[p];f?f.hash!==_?(l.push([p,o.default.yellow("MODIFIED"),f.updatedAt]),d++):l.push([p,o.default.cyan("Synced"),f.updatedAt]):(l.push([p,o.default.green("NEW (Remote)"),"-"]),d++)}),Object.keys(i.secrets).forEach(p=>{u[p]||(l.push([p,o.default.red("DELETED (Remote)"),i.secrets[p].updatedAt]),d++)}),console.log(""),console.log((0,F.table)(l)),d===0?console.log(o.default.green("\u2714 Everything is in sync.")):(console.log(o.default.yellow(`\u26A0 Found ${d} difference(s).
2
+ `)),console.log(o.default.bold(" Next steps:")),console.log(o.default.gray(" xtra generate ")+o.default.white("# pull cloud secrets \xE2\u2020\u2019 .env (merge)")),console.log(o.default.gray(" xtra generate -f json ")+o.default.white("# pull cloud secrets \xE2\u2020\u2019 secrets.json")),console.log(o.default.gray(" xtra run node app.js ")+o.default.white("# inject secrets at runtime (no file)")),console.log(o.default.gray(" xtra local sync ")+o.default.white("# pull cloud secrets \xE2\u2020\u2019 .env.local (offline mode)")))}catch(u){h.fail("Failed to fetch remote secrets."),console.error(o.default.red(u.message))}});0&&(module.exports={statusCommand});