@atlasauth/cli 0.2.0 → 0.3.0
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/CHANGELOG.md +38 -0
- package/README.md +40 -1
- package/dist/args.d.ts +67 -1
- package/dist/args.js +33 -0
- package/dist/args.js.map +1 -1
- package/dist/commands/api-keys.js +18 -3
- package/dist/commands/api-keys.js.map +1 -1
- package/dist/commands/auth.js +7 -3
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/config.js +7 -2
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.js +409 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/project-commands.d.ts +8 -0
- package/dist/commands/project-commands.js +236 -0
- package/dist/commands/project-commands.js.map +1 -0
- package/dist/commands/webhooks.d.ts +5 -2
- package/dist/commands/webhooks.js +37 -3
- package/dist/commands/webhooks.js.map +1 -1
- package/dist/help.d.ts +1 -1
- package/dist/help.js +69 -4
- package/dist/help.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/project.d.ts +63 -0
- package/dist/project.js +86 -0
- package/dist/project.js.map +1 -0
- package/dist/run.js +6 -0
- package/dist/run.js.map +1 -1
- package/dist/secrets.d.ts +41 -0
- package/dist/secrets.js +142 -0
- package/dist/secrets.js.map +1 -0
- package/package.json +5 -4
package/dist/project.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MANIFEST_FILE = void 0;
|
|
4
|
+
exports.manifestPath = manifestPath;
|
|
5
|
+
exports.readManifest = readManifest;
|
|
6
|
+
exports.writeManifest = writeManifest;
|
|
7
|
+
exports.findInstance = findInstance;
|
|
8
|
+
exports.parseInstanceEnv = parseInstanceEnv;
|
|
9
|
+
exports.httpFor = httpFor;
|
|
10
|
+
exports.instanceSecretFromFile = instanceSecretFromFile;
|
|
11
|
+
const node_fs_1 = require("node:fs");
|
|
12
|
+
const node_os_1 = require("node:os");
|
|
13
|
+
const node_path_1 = require("node:path");
|
|
14
|
+
const config_http_1 = require("./config-http");
|
|
15
|
+
const errors_1 = require("./errors");
|
|
16
|
+
const secrets_1 = require("./secrets");
|
|
17
|
+
exports.MANIFEST_FILE = 'atlas.json';
|
|
18
|
+
function manifestPath(env, product) {
|
|
19
|
+
return (0, node_path_1.join)((0, secrets_1.productDir)(env, product), exports.MANIFEST_FILE);
|
|
20
|
+
}
|
|
21
|
+
function readManifest(env, product) {
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse((0, node_fs_1.readFileSync)(manifestPath(env, product), 'utf8'));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function writeManifest(env, manifest) {
|
|
30
|
+
const dir = (0, secrets_1.productDir)(env, manifest.product);
|
|
31
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true, mode: 0o700 });
|
|
32
|
+
const path = (0, node_path_1.join)(dir, exports.MANIFEST_FILE);
|
|
33
|
+
(0, node_fs_1.writeFileSync)(path, JSON.stringify(manifest, null, 2) + '\n', { mode: 0o600 });
|
|
34
|
+
(0, node_fs_1.chmodSync)(path, 0o600);
|
|
35
|
+
return path;
|
|
36
|
+
}
|
|
37
|
+
/** Find the project + instance an instance id belongs to, scanning every product directory. */
|
|
38
|
+
function findInstance(env, instanceId, product) {
|
|
39
|
+
const products = product ? [product] : listProducts(env);
|
|
40
|
+
for (const p of products) {
|
|
41
|
+
const m = readManifest(env, p);
|
|
42
|
+
for (const inst of Object.values(m?.instances ?? {})) {
|
|
43
|
+
if (inst && inst.instance_id === instanceId)
|
|
44
|
+
return { manifest: m, instance: inst };
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
function listProducts(env) {
|
|
50
|
+
const base = env.XDG_CONFIG_HOME?.trim() || (0, node_path_1.join)(env.HOME?.trim() || (0, node_os_1.homedir)(), '.config');
|
|
51
|
+
try {
|
|
52
|
+
return (0, node_fs_1.readdirSync)(base).filter((d) => {
|
|
53
|
+
try {
|
|
54
|
+
(0, node_fs_1.readFileSync)((0, node_path_1.join)(base, d, exports.MANIFEST_FILE));
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function parseInstanceEnv(raw, fallback) {
|
|
67
|
+
if (raw === undefined)
|
|
68
|
+
return fallback;
|
|
69
|
+
if (raw !== 'development' && raw !== 'production') {
|
|
70
|
+
throw new errors_1.CliError(`--instance-env must be development or production, got '${raw}'.`);
|
|
71
|
+
}
|
|
72
|
+
return raw;
|
|
73
|
+
}
|
|
74
|
+
/** The raw HTTP client for a credential (the context's, or the real one). */
|
|
75
|
+
function httpFor(ctx, opts) {
|
|
76
|
+
return (ctx.makeHttp ?? config_http_1.createConfigHttp)(opts);
|
|
77
|
+
}
|
|
78
|
+
/** Read the instance secret key from the project's secret file. */
|
|
79
|
+
function instanceSecretFromFile(instance) {
|
|
80
|
+
const key = (0, secrets_1.readEnvFile)(instance.secret_file)?.ATLAS_SECRET_KEY;
|
|
81
|
+
if (!key) {
|
|
82
|
+
throw new errors_1.CliError(`No ATLAS_SECRET_KEY in ${instance.secret_file}. Re-run 'atlas init' with --rotate-secret to mint a new one.`);
|
|
83
|
+
}
|
|
84
|
+
return key;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":";;;AA0CA,oCAEC;AAED,oCAMC;AAED,sCAOC;AAGD,oCAaC;AAkBD,4CAMC;AAGD,0BAEC;AAGD,wDAQC;AArHD,qCAAyF;AACzF,qCAAkC;AAClC,yCAAiC;AACjC,+CAAkE;AAElE,qCAAoC;AACpC,uCAAoD;AAkCvC,QAAA,aAAa,GAAG,YAAY,CAAC;AAE1C,SAAgB,YAAY,CAAC,GAAsB,EAAE,OAAe;IAClE,OAAO,IAAA,gBAAI,EAAC,IAAA,oBAAU,EAAC,GAAG,EAAE,OAAO,CAAC,EAAE,qBAAa,CAAC,CAAC;AACvD,CAAC;AAED,SAAgB,YAAY,CAAC,GAAsB,EAAE,OAAe;IAClE,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAA,sBAAY,EAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAoB,CAAC;IACzF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAgB,aAAa,CAAC,GAAsB,EAAE,QAAyB;IAC7E,MAAM,GAAG,GAAG,IAAA,oBAAU,EAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC9C,IAAA,mBAAS,EAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,IAAA,gBAAI,EAAC,GAAG,EAAE,qBAAa,CAAC,CAAC;IACtC,IAAA,uBAAa,EAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/E,IAAA,mBAAS,EAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACvB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,+FAA+F;AAC/F,SAAgB,YAAY,CAC1B,GAAsB,EACtB,UAAkB,EAClB,OAAgB;IAEhB,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IACzD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,IAAI,EAAE,CAAC,EAAE,CAAC;YACrD,IAAI,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,UAAU;gBAAE,OAAO,EAAE,QAAQ,EAAE,CAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACvF,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,YAAY,CAAC,GAAsB;IAC1C,MAAM,IAAI,GAAG,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,IAAI,IAAA,gBAAI,EAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,IAAA,iBAAO,GAAE,EAAE,SAAS,CAAC,CAAC;IAC3F,IAAI,CAAC;QACH,OAAO,IAAA,qBAAW,EAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;YACpC,IAAI,CAAC;gBACH,IAAA,sBAAY,EAAC,IAAA,gBAAI,EAAC,IAAI,EAAE,CAAC,EAAE,qBAAa,CAAC,CAAC,CAAC;gBAC3C,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAgB,gBAAgB,CAAC,GAAuB,EAAE,QAAqB;IAC7E,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IACvC,IAAI,GAAG,KAAK,aAAa,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;QAClD,MAAM,IAAI,iBAAQ,CAAC,0DAA0D,GAAG,IAAI,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,6EAA6E;AAC7E,SAAgB,OAAO,CAAC,GAAe,EAAE,IAA2C;IAClF,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,8BAAgB,CAAC,CAAC,IAAI,CAAC,CAAC;AAClD,CAAC;AAED,mEAAmE;AACnE,SAAgB,sBAAsB,CAAC,QAAyB;IAC9D,MAAM,GAAG,GAAG,IAAA,qBAAW,EAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAChE,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,iBAAQ,CAChB,0BAA0B,QAAQ,CAAC,WAAW,+DAA+D,CAC9G,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/run.js
CHANGED
|
@@ -7,6 +7,8 @@ const actions_1 = require("./commands/actions");
|
|
|
7
7
|
const api_keys_1 = require("./commands/api-keys");
|
|
8
8
|
const auth_1 = require("./commands/auth");
|
|
9
9
|
const config_1 = require("./commands/config");
|
|
10
|
+
const init_1 = require("./commands/init");
|
|
11
|
+
const project_commands_1 = require("./commands/project-commands");
|
|
10
12
|
const orgs_1 = require("./commands/orgs");
|
|
11
13
|
const sessions_1 = require("./commands/sessions");
|
|
12
14
|
const users_1 = require("./commands/users");
|
|
@@ -26,6 +28,10 @@ const COMMANDS = {
|
|
|
26
28
|
sessions: sessions_1.sessions,
|
|
27
29
|
config: config_1.config,
|
|
28
30
|
actions: actions_1.actions,
|
|
31
|
+
init: init_1.init,
|
|
32
|
+
preflight: project_commands_1.preflight,
|
|
33
|
+
env: project_commands_1.envCommand,
|
|
34
|
+
client: project_commands_1.client,
|
|
29
35
|
};
|
|
30
36
|
/**
|
|
31
37
|
* The CLI's whole control flow, as a pure function of (argv, context) → exit
|
package/dist/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":";;AA6CA,kBAwCC;AArFD,gDAAmD;AACnD,iCAAgD;AAChD,gDAA6C;AAC7C,kDAA8C;AAC9C,0CAAwD;AACxD,8CAA2C;AAC3C,0CAAuC;AACvC,kEAA4E;AAC5E,0CAAuC;AACvC,kDAA+C;AAC/C,4CAAyC;AACzC,kDAA+C;AAE/C,qCAAoC;AACpC,iCAAgD;AAChD,uCAAuC;AAKvC,kFAAkF;AAClF,MAAM,QAAQ,GAA4B;IACxC,KAAK,EAAL,YAAK;IACL,MAAM,EAAN,aAAM;IACN,MAAM,EAAN,aAAM;IACN,KAAK,EAAL,aAAK;IACL,IAAI,EAAJ,WAAI;IACJ,UAAU,EAAE,kBAAO;IACnB,QAAQ,EAAR,mBAAQ;IACR,QAAQ,EAAR,mBAAQ;IACR,MAAM,EAAN,eAAM;IACN,OAAO,EAAP,iBAAO;IACP,IAAI,EAAJ,WAAI;IACJ,SAAS,EAAT,4BAAS;IACT,GAAG,EAAE,6BAAU;IACf,MAAM,EAAN,yBAAM;CACP,CAAC;AAEF;;;;;;GAMG;AACI,KAAK,UAAU,GAAG,CAAC,IAAc,EAAE,GAAe;IACvD,IAAI,IAAgB,CAAC;IACrB,IAAI,CAAC;QACH,IAAI,GAAG,IAAA,YAAK,EAAC,IAAI,CAAC,CAAC;IACrB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED,kDAAkD;IAClD,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACxB,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAA,oBAAU,GAAE,CAAC,CAAC;QACzB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAEpC,qEAAqE;IACrE,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,eAAQ,CAAC,CAAC;QACrB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;IAClC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,oBAAoB,OAAO,IAAI,CAAC,CAAC;QAC5C,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;QAC5D,OAAO,CAAC,CAAC;IACX,CAAC;IAED,sEAAsE;IACtE,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACrB,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,mBAAY,CAAC,OAAO,CAAC,IAAI,eAAQ,CAAC,CAAC;QAC9C,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,MAAM,CAAC,GAAe,EAAE,GAAY;IAC3C,IAAI,GAAG,YAAY,uBAAa,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9C,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,0BAA0B,GAAG,CAAC,MAAM,IAAI,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3E,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,GAAG,YAAY,iBAAQ,EAAE,CAAC;QAC5B,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACpC,OAAO,GAAG,CAAC,QAAQ,CAAC;IACtB,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC;IAChC,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { IO } from './io';
|
|
2
|
+
export declare function assertProductName(product: string): string;
|
|
3
|
+
/** `$XDG_CONFIG_HOME/<product>` (default `~/.config/<product>`). */
|
|
4
|
+
export declare function productDir(env: NodeJS.ProcessEnv, product: string): string;
|
|
5
|
+
export declare function renderDotenv(entries: Record<string, string>, comment?: string): string;
|
|
6
|
+
/** Parse a dotenv file this CLI wrote (KEY=value lines, `#` comments). */
|
|
7
|
+
export declare function parseDotenv(text: string): Record<string, string>;
|
|
8
|
+
/**
|
|
9
|
+
* Write a 0600 dotenv file inside a 0700 directory. Refuses an existing file
|
|
10
|
+
* unless `force` (the same content is not a conflict: a re-run is a no-op).
|
|
11
|
+
* Returns the path.
|
|
12
|
+
*/
|
|
13
|
+
export declare function writeSecretFile(dir: string, fileName: string, entries: Record<string, string>, opts?: {
|
|
14
|
+
force?: boolean;
|
|
15
|
+
comment?: string;
|
|
16
|
+
}): {
|
|
17
|
+
path: string;
|
|
18
|
+
written: boolean;
|
|
19
|
+
};
|
|
20
|
+
/** Read one of the CLI's env files, or undefined when it does not exist. */
|
|
21
|
+
export declare function readEnvFile(path: string): Record<string, string> | undefined;
|
|
22
|
+
/** The env files in a product directory (for `atlas env`). */
|
|
23
|
+
export declare function listEnvFiles(dir: string): string[];
|
|
24
|
+
/**
|
|
25
|
+
* The common "a secret arrived" path for single-secret commands: write it to
|
|
26
|
+
* `<dir>/<fileName>` (0600) and print the path, or — only with
|
|
27
|
+
* `--print-secret` — print it after a warning on stderr.
|
|
28
|
+
*/
|
|
29
|
+
export declare function deliverSecret(input: {
|
|
30
|
+
io: IO;
|
|
31
|
+
env: NodeJS.ProcessEnv;
|
|
32
|
+
product: string;
|
|
33
|
+
fileName: string;
|
|
34
|
+
entries: Record<string, string>;
|
|
35
|
+
label: string;
|
|
36
|
+
printSecret?: boolean;
|
|
37
|
+
force?: boolean;
|
|
38
|
+
comment?: string;
|
|
39
|
+
}): {
|
|
40
|
+
path?: string;
|
|
41
|
+
};
|
package/dist/secrets.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertProductName = assertProductName;
|
|
4
|
+
exports.productDir = productDir;
|
|
5
|
+
exports.renderDotenv = renderDotenv;
|
|
6
|
+
exports.parseDotenv = parseDotenv;
|
|
7
|
+
exports.writeSecretFile = writeSecretFile;
|
|
8
|
+
exports.readEnvFile = readEnvFile;
|
|
9
|
+
exports.listEnvFiles = listEnvFiles;
|
|
10
|
+
exports.deliverSecret = deliverSecret;
|
|
11
|
+
const node_fs_1 = require("node:fs");
|
|
12
|
+
const node_os_1 = require("node:os");
|
|
13
|
+
const node_path_1 = require("node:path");
|
|
14
|
+
const errors_1 = require("./errors");
|
|
15
|
+
/**
|
|
16
|
+
* Secrets the CLI receives are written to disk, never printed.
|
|
17
|
+
*
|
|
18
|
+
* Every command that gets a secret back from the API (an instance secret key,
|
|
19
|
+
* an OAuth client secret, a webhook signing secret, an end-user API key) writes
|
|
20
|
+
* it to a dotenv file under `~/.config/<product>/` — directory 0700, file 0600 —
|
|
21
|
+
* and prints only the file path. `--print-secret` is the one explicit opt-out,
|
|
22
|
+
* and it prints a warning first. An existing file is never overwritten unless
|
|
23
|
+
* the command was given `--force`, so a re-run cannot silently destroy the only
|
|
24
|
+
* copy of a working secret.
|
|
25
|
+
*
|
|
26
|
+
* The product name doubles as the directory name, so it is restricted to a safe
|
|
27
|
+
* slug (no path separators, no dot-dot).
|
|
28
|
+
*/
|
|
29
|
+
const PRODUCT_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/i;
|
|
30
|
+
function assertProductName(product) {
|
|
31
|
+
if (!PRODUCT_RE.test(product)) {
|
|
32
|
+
throw new errors_1.CliError(`--product must be letters, digits, '-' or '_' (up to 63 characters), got '${product}'.`);
|
|
33
|
+
}
|
|
34
|
+
return product;
|
|
35
|
+
}
|
|
36
|
+
/** `$XDG_CONFIG_HOME/<product>` (default `~/.config/<product>`). */
|
|
37
|
+
function productDir(env, product) {
|
|
38
|
+
const base = env.XDG_CONFIG_HOME?.trim() || (0, node_path_1.join)(env.HOME?.trim() || (0, node_os_1.homedir)(), '.config');
|
|
39
|
+
return (0, node_path_1.join)(base, assertProductName(product));
|
|
40
|
+
}
|
|
41
|
+
/** Quote a dotenv value when it needs it. Secrets are token-shaped, so this is rarely used. */
|
|
42
|
+
function dotenvValue(v) {
|
|
43
|
+
return /^[A-Za-z0-9_./:@+=,-]*$/.test(v) ? v : JSON.stringify(v);
|
|
44
|
+
}
|
|
45
|
+
function renderDotenv(entries, comment) {
|
|
46
|
+
const lines = comment ? comment.split('\n').map((l) => `# ${l}`) : [];
|
|
47
|
+
for (const [k, v] of Object.entries(entries))
|
|
48
|
+
lines.push(`${k}=${dotenvValue(v)}`);
|
|
49
|
+
return lines.join('\n') + '\n';
|
|
50
|
+
}
|
|
51
|
+
/** Parse a dotenv file this CLI wrote (KEY=value lines, `#` comments). */
|
|
52
|
+
function parseDotenv(text) {
|
|
53
|
+
const out = {};
|
|
54
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
55
|
+
const line = raw.trim();
|
|
56
|
+
if (!line || line.startsWith('#'))
|
|
57
|
+
continue;
|
|
58
|
+
const i = line.indexOf('=');
|
|
59
|
+
if (i < 1)
|
|
60
|
+
continue;
|
|
61
|
+
const key = line.slice(0, i).trim();
|
|
62
|
+
let value = line.slice(i + 1).trim();
|
|
63
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
64
|
+
try {
|
|
65
|
+
value = JSON.parse(value);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
/* keep raw */
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
out[key] = value;
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Write a 0600 dotenv file inside a 0700 directory. Refuses an existing file
|
|
77
|
+
* unless `force` (the same content is not a conflict: a re-run is a no-op).
|
|
78
|
+
* Returns the path.
|
|
79
|
+
*/
|
|
80
|
+
function writeSecretFile(dir, fileName, entries, opts = {}) {
|
|
81
|
+
if (fileName.includes('/') || fileName.includes('\\') || fileName.startsWith('.')) {
|
|
82
|
+
throw new errors_1.CliError(`Refusing to write a secret file named '${fileName}'.`);
|
|
83
|
+
}
|
|
84
|
+
const path = (0, node_path_1.join)(dir, fileName);
|
|
85
|
+
const content = renderDotenv(entries, opts.comment);
|
|
86
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true, mode: 0o700 });
|
|
87
|
+
(0, node_fs_1.chmodSync)(dir, 0o700);
|
|
88
|
+
if ((0, node_fs_1.existsSync)(path)) {
|
|
89
|
+
const current = (0, node_fs_1.readFileSync)(path, 'utf8');
|
|
90
|
+
if (current === content) {
|
|
91
|
+
(0, node_fs_1.chmodSync)(path, 0o600);
|
|
92
|
+
return { path, written: false };
|
|
93
|
+
}
|
|
94
|
+
if (!opts.force) {
|
|
95
|
+
throw new errors_1.CliError(`${path} already exists and holds a different secret. Nothing was overwritten. Move it aside, or re-run with --force to replace it.`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Write THEN chmod: `mode` is masked by umask and ignored for an existing file.
|
|
99
|
+
(0, node_fs_1.writeFileSync)(path, content, { mode: 0o600 });
|
|
100
|
+
(0, node_fs_1.chmodSync)(path, 0o600);
|
|
101
|
+
return { path, written: true };
|
|
102
|
+
}
|
|
103
|
+
/** Read one of the CLI's env files, or undefined when it does not exist. */
|
|
104
|
+
function readEnvFile(path) {
|
|
105
|
+
try {
|
|
106
|
+
return parseDotenv((0, node_fs_1.readFileSync)(path, 'utf8'));
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** The env files in a product directory (for `atlas env`). */
|
|
113
|
+
function listEnvFiles(dir) {
|
|
114
|
+
try {
|
|
115
|
+
return (0, node_fs_1.readdirSync)(dir)
|
|
116
|
+
.filter((f) => f.endsWith('.env'))
|
|
117
|
+
.sort();
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* The common "a secret arrived" path for single-secret commands: write it to
|
|
125
|
+
* `<dir>/<fileName>` (0600) and print the path, or — only with
|
|
126
|
+
* `--print-secret` — print it after a warning on stderr.
|
|
127
|
+
*/
|
|
128
|
+
function deliverSecret(input) {
|
|
129
|
+
if (input.printSecret) {
|
|
130
|
+
input.io.err(`atlas: warning: printing ${input.label} because --print-secret was given. It may end up in your shell history, terminal scrollback or CI logs.`);
|
|
131
|
+
for (const [k, v] of Object.entries(input.entries))
|
|
132
|
+
input.io.out(`${k}=${v}`);
|
|
133
|
+
return {};
|
|
134
|
+
}
|
|
135
|
+
const { path } = writeSecretFile(productDir(input.env, input.product), input.fileName, input.entries, {
|
|
136
|
+
force: input.force,
|
|
137
|
+
comment: input.comment,
|
|
138
|
+
});
|
|
139
|
+
input.io.out(`${input.label} written to ${path} (mode 0600).`);
|
|
140
|
+
return { path };
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=secrets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlasauth/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "atlas — manage an Atlas instance from the terminal via the Backend API.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"atlas": "dist/cli.js"
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"./package.json": "./package.json"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@atlasauth/
|
|
19
|
-
"@atlasauth/
|
|
18
|
+
"@atlasauth/actions": "0.1.1",
|
|
19
|
+
"@atlasauth/backend": "0.9.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"@types/node": "^22.9.0",
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
},
|
|
29
29
|
"files": [
|
|
30
30
|
"dist",
|
|
31
|
-
"README.md"
|
|
31
|
+
"README.md",
|
|
32
|
+
"CHANGELOG.md"
|
|
32
33
|
],
|
|
33
34
|
"scripts": {
|
|
34
35
|
"build": "tsc -p tsconfig.build.json",
|