xtra-cli 1.0.4 → 1.0.6
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.
- package/dist/bin/xtra.js +2 -294
- package/dist/commands/access.js +1 -184
- package/dist/commands/admin.js +5 -118
- package/dist/commands/audit.js +1 -67
- package/dist/commands/branch.js +1 -212
- package/dist/commands/checkout.js +1 -80
- package/dist/commands/ci.js +31 -341
- package/dist/commands/completion.js +85 -224
- package/dist/commands/diff.js +6 -162
- package/dist/commands/doctor.js +2 -164
- package/dist/commands/env.js +2 -70
- package/dist/commands/export.js +2 -83
- package/dist/commands/generate.js +3 -179
- package/dist/commands/history.js +4 -77
- package/dist/commands/import.js +1 -121
- package/dist/commands/init.js +7 -205
- package/dist/commands/integration.js +11 -188
- package/dist/commands/jit-run.js +5 -0
- package/dist/commands/local.js +16 -198
- package/dist/commands/login.js +16 -198
- package/dist/commands/login.test.js +16 -51
- package/dist/commands/logout.js +1 -0
- package/dist/commands/logs.js +3 -121
- package/dist/commands/profile.js +14 -184
- package/dist/commands/project.js +1 -165
- package/dist/commands/rollback.js +1 -95
- package/dist/commands/rotate.js +3 -93
- package/dist/commands/run.js +11 -215
- package/dist/commands/scan.js +25 -127
- package/dist/commands/secrets.js +14 -305
- package/dist/commands/service-account.js +7 -0
- package/dist/commands/simulate.js +6 -109
- package/dist/commands/status.js +2 -93
- package/dist/commands/template.js +22 -276
- package/dist/commands/ui.js +2 -289
- package/dist/commands/watch.js +17 -123
- package/dist/lib/api.js +1 -187
- package/dist/lib/api.test.js +1 -89
- package/dist/lib/audit.js +1 -136
- package/dist/lib/config.js +1 -72
- package/dist/lib/config.test.js +1 -47
- package/dist/lib/crypto.js +1 -50
- package/dist/lib/manifest.js +1 -52
- package/dist/lib/profiles.js +1 -103
- package/package.json +2 -2
package/dist/commands/history.js
CHANGED
|
@@ -1,77 +1,4 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.rollbackCommand = exports.historyCommand = void 0;
|
|
7
|
-
const commander_1 = require("commander");
|
|
8
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const api_1 = require("../lib/api");
|
|
10
|
-
const config_1 = require("../lib/config");
|
|
11
|
-
exports.historyCommand = new commander_1.Command("history");
|
|
12
|
-
exports.historyCommand
|
|
13
|
-
.argument("<key>", "Secret key")
|
|
14
|
-
.option("-p, --project <id>", "Project ID")
|
|
15
|
-
.option("-e, --env <environment>", "Environment", "development")
|
|
16
|
-
.description("View version history of a secret")
|
|
17
|
-
.action(async (key, options) => {
|
|
18
|
-
try {
|
|
19
|
-
let projectId = options.project;
|
|
20
|
-
if (!projectId) {
|
|
21
|
-
projectId = (0, config_1.getRcConfig)().project;
|
|
22
|
-
if (!projectId) {
|
|
23
|
-
console.error(chalk_1.default.red("Error: Project ID not found. Use -p <id> or run 'xtra project set' first."));
|
|
24
|
-
process.exit(1);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
const data = await api_1.api.getSecretHistory(projectId, options.env, key);
|
|
28
|
-
console.log(chalk_1.default.bold(`\nHistory for ${key} (${options.env})`));
|
|
29
|
-
console.log(chalk_1.default.gray(`Current Version: ${data.currentVersion}\n`));
|
|
30
|
-
const history = data.history || [];
|
|
31
|
-
if (history.length === 0) {
|
|
32
|
-
console.log("No history found.");
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
history.forEach((h) => {
|
|
36
|
-
const dateStr = new Date(h.updatedAt).toLocaleString();
|
|
37
|
-
console.log(chalk_1.default.blue(`v${h.version}`) + ` - ${dateStr} by ${h.updatedBy}`);
|
|
38
|
-
if (h.description)
|
|
39
|
-
console.log(chalk_1.default.gray(` ${h.description}`));
|
|
40
|
-
console.log("");
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
catch (error) {
|
|
45
|
-
console.error(chalk_1.default.red("Error fetching history:"), error.message || error);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
exports.rollbackCommand = new commander_1.Command("rollback");
|
|
49
|
-
exports.rollbackCommand
|
|
50
|
-
.argument("<key>", "Secret key")
|
|
51
|
-
.argument("<version>", "Version to rollback to")
|
|
52
|
-
.option("-p, --project <id>", "Project ID")
|
|
53
|
-
.option("-e, --env <environment>", "Environment", "development")
|
|
54
|
-
.description("Rollback a secret to a previous version")
|
|
55
|
-
.action(async (key, version, options) => {
|
|
56
|
-
try {
|
|
57
|
-
let projectId = options.project;
|
|
58
|
-
if (!projectId) {
|
|
59
|
-
projectId = (0, config_1.getRcConfig)().project;
|
|
60
|
-
if (!projectId) {
|
|
61
|
-
console.error(chalk_1.default.red("Error: Project ID not found. Use -p <id> or run 'xtra project set' first."));
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
console.log(chalk_1.default.yellow(`Rolling back ${key} to v${version}...`));
|
|
66
|
-
const result = await api_1.api.rollbackSecret(projectId, options.env, key, version);
|
|
67
|
-
if (result.success) {
|
|
68
|
-
console.log(chalk_1.default.green(`\nSuccessfully rolled back to v${version} (New current version: v${result.version})`));
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
console.log(chalk_1.default.red("Rollback failed."));
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
catch (error) {
|
|
75
|
-
console.error(chalk_1.default.red("Error rolling back:"), error.message || error);
|
|
76
|
-
}
|
|
77
|
-
});
|
|
1
|
+
var C=Object.create;var g=Object.defineProperty;var U=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,L=Object.prototype.hasOwnProperty;var _=(e,t)=>{for(var s in t)g(e,s,{get:t[s],enumerable:!0})},v=(e,t,s,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of R(t))!L.call(e,o)&&o!==s&&g(e,o,{get:()=>t[o],enumerable:!(r=U(t,o))||r.enumerable});return e};var p=(e,t,s)=>(s=e!=null?C(P(e)):{},v(t||!e||!e.__esModule?g(s,"default",{value:e,enumerable:!0}):s,e)),D=e=>v(g({},"__esModule",{value:!0}),e);var B={};_(B,{historyCommand:()=>I,rollbackCommand:()=>A});module.exports=D(B);var w=require("commander"),a=p(require("chalk"));var k=p(require("axios"));var j=p(require("conf")),u=p(require("fs")),S=p(require("path")),y="https://www.xtrasecurity.in/api",i=new j.default({projectName:"xtra-cli",defaults:{apiUrl:y}}),d=i.get("apiUrl");d&&!process.env.XTRA_API_URL&&(d.includes("localhost")||d.includes("xtra-security.vercel.app"))&&i.set("apiUrl",y);var l=()=>({...i.store,apiUrl:process.env.XTRA_API_URL||i.get("apiUrl")||y});var h=()=>i.get("token");var m=()=>{let e={};try{let t=S.default.join(process.cwd(),".xtrarc");u.default.existsSync(t)&&(e=JSON.parse(u.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||i.get("project")||"",env:e.env||i.get("env")||"development",branch:e.branch||i.get("branch")||"main"}};var b=p(require("fs")),x=p(require("path")),V=JSON.parse(b.readFileSync(x.join(__dirname,"../../package.json"),"utf-8")),n=()=>{let{apiUrl:e}=l(),t=h();return k.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":V.version,...t?{Authorization:`Bearer ${t}`}:{}}})},f={login:async(e,t,s)=>(await n().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await n().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await n().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,r,o="main")=>(await n().post(`/projects/${e}/envs/${t}/secrets`,{secrets:s,expectedVersions:r,branch:o})).data,getSecretDetails:async(e,t,s,r="main")=>(await n().get(`/projects/${e}/envs/${t}/secrets/${s}?branch=${r}`)).data,syncLogs:async e=>(await n().post("/audit/cli-logs",{logs:e})).data,linkSecret:async(e,t,s,r,o,c)=>(await n().post(`/projects/${e}/envs/${t}/secrets/link`,{key:s,sourceProjectId:r,sourceEnv:o,sourceKey:c})).data,rotateSecret:async(e,t,s,r,o)=>(await n().post(`/projects/${e}/envs/${t}/secrets/${s}/rotate`,{strategy:r,parsedNewValue:o})).data,promoteSecret:async(e,t,s)=>(await n().post(`/projects/${e}/envs/${t}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await n().get("/audit/verify")).data,exportAuditLogs:async(e,t,s,r)=>{let o={format:e};return t&&(o.startDate=t),s&&(o.endDate=s),r&&(o.projectId=r),(await n().post("/audit/export",o,{responseType:e==="csv"?"text":"json"})).data},requestAccess:async(e,t,s,r)=>(await n().post("/access/request",{projectId:e,secretId:r,reason:t,duration:s})).data,approveAccess:async(e,t)=>(await n().post("/access/approve",{requestId:e,decision:t})).data,listAccessRequests:async e=>{let{workspace:t}=l(),s=t?`&workspaceId=${t}`:"";return(await n().get(`/access/list?mode=${e}${s}`)).data},getAccessRequestStatus:async e=>(await n().get(`/access/request?id=${e}`)).data,getProjects:async()=>{let{workspace:e}=l(),t=e?`/project?workspaceId=${e}`:"/project";return(await n().get(t)).data},getBranches:async e=>(await n().get(`/branch?projectId=${e}`)).data,createBranch:async(e,t,s)=>(await n().post("/branch",{projectId:e,name:t,description:s})).data,deleteBranch:async e=>(await n().delete(`/branch/${e}`)).data,updateBranch:async(e,t)=>(await n().put("/branch",{id:e,...t})).data,getRoles:async()=>(await n().get("/admin/roles")).data,getUsers:async e=>{let t=e?`?teamId=${e}`:"";return(await n().get(`/admin/users${t}`)).data},setUserRole:async(e,t,s)=>(await n().put("/admin/users/role",{email:e,role:t,teamId:s})).data,getIntegrationStatus:async e=>(await n().get(`/integrations/${e}`)).data,getIntegrationRepos:async e=>(await n().get(`/integrations/${e}/sync`)).data.repos,syncSecretsToGithub:async e=>(await n().post("/integrations/github/sync",e)).data,exportKubernetesSecret:async(e,t)=>{let s=new URLSearchParams(t).toString();return(await n().get(`/projects/${e}/kubernetes?${s}`)).data},getSecretHistory:async(e,t,s)=>(await n().get(`/projects/${e}/envs/${t}/secrets/${s}/history`)).data,rollbackSecret:async(e,t,s,r)=>(await n().post(`/projects/${e}/envs/${t}/secrets/${s}/history`,{version:r})).data,cloneEnvironment:async(e,t,s,r,o)=>(await n().post(`/projects/${e}/envs/clone`,{fromEnv:t,toEnv:s,overwrite:r,branch:o})).data,generateJitLink:async e=>(await n().post("/jit/generate",e)).data,claimJitLink:async e=>(await n().post("/jit/claim",{token:e})).data,getJitInfo:async e=>(await n().get(`/jit/${e}`)).data,getServiceAccounts:async e=>(await n().get(`/projects/${e}/service-accounts`)).data,createServiceAccount:async(e,t)=>(await n().post(`/projects/${e}/service-accounts`,t)).data,deleteServiceAccount:async(e,t)=>(await n().delete(`/projects/${e}/service-accounts/${t}`)).data,getServiceAccountKeys:async(e,t)=>(await n().get(`/projects/${e}/service-accounts/${t}/keys`)).data,createServiceAccountKey:async(e,t,s,r)=>(await n().post(`/projects/${e}/service-accounts/${t}/keys`,{label:s,expiresAt:r})).data,deleteServiceAccountKey:async(e,t,s)=>(await n().delete(`/projects/${e}/service-accounts/${t}/keys/${s}`)).data,post:async(e,t)=>(await n().post(e,t)).data};var I=new w.Command("history");I.argument("<key>","Secret key").option("-p, --project <id>","Project ID").option("-e, --env <environment>","Environment","development").description("View version history of a secret").action(async(e,t)=>{try{let s=t.project;s||(s=m().project,s||(console.error(a.default.red("Error: Project ID not found. Use -p <id> or run 'xtra project set' first.")),process.exit(1)));let r=await f.getSecretHistory(s,t.env,e);console.log(a.default.bold(`
|
|
2
|
+
History for ${e} (${t.env})`)),console.log(a.default.gray(`Current Version: ${r.currentVersion}
|
|
3
|
+
`));let o=r.history||[];o.length===0?console.log("No history found."):o.forEach(c=>{let $=new Date(c.updatedAt).toLocaleString();console.log(a.default.blue(`v${c.version}`)+` - ${$} by ${c.updatedBy}`),c.description&&console.log(a.default.gray(` ${c.description}`)),console.log("")})}catch(s){console.error(a.default.red("Error fetching history:"),s?.response?.data?.error||"Unknown error")}});var A=new w.Command("rollback");A.argument("<key>","Secret key").argument("<version>","Version to rollback to").option("-p, --project <id>","Project ID").option("-e, --env <environment>","Environment","development").description("Rollback a secret to a previous version").action(async(e,t,s)=>{try{let r=s.project;r||(r=m().project,r||(console.error(a.default.red("Error: Project ID not found. Use -p <id> or run 'xtra project set' first.")),process.exit(1))),console.log(a.default.yellow(`Rolling back ${e} to v${t}...`));let o=await f.rollbackSecret(r,s.env,e,t);o.success?console.log(a.default.green(`
|
|
4
|
+
Successfully rolled back to v${t} (New current version: v${o.version})`)):console.log(a.default.red("Rollback failed."))}catch(r){console.error(a.default.red("Error rolling back:"),r?.response?.data?.error||"Unknown error")}});0&&(module.exports={historyCommand,rollbackCommand});
|
package/dist/commands/import.js
CHANGED
|
@@ -1,121 +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.importCommand = void 0;
|
|
7
|
-
const commander_1 = require("commander");
|
|
8
|
-
const api_1 = require("../lib/api");
|
|
9
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
-
const fs_1 = __importDefault(require("fs"));
|
|
11
|
-
const path_1 = __importDefault(require("path"));
|
|
12
|
-
const dotenv_1 = __importDefault(require("dotenv"));
|
|
13
|
-
const sync_1 = require("csv-parse/sync");
|
|
14
|
-
const config_1 = require("../lib/config");
|
|
15
|
-
exports.importCommand = new commander_1.Command("import")
|
|
16
|
-
.description("Import secrets from a file (JSON, Dotenv, CSV)")
|
|
17
|
-
.argument("<file>", "Path to the file to import")
|
|
18
|
-
.option("-p, --project <projectId>", "Project ID")
|
|
19
|
-
.option("-e, --env <environment>", "Environment (development, staging, production)", "development")
|
|
20
|
-
.option("-b, --branch <branchName>", "Branch Name")
|
|
21
|
-
.option("-f, --format <format>", "Input format (json, dotenv, csv). Auto-detected if omitted.")
|
|
22
|
-
.option("--prefix <prefix>", "Add prefix to all imported keys")
|
|
23
|
-
.option("--overwrite", "Overwrite existing secrets (default: merged, but API usually upserts)", true)
|
|
24
|
-
.action(async (file, options) => {
|
|
25
|
-
let { project, env, branch, format, prefix } = options;
|
|
26
|
-
// Use config fallback
|
|
27
|
-
if (!project)
|
|
28
|
-
project = (0, config_1.getRcConfig)().project;
|
|
29
|
-
if (!branch) {
|
|
30
|
-
branch = (0, config_1.getRcConfig)().branch || "main";
|
|
31
|
-
}
|
|
32
|
-
// Normalize Env
|
|
33
|
-
const envMap = { dev: "development", stg: "staging", prod: "production" };
|
|
34
|
-
env = envMap[env] || env;
|
|
35
|
-
if (!project) {
|
|
36
|
-
console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
|
|
37
|
-
process.exit(1);
|
|
38
|
-
}
|
|
39
|
-
const filePath = path_1.default.resolve(process.cwd(), file);
|
|
40
|
-
if (!fs_1.default.existsSync(filePath)) {
|
|
41
|
-
console.error(chalk_1.default.red(`Error: File not found: ${filePath}`));
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
let detectedFormat = format;
|
|
45
|
-
if (!detectedFormat) {
|
|
46
|
-
const ext = path_1.default.extname(filePath).toLowerCase();
|
|
47
|
-
if (ext === ".json")
|
|
48
|
-
detectedFormat = "json";
|
|
49
|
-
else if (ext === ".env")
|
|
50
|
-
detectedFormat = "dotenv";
|
|
51
|
-
else if (ext === ".csv")
|
|
52
|
-
detectedFormat = "csv";
|
|
53
|
-
else {
|
|
54
|
-
console.error(chalk_1.default.red("Error: Could not detect format. Please specify -f <format>"));
|
|
55
|
-
process.exit(1);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
const spinner = require("ora")(`Reading ${detectedFormat} file...`).start();
|
|
59
|
-
const fileContent = fs_1.default.readFileSync(filePath, "utf-8");
|
|
60
|
-
let secrets = {};
|
|
61
|
-
try {
|
|
62
|
-
switch (detectedFormat.toLowerCase()) {
|
|
63
|
-
case "json":
|
|
64
|
-
secrets = JSON.parse(fileContent);
|
|
65
|
-
break;
|
|
66
|
-
case "dotenv":
|
|
67
|
-
secrets = dotenv_1.default.parse(fileContent);
|
|
68
|
-
break;
|
|
69
|
-
case "csv":
|
|
70
|
-
const records = (0, sync_1.parse)(fileContent, {
|
|
71
|
-
columns: true,
|
|
72
|
-
skip_empty_lines: true
|
|
73
|
-
});
|
|
74
|
-
// Expect header: key, value or Key, Value
|
|
75
|
-
records.forEach((record) => {
|
|
76
|
-
// Try case-insensitive key lookup
|
|
77
|
-
const key = record.key || record.Key || record.KEY;
|
|
78
|
-
const value = record.value || record.Value || record.VALUE;
|
|
79
|
-
if (key) {
|
|
80
|
-
secrets[key] = value || "";
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
break;
|
|
84
|
-
default:
|
|
85
|
-
spinner.fail(`Unsupported format: ${detectedFormat}`);
|
|
86
|
-
process.exit(1);
|
|
87
|
-
}
|
|
88
|
-
if (Object.keys(secrets).length === 0) {
|
|
89
|
-
spinner.fail("No valid secrets found in file.");
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
// Apply prefix
|
|
93
|
-
if (prefix) {
|
|
94
|
-
const prefixedSecrets = {};
|
|
95
|
-
Object.entries(secrets).forEach(([key, value]) => {
|
|
96
|
-
prefixedSecrets[`${prefix}${key}`] = value;
|
|
97
|
-
});
|
|
98
|
-
secrets = prefixedSecrets;
|
|
99
|
-
}
|
|
100
|
-
// Upload
|
|
101
|
-
spinner.text = `Importing ${Object.keys(secrets).length} secrets to ${env} (branch: ${branch})...`;
|
|
102
|
-
await api_1.api.setSecrets(project, env, secrets, undefined, branch);
|
|
103
|
-
spinner.succeed(`Successfully imported ${Object.keys(secrets).length} secrets.`);
|
|
104
|
-
// Log Audit
|
|
105
|
-
try {
|
|
106
|
-
const { logAudit } = require("../lib/audit");
|
|
107
|
-
logAudit("SECRET_IMPORT", project, env, {
|
|
108
|
-
file: path_1.default.basename(filePath),
|
|
109
|
-
format: detectedFormat,
|
|
110
|
-
count: Object.keys(secrets).length,
|
|
111
|
-
branch: branch
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
catch (e) { }
|
|
115
|
-
}
|
|
116
|
-
catch (error) {
|
|
117
|
-
spinner.fail("Import failed.");
|
|
118
|
-
console.error(chalk_1.default.red(error.message));
|
|
119
|
-
process.exit(1);
|
|
120
|
-
}
|
|
121
|
-
});
|
|
1
|
+
var ge=Object.create;var S=Object.defineProperty;var de=Object.getOwnPropertyDescriptor;var ue=Object.getOwnPropertyNames;var fe=Object.getPrototypeOf,le=Object.prototype.hasOwnProperty;var $=(e,t)=>()=>(e&&(t=e(e=0)),t);var D=(e,t)=>{for(var s in t)S(e,s,{get:t[s],enumerable:!0})},J=(e,t,s,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of ue(t))!le.call(e,n)&&n!==s&&S(e,n,{get:()=>t[n],enumerable:!(r=de(t,n))||r.enumerable});return e};var a=(e,t,s)=>(s=e!=null?ge(fe(e)):{},J(t||!e||!e.__esModule?S(s,"default",{value:e,enumerable:!0}):s,e)),F=e=>J(S({},"__esModule",{value:!0}),e);var K,U,V,E,f,O,l,q,L,b=$(()=>{K=a(require("conf")),U=a(require("fs")),V=a(require("path")),E="https://www.xtrasecurity.in/api",f=new K.default({projectName:"xtra-cli",defaults:{apiUrl:E}}),O=f.get("apiUrl");O&&!process.env.XTRA_API_URL&&(O.includes("localhost")||O.includes("xtra-security.vercel.app"))&&f.set("apiUrl",E);l=()=>({...f.store,apiUrl:process.env.XTRA_API_URL||f.get("apiUrl")||E}),q=()=>f.get("token"),L=()=>{let e={};try{let t=V.default.join(process.cwd(),".xtrarc");U.default.existsSync(t)&&(e=JSON.parse(U.default.readFileSync(t,"utf-8")))}catch{}return{project:e.project||f.get("project")||"",env:e.env||f.get("env")||"development",branch:e.branch||f.get("branch")||"main"}}});var G,M,z,me,o,k,P=$(()=>{G=a(require("axios"));b();M=a(require("fs")),z=a(require("path")),me=JSON.parse(M.readFileSync(z.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:e}=l(),t=q();return G.default.create({baseURL:e,headers:{"Content-Type":"application/json","X-CLI-Version":me.version,...t?{Authorization:`Bearer ${t}`}:{}}})},k={login:async(e,t,s)=>(await o().post("/auth/cli-login",{email:e,password:t,apiKey:s})).data,getSecrets:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?branch=${s}`)).data,getSecretVersions:async(e,t,s="main")=>(await o().get(`/projects/${e}/envs/${t}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(e,t,s,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}=l(),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}=l(),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,getServiceAccounts:async e=>(await o().get(`/projects/${e}/service-accounts`)).data,createServiceAccount:async(e,t)=>(await o().post(`/projects/${e}/service-accounts`,t)).data,deleteServiceAccount:async(e,t)=>(await o().delete(`/projects/${e}/service-accounts/${t}`)).data,getServiceAccountKeys:async(e,t)=>(await o().get(`/projects/${e}/service-accounts/${t}/keys`)).data,createServiceAccountKey:async(e,t,s,r)=>(await o().post(`/projects/${e}/service-accounts/${t}/keys`,{label:s,expiresAt:r})).data,deleteServiceAccountKey:async(e,t,s)=>(await o().delete(`/projects/${e}/service-accounts/${t}/keys/${s}`)).data,post:async(e,t)=>(await o().post(e,t)).data}});function W(){let e=H.get("masterKey");e||(e=m.default.randomBytes(32).toString("hex"),H.set("masterKey",e));let t=(0,Y.machineIdSync)();return m.default.createHash("sha256").update(e+t).digest()}var m,X,Y,Q,H,Z,ee,te=$(()=>{m=a(require("crypto")),X=a(require("conf")),Y=require("node-machine-id"),Q="aes-256-gcm",H=new X.default({projectName:"xtra-cli-crypto"});Z=e=>{let t=m.default.randomBytes(16),s=W(),r=m.default.createCipheriv(Q,s,t),n=r.update(e,"utf8","hex");n+=r.final("hex");let i=r.getAuthTag();return{iv:t.toString("hex"),content:n,tag:i.toString("hex")}},ee=e=>{let t=W(),s=Buffer.from(e.iv,"hex"),r=Buffer.from(e.tag,"hex"),n=m.default.createDecipheriv(Q,t,s);n.setAuthTag(r);let i=n.update(e.content,"hex","utf8");return i+=n.final("utf8"),i}});var ne={};D(ne,{loadAuditLogs:()=>I,logAudit:()=>he,saveAuditLogs:()=>A,syncAuditLogs:()=>ve});function ye(e){if(!e||typeof e!="object")return e;let t={...e},s=["password","token","secret","value","apiKey","secretValue"];for(let r of Object.keys(t))s.some(n=>r.toLowerCase().includes(n))&&(t[r]="[REDACTED]");return t}async function re(e){try{if(!l().token)return!1;let s={action:e.action,entity:"cli-project",entityId:e.projectId||"global",details:ye(e.details),timestamp:e.timestamp,projectId:e.projectId};return await k.post("/audit/cli-logs",{logs:[s]}),!0}catch(t){return process.env.DEBUG&&console.error("Failed to send audit log to backend:",t),!1}}function he(e,t,s,r){let n={id:(0,se.v4)(),timestamp:new Date().toISOString(),action:e,projectId:t,environment:s,details:r,synced:!1},i=I();i.push(n),A(i),re(n).then(h=>{if(h){n.synced=!0;let j=I(),d=j.findIndex(p=>p.id===n.id);d!==-1&&(j[d].synced=!0,A(j))}}).catch(()=>{})}function I(){if(!y.default.existsSync(B))return[];try{let e=y.default.readFileSync(B,"utf-8"),t=JSON.parse(e),s=ee(t);return JSON.parse(s)}catch{return[]}}function A(e){y.default.existsSync(N)||y.default.mkdirSync(N,{recursive:!0});let t=JSON.stringify(e),s=Z(t);y.default.writeFileSync(B,JSON.stringify(s),"utf-8")}async function ve(){let e=I(),t=e.filter(r=>!r.synced);if(t.length===0)return 0;let s=0;for(let r of t)await re(r)&&(r.synced=!0,s++);return s>0&&A(e),s}var y,T,se,N,B,oe=$(()=>{y=a(require("fs")),T=a(require("path")),se=require("uuid");te();b();P();N=T.default.join(process.cwd(),".xtra"),B=T.default.join(N,"audit.enc")});var je={};D(je,{importCommand:()=>we});module.exports=F(je);var ie=require("commander");P();var w=a(require("chalk")),_=a(require("fs")),C=a(require("path")),ae=a(require("dotenv")),ce=require("csv-parse/sync");b();var we=new ie.Command("import").description("Import secrets from a file (JSON, Dotenv, CSV)").argument("<file>","Path to the file to import").option("-p, --project <projectId>","Project ID").option("-e, --env <environment>","Environment (development, staging, production)","development").option("-b, --branch <branchName>","Branch Name").option("-f, --format <format>","Input format (json, dotenv, csv). Auto-detected if omitted.").option("--prefix <prefix>","Add prefix to all imported keys").option("--overwrite","Overwrite existing secrets (default: merged, but API usually upserts)",!0).action(async(e,t)=>{let{project:s,env:r,branch:n,format:i,prefix:h}=t;s||(s=L().project),n||(n=L().branch||"main"),r={dev:"development",stg:"staging",prod:"production"}[r]||r,s||(console.error(w.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first.")),process.exit(1));let d=C.default.resolve(process.cwd(),e);_.default.existsSync(d)||(console.error(w.default.red(`Error: File not found: ${d}`)),process.exit(1));let p=i;if(!p){let c=C.default.extname(d).toLowerCase();c===".json"?p="json":c===".env"?p="dotenv":c===".csv"?p="csv":(console.error(w.default.red("Error: Could not detect format. Please specify -f <format>")),process.exit(1))}let v=require("ora")(`Reading ${p} file...`).start(),R=_.default.readFileSync(d,"utf-8"),g={};try{switch(p.toLowerCase()){case"json":g=JSON.parse(R);break;case"dotenv":g=ae.default.parse(R);break;case"csv":(0,ce.parse)(R,{columns:!0,skip_empty_lines:!0}).forEach(u=>{let x=u.key||u.Key||u.KEY,pe=u.value||u.Value||u.VALUE;x&&(g[x]=pe||"")});break;default:v.fail(`Unsupported format: ${p}`),process.exit(1)}if(Object.keys(g).length===0){v.fail("No valid secrets found in file.");return}if(h){let c={};Object.entries(g).forEach(([u,x])=>{c[`${h}${u}`]=x}),g=c}v.text=`Importing ${Object.keys(g).length} secrets to ${r} (branch: ${n})...`,await k.setSecrets(s,r,g,void 0,n),v.succeed(`Successfully imported ${Object.keys(g).length} secrets.`);try{let{logAudit:c}=(oe(),F(ne));c("SECRET_IMPORT",s,r,{file:C.default.basename(d),format:p,count:Object.keys(g).length,branch:n})}catch{}}catch(c){v.fail("Import failed."),console.error(w.default.red(c?.response?.data?.error||"An unexpected error occurred")),process.exit(1)}});0&&(module.exports={importCommand});
|
package/dist/commands/init.js
CHANGED
|
@@ -1,205 +1,7 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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.initCommand = void 0;
|
|
40
|
-
/**
|
|
41
|
-
* init.ts — Bootstrap a new project with .xtrarc and recommended structure
|
|
42
|
-
*/
|
|
43
|
-
const commander_1 = require("commander");
|
|
44
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
45
|
-
const inquirer_1 = __importDefault(require("inquirer"));
|
|
46
|
-
const fs = __importStar(require("fs"));
|
|
47
|
-
const path = __importStar(require("path"));
|
|
48
|
-
const config_1 = require("../lib/config");
|
|
49
|
-
const RC_FILE = ".xtrarc";
|
|
50
|
-
exports.initCommand = new commander_1.Command("init")
|
|
51
|
-
.description("Bootstrap a new project — creates .xtrarc and recommended structure")
|
|
52
|
-
.option("--project <id>", "Project ID (skip prompt)")
|
|
53
|
-
.option("--env <env>", "Default environment", "development")
|
|
54
|
-
.option("--branch <branch>", "Default branch", "main")
|
|
55
|
-
.option("-y, --yes", "Accept all defaults without prompting", false)
|
|
56
|
-
.action(async (options) => {
|
|
57
|
-
const cwd = process.cwd();
|
|
58
|
-
const rcPath = path.join(cwd, RC_FILE);
|
|
59
|
-
console.log(chalk_1.default.bold("\n🚀 xtra init — setting up your project\n"));
|
|
60
|
-
// Warn if already initialized
|
|
61
|
-
if (fs.existsSync(rcPath)) {
|
|
62
|
-
const { overwrite } = await inquirer_1.default.prompt([{
|
|
63
|
-
type: "confirm",
|
|
64
|
-
name: "overwrite",
|
|
65
|
-
message: chalk_1.default.yellow(`.xtrarc already exists. Overwrite it?`),
|
|
66
|
-
default: false,
|
|
67
|
-
}]);
|
|
68
|
-
if (!overwrite) {
|
|
69
|
-
console.log(chalk_1.default.gray("Aborted."));
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
let { project, env, branch } = options;
|
|
74
|
-
// Interactive prompts if not --yes
|
|
75
|
-
if (!options.yes) {
|
|
76
|
-
// ── API Projects Fetch ─────────────────────────────────────────────
|
|
77
|
-
const { getAuthToken } = await Promise.resolve().then(() => __importStar(require("../lib/config")));
|
|
78
|
-
const token = getAuthToken();
|
|
79
|
-
const ora = (await Promise.resolve().then(() => __importStar(require("ora")))).default;
|
|
80
|
-
let remoteProjects = [];
|
|
81
|
-
if (!token) {
|
|
82
|
-
console.log(chalk_1.default.yellow(" ℹ Not logged in — project list unavailable. Run `xtra login` first."));
|
|
83
|
-
console.log(chalk_1.default.yellow(" You can still enter a Project ID manually below.\n"));
|
|
84
|
-
}
|
|
85
|
-
else {
|
|
86
|
-
const apiSpinner = ora("Fetching your projects...").start();
|
|
87
|
-
try {
|
|
88
|
-
const { api } = await Promise.resolve().then(() => __importStar(require("../lib/api")));
|
|
89
|
-
const result = await api.getProjects();
|
|
90
|
-
// API might return { projects: [...] } or directly an array
|
|
91
|
-
remoteProjects = Array.isArray(result) ? result : result.projects ?? [];
|
|
92
|
-
if (remoteProjects.length === 0) {
|
|
93
|
-
apiSpinner.warn(chalk_1.default.yellow("No projects found in your workspace. Create one at www.xtrasecurity.in first."));
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
apiSpinner.succeed(`Found ${remoteProjects.length} project${remoteProjects.length > 1 ? "s" : ""}`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
const reason = err?.response?.status === 401
|
|
101
|
-
? "session expired — run `xtra login` again"
|
|
102
|
-
: err?.response?.data?.error || err?.message || "network error";
|
|
103
|
-
apiSpinner.warn(chalk_1.default.yellow(`Could not fetch projects (${reason}). Enter the Project ID manually.`));
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
const fallbackProject = project || (0, config_1.getConfigValue)("project") || "";
|
|
107
|
-
const { project: selectedProject } = await inquirer_1.default.prompt([
|
|
108
|
-
{
|
|
109
|
-
type: remoteProjects.length > 0 ? "list" : "input",
|
|
110
|
-
name: "project",
|
|
111
|
-
message: remoteProjects.length > 0 ? "Select a project:" : "Project ID:",
|
|
112
|
-
choices: remoteProjects.length > 0
|
|
113
|
-
? remoteProjects.map(p => ({ name: `${p.name} (${p.id})`, value: p.id }))
|
|
114
|
-
: undefined,
|
|
115
|
-
default: fallbackProject,
|
|
116
|
-
validate: (v) => v.trim() ? true : "Project ID is required",
|
|
117
|
-
}
|
|
118
|
-
]);
|
|
119
|
-
project = selectedProject.trim();
|
|
120
|
-
// Fetch branches for selected project
|
|
121
|
-
let remoteBranches = [];
|
|
122
|
-
const branchSpinner = ora("Fetching branches...").start();
|
|
123
|
-
try {
|
|
124
|
-
const { api } = await Promise.resolve().then(() => __importStar(require("../lib/api")));
|
|
125
|
-
remoteBranches = await api.getBranches(project);
|
|
126
|
-
branchSpinner.stop();
|
|
127
|
-
}
|
|
128
|
-
catch (err) {
|
|
129
|
-
branchSpinner.warn(chalk_1.default.yellow("Could not fetch branches."));
|
|
130
|
-
}
|
|
131
|
-
const answers = await inquirer_1.default.prompt([
|
|
132
|
-
{
|
|
133
|
-
type: "list",
|
|
134
|
-
name: "env",
|
|
135
|
-
message: "Default environment:",
|
|
136
|
-
choices: ["development", "staging", "production"],
|
|
137
|
-
default: env || "development",
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
type: remoteBranches.length > 0 ? "list" : "input",
|
|
141
|
-
name: "branch",
|
|
142
|
-
message: remoteBranches.length > 0 ? "Default branch:" : "Default branch name:",
|
|
143
|
-
choices: remoteBranches.length > 0
|
|
144
|
-
? remoteBranches.map(b => ({ name: b.name, value: b.name }))
|
|
145
|
-
: undefined,
|
|
146
|
-
default: branch || (remoteBranches.length > 0 ? remoteBranches[0].name : "main"),
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
type: "confirm",
|
|
150
|
-
name: "addGitignore",
|
|
151
|
-
message: "Add .xtrarc to .gitignore? (recommended)",
|
|
152
|
-
default: true,
|
|
153
|
-
},
|
|
154
|
-
]);
|
|
155
|
-
env = answers.env;
|
|
156
|
-
branch = answers.branch;
|
|
157
|
-
// Add to .gitignore
|
|
158
|
-
if (answers.addGitignore) {
|
|
159
|
-
const gitignorePath = path.join(cwd, ".gitignore");
|
|
160
|
-
let existing = "";
|
|
161
|
-
try {
|
|
162
|
-
existing = fs.readFileSync(gitignorePath, "utf8");
|
|
163
|
-
}
|
|
164
|
-
catch (_) { }
|
|
165
|
-
if (!existing.includes(".xtrarc")) {
|
|
166
|
-
fs.appendFileSync(gitignorePath, "\n# XtraSecurity config\n.xtrarc\n");
|
|
167
|
-
console.log(chalk_1.default.gray(" ✔ Added .xtrarc to .gitignore"));
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
if (!project) {
|
|
172
|
-
console.error(chalk_1.default.red("Error: Project ID is required."));
|
|
173
|
-
process.exit(1);
|
|
174
|
-
}
|
|
175
|
-
// Write .xtrarc
|
|
176
|
-
const rc = {
|
|
177
|
-
project,
|
|
178
|
-
env,
|
|
179
|
-
branch,
|
|
180
|
-
apiUrl: process.env.XTRA_API_URL || "https://www.xtrasecurity.in/api",
|
|
181
|
-
createdAt: new Date().toISOString(),
|
|
182
|
-
};
|
|
183
|
-
fs.writeFileSync(rcPath, JSON.stringify(rc, null, 2), "utf8");
|
|
184
|
-
// ── Sync global conf store so `xtra run` / `xtra secrets` pick up the new values ──
|
|
185
|
-
(0, config_1.setConfig)("project", project);
|
|
186
|
-
(0, config_1.setConfig)("env", env);
|
|
187
|
-
(0, config_1.setConfig)("branch", branch);
|
|
188
|
-
// Summary
|
|
189
|
-
console.log(chalk_1.default.gray(` Branch : ${chalk_1.default.white(branch)}`));
|
|
190
|
-
console.log();
|
|
191
|
-
// ── Audit Log (Local Chain) ─────────────────────────────────────────
|
|
192
|
-
try {
|
|
193
|
-
const { logAudit } = await Promise.resolve().then(() => __importStar(require("../lib/audit")));
|
|
194
|
-
logAudit("PROJECT_INIT", project, env, { branch, rcPath });
|
|
195
|
-
}
|
|
196
|
-
catch (e) {
|
|
197
|
-
// Non-fatal if audit fails
|
|
198
|
-
}
|
|
199
|
-
console.log(chalk_1.default.bold(" Next steps:"));
|
|
200
|
-
console.log(chalk_1.default.gray(" xtra login # authenticate"));
|
|
201
|
-
console.log(chalk_1.default.gray(" xtra secrets list # view secrets"));
|
|
202
|
-
console.log(chalk_1.default.gray(" xtra run node app.js # inject and run"));
|
|
203
|
-
console.log(chalk_1.default.gray(" xtra doctor # verify everything works"));
|
|
204
|
-
console.log();
|
|
205
|
-
});
|
|
1
|
+
var lt=Object.create;var A=Object.defineProperty;var yt=Object.getOwnPropertyDescriptor;var mt=Object.getOwnPropertyNames;var ft=Object.getPrototypeOf,ht=Object.prototype.hasOwnProperty;var I=(t,e)=>()=>(t&&(e=t(t=0)),e);var C=(t,e)=>{for(var s in e)A(t,s,{get:e[s],enumerable:!0})},X=(t,e,s,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of mt(e))!ht.call(t,r)&&r!==s&&A(t,r,{get:()=>e[r],enumerable:!(n=yt(e,r))||n.enumerable});return t};var g=(t,e,s)=>(s=t!=null?lt(ft(t)):{},X(e||!t||!t.__esModule?A(s,"default",{value:t,enumerable:!0}):s,t)),wt=t=>X(A({},"__esModule",{value:!0}),t);var H={};C(H,{clearConfig:()=>jt,deleteConfig:()=>vt,getAuthToken:()=>_,getBreakGlassSession:()=>xt,getConfig:()=>h,getConfigValue:()=>T,getProjectConfig:()=>$t,getRcConfig:()=>bt,setBreakGlassSession:()=>St,setConfig:()=>x});var z,f,N,O,p,L,h,T,x,jt,vt,_,xt,St,$t,bt,S=I(()=>{z=g(require("conf")),f=g(require("fs")),N=g(require("path")),O="https://www.xtrasecurity.in/api",p=new z.default({projectName:"xtra-cli",defaults:{apiUrl:O}}),L=p.get("apiUrl");L&&!process.env.XTRA_API_URL&&(L.includes("localhost")||L.includes("xtra-security.vercel.app"))&&p.set("apiUrl",O);h=()=>({...p.store,apiUrl:process.env.XTRA_API_URL||p.get("apiUrl")||O}),T=t=>p.get(t),x=(t,e)=>{if(p.set(t,e),t==="token"&&process.platform!=="win32"&&f.default.existsSync(p.path))try{f.default.chmodSync(p.path,384)}catch{}},jt=()=>p.clear(),vt=t=>p.delete(t),_=()=>p.get("token"),xt=()=>p.get("breakGlassSessionId"),St=t=>{t?p.set("breakGlassSessionId",t):p.delete("breakGlassSessionId")},$t=async()=>{try{let t=N.default.join(process.cwd(),"xtra.json");if(f.default.existsSync(t)){let e=f.default.readFileSync(t,"utf-8");return JSON.parse(e)}return null}catch{return null}},bt=()=>{let t={};try{let e=N.default.join(process.cwd(),".xtrarc");f.default.existsSync(e)&&(t=JSON.parse(f.default.readFileSync(e,"utf-8")))}catch{}return{project:t.project||p.get("project")||"",env:t.env||p.get("env")||"development",branch:t.branch||p.get("branch")||"main"}}});var F={};C(F,{api:()=>E});var M,Y,Q,kt,o,E,P=I(()=>{M=g(require("axios"));S();Y=g(require("fs")),Q=g(require("path")),kt=JSON.parse(Y.readFileSync(Q.join(__dirname,"../../package.json"),"utf-8")),o=()=>{let{apiUrl:t}=h(),e=_();return M.default.create({baseURL:t,headers:{"Content-Type":"application/json","X-CLI-Version":kt.version,...e?{Authorization:`Bearer ${e}`}:{}}})},E={login:async(t,e,s)=>(await o().post("/auth/cli-login",{email:t,password:e,apiKey:s})).data,getSecrets:async(t,e,s="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets?branch=${s}`)).data,getSecretVersions:async(t,e,s="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets?includeVersions=true&branch=${s}`)).data,setSecrets:async(t,e,s,n,r="main")=>(await o().post(`/projects/${t}/envs/${e}/secrets`,{secrets:s,expectedVersions:n,branch:r})).data,getSecretDetails:async(t,e,s,n="main")=>(await o().get(`/projects/${t}/envs/${e}/secrets/${s}?branch=${n}`)).data,syncLogs:async t=>(await o().post("/audit/cli-logs",{logs:t})).data,linkSecret:async(t,e,s,n,r,a)=>(await o().post(`/projects/${t}/envs/${e}/secrets/link`,{key:s,sourceProjectId:n,sourceEnv:r,sourceKey:a})).data,rotateSecret:async(t,e,s,n,r)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/rotate`,{strategy:n,parsedNewValue:r})).data,promoteSecret:async(t,e,s)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/promote`,{})).data,verifyAuditLogs:async()=>(await o().get("/audit/verify")).data,exportAuditLogs:async(t,e,s,n)=>{let r={format:t};return e&&(r.startDate=e),s&&(r.endDate=s),n&&(r.projectId=n),(await o().post("/audit/export",r,{responseType:t==="csv"?"text":"json"})).data},requestAccess:async(t,e,s,n)=>(await o().post("/access/request",{projectId:t,secretId:n,reason:e,duration:s})).data,approveAccess:async(t,e)=>(await o().post("/access/approve",{requestId:t,decision:e})).data,listAccessRequests:async t=>{let{workspace:e}=h(),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}=h(),e=t?`/project?workspaceId=${t}`:"/project";return(await o().get(e)).data},getBranches:async t=>(await o().get(`/branch?projectId=${t}`)).data,createBranch:async(t,e,s)=>(await o().post("/branch",{projectId:t,name:e,description:s})).data,deleteBranch:async t=>(await o().delete(`/branch/${t}`)).data,updateBranch:async(t,e)=>(await o().put("/branch",{id:t,...e})).data,getRoles:async()=>(await o().get("/admin/roles")).data,getUsers:async t=>{let e=t?`?teamId=${t}`:"";return(await o().get(`/admin/users${e}`)).data},setUserRole:async(t,e,s)=>(await o().put("/admin/users/role",{email:t,role:e,teamId:s})).data,getIntegrationStatus:async t=>(await o().get(`/integrations/${t}`)).data,getIntegrationRepos:async t=>(await o().get(`/integrations/${t}/sync`)).data.repos,syncSecretsToGithub:async t=>(await o().post("/integrations/github/sync",t)).data,exportKubernetesSecret:async(t,e)=>{let s=new URLSearchParams(e).toString();return(await o().get(`/projects/${t}/kubernetes?${s}`)).data},getSecretHistory:async(t,e,s)=>(await o().get(`/projects/${t}/envs/${e}/secrets/${s}/history`)).data,rollbackSecret:async(t,e,s,n)=>(await o().post(`/projects/${t}/envs/${e}/secrets/${s}/history`,{version:n})).data,cloneEnvironment:async(t,e,s,n,r)=>(await o().post(`/projects/${t}/envs/clone`,{fromEnv:e,toEnv:s,overwrite:n,branch:r})).data,generateJitLink:async t=>(await o().post("/jit/generate",t)).data,claimJitLink:async t=>(await o().post("/jit/claim",{token:t})).data,getJitInfo:async t=>(await o().get(`/jit/${t}`)).data,getServiceAccounts:async t=>(await o().get(`/projects/${t}/service-accounts`)).data,createServiceAccount:async(t,e)=>(await o().post(`/projects/${t}/service-accounts`,e)).data,deleteServiceAccount:async(t,e)=>(await o().delete(`/projects/${t}/service-accounts/${e}`)).data,getServiceAccountKeys:async(t,e)=>(await o().get(`/projects/${t}/service-accounts/${e}/keys`)).data,createServiceAccountKey:async(t,e,s,n)=>(await o().post(`/projects/${t}/service-accounts/${e}/keys`,{label:s,expiresAt:n})).data,deleteServiceAccountKey:async(t,e,s)=>(await o().delete(`/projects/${t}/service-accounts/${e}/keys/${s}`)).data,post:async(t,e)=>(await o().post(t,e)).data}});function st(){let t=W.get("masterKey");t||(t=j.default.randomBytes(32).toString("hex"),W.set("masterKey",t));let e=(0,tt.machineIdSync)();return j.default.createHash("sha256").update(t+e).digest()}var j,Z,tt,et,W,nt,rt,ot=I(()=>{j=g(require("crypto")),Z=g(require("conf")),tt=require("node-machine-id"),et="aes-256-gcm",W=new Z.default({projectName:"xtra-cli-crypto"});nt=t=>{let e=j.default.randomBytes(16),s=st(),n=j.default.createCipheriv(et,s,e),r=n.update(t,"utf8","hex");r+=n.final("hex");let a=n.getAuthTag();return{iv:e.toString("hex"),content:r,tag:a.toString("hex")}},rt=t=>{let e=st(),s=Buffer.from(t.iv,"hex"),n=Buffer.from(t.tag,"hex"),r=j.default.createDecipheriv(et,e,s);r.setAuthTag(n);let a=r.update(t.content,"hex","utf8");return a+=r.final("utf8"),a}});var ct={};C(ct,{loadAuditLogs:()=>D,logAudit:()=>It,saveAuditLogs:()=>R,syncAuditLogs:()=>Ct});function At(t){if(!t||typeof t!="object")return t;let e={...t},s=["password","token","secret","value","apiKey","secretValue"];for(let n of Object.keys(e))s.some(r=>n.toLowerCase().includes(r))&&(e[n]="[REDACTED]");return e}async function it(t){try{if(!h().token)return!1;let s={action:t.action,entity:"cli-project",entityId:t.projectId||"global",details:At(t.details),timestamp:t.timestamp,projectId:t.projectId};return await E.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 It(t,e,s,n){let r={id:(0,at.v4)(),timestamp:new Date().toISOString(),action:t,projectId:e,environment:s,details:n,synced:!1},a=D();a.push(r),R(a),it(r).then($=>{if($){r.synced=!0;let d=D(),b=d.findIndex(k=>k.id===r.id);b!==-1&&(d[b].synced=!0,R(d))}}).catch(()=>{})}function D(){if(!v.default.existsSync(G))return[];try{let t=v.default.readFileSync(G,"utf-8"),e=JSON.parse(t),s=rt(e);return JSON.parse(s)}catch{return[]}}function R(t){v.default.existsSync(J)||v.default.mkdirSync(J,{recursive:!0});let e=JSON.stringify(t),s=nt(e);v.default.writeFileSync(G,JSON.stringify(s),"utf-8")}async function Ct(){let t=D(),e=t.filter(n=>!n.synced);if(e.length===0)return 0;let s=0;for(let n of e)await it(n)&&(n.synced=!0,s++);return s>0&&R(t),s}var v,q,at,J,G,pt=I(()=>{v=g(require("fs")),q=g(require("path")),at=require("uuid");ot();S();P();J=q.default.join(process.cwd(),".xtra"),G=q.default.join(J,"audit.enc")});var Rt={};C(Rt,{initCommand:()=>Dt});module.exports=wt(Rt);var gt=require("commander"),c=g(require("chalk")),U=g(require("inquirer")),y=g(require("fs")),K=g(require("path"));S();var Pt=".xtrarc",Dt=new gt.Command("init").description("Bootstrap a new project \u2014 creates .xtrarc and recommended structure").option("--project <id>","Project ID (skip prompt)").option("--env <env>","Default environment","development").option("--branch <branch>","Default branch","main").option("-y, --yes","Accept all defaults without prompting",!1).action(async t=>{let e=process.cwd(),s=K.join(e,Pt);if(console.log(c.default.bold(`
|
|
2
|
+
\u{1F680} xtra init \u2014 setting up your project
|
|
3
|
+
`)),y.existsSync(s)){let{overwrite:d}=await U.default.prompt([{type:"confirm",name:"overwrite",message:c.default.yellow(".xtrarc already exists. Overwrite it?"),default:!1}]);if(!d){console.log(c.default.gray("Aborted."));return}}let{project:n,env:r,branch:a}=t;if(!t.yes){let{getAuthToken:d}=await Promise.resolve().then(()=>(S(),H)),b=d(),k=(await import("ora")).default,u=[];if(!b)console.log(c.default.yellow(" \u2139 Not logged in \u2014 project list unavailable. Run `xtra login` first.")),console.log(c.default.yellow(` You can still enter a Project ID manually below.
|
|
4
|
+
`));else{let i=k("Fetching your projects...").start();try{let{api:l}=await Promise.resolve().then(()=>(P(),F)),w=await l.getProjects();u=Array.isArray(w)?w:w.projects??[],u.length===0?i.warn(c.default.yellow("No projects found in your workspace. Create one at www.xtrasecurity.in first.")):i.succeed(`Found ${u.length} project${u.length>1?"s":""}`)}catch(l){let w=l?.response?.status===401?"session expired \u2014 run `xtra login` again":l?.response?.data?.error||l?.message||"network error";i.warn(c.default.yellow(`Could not fetch projects (${w}). Enter the Project ID manually.`))}}let dt=n||T("project")||"",{project:ut}=await U.default.prompt([{type:u.length>0?"list":"input",name:"project",message:u.length>0?"Select a project:":"Project ID:",choices:u.length>0?u.map(i=>({name:`${i.name} (${i.id})`,value:i.id})):void 0,default:dt,validate:i=>i.trim()?!0:"Project ID is required"}]);n=ut.trim();let m=[],V=k("Fetching branches...").start();try{let{api:i}=await Promise.resolve().then(()=>(P(),F));m=await i.getBranches(n),V.stop()}catch{V.warn(c.default.yellow("Could not fetch branches."))}let B=await U.default.prompt([{type:"list",name:"env",message:"Default environment:",choices:["development","staging","production"],default:r||"development"},{type:m.length>0?"list":"input",name:"branch",message:m.length>0?"Default branch:":"Default branch name:",choices:m.length>0?m.map(i=>({name:i.name,value:i.name})):void 0,default:a||(m.length>0?m[0].name:"main")},{type:"confirm",name:"addGitignore",message:"Add .xtrarc to .gitignore? (recommended)",default:!0}]);if(r=B.env,a=B.branch,B.addGitignore){let i=K.join(e,".gitignore"),l="";try{l=y.readFileSync(i,"utf8")}catch{}l.includes(".xtrarc")||(y.appendFileSync(i,`
|
|
5
|
+
# XtraSecurity config
|
|
6
|
+
.xtrarc
|
|
7
|
+
`),console.log(c.default.gray(" \u2714 Added .xtrarc to .gitignore")))}}n||(console.error(c.default.red("Error: Project ID is required.")),process.exit(1));let $={project:n,env:r,branch:a,apiUrl:process.env.XTRA_API_URL||"https://www.xtrasecurity.in/api",createdAt:new Date().toISOString()};y.writeFileSync(s,JSON.stringify($,null,2),"utf8"),x("project",n),x("env",r),x("branch",a),console.log(c.default.gray(` Branch : ${c.default.white(a)}`)),console.log();try{let{logAudit:d}=await Promise.resolve().then(()=>(pt(),ct));d("PROJECT_INIT",n,r,{branch:a,rcPath:s})}catch{}console.log(c.default.bold(" Next steps:")),console.log(c.default.gray(" xtra login # authenticate")),console.log(c.default.gray(" xtra secrets list # view secrets")),console.log(c.default.gray(" xtra run node app.js # inject and run")),console.log(c.default.gray(" xtra doctor # verify everything works")),console.log()});0&&(module.exports={initCommand});
|