@secretstash/cli 0.1.8 → 0.1.9
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/index.js +395 -162
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -314,7 +314,9 @@ var ApiClient = class {
|
|
|
314
314
|
body: JSON.stringify({ refreshToken })
|
|
315
315
|
});
|
|
316
316
|
if (!response.ok) {
|
|
317
|
-
|
|
317
|
+
if (response.status === 401 || response.status === 403) {
|
|
318
|
+
configManager.logout();
|
|
319
|
+
}
|
|
318
320
|
return false;
|
|
319
321
|
}
|
|
320
322
|
const json = await response.json();
|
|
@@ -322,11 +324,10 @@ var ApiClient = class {
|
|
|
322
324
|
configManager.setTokens(
|
|
323
325
|
tokens.accessToken,
|
|
324
326
|
tokens.refreshToken,
|
|
325
|
-
tokens.expiresIn ||
|
|
327
|
+
tokens.expiresIn || 3600
|
|
326
328
|
);
|
|
327
329
|
return true;
|
|
328
330
|
} catch {
|
|
329
|
-
configManager.logout();
|
|
330
331
|
return false;
|
|
331
332
|
}
|
|
332
333
|
}
|
|
@@ -891,9 +892,21 @@ async function handleBrowserLogin() {
|
|
|
891
892
|
configManager.setUser(user.id, user.email);
|
|
892
893
|
ui.br();
|
|
893
894
|
ui.keyValue("Email", user.email);
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
895
|
+
const hasTeam = configManager.getCurrentTeam();
|
|
896
|
+
const hasProject = configManager.getCurrentProject();
|
|
897
|
+
if (hasTeam && hasProject) {
|
|
898
|
+
ui.br();
|
|
899
|
+
ui.subheading("Current Context");
|
|
900
|
+
ui.keyValue("Team", hasTeam.name);
|
|
901
|
+
ui.keyValue("Project", hasProject.name);
|
|
902
|
+
const env = configManager.getCurrentEnvironment();
|
|
903
|
+
if (env) ui.keyValue("Environment", ui.envBadge(env));
|
|
904
|
+
} else {
|
|
905
|
+
ui.br();
|
|
906
|
+
ui.box("Get Started", [
|
|
907
|
+
`Run ${colors.highlight("stash init")} to set up a project in this directory`
|
|
908
|
+
]);
|
|
909
|
+
}
|
|
897
910
|
return;
|
|
898
911
|
}
|
|
899
912
|
if (status === "expired") {
|
|
@@ -949,7 +962,7 @@ async function handleServiceTokenLogin(token, fromEnvVar = false) {
|
|
|
949
962
|
` ${colors.highlight("export SECRETSTASH_TOKEN=" + token.substring(0, 16) + "...")}`,
|
|
950
963
|
"",
|
|
951
964
|
` ${colors.muted("# Then run CLI commands normally")}`,
|
|
952
|
-
` ${colors.highlight("
|
|
965
|
+
` ${colors.highlight("stash pull -q")}`
|
|
953
966
|
]);
|
|
954
967
|
}
|
|
955
968
|
function registerAuthCommands(program2) {
|
|
@@ -986,7 +999,7 @@ function registerAuthCommands(program2) {
|
|
|
986
999
|
});
|
|
987
1000
|
program2.command("whoami").description("Display current user information").action(async () => {
|
|
988
1001
|
if (!configManager.isAuthenticated()) {
|
|
989
|
-
ui.error("Not authenticated. Run `
|
|
1002
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
990
1003
|
process.exit(1);
|
|
991
1004
|
}
|
|
992
1005
|
if (configManager.isServiceTokenAuth()) {
|
|
@@ -1032,7 +1045,7 @@ function registerAuthCommands(program2) {
|
|
|
1032
1045
|
});
|
|
1033
1046
|
program2.command("2fa").description("Manage two-factor authentication").command("setup").description("Set up two-factor authentication").action(async () => {
|
|
1034
1047
|
if (!configManager.isAuthenticated()) {
|
|
1035
|
-
ui.error("Not authenticated. Run `
|
|
1048
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1036
1049
|
process.exit(1);
|
|
1037
1050
|
}
|
|
1038
1051
|
const spinner = ui.spinner("Setting up 2FA...");
|
|
@@ -1130,8 +1143,10 @@ function registerAuthCommands(program2) {
|
|
|
1130
1143
|
ui.br();
|
|
1131
1144
|
ui.keyValue("Email", email);
|
|
1132
1145
|
ui.br();
|
|
1133
|
-
ui.
|
|
1134
|
-
|
|
1146
|
+
ui.box("Get Started", [
|
|
1147
|
+
`${colors.highlight("stash init")} - Set up your first project`,
|
|
1148
|
+
`${colors.muted("stash 2fa setup")} - Enable two-factor authentication (recommended)`
|
|
1149
|
+
]);
|
|
1135
1150
|
});
|
|
1136
1151
|
}
|
|
1137
1152
|
|
|
@@ -1142,7 +1157,7 @@ function registerTeamCommands(program2) {
|
|
|
1142
1157
|
const teams = program2.command("teams").description("Manage teams");
|
|
1143
1158
|
teams.command("list").alias("ls").description("List all teams you belong to").action(async () => {
|
|
1144
1159
|
if (!configManager.isAuthenticated()) {
|
|
1145
|
-
ui.error("Not authenticated. Run `
|
|
1160
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1146
1161
|
process.exit(1);
|
|
1147
1162
|
}
|
|
1148
1163
|
const spinner = ui.spinner("Fetching teams...");
|
|
@@ -1155,7 +1170,7 @@ function registerTeamCommands(program2) {
|
|
|
1155
1170
|
spinner.stop();
|
|
1156
1171
|
if (!result.data?.teams.length) {
|
|
1157
1172
|
ui.warning("You are not a member of any teams");
|
|
1158
|
-
ui.info(`Create one with ${ui.code("
|
|
1173
|
+
ui.info(`Create one with ${ui.code("stash teams create")}`);
|
|
1159
1174
|
return;
|
|
1160
1175
|
}
|
|
1161
1176
|
ui.heading("Your Teams");
|
|
@@ -1170,11 +1185,11 @@ function registerTeamCommands(program2) {
|
|
|
1170
1185
|
header: ["", "Name", "Slug", "Role"]
|
|
1171
1186
|
});
|
|
1172
1187
|
ui.br();
|
|
1173
|
-
ui.info(`Switch teams with ${ui.code("
|
|
1188
|
+
ui.info(`Switch teams with ${ui.code("stash teams use <slug>")}`);
|
|
1174
1189
|
});
|
|
1175
1190
|
teams.command("create").description("Create a new team").option("-n, --name <name>", "Team name").action(async (options) => {
|
|
1176
1191
|
if (!configManager.isAuthenticated()) {
|
|
1177
|
-
ui.error("Not authenticated. Run `
|
|
1192
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1178
1193
|
process.exit(1);
|
|
1179
1194
|
}
|
|
1180
1195
|
let name = options.name;
|
|
@@ -1198,21 +1213,22 @@ function registerTeamCommands(program2) {
|
|
|
1198
1213
|
ui.error(result.error.message);
|
|
1199
1214
|
process.exit(1);
|
|
1200
1215
|
}
|
|
1216
|
+
const team = result.data.team;
|
|
1201
1217
|
configManager.setCurrentTeam({
|
|
1202
|
-
id:
|
|
1203
|
-
name:
|
|
1204
|
-
slug:
|
|
1218
|
+
id: team.id,
|
|
1219
|
+
name: team.name,
|
|
1220
|
+
slug: team.slug
|
|
1205
1221
|
});
|
|
1206
1222
|
spinner.succeed(`Team "${name}" created successfully`);
|
|
1207
1223
|
ui.br();
|
|
1208
|
-
ui.keyValue("ID",
|
|
1209
|
-
ui.keyValue("Slug",
|
|
1224
|
+
ui.keyValue("ID", team.id);
|
|
1225
|
+
ui.keyValue("Slug", team.slug);
|
|
1210
1226
|
ui.br();
|
|
1211
|
-
ui.info(`Create your first project with ${ui.code("
|
|
1227
|
+
ui.info(`Create your first project with ${ui.code("stash projects create")}`);
|
|
1212
1228
|
});
|
|
1213
1229
|
teams.command("use <slug>").description("Switch to a different team").action(async (slug) => {
|
|
1214
1230
|
if (!configManager.isAuthenticated()) {
|
|
1215
|
-
ui.error("Not authenticated. Run `
|
|
1231
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1216
1232
|
process.exit(1);
|
|
1217
1233
|
}
|
|
1218
1234
|
const spinner = ui.spinner("Fetching teams...");
|
|
@@ -1226,6 +1242,15 @@ function registerTeamCommands(program2) {
|
|
|
1226
1242
|
if (!team) {
|
|
1227
1243
|
spinner.fail();
|
|
1228
1244
|
ui.error(`Team "${slug}" not found or you don't have access`);
|
|
1245
|
+
if (result.data?.teams.length) {
|
|
1246
|
+
ui.br();
|
|
1247
|
+
ui.info("Your teams:");
|
|
1248
|
+
result.data.teams.forEach((t) => {
|
|
1249
|
+
ui.info(` ${t.slug} - ${t.name}`);
|
|
1250
|
+
});
|
|
1251
|
+
} else {
|
|
1252
|
+
ui.info(`You're not a member of any teams. Create one with ${ui.code("stash teams create")}`);
|
|
1253
|
+
}
|
|
1229
1254
|
process.exit(1);
|
|
1230
1255
|
}
|
|
1231
1256
|
configManager.setCurrentTeam({
|
|
@@ -1241,7 +1266,7 @@ function registerTeamCommands(program2) {
|
|
|
1241
1266
|
const currentTeam = configManager.getCurrentTeam();
|
|
1242
1267
|
if (!currentTeam) {
|
|
1243
1268
|
ui.warning("No team selected");
|
|
1244
|
-
ui.info(`Select one with ${ui.code("
|
|
1269
|
+
ui.info(`Select one with ${ui.code("stash teams use <slug>")}`);
|
|
1245
1270
|
return;
|
|
1246
1271
|
}
|
|
1247
1272
|
ui.heading("Current Team");
|
|
@@ -1251,12 +1276,12 @@ function registerTeamCommands(program2) {
|
|
|
1251
1276
|
});
|
|
1252
1277
|
teams.command("invite <email>").description("Invite a member to the current team").option("-r, --role <role>", "Role for the invited member (member|admin)", "member").action(async (email, options) => {
|
|
1253
1278
|
if (!configManager.isAuthenticated()) {
|
|
1254
|
-
ui.error("Not authenticated. Run `
|
|
1279
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1255
1280
|
process.exit(1);
|
|
1256
1281
|
}
|
|
1257
1282
|
const currentTeam = configManager.getCurrentTeam();
|
|
1258
1283
|
if (!currentTeam) {
|
|
1259
|
-
ui.error("No team selected. Run `
|
|
1284
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
1260
1285
|
process.exit(1);
|
|
1261
1286
|
}
|
|
1262
1287
|
const role = options.role.toLowerCase();
|
|
@@ -1282,12 +1307,12 @@ function registerTeamCommands(program2) {
|
|
|
1282
1307
|
});
|
|
1283
1308
|
teams.command("members").description("List members of the current team").action(async () => {
|
|
1284
1309
|
if (!configManager.isAuthenticated()) {
|
|
1285
|
-
ui.error("Not authenticated. Run `
|
|
1310
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1286
1311
|
process.exit(1);
|
|
1287
1312
|
}
|
|
1288
1313
|
const currentTeam = configManager.getCurrentTeam();
|
|
1289
1314
|
if (!currentTeam) {
|
|
1290
|
-
ui.error("No team selected. Run `
|
|
1315
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
1291
1316
|
process.exit(1);
|
|
1292
1317
|
}
|
|
1293
1318
|
const spinner = ui.spinner("Fetching team members...");
|
|
@@ -1319,12 +1344,12 @@ function registerTeamCommands(program2) {
|
|
|
1319
1344
|
});
|
|
1320
1345
|
teams.command("remove <email>").description("Remove a member from the current team").option("-f, --force", "Skip confirmation prompt").action(async (email, options) => {
|
|
1321
1346
|
if (!configManager.isAuthenticated()) {
|
|
1322
|
-
ui.error("Not authenticated. Run `
|
|
1347
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1323
1348
|
process.exit(1);
|
|
1324
1349
|
}
|
|
1325
1350
|
const currentTeam = configManager.getCurrentTeam();
|
|
1326
1351
|
if (!currentTeam) {
|
|
1327
|
-
ui.error("No team selected. Run `
|
|
1352
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
1328
1353
|
process.exit(1);
|
|
1329
1354
|
}
|
|
1330
1355
|
const spinner = ui.spinner("Looking up member...");
|
|
@@ -1377,12 +1402,12 @@ function registerTeamCommands(program2) {
|
|
|
1377
1402
|
});
|
|
1378
1403
|
teams.command("role <email> <role>").description("Change a member's role in the current team").option("-f, --force", "Skip confirmation prompt").action(async (email, role, options) => {
|
|
1379
1404
|
if (!configManager.isAuthenticated()) {
|
|
1380
|
-
ui.error("Not authenticated. Run `
|
|
1405
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1381
1406
|
process.exit(1);
|
|
1382
1407
|
}
|
|
1383
1408
|
const currentTeam = configManager.getCurrentTeam();
|
|
1384
1409
|
if (!currentTeam) {
|
|
1385
|
-
ui.error("No team selected. Run `
|
|
1410
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
1386
1411
|
process.exit(1);
|
|
1387
1412
|
}
|
|
1388
1413
|
const validRoles = ["admin", "member"];
|
|
@@ -1457,7 +1482,7 @@ var { prompt: prompt3 } = enquirer3;
|
|
|
1457
1482
|
function requireTeam() {
|
|
1458
1483
|
const team = configManager.getCurrentTeam();
|
|
1459
1484
|
if (!team) {
|
|
1460
|
-
ui.error("No team selected. Run `
|
|
1485
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
1461
1486
|
process.exit(1);
|
|
1462
1487
|
}
|
|
1463
1488
|
return team;
|
|
@@ -1466,7 +1491,7 @@ function registerProjectCommands(program2) {
|
|
|
1466
1491
|
const projects = program2.command("projects").description("Manage projects");
|
|
1467
1492
|
projects.command("list").alias("ls").description("List all projects in the current team").action(async () => {
|
|
1468
1493
|
if (!configManager.isAuthenticated()) {
|
|
1469
|
-
ui.error("Not authenticated. Run `
|
|
1494
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1470
1495
|
process.exit(1);
|
|
1471
1496
|
}
|
|
1472
1497
|
const team = requireTeam();
|
|
@@ -1480,7 +1505,7 @@ function registerProjectCommands(program2) {
|
|
|
1480
1505
|
spinner.stop();
|
|
1481
1506
|
if (!result.data?.projects.length) {
|
|
1482
1507
|
ui.warning(`No projects in team "${team.name}"`);
|
|
1483
|
-
ui.info(`Create one with ${ui.code("
|
|
1508
|
+
ui.info(`Create one with ${ui.code("stash projects create")}`);
|
|
1484
1509
|
return;
|
|
1485
1510
|
}
|
|
1486
1511
|
ui.heading(`Projects in ${team.name}`);
|
|
@@ -1496,11 +1521,11 @@ function registerProjectCommands(program2) {
|
|
|
1496
1521
|
header: ["", "Name", "Slug", "Environments", "Secrets"]
|
|
1497
1522
|
});
|
|
1498
1523
|
ui.br();
|
|
1499
|
-
ui.info(`Switch projects with ${ui.code("
|
|
1524
|
+
ui.info(`Switch projects with ${ui.code("stash projects use <slug>")}`);
|
|
1500
1525
|
});
|
|
1501
1526
|
projects.command("create").description("Create a new project").option("-n, --name <name>", "Project name").option("-d, --description <description>", "Project description").action(async (options) => {
|
|
1502
1527
|
if (!configManager.isAuthenticated()) {
|
|
1503
|
-
ui.error("Not authenticated. Run `
|
|
1528
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1504
1529
|
process.exit(1);
|
|
1505
1530
|
}
|
|
1506
1531
|
const team = requireTeam();
|
|
@@ -1534,21 +1559,22 @@ function registerProjectCommands(program2) {
|
|
|
1534
1559
|
ui.error(result.error.message);
|
|
1535
1560
|
process.exit(1);
|
|
1536
1561
|
}
|
|
1562
|
+
const project = result.data.project;
|
|
1537
1563
|
configManager.setCurrentProject({
|
|
1538
|
-
id:
|
|
1539
|
-
name:
|
|
1540
|
-
slug:
|
|
1564
|
+
id: project.id,
|
|
1565
|
+
name: project.name,
|
|
1566
|
+
slug: project.slug
|
|
1541
1567
|
});
|
|
1542
1568
|
spinner.succeed(`Project "${name}" created successfully`);
|
|
1543
1569
|
ui.br();
|
|
1544
|
-
ui.keyValue("ID",
|
|
1545
|
-
ui.keyValue("Slug",
|
|
1570
|
+
ui.keyValue("ID", project.id);
|
|
1571
|
+
ui.keyValue("Slug", project.slug);
|
|
1546
1572
|
ui.br();
|
|
1547
|
-
ui.info(`Create environments with ${ui.code("
|
|
1573
|
+
ui.info(`Create environments with ${ui.code("stash environments create")}`);
|
|
1548
1574
|
});
|
|
1549
1575
|
projects.command("use <slug>").description("Switch to a different project").action(async (slug) => {
|
|
1550
1576
|
if (!configManager.isAuthenticated()) {
|
|
1551
|
-
ui.error("Not authenticated. Run `
|
|
1577
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1552
1578
|
process.exit(1);
|
|
1553
1579
|
}
|
|
1554
1580
|
const team = requireTeam();
|
|
@@ -1563,6 +1589,15 @@ function registerProjectCommands(program2) {
|
|
|
1563
1589
|
if (!project) {
|
|
1564
1590
|
spinner.fail();
|
|
1565
1591
|
ui.error(`Project "${slug}" not found in team "${team.name}"`);
|
|
1592
|
+
if (result.data?.projects.length) {
|
|
1593
|
+
ui.br();
|
|
1594
|
+
ui.info("Available projects:");
|
|
1595
|
+
result.data.projects.forEach((p) => {
|
|
1596
|
+
ui.info(` ${p.slug} - ${p.name}`);
|
|
1597
|
+
});
|
|
1598
|
+
} else {
|
|
1599
|
+
ui.info(`No projects exist yet. Create one with ${ui.code("stash projects create")}`);
|
|
1600
|
+
}
|
|
1566
1601
|
process.exit(1);
|
|
1567
1602
|
}
|
|
1568
1603
|
configManager.setCurrentProject({
|
|
@@ -1577,7 +1612,7 @@ function registerProjectCommands(program2) {
|
|
|
1577
1612
|
const currentProject = configManager.getCurrentProject();
|
|
1578
1613
|
if (!currentProject) {
|
|
1579
1614
|
ui.warning("No project selected");
|
|
1580
|
-
ui.info(`Select one with ${ui.code("
|
|
1615
|
+
ui.info(`Select one with ${ui.code("stash projects use <slug>")}`);
|
|
1581
1616
|
return;
|
|
1582
1617
|
}
|
|
1583
1618
|
ui.heading("Current Project");
|
|
@@ -1587,7 +1622,7 @@ function registerProjectCommands(program2) {
|
|
|
1587
1622
|
});
|
|
1588
1623
|
projects.command("delete <slug>").alias("rm").description("Delete a project and all its environments and secrets").option("-f, --force", "Skip confirmation prompt").action(async (slug, options) => {
|
|
1589
1624
|
if (!configManager.isAuthenticated()) {
|
|
1590
|
-
ui.error("Not authenticated. Run `
|
|
1625
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1591
1626
|
process.exit(1);
|
|
1592
1627
|
}
|
|
1593
1628
|
const team = requireTeam();
|
|
@@ -1653,7 +1688,7 @@ var { prompt: prompt4 } = enquirer4;
|
|
|
1653
1688
|
function requireProject() {
|
|
1654
1689
|
const project = configManager.getCurrentProject();
|
|
1655
1690
|
if (!project) {
|
|
1656
|
-
ui.error("No project selected. Run `
|
|
1691
|
+
ui.error("No project selected. Run `stash projects use <slug>` first.");
|
|
1657
1692
|
process.exit(1);
|
|
1658
1693
|
}
|
|
1659
1694
|
return project;
|
|
@@ -1662,7 +1697,7 @@ function registerEnvironmentCommands(program2) {
|
|
|
1662
1697
|
const envs = program2.command("environments").alias("envs").description("Manage environments");
|
|
1663
1698
|
envs.command("list").alias("ls").description("List all environments in the current project").action(async () => {
|
|
1664
1699
|
if (!configManager.isAuthenticated()) {
|
|
1665
|
-
ui.error("Not authenticated. Run `
|
|
1700
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1666
1701
|
process.exit(1);
|
|
1667
1702
|
}
|
|
1668
1703
|
const project = requireProject();
|
|
@@ -1676,7 +1711,7 @@ function registerEnvironmentCommands(program2) {
|
|
|
1676
1711
|
spinner.stop();
|
|
1677
1712
|
if (!result.data?.environments.length) {
|
|
1678
1713
|
ui.warning(`No environments in project "${project.name}"`);
|
|
1679
|
-
ui.info(`Create one with ${ui.code("
|
|
1714
|
+
ui.info(`Create one with ${ui.code("stash environments create")}`);
|
|
1680
1715
|
return;
|
|
1681
1716
|
}
|
|
1682
1717
|
ui.heading(`Environments in ${project.name}`);
|
|
@@ -1696,11 +1731,11 @@ function registerEnvironmentCommands(program2) {
|
|
|
1696
1731
|
header: ["", "Name", "Slug", "Secrets", "Inherits From"]
|
|
1697
1732
|
});
|
|
1698
1733
|
ui.br();
|
|
1699
|
-
ui.info(`Switch environments with ${ui.code("
|
|
1734
|
+
ui.info(`Switch environments with ${ui.code("stash environments use <slug>")}`);
|
|
1700
1735
|
});
|
|
1701
1736
|
envs.command("create").description("Create a new environment").option("-n, --name <name>", "Environment name").option("--inherit-from <slug>", "Inherit secrets from parent environment (e.g., development)").action(async (options) => {
|
|
1702
1737
|
if (!configManager.isAuthenticated()) {
|
|
1703
|
-
ui.error("Not authenticated. Run `
|
|
1738
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1704
1739
|
process.exit(1);
|
|
1705
1740
|
}
|
|
1706
1741
|
const project = requireProject();
|
|
@@ -1751,20 +1786,21 @@ function registerEnvironmentCommands(program2) {
|
|
|
1751
1786
|
ui.error(result.error.message);
|
|
1752
1787
|
process.exit(1);
|
|
1753
1788
|
}
|
|
1754
|
-
|
|
1789
|
+
const environment = result.data.environment;
|
|
1790
|
+
configManager.setCurrentEnvironment(environment.slug);
|
|
1755
1791
|
spinner.succeed(`Environment "${name}" created successfully`);
|
|
1756
1792
|
ui.br();
|
|
1757
|
-
ui.keyValue("ID",
|
|
1758
|
-
ui.keyValue("Slug",
|
|
1793
|
+
ui.keyValue("ID", environment.id);
|
|
1794
|
+
ui.keyValue("Slug", environment.slug);
|
|
1759
1795
|
if (options.inheritFrom) {
|
|
1760
1796
|
ui.keyValue("Inherits from", options.inheritFrom);
|
|
1761
1797
|
}
|
|
1762
1798
|
ui.br();
|
|
1763
|
-
ui.info(`Add secrets with ${ui.code("
|
|
1799
|
+
ui.info(`Add secrets with ${ui.code("stash secrets create")} or ${ui.code("stash push")}`);
|
|
1764
1800
|
});
|
|
1765
1801
|
envs.command("use <slug>").description("Switch to a different environment").action(async (slug) => {
|
|
1766
1802
|
if (!configManager.isAuthenticated()) {
|
|
1767
|
-
ui.error("Not authenticated. Run `
|
|
1803
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1768
1804
|
process.exit(1);
|
|
1769
1805
|
}
|
|
1770
1806
|
const project = requireProject();
|
|
@@ -1779,6 +1815,15 @@ function registerEnvironmentCommands(program2) {
|
|
|
1779
1815
|
if (!env) {
|
|
1780
1816
|
spinner.fail();
|
|
1781
1817
|
ui.error(`Environment "${slug}" not found in project "${project.name}"`);
|
|
1818
|
+
if (result.data?.environments.length) {
|
|
1819
|
+
ui.br();
|
|
1820
|
+
ui.info("Available environments:");
|
|
1821
|
+
result.data.environments.forEach((e) => {
|
|
1822
|
+
ui.info(` ${e.slug} - ${e.name}`);
|
|
1823
|
+
});
|
|
1824
|
+
} else {
|
|
1825
|
+
ui.info(`No environments exist yet. Create one with ${ui.code("stash environments create")}`);
|
|
1826
|
+
}
|
|
1782
1827
|
process.exit(1);
|
|
1783
1828
|
}
|
|
1784
1829
|
configManager.setCurrentEnvironment(env.slug);
|
|
@@ -1788,7 +1833,7 @@ function registerEnvironmentCommands(program2) {
|
|
|
1788
1833
|
const currentEnv = configManager.getCurrentEnvironment();
|
|
1789
1834
|
if (!currentEnv) {
|
|
1790
1835
|
ui.warning("No environment selected");
|
|
1791
|
-
ui.info(`Select one with ${ui.code("
|
|
1836
|
+
ui.info(`Select one with ${ui.code("stash environments use <slug>")}`);
|
|
1792
1837
|
return;
|
|
1793
1838
|
}
|
|
1794
1839
|
ui.heading("Current Environment");
|
|
@@ -1796,17 +1841,17 @@ function registerEnvironmentCommands(program2) {
|
|
|
1796
1841
|
});
|
|
1797
1842
|
envs.command("clone <source> <target>").description("Clone an environment with all its secrets").action(async (source, target) => {
|
|
1798
1843
|
if (!configManager.isAuthenticated()) {
|
|
1799
|
-
ui.error("Not authenticated. Run `
|
|
1844
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1800
1845
|
process.exit(1);
|
|
1801
1846
|
}
|
|
1802
1847
|
const teamSlug = projectConfig.getEffectiveTeam();
|
|
1803
1848
|
const projectSlug = projectConfig.getEffectiveProject();
|
|
1804
1849
|
if (!teamSlug) {
|
|
1805
|
-
ui.error("No team selected. Run `
|
|
1850
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
1806
1851
|
process.exit(1);
|
|
1807
1852
|
}
|
|
1808
1853
|
if (!projectSlug) {
|
|
1809
|
-
ui.error("No project selected. Run `
|
|
1854
|
+
ui.error("No project selected. Run `stash projects use <slug>` first.");
|
|
1810
1855
|
process.exit(1);
|
|
1811
1856
|
}
|
|
1812
1857
|
const { password } = await prompt4({
|
|
@@ -1875,11 +1920,11 @@ function registerEnvironmentCommands(program2) {
|
|
|
1875
1920
|
console.log(` ${colors.success("+")} ${secret.key}`);
|
|
1876
1921
|
}
|
|
1877
1922
|
ui.br();
|
|
1878
|
-
ui.info(`Switch to the new environment with ${ui.code(`
|
|
1923
|
+
ui.info(`Switch to the new environment with ${ui.code(`stash environments use ${target}`)}`);
|
|
1879
1924
|
});
|
|
1880
1925
|
envs.command("delete <slug>").description("Delete an environment").option("-f, --force", "Skip confirmation prompts").action(async (slug, options) => {
|
|
1881
1926
|
if (!configManager.isAuthenticated()) {
|
|
1882
|
-
ui.error("Not authenticated. Run `
|
|
1927
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
1883
1928
|
process.exit(1);
|
|
1884
1929
|
}
|
|
1885
1930
|
const project = requireProject();
|
|
@@ -1957,16 +2002,26 @@ function requireContext() {
|
|
|
1957
2002
|
const teamSlug = projectConfig.getEffectiveTeam();
|
|
1958
2003
|
const projectSlug = projectConfig.getEffectiveProject();
|
|
1959
2004
|
const environment = projectConfig.getEffectiveEnvironment();
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
if (
|
|
1965
|
-
ui.error(
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
ui.
|
|
2005
|
+
const missing = [];
|
|
2006
|
+
if (!teamSlug) missing.push("team");
|
|
2007
|
+
if (!projectSlug) missing.push("project");
|
|
2008
|
+
if (!environment) missing.push("environment");
|
|
2009
|
+
if (missing.length > 0) {
|
|
2010
|
+
ui.error(`Missing context: ${missing.join(", ")}`);
|
|
2011
|
+
ui.br();
|
|
2012
|
+
ui.info("Set up your context with one of these options:");
|
|
2013
|
+
ui.br();
|
|
2014
|
+
ui.keyValue("Quick setup", ui.code("stash init"));
|
|
2015
|
+
ui.keyValue("View context", ui.code("stash context"));
|
|
2016
|
+
if (missing.includes("team")) {
|
|
2017
|
+
ui.keyValue("Set team", ui.code("stash teams use <slug>"));
|
|
2018
|
+
}
|
|
2019
|
+
if (missing.includes("project")) {
|
|
2020
|
+
ui.keyValue("Set project", ui.code("stash projects use <slug>"));
|
|
2021
|
+
}
|
|
2022
|
+
if (missing.includes("environment")) {
|
|
2023
|
+
ui.keyValue("Set environment", ui.code("stash environments use <slug>"));
|
|
2024
|
+
}
|
|
1970
2025
|
process.exit(1);
|
|
1971
2026
|
}
|
|
1972
2027
|
return { teamSlug, projectSlug, environment };
|
|
@@ -2014,7 +2069,7 @@ function registerSecretCommands(program2) {
|
|
|
2014
2069
|
process.exit(1);
|
|
2015
2070
|
}
|
|
2016
2071
|
if (!configManager.isAuthenticated()) {
|
|
2017
|
-
ui.error("Not authenticated. Run `
|
|
2072
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2018
2073
|
process.exit(1);
|
|
2019
2074
|
}
|
|
2020
2075
|
const ctx = requireContext();
|
|
@@ -2038,7 +2093,7 @@ function registerSecretCommands(program2) {
|
|
|
2038
2093
|
} else if (options.format === "env") {
|
|
2039
2094
|
} else {
|
|
2040
2095
|
ui.warning("No secrets in this environment");
|
|
2041
|
-
ui.info(`Add secrets with ${ui.code("
|
|
2096
|
+
ui.info(`Add secrets with ${ui.code("stash secrets create")} or ${ui.code("stash push")}`);
|
|
2042
2097
|
}
|
|
2043
2098
|
return;
|
|
2044
2099
|
}
|
|
@@ -2101,7 +2156,7 @@ function registerSecretCommands(program2) {
|
|
|
2101
2156
|
});
|
|
2102
2157
|
secrets.command("set <key> [value]").description("Create or update a single secret").option("-e, --env <environment>", "Environment to use").option("-p, --project <project>", "Project slug to use").option("-d, --description <description>", "Secret description").option("--from-file <file>", "Read value from file").option("--expires <date>", "Set expiration date (YYYY-MM-DD format)").action(async (key, value, options) => {
|
|
2103
2158
|
if (!configManager.isAuthenticated()) {
|
|
2104
|
-
ui.error("Not authenticated. Run `
|
|
2159
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2105
2160
|
process.exit(1);
|
|
2106
2161
|
}
|
|
2107
2162
|
const ctx = requireContext();
|
|
@@ -2177,7 +2232,7 @@ function registerSecretCommands(program2) {
|
|
|
2177
2232
|
});
|
|
2178
2233
|
secrets.command("get <key>").description("Get a single secret value").option("-e, --env <environment>", "Environment to use").option("-p, --project <project>", "Project slug to use").option("-r, --reveal", "Show unmasked value").action(async (key, options) => {
|
|
2179
2234
|
if (!configManager.isAuthenticated()) {
|
|
2180
|
-
ui.error("Not authenticated. Run `
|
|
2235
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2181
2236
|
process.exit(1);
|
|
2182
2237
|
}
|
|
2183
2238
|
const ctx = requireContext();
|
|
@@ -2215,7 +2270,7 @@ function registerSecretCommands(program2) {
|
|
|
2215
2270
|
});
|
|
2216
2271
|
secrets.command("delete <key>").alias("rm").description("Delete a single secret").option("-e, --env <environment>", "Environment to use").option("-p, --project <project>", "Project slug to use").option("-f, --force", "Skip confirmation").action(async (key, options) => {
|
|
2217
2272
|
if (!configManager.isAuthenticated()) {
|
|
2218
|
-
ui.error("Not authenticated. Run `
|
|
2273
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2219
2274
|
process.exit(1);
|
|
2220
2275
|
}
|
|
2221
2276
|
const ctx = requireContext();
|
|
@@ -2266,7 +2321,7 @@ function registerSecretCommands(program2) {
|
|
|
2266
2321
|
});
|
|
2267
2322
|
secrets.command("history <key>").description("Show version history for a secret").option("-e, --env <environment>", "Environment to use").option("-p, --project <project>", "Project slug to use").option("-l, --limit <n>", "Number of versions to show", "10").action(async (key, options) => {
|
|
2268
2323
|
if (!configManager.isAuthenticated()) {
|
|
2269
|
-
ui.error("Not authenticated. Run `
|
|
2324
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2270
2325
|
process.exit(1);
|
|
2271
2326
|
}
|
|
2272
2327
|
const ctx = requireContext();
|
|
@@ -2354,16 +2409,16 @@ function registerSecretCommands(program2) {
|
|
|
2354
2409
|
});
|
|
2355
2410
|
ui.br();
|
|
2356
2411
|
ui.info(`Showing ${versions.length} version(s)`);
|
|
2357
|
-
ui.info(`Use ${ui.code(`
|
|
2412
|
+
ui.info(`Use ${ui.code(`stash secrets rollback ${key} --version <n>`)} to restore a previous version`);
|
|
2358
2413
|
});
|
|
2359
2414
|
secrets.command("rollback <key>").description("Restore a secret to a previous version").option("-e, --env <environment>", "Environment to use").option("-p, --project <project>", "Project slug to use").option("-v, --version <n>", "Version number to restore (required)").action(async (key, options) => {
|
|
2360
2415
|
if (!configManager.isAuthenticated()) {
|
|
2361
|
-
ui.error("Not authenticated. Run `
|
|
2416
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2362
2417
|
process.exit(1);
|
|
2363
2418
|
}
|
|
2364
2419
|
if (!options.version) {
|
|
2365
2420
|
ui.error("Version number is required. Use --version <n>");
|
|
2366
|
-
ui.info(`Use ${ui.code(`
|
|
2421
|
+
ui.info(`Use ${ui.code(`stash secrets history ${key}`)} to see available versions`);
|
|
2367
2422
|
process.exit(1);
|
|
2368
2423
|
}
|
|
2369
2424
|
const version2 = parseInt(options.version, 10);
|
|
@@ -2482,7 +2537,7 @@ function registerSecretCommands(program2) {
|
|
|
2482
2537
|
});
|
|
2483
2538
|
program2.command("pull").description("Pull secrets from SecretStash to a local .env file").option("-e, --env <environment>", "Environment to pull from").option("-o, --output <file>", "Output file path").option("-f, --force", "Overwrite existing file without confirmation").action(async (options) => {
|
|
2484
2539
|
if (!configManager.isAuthenticated()) {
|
|
2485
|
-
ui.error("Not authenticated. Run `
|
|
2540
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2486
2541
|
process.exit(1);
|
|
2487
2542
|
}
|
|
2488
2543
|
const ctx = requireContext();
|
|
@@ -2525,7 +2580,7 @@ function registerSecretCommands(program2) {
|
|
|
2525
2580
|
});
|
|
2526
2581
|
program2.command("export").description("Export secrets in various formats (env, json, yaml)").option("-e, --env <environment>", "Environment to export from").option("-f, --format <format>", "Output format (env, json, yaml)", "env").option("-o, --output <file>", "Output file path (default: stdout)").action(async (options) => {
|
|
2527
2582
|
if (!configManager.isAuthenticated()) {
|
|
2528
|
-
ui.error("Not authenticated. Run `
|
|
2583
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2529
2584
|
process.exit(1);
|
|
2530
2585
|
}
|
|
2531
2586
|
const ctx = requireContext();
|
|
@@ -2603,7 +2658,7 @@ function registerSecretCommands(program2) {
|
|
|
2603
2658
|
});
|
|
2604
2659
|
program2.command("push").description("Push secrets from a local .env file to SecretStash").option("-e, --env <environment>", "Environment to push to").option("-i, --input <file>", "Input file path").option("--dry-run", "Show what would be pushed without making changes").action(async (options) => {
|
|
2605
2660
|
if (!configManager.isAuthenticated()) {
|
|
2606
|
-
ui.error("Not authenticated. Run `
|
|
2661
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2607
2662
|
process.exit(1);
|
|
2608
2663
|
}
|
|
2609
2664
|
const ctx = requireContext();
|
|
@@ -2685,7 +2740,7 @@ function registerSecretCommands(program2) {
|
|
|
2685
2740
|
});
|
|
2686
2741
|
program2.command("run").description("Run a command with secrets injected as environment variables").option("-e, --env <environment>", "Environment to use").argument("<command...>", "Command to run").action(async (commandArgs, options) => {
|
|
2687
2742
|
if (!configManager.isAuthenticated()) {
|
|
2688
|
-
ui.error("Not authenticated. Run `
|
|
2743
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2689
2744
|
process.exit(1);
|
|
2690
2745
|
}
|
|
2691
2746
|
const ctx = requireContext();
|
|
@@ -2728,7 +2783,7 @@ function registerSecretCommands(program2) {
|
|
|
2728
2783
|
});
|
|
2729
2784
|
program2.command("init").description("Initialize SecretStash in the current directory").action(async () => {
|
|
2730
2785
|
if (!configManager.isAuthenticated()) {
|
|
2731
|
-
ui.error("Not authenticated. Run `
|
|
2786
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2732
2787
|
process.exit(1);
|
|
2733
2788
|
}
|
|
2734
2789
|
ui.heading("Initialize SecretStash");
|
|
@@ -2740,20 +2795,46 @@ function registerSecretCommands(program2) {
|
|
|
2740
2795
|
process.exit(1);
|
|
2741
2796
|
}
|
|
2742
2797
|
teamsSpinner.stop();
|
|
2798
|
+
let selectedTeam;
|
|
2743
2799
|
if (!teamsResult.data?.teams.length) {
|
|
2744
|
-
ui.
|
|
2745
|
-
|
|
2800
|
+
ui.info("No teams found. Let's create your first team.");
|
|
2801
|
+
const { name } = await prompt5({
|
|
2802
|
+
type: "input",
|
|
2803
|
+
name: "name",
|
|
2804
|
+
message: "Team name:",
|
|
2805
|
+
initial: "My Team",
|
|
2806
|
+
validate: (value) => value ? true : "Name is required"
|
|
2807
|
+
});
|
|
2808
|
+
const createTeamSpinner = ui.spinner("Creating team...");
|
|
2809
|
+
const createTeamResult = await apiClient.createTeam(name);
|
|
2810
|
+
if (createTeamResult.error) {
|
|
2811
|
+
createTeamSpinner.fail();
|
|
2812
|
+
ui.error(createTeamResult.error.message);
|
|
2813
|
+
process.exit(1);
|
|
2814
|
+
}
|
|
2815
|
+
createTeamSpinner.succeed(`Team "${name}" created`);
|
|
2816
|
+
selectedTeam = createTeamResult.data.team;
|
|
2817
|
+
configManager.setCurrentTeam({
|
|
2818
|
+
id: selectedTeam.id,
|
|
2819
|
+
name: selectedTeam.name,
|
|
2820
|
+
slug: selectedTeam.slug
|
|
2821
|
+
});
|
|
2822
|
+
} else if (teamsResult.data.teams.length === 1) {
|
|
2823
|
+
selectedTeam = teamsResult.data.teams[0];
|
|
2824
|
+
ui.info(`Using team: ${selectedTeam.name}`);
|
|
2825
|
+
} else {
|
|
2826
|
+
const { teamSlug: teamSlug2 } = await prompt5({
|
|
2827
|
+
type: "select",
|
|
2828
|
+
name: "teamSlug",
|
|
2829
|
+
message: "Select team:",
|
|
2830
|
+
choices: teamsResult.data.teams.map((t) => ({
|
|
2831
|
+
name: t.slug,
|
|
2832
|
+
message: `${t.name} (${t.slug})`
|
|
2833
|
+
}))
|
|
2834
|
+
});
|
|
2835
|
+
selectedTeam = teamsResult.data.teams.find((t) => t.slug === teamSlug2);
|
|
2746
2836
|
}
|
|
2747
|
-
const
|
|
2748
|
-
type: "select",
|
|
2749
|
-
name: "teamSlug",
|
|
2750
|
-
message: "Select team:",
|
|
2751
|
-
choices: teamsResult.data.teams.map((t) => ({
|
|
2752
|
-
name: t.slug,
|
|
2753
|
-
message: `${t.name} (${t.slug})`
|
|
2754
|
-
}))
|
|
2755
|
-
});
|
|
2756
|
-
const selectedTeam = teamsResult.data.teams.find((t) => t.slug === teamSlug);
|
|
2837
|
+
const teamSlug = selectedTeam.slug;
|
|
2757
2838
|
const projectsSpinner = ui.spinner("Fetching projects...");
|
|
2758
2839
|
const projectsResult = await apiClient.getProjects(selectedTeam.id);
|
|
2759
2840
|
projectsSpinner.stop();
|
|
@@ -2771,7 +2852,7 @@ function registerSecretCommands(program2) {
|
|
|
2771
2852
|
ui.error(createResult.error.message);
|
|
2772
2853
|
process.exit(1);
|
|
2773
2854
|
}
|
|
2774
|
-
projectSlug = createResult.data.slug;
|
|
2855
|
+
projectSlug = createResult.data.project.slug;
|
|
2775
2856
|
} else {
|
|
2776
2857
|
const response = await prompt5({
|
|
2777
2858
|
type: "select",
|
|
@@ -2797,7 +2878,7 @@ function registerSecretCommands(program2) {
|
|
|
2797
2878
|
ui.error(createResult.error.message);
|
|
2798
2879
|
process.exit(1);
|
|
2799
2880
|
}
|
|
2800
|
-
projectSlug = createResult.data.slug;
|
|
2881
|
+
projectSlug = createResult.data.project.slug;
|
|
2801
2882
|
} else {
|
|
2802
2883
|
projectSlug = response.projectSlug;
|
|
2803
2884
|
}
|
|
@@ -2820,9 +2901,9 @@ function registerSecretCommands(program2) {
|
|
|
2820
2901
|
ui.success(`Created ${configPath}`);
|
|
2821
2902
|
ui.br();
|
|
2822
2903
|
ui.box("Next Steps", [
|
|
2823
|
-
`1. Add secrets: ${ui.code("
|
|
2824
|
-
`2. Pull secrets: ${ui.code("
|
|
2825
|
-
`3. Run with secrets: ${ui.code("
|
|
2904
|
+
`1. Add secrets: ${ui.code("stash push .env")}`,
|
|
2905
|
+
`2. Pull secrets: ${ui.code("stash pull")}`,
|
|
2906
|
+
`3. Run with secrets: ${ui.code("stash run npm start")}`,
|
|
2826
2907
|
"",
|
|
2827
2908
|
`Add ${ui.code(".secretstash.json")} to version control`,
|
|
2828
2909
|
`Add ${ui.code(".env*")} to .gitignore`
|
|
@@ -2830,7 +2911,7 @@ function registerSecretCommands(program2) {
|
|
|
2830
2911
|
});
|
|
2831
2912
|
secrets.command("tag <key> <tagname>").description("Add a tag to a secret").option("-e, --env <environment>", "Environment to use").option("-p, --project <project>", "Project slug to use").action(async (key, tagname, options) => {
|
|
2832
2913
|
if (!configManager.isAuthenticated()) {
|
|
2833
|
-
ui.error("Not authenticated. Run `
|
|
2914
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2834
2915
|
process.exit(1);
|
|
2835
2916
|
}
|
|
2836
2917
|
const ctx = requireContext();
|
|
@@ -2838,7 +2919,7 @@ function registerSecretCommands(program2) {
|
|
|
2838
2919
|
const projectSlug = options.project || ctx.projectSlug;
|
|
2839
2920
|
const currentTeam = configManager.getCurrentTeam();
|
|
2840
2921
|
if (!currentTeam) {
|
|
2841
|
-
ui.error("No team selected. Run `
|
|
2922
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
2842
2923
|
process.exit(1);
|
|
2843
2924
|
}
|
|
2844
2925
|
const spinner = ui.spinner("Looking up secret and tag...");
|
|
@@ -2878,7 +2959,7 @@ function registerSecretCommands(program2) {
|
|
|
2878
2959
|
if (!tag) {
|
|
2879
2960
|
spinner.fail();
|
|
2880
2961
|
ui.error(`Tag "${tagname}" not found`);
|
|
2881
|
-
ui.info(`Create it with ${ui.code(`
|
|
2962
|
+
ui.info(`Create it with ${ui.code(`stash tags create ${tagname}`)}`);
|
|
2882
2963
|
process.exit(1);
|
|
2883
2964
|
}
|
|
2884
2965
|
const secretsResult = await apiClient.getSecrets(env.id);
|
|
@@ -2910,7 +2991,7 @@ function registerSecretCommands(program2) {
|
|
|
2910
2991
|
});
|
|
2911
2992
|
secrets.command("untag <key> <tagname>").description("Remove a tag from a secret").option("-e, --env <environment>", "Environment to use").option("-p, --project <project>", "Project slug to use").action(async (key, tagname, options) => {
|
|
2912
2993
|
if (!configManager.isAuthenticated()) {
|
|
2913
|
-
ui.error("Not authenticated. Run `
|
|
2994
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2914
2995
|
process.exit(1);
|
|
2915
2996
|
}
|
|
2916
2997
|
const ctx = requireContext();
|
|
@@ -2918,7 +2999,7 @@ function registerSecretCommands(program2) {
|
|
|
2918
2999
|
const projectSlug = options.project || ctx.projectSlug;
|
|
2919
3000
|
const currentTeam = configManager.getCurrentTeam();
|
|
2920
3001
|
if (!currentTeam) {
|
|
2921
|
-
ui.error("No team selected. Run `
|
|
3002
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
2922
3003
|
process.exit(1);
|
|
2923
3004
|
}
|
|
2924
3005
|
const spinner = ui.spinner("Looking up secret and tag...");
|
|
@@ -2985,12 +3066,12 @@ function registerSecretCommands(program2) {
|
|
|
2985
3066
|
});
|
|
2986
3067
|
secrets.command("expiring").description("List secrets that are expiring soon").option("--days <days>", "Number of days to look ahead", "7").action(async (options) => {
|
|
2987
3068
|
if (!configManager.isAuthenticated()) {
|
|
2988
|
-
ui.error("Not authenticated. Run `
|
|
3069
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
2989
3070
|
process.exit(1);
|
|
2990
3071
|
}
|
|
2991
3072
|
const teamSlug = projectConfig.getEffectiveTeam();
|
|
2992
3073
|
if (!teamSlug) {
|
|
2993
|
-
ui.error("No team selected. Run `
|
|
3074
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
2994
3075
|
process.exit(1);
|
|
2995
3076
|
}
|
|
2996
3077
|
const days = parseInt(options.days) || 7;
|
|
@@ -3139,11 +3220,11 @@ function requirePartialContext() {
|
|
|
3139
3220
|
const teamSlug = projectConfig.getEffectiveTeam();
|
|
3140
3221
|
const projectSlug = projectConfig.getEffectiveProject();
|
|
3141
3222
|
if (!teamSlug) {
|
|
3142
|
-
ui.error("No team selected. Run `
|
|
3223
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
3143
3224
|
process.exit(1);
|
|
3144
3225
|
}
|
|
3145
3226
|
if (!projectSlug) {
|
|
3146
|
-
ui.error("No project selected. Run `
|
|
3227
|
+
ui.error("No project selected. Run `stash projects use <slug>` first.");
|
|
3147
3228
|
process.exit(1);
|
|
3148
3229
|
}
|
|
3149
3230
|
return { teamSlug, projectSlug };
|
|
@@ -3151,7 +3232,7 @@ function requirePartialContext() {
|
|
|
3151
3232
|
function registerDiffCommand(program2) {
|
|
3152
3233
|
program2.command("diff <env1> <env2>").description("Compare secrets between two environments").option("-p, --project <slug>", "Use specific project").option("--show-unchanged", "Include secrets that are the same in both environments").option("-f, --format <format>", "Output format: table or json", "table").action(async (env1, env2, options) => {
|
|
3153
3234
|
if (!configManager.isAuthenticated()) {
|
|
3154
|
-
ui.error("Not authenticated. Run `
|
|
3235
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
3155
3236
|
process.exit(1);
|
|
3156
3237
|
}
|
|
3157
3238
|
const ctx = requirePartialContext();
|
|
@@ -3205,15 +3286,15 @@ function requireContext2() {
|
|
|
3205
3286
|
const projectSlug = projectConfig.getEffectiveProject();
|
|
3206
3287
|
const environment = projectConfig.getEffectiveEnvironment();
|
|
3207
3288
|
if (!teamSlug) {
|
|
3208
|
-
ui.error("No team selected. Run `
|
|
3289
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
3209
3290
|
process.exit(1);
|
|
3210
3291
|
}
|
|
3211
3292
|
if (!projectSlug) {
|
|
3212
|
-
ui.error("No project selected. Run `
|
|
3293
|
+
ui.error("No project selected. Run `stash projects use <slug>` first.");
|
|
3213
3294
|
process.exit(1);
|
|
3214
3295
|
}
|
|
3215
3296
|
if (!environment) {
|
|
3216
|
-
ui.error("No environment selected. Run `
|
|
3297
|
+
ui.error("No environment selected. Run `stash environments use <slug>` first.");
|
|
3217
3298
|
process.exit(1);
|
|
3218
3299
|
}
|
|
3219
3300
|
return { teamSlug, projectSlug, environment };
|
|
@@ -3249,7 +3330,7 @@ function registerShareCommands(program2) {
|
|
|
3249
3330
|
const share = program2.command("share").description("Share secrets via temporary links");
|
|
3250
3331
|
share.command("create <key>").alias("new").description("Create a share link for a secret").option("-e, --expires <time>", "Expiration time (e.g., 1h, 24h, 7d, 30m)", "24h").option("--one-time", "Link can only be viewed once").option("--env <environment>", "Environment (overrides current)").action(async (key, options) => {
|
|
3251
3332
|
if (!configManager.isAuthenticated()) {
|
|
3252
|
-
ui.error("Not authenticated. Run `
|
|
3333
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
3253
3334
|
process.exit(1);
|
|
3254
3335
|
}
|
|
3255
3336
|
const ctx = requireContext2();
|
|
@@ -3293,7 +3374,7 @@ function registerShareCommands(program2) {
|
|
|
3293
3374
|
});
|
|
3294
3375
|
share.command("list").alias("ls").description("List active share links").option("-a, --all", "Include expired and revoked links").action(async (options) => {
|
|
3295
3376
|
if (!configManager.isAuthenticated()) {
|
|
3296
|
-
ui.error("Not authenticated. Run `
|
|
3377
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
3297
3378
|
process.exit(1);
|
|
3298
3379
|
}
|
|
3299
3380
|
const spinner = ui.spinner("Fetching share links...");
|
|
@@ -3308,7 +3389,7 @@ function registerShareCommands(program2) {
|
|
|
3308
3389
|
spinner.stop();
|
|
3309
3390
|
if (!result.data?.shares.length) {
|
|
3310
3391
|
ui.warning("No share links found");
|
|
3311
|
-
ui.info(`Create one with ${ui.code("
|
|
3392
|
+
ui.info(`Create one with ${ui.code("stash share create <KEY>")}`);
|
|
3312
3393
|
return;
|
|
3313
3394
|
}
|
|
3314
3395
|
ui.heading("Share Links");
|
|
@@ -3335,11 +3416,11 @@ function registerShareCommands(program2) {
|
|
|
3335
3416
|
});
|
|
3336
3417
|
ui.br();
|
|
3337
3418
|
ui.info(`${result.data.shares.length} share link(s) total`);
|
|
3338
|
-
ui.info(`Revoke with ${ui.code("
|
|
3419
|
+
ui.info(`Revoke with ${ui.code("stash share revoke <id>")}`);
|
|
3339
3420
|
});
|
|
3340
3421
|
share.command("revoke <id>").description("Revoke a share link").option("-f, --force", "Skip confirmation prompt").action(async (id, options) => {
|
|
3341
3422
|
if (!configManager.isAuthenticated()) {
|
|
3342
|
-
ui.error("Not authenticated. Run `
|
|
3423
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
3343
3424
|
process.exit(1);
|
|
3344
3425
|
}
|
|
3345
3426
|
if (!options.force) {
|
|
@@ -3472,7 +3553,7 @@ async function checkAuthentication() {
|
|
|
3472
3553
|
name: "Authentication",
|
|
3473
3554
|
status: "fail",
|
|
3474
3555
|
message: "Not authenticated",
|
|
3475
|
-
hint: "Run:
|
|
3556
|
+
hint: "Run: stash login"
|
|
3476
3557
|
};
|
|
3477
3558
|
}
|
|
3478
3559
|
const user = configManager.getUser();
|
|
@@ -3503,7 +3584,7 @@ function checkTokenExpiration() {
|
|
|
3503
3584
|
name: "Token expiration",
|
|
3504
3585
|
status: "fail",
|
|
3505
3586
|
message: "No token found",
|
|
3506
|
-
hint: "Run:
|
|
3587
|
+
hint: "Run: stash login"
|
|
3507
3588
|
};
|
|
3508
3589
|
}
|
|
3509
3590
|
if (configManager.isTokenExpired()) {
|
|
@@ -3511,7 +3592,7 @@ function checkTokenExpiration() {
|
|
|
3511
3592
|
name: "Token expiration",
|
|
3512
3593
|
status: "warn",
|
|
3513
3594
|
message: "Token expired or expiring soon",
|
|
3514
|
-
hint: "Run:
|
|
3595
|
+
hint: "Run: stash login"
|
|
3515
3596
|
};
|
|
3516
3597
|
}
|
|
3517
3598
|
return {
|
|
@@ -3535,7 +3616,7 @@ function checkTeamSelected() {
|
|
|
3535
3616
|
name: "Team selected",
|
|
3536
3617
|
status: "fail",
|
|
3537
3618
|
message: "No team selected",
|
|
3538
|
-
hint: "Run:
|
|
3619
|
+
hint: "Run: stash teams use <slug>"
|
|
3539
3620
|
};
|
|
3540
3621
|
}
|
|
3541
3622
|
function checkProjectSelected() {
|
|
@@ -3553,7 +3634,7 @@ function checkProjectSelected() {
|
|
|
3553
3634
|
name: "Project selected",
|
|
3554
3635
|
status: "fail",
|
|
3555
3636
|
message: "No project selected",
|
|
3556
|
-
hint: "Run:
|
|
3637
|
+
hint: "Run: stash projects use <slug>"
|
|
3557
3638
|
};
|
|
3558
3639
|
}
|
|
3559
3640
|
function checkEnvironmentSelected() {
|
|
@@ -3570,7 +3651,7 @@ function checkEnvironmentSelected() {
|
|
|
3570
3651
|
name: "Environment selected",
|
|
3571
3652
|
status: "fail",
|
|
3572
3653
|
message: "No environment selected",
|
|
3573
|
-
hint: "Run:
|
|
3654
|
+
hint: "Run: stash environments use <name>"
|
|
3574
3655
|
};
|
|
3575
3656
|
}
|
|
3576
3657
|
function checkLocalConfigExists() {
|
|
@@ -3585,7 +3666,7 @@ function checkLocalConfigExists() {
|
|
|
3585
3666
|
name: "Local config file",
|
|
3586
3667
|
status: "warn",
|
|
3587
3668
|
message: ".secretstash.json not found",
|
|
3588
|
-
hint: "Run:
|
|
3669
|
+
hint: "Run: stash init (optional, for project-specific config)"
|
|
3589
3670
|
};
|
|
3590
3671
|
}
|
|
3591
3672
|
function checkLocalConfigValid() {
|
|
@@ -3758,12 +3839,12 @@ function registerTagCommands(program2) {
|
|
|
3758
3839
|
const tags = program2.command("tags").description("Manage tags for organizing secrets");
|
|
3759
3840
|
tags.command("list").alias("ls").description("List all tags in the current team").action(async () => {
|
|
3760
3841
|
if (!configManager.isAuthenticated()) {
|
|
3761
|
-
ui.error("Not authenticated. Run `
|
|
3842
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
3762
3843
|
process.exit(1);
|
|
3763
3844
|
}
|
|
3764
3845
|
const currentTeam = configManager.getCurrentTeam();
|
|
3765
3846
|
if (!currentTeam) {
|
|
3766
|
-
ui.error("No team selected. Run `
|
|
3847
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
3767
3848
|
process.exit(1);
|
|
3768
3849
|
}
|
|
3769
3850
|
const spinner = ui.spinner("Fetching tags...");
|
|
@@ -3776,7 +3857,7 @@ function registerTagCommands(program2) {
|
|
|
3776
3857
|
spinner.stop();
|
|
3777
3858
|
if (!result.data?.tags.length) {
|
|
3778
3859
|
ui.warning("No tags found");
|
|
3779
|
-
ui.info(`Create one with ${ui.code("
|
|
3860
|
+
ui.info(`Create one with ${ui.code("stash tags create <name>")}`);
|
|
3780
3861
|
return;
|
|
3781
3862
|
}
|
|
3782
3863
|
ui.heading(`Tags in ${currentTeam.name}`);
|
|
@@ -3793,12 +3874,12 @@ function registerTagCommands(program2) {
|
|
|
3793
3874
|
});
|
|
3794
3875
|
tags.command("create <name>").description("Create a new tag").option("-c, --color <hex>", "Hex color for the tag (e.g., #FF5733)").action(async (name, options) => {
|
|
3795
3876
|
if (!configManager.isAuthenticated()) {
|
|
3796
|
-
ui.error("Not authenticated. Run `
|
|
3877
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
3797
3878
|
process.exit(1);
|
|
3798
3879
|
}
|
|
3799
3880
|
const currentTeam = configManager.getCurrentTeam();
|
|
3800
3881
|
if (!currentTeam) {
|
|
3801
|
-
ui.error("No team selected. Run `
|
|
3882
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
3802
3883
|
process.exit(1);
|
|
3803
3884
|
}
|
|
3804
3885
|
if (options.color && !/^#[0-9A-Fa-f]{6}$/.test(options.color)) {
|
|
@@ -3821,12 +3902,12 @@ function registerTagCommands(program2) {
|
|
|
3821
3902
|
});
|
|
3822
3903
|
tags.command("delete <name>").alias("rm").description("Delete a tag").option("-f, --force", "Skip confirmation prompt").action(async (name, options) => {
|
|
3823
3904
|
if (!configManager.isAuthenticated()) {
|
|
3824
|
-
ui.error("Not authenticated. Run `
|
|
3905
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
3825
3906
|
process.exit(1);
|
|
3826
3907
|
}
|
|
3827
3908
|
const currentTeam = configManager.getCurrentTeam();
|
|
3828
3909
|
if (!currentTeam) {
|
|
3829
|
-
ui.error("No team selected. Run `
|
|
3910
|
+
ui.error("No team selected. Run `stash teams use <slug>` first.");
|
|
3830
3911
|
process.exit(1);
|
|
3831
3912
|
}
|
|
3832
3913
|
const spinner = ui.spinner("Looking up tag...");
|
|
@@ -4034,10 +4115,10 @@ function registerExecCommand(program2) {
|
|
|
4034
4115
|
program2.command("exec").description("Run a command with secrets injected as environment variables (CI/CD friendly)").requiredOption("--project <slug>", "Project slug").requiredOption("--env <environment>", "Environment name (e.g., production, staging)").option("--token <token>", "Service token (defaults to SECRETS_TOKEN env var)").option("--api-url <url>", "API URL (defaults to VAULT_API_URL env var or configured URL)").argument("<command...>", "Command to run").allowExcessArguments(true).action(async (commandArgs, options) => {
|
|
4035
4116
|
if (!commandArgs || commandArgs.length === 0) {
|
|
4036
4117
|
ui.error("No command provided");
|
|
4037
|
-
ui.info("Usage:
|
|
4118
|
+
ui.info("Usage: stash exec --project=<slug> --env=<environment> -- <command> [args...]");
|
|
4038
4119
|
ui.info("");
|
|
4039
4120
|
ui.info("Example:");
|
|
4040
|
-
ui.info("
|
|
4121
|
+
ui.info(" stash exec --project=myapp --env=production -- npm run build");
|
|
4041
4122
|
process.exit(1);
|
|
4042
4123
|
}
|
|
4043
4124
|
const token = options.token || process.env.SECRETS_TOKEN;
|
|
@@ -4046,7 +4127,7 @@ function registerExecCommand(program2) {
|
|
|
4046
4127
|
ui.info("Provide a token via --token flag or SECRETS_TOKEN environment variable");
|
|
4047
4128
|
ui.info("");
|
|
4048
4129
|
ui.info("Generate a service token from the SecretStash dashboard or CLI:");
|
|
4049
|
-
ui.info('
|
|
4130
|
+
ui.info(' stash tokens create --name "CI Token" --env production');
|
|
4050
4131
|
process.exit(1);
|
|
4051
4132
|
}
|
|
4052
4133
|
if (!token.startsWith("stk_")) {
|
|
@@ -4126,6 +4207,154 @@ function registerExecCommand(program2) {
|
|
|
4126
4207
|
});
|
|
4127
4208
|
}
|
|
4128
4209
|
|
|
4210
|
+
// src/commands/context.ts
|
|
4211
|
+
function registerContextCommands(program2) {
|
|
4212
|
+
const context = program2.command("context").alias("ctx").description("View and manage current context (team, project, environment)");
|
|
4213
|
+
context.action(async () => {
|
|
4214
|
+
ui.heading("Current Context");
|
|
4215
|
+
const team = configManager.getCurrentTeam();
|
|
4216
|
+
const project = configManager.getCurrentProject();
|
|
4217
|
+
const environment = configManager.getCurrentEnvironment();
|
|
4218
|
+
const localTeam = projectConfig.getEffectiveTeam();
|
|
4219
|
+
const localProject = projectConfig.getEffectiveProject();
|
|
4220
|
+
const localEnv = projectConfig.getEffectiveEnvironment();
|
|
4221
|
+
const hasLocalConfig = localTeam || localProject || localEnv;
|
|
4222
|
+
if (team) {
|
|
4223
|
+
ui.keyValue("Team", `${team.name} ${colors.muted(`(${team.slug})`)}`);
|
|
4224
|
+
} else {
|
|
4225
|
+
ui.keyValue("Team", colors.warning("Not set"));
|
|
4226
|
+
}
|
|
4227
|
+
if (project) {
|
|
4228
|
+
ui.keyValue("Project", `${project.name} ${colors.muted(`(${project.slug})`)}`);
|
|
4229
|
+
} else {
|
|
4230
|
+
ui.keyValue("Project", colors.warning("Not set"));
|
|
4231
|
+
}
|
|
4232
|
+
if (environment) {
|
|
4233
|
+
ui.keyValue("Environment", ui.envBadge(environment));
|
|
4234
|
+
} else {
|
|
4235
|
+
ui.keyValue("Environment", colors.warning("Not set"));
|
|
4236
|
+
}
|
|
4237
|
+
if (hasLocalConfig) {
|
|
4238
|
+
ui.br();
|
|
4239
|
+
ui.subheading("Local Config (.secretstash.json)");
|
|
4240
|
+
if (localTeam) ui.keyValue("Team", localTeam);
|
|
4241
|
+
if (localProject) ui.keyValue("Project", localProject);
|
|
4242
|
+
if (localEnv) ui.keyValue("Environment", localEnv);
|
|
4243
|
+
}
|
|
4244
|
+
const missing = [];
|
|
4245
|
+
if (!team && !localTeam) missing.push("team");
|
|
4246
|
+
if (!project && !localProject) missing.push("project");
|
|
4247
|
+
if (!environment && !localEnv) missing.push("environment");
|
|
4248
|
+
if (missing.length > 0) {
|
|
4249
|
+
ui.br();
|
|
4250
|
+
ui.warning(`Missing: ${missing.join(", ")}`);
|
|
4251
|
+
ui.info(`Run ${ui.code("stash init")} to set up your context`);
|
|
4252
|
+
} else {
|
|
4253
|
+
ui.br();
|
|
4254
|
+
ui.success("Context is fully configured");
|
|
4255
|
+
}
|
|
4256
|
+
});
|
|
4257
|
+
context.command("show").description("Show current context").action(async () => {
|
|
4258
|
+
await context.parseAsync([], { from: "user" });
|
|
4259
|
+
});
|
|
4260
|
+
context.command("clear").description("Clear all context (team, project, environment)").option("--team", "Clear only team context").option("--project", "Clear only project context").option("--env", "Clear only environment context").action((options) => {
|
|
4261
|
+
if (options.team) {
|
|
4262
|
+
configManager.clearCurrentTeam();
|
|
4263
|
+
configManager.clearCurrentProject();
|
|
4264
|
+
configManager.clearCurrentEnvironment();
|
|
4265
|
+
ui.success("Team context cleared (project and environment also cleared)");
|
|
4266
|
+
} else if (options.project) {
|
|
4267
|
+
configManager.clearCurrentProject();
|
|
4268
|
+
configManager.clearCurrentEnvironment();
|
|
4269
|
+
ui.success("Project context cleared (environment also cleared)");
|
|
4270
|
+
} else if (options.env) {
|
|
4271
|
+
configManager.clearCurrentEnvironment();
|
|
4272
|
+
ui.success("Environment context cleared");
|
|
4273
|
+
} else {
|
|
4274
|
+
configManager.clearCurrentTeam();
|
|
4275
|
+
configManager.clearCurrentProject();
|
|
4276
|
+
configManager.clearCurrentEnvironment();
|
|
4277
|
+
ui.success("All context cleared");
|
|
4278
|
+
}
|
|
4279
|
+
});
|
|
4280
|
+
context.command("set").description("Interactively set context (team, project, environment)").action(async () => {
|
|
4281
|
+
if (!configManager.isAuthenticated()) {
|
|
4282
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
4283
|
+
process.exit(1);
|
|
4284
|
+
}
|
|
4285
|
+
ui.info("Use `stash init` for full interactive setup");
|
|
4286
|
+
ui.info("Or use these commands to set context individually:");
|
|
4287
|
+
ui.br();
|
|
4288
|
+
ui.keyValue("Team", ui.code("stash teams use <slug>"));
|
|
4289
|
+
ui.keyValue("Project", ui.code("stash projects use <slug>"));
|
|
4290
|
+
ui.keyValue("Environment", ui.code("stash environments use <slug>"));
|
|
4291
|
+
});
|
|
4292
|
+
context.command("verify").description("Verify current context is valid and accessible").action(async () => {
|
|
4293
|
+
if (!configManager.isAuthenticated()) {
|
|
4294
|
+
ui.error("Not authenticated. Run `stash login` first.");
|
|
4295
|
+
process.exit(1);
|
|
4296
|
+
}
|
|
4297
|
+
const team = configManager.getCurrentTeam();
|
|
4298
|
+
const project = configManager.getCurrentProject();
|
|
4299
|
+
const environment = configManager.getCurrentEnvironment();
|
|
4300
|
+
let allValid = true;
|
|
4301
|
+
const spinner = ui.spinner("Verifying context...");
|
|
4302
|
+
if (team) {
|
|
4303
|
+
const teamsResult = await apiClient.getTeams();
|
|
4304
|
+
const teamExists = teamsResult.data?.teams.some((t) => t.id === team.id);
|
|
4305
|
+
if (teamExists) {
|
|
4306
|
+
spinner.text = `Team "${team.name}" \u2713`;
|
|
4307
|
+
} else {
|
|
4308
|
+
spinner.stop();
|
|
4309
|
+
ui.error(`Team "${team.name}" not found or no longer accessible`);
|
|
4310
|
+
allValid = false;
|
|
4311
|
+
}
|
|
4312
|
+
} else {
|
|
4313
|
+
spinner.stop();
|
|
4314
|
+
ui.warning("No team set");
|
|
4315
|
+
allValid = false;
|
|
4316
|
+
}
|
|
4317
|
+
if (team && project) {
|
|
4318
|
+
const projectsResult = await apiClient.getProjects(team.id);
|
|
4319
|
+
const projectExists = projectsResult.data?.projects.some((p) => p.id === project.id);
|
|
4320
|
+
if (projectExists) {
|
|
4321
|
+
spinner.text = `Project "${project.name}" \u2713`;
|
|
4322
|
+
} else {
|
|
4323
|
+
spinner.stop();
|
|
4324
|
+
ui.error(`Project "${project.name}" not found in team "${team.name}"`);
|
|
4325
|
+
allValid = false;
|
|
4326
|
+
}
|
|
4327
|
+
} else if (!project) {
|
|
4328
|
+
spinner.stop();
|
|
4329
|
+
ui.warning("No project set");
|
|
4330
|
+
allValid = false;
|
|
4331
|
+
}
|
|
4332
|
+
if (team && project && environment) {
|
|
4333
|
+
const envsResult = await apiClient.getEnvironments(project.id);
|
|
4334
|
+
const envExists = envsResult.data?.environments.some((e) => e.slug === environment);
|
|
4335
|
+
if (envExists) {
|
|
4336
|
+
spinner.succeed("Context verified");
|
|
4337
|
+
} else {
|
|
4338
|
+
spinner.stop();
|
|
4339
|
+
ui.error(`Environment "${environment}" not found in project "${project.name}"`);
|
|
4340
|
+
allValid = false;
|
|
4341
|
+
}
|
|
4342
|
+
} else if (!environment) {
|
|
4343
|
+
spinner.stop();
|
|
4344
|
+
ui.warning("No environment set");
|
|
4345
|
+
allValid = false;
|
|
4346
|
+
}
|
|
4347
|
+
if (allValid) {
|
|
4348
|
+
ui.br();
|
|
4349
|
+
ui.success("All context is valid and accessible");
|
|
4350
|
+
} else {
|
|
4351
|
+
ui.br();
|
|
4352
|
+
ui.info(`Run ${ui.code("stash init")} to fix context issues`);
|
|
4353
|
+
process.exit(1);
|
|
4354
|
+
}
|
|
4355
|
+
});
|
|
4356
|
+
}
|
|
4357
|
+
|
|
4129
4358
|
// src/index.ts
|
|
4130
4359
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
4131
4360
|
var version = "0.1.0";
|
|
@@ -4150,7 +4379,7 @@ var banner = chalk3.hex("#6366f1")(`
|
|
|
4150
4379
|
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
4151
4380
|
`);
|
|
4152
4381
|
var program = new Command();
|
|
4153
|
-
program.name("
|
|
4382
|
+
program.name("stash").description("SecretStash CLI - Ultra-secure team secrets management").version(version, "-v, --version", "Output the current version").option("--no-banner", "Disable the banner").option("-q, --quiet", "Suppress non-essential output (useful for CI/CD)").hook("preAction", (thisCommand) => {
|
|
4154
4383
|
const opts = thisCommand.opts();
|
|
4155
4384
|
if (opts.quiet) {
|
|
4156
4385
|
configManager.setQuiet(true);
|
|
@@ -4164,6 +4393,7 @@ registerTeamCommands(program);
|
|
|
4164
4393
|
registerProjectCommands(program);
|
|
4165
4394
|
registerEnvironmentCommands(program);
|
|
4166
4395
|
registerSecretCommands(program);
|
|
4396
|
+
registerContextCommands(program);
|
|
4167
4397
|
registerDiffCommand(program);
|
|
4168
4398
|
registerShareCommands(program);
|
|
4169
4399
|
registerDoctorCommand(program);
|
|
@@ -4173,44 +4403,47 @@ registerExecCommand(program);
|
|
|
4173
4403
|
program.addHelpText("after", `
|
|
4174
4404
|
${chalk3.bold("Examples:")}
|
|
4175
4405
|
${chalk3.dim("# Authenticate")}
|
|
4176
|
-
$
|
|
4177
|
-
$
|
|
4406
|
+
$ stash login
|
|
4407
|
+
$ stash whoami
|
|
4408
|
+
|
|
4409
|
+
${chalk3.dim("# View current context")}
|
|
4410
|
+
$ stash context
|
|
4178
4411
|
|
|
4179
|
-
${chalk3.dim("# Set up context")}
|
|
4180
|
-
$
|
|
4181
|
-
$ sstash projects use my-project
|
|
4182
|
-
$ sstash environments use development
|
|
4412
|
+
${chalk3.dim("# Set up context interactively")}
|
|
4413
|
+
$ stash init
|
|
4183
4414
|
|
|
4184
|
-
${chalk3.dim("# Or
|
|
4185
|
-
$
|
|
4415
|
+
${chalk3.dim("# Or set context manually")}
|
|
4416
|
+
$ stash teams use my-team
|
|
4417
|
+
$ stash projects use my-project
|
|
4418
|
+
$ stash environments use development
|
|
4186
4419
|
|
|
4187
4420
|
${chalk3.dim("# Manage secrets")}
|
|
4188
|
-
$
|
|
4189
|
-
$
|
|
4190
|
-
$
|
|
4421
|
+
$ stash pull # Pull secrets to .env
|
|
4422
|
+
$ stash push # Push secrets from .env
|
|
4423
|
+
$ stash run npm start # Run with secrets injected
|
|
4191
4424
|
|
|
4192
4425
|
${chalk3.dim("# View secrets")}
|
|
4193
|
-
$
|
|
4194
|
-
$
|
|
4426
|
+
$ stash secrets list
|
|
4427
|
+
$ stash secrets list --reveal
|
|
4195
4428
|
|
|
4196
4429
|
${chalk3.dim("# Compare environments")}
|
|
4197
|
-
$
|
|
4430
|
+
$ stash diff development production
|
|
4198
4431
|
|
|
4199
4432
|
${chalk3.dim("# Share secrets")}
|
|
4200
|
-
$
|
|
4201
|
-
$
|
|
4202
|
-
$
|
|
4433
|
+
$ stash share create DATABASE_URL --expires 24h --one-time
|
|
4434
|
+
$ stash share list
|
|
4435
|
+
$ stash share revoke <id>
|
|
4203
4436
|
|
|
4204
4437
|
${chalk3.dim("# Organize with tags")}
|
|
4205
|
-
$
|
|
4206
|
-
$
|
|
4207
|
-
$
|
|
4438
|
+
$ stash tags create database --color #FF5733
|
|
4439
|
+
$ stash tags list
|
|
4440
|
+
$ stash secrets tag DATABASE_URL database
|
|
4208
4441
|
|
|
4209
4442
|
${chalk3.dim("# CI/CD - pull secrets or run commands with secrets injected")}
|
|
4210
|
-
$ SECRETS_TOKEN=stk_xxx
|
|
4211
|
-
$ SECRETS_TOKEN=stk_xxx
|
|
4212
|
-
$ eval "$(SECRETS_TOKEN=stk_xxx
|
|
4213
|
-
$ SECRETS_TOKEN=stk_...
|
|
4443
|
+
$ SECRETS_TOKEN=stk_xxx stash ci-pull -p myapp -e production
|
|
4444
|
+
$ SECRETS_TOKEN=stk_xxx stash ci-pull -p myapp -e production --format json
|
|
4445
|
+
$ eval "$(SECRETS_TOKEN=stk_xxx stash ci-pull -p myapp -e production --format shell)"
|
|
4446
|
+
$ SECRETS_TOKEN=stk_... stash exec --project=myapp --env=production -- npm run build
|
|
4214
4447
|
|
|
4215
4448
|
${chalk3.bold("Documentation:")}
|
|
4216
4449
|
https://secretstash.dev/docs
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@secretstash/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "CLI tool for SecretStash - secure team secrets management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
|
+
"stash": "./bin/vault.js",
|
|
8
9
|
"sstash": "./bin/vault.js"
|
|
9
10
|
},
|
|
10
11
|
"scripts": {
|