@atlasauth/cli 0.1.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 +74 -1
- package/dist/args.d.ts +82 -1
- package/dist/args.js +40 -0
- package/dist/args.js.map +1 -1
- package/dist/commands/actions.d.ts +11 -0
- package/dist/commands/actions.js +120 -0
- package/dist/commands/actions.js.map +1 -0
- 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.d.ts +4 -0
- package/dist/commands/config.js +721 -0
- package/dist/commands/config.js.map +1 -0
- 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/config-http.d.ts +27 -0
- package/dist/config-http.js +63 -0
- package/dist/config-http.js.map +1 -0
- package/dist/context.d.ts +17 -1
- package/dist/context.js +4 -0
- package/dist/context.js.map +1 -1
- package/dist/help.d.ts +1 -1
- package/dist/help.js +104 -4
- package/dist/help.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.js +25 -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 +10 -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/dist/serialize.d.ts +31 -0
- package/dist/serialize.js +248 -0
- package/dist/serialize.js.map +1 -0
- package/package.json +5 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# @atlasauth/cli changelog
|
|
2
|
+
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `atlas init --product <name>`: creates or completes an app's setup in one idempotent command, through the platform API (needs a `psk_` platform key: `ATLAS_PLATFORM_KEY`, or a profile stored with `atlas login --secret-key psk_…`). Flags: `--domain`, `--auth-host`, `--instance-env development|production`, `--name`, `--strategies`, `--email managed|development|none`, `--email-from`, `--email-provider resend|brevo`, `--email-key-file <path|->`, `--client-redirect` (repeatable), `--webhook-url`, `--yes`, `--force`, `--rotate-secret`, `--json`. Email goes through your own provider account: the key is read from `--email-key-file` (or stdin with `-`), never from argv, and never printed. Prints the managed-email DNS records and the custom-domain CNAME, and a summary of public values (publishable key, Frontend API, issuer, discovery URL; `issuer` / `discovery_url` / `jwks_uri` from the API when it returns them).
|
|
7
|
+
- A project manifest at `~/.config/<product>/atlas.json` with public values and secret file paths only.
|
|
8
|
+
- `atlas preflight [--instance <id> | --product <name>] [--fail-on error|warning] [--json]`: prints findings and exits 1 on errors (or warnings).
|
|
9
|
+
- `atlas env --product <name> --format dotenv|coolify|vercel`: public values plus secret file references (`*_FILE=<path>`, `KEY=@<path>`, or `vercel env add` commands that read the file), never secret values.
|
|
10
|
+
- `atlas client rotate <client-id> [--now | --overlap <seconds>]`: sends `overlap_seconds`, writes the new secret straight to its file, and prints when the old one stops working (`previous_secret_expires_at`).
|
|
11
|
+
- `atlas webhooks create --url <url> [--events a,b]`.
|
|
12
|
+
- `atlas login` accepts a platform key (`psk_…`) and validates it against the platform API.
|
|
13
|
+
- New flags: `--product`, `--print-secret`, `--force` on secret-returning commands.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- Secrets are written to files by default. Every command that receives a secret writes it to a `0600` dotenv file under `~/.config/<product>/` (directory `0700`; `~/.config/atlasauth/` without `--product`) and prints only the path. An existing different file is never overwritten without `--force`.
|
|
17
|
+
- `atlas api-keys create` no longer prints the secret. It writes `ATLAS_API_KEY` to `api-key-<id>.env` and prints the path; `--json` returns `secret_file` instead of `secret`. Pass `--print-secret` for the old behaviour (with a warning on stderr).
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- `atlas config import` no longer sends `signing_alg` when creating or updating a resource server, or `type` when updating an SSO connection. Instances that refuse unknown fields (every new instance) answered those writes with `422 UNKNOWN_FIELD`.
|
|
21
|
+
|
|
22
|
+
## 0.2.0
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
- `atlas config export` / `atlas config import` for config-as-code: round-trips an instance's configuration (auth config and allowed origins, OAuth clients and providers, SSO connections, resource servers, JWT templates, roles, webhook endpoints, billing plans, redirect URLs, organization settings schema, notification and email templates, organization policies) to a directory in JSON or YAML.
|
|
26
|
+
- Output is deterministic (sorted keys) and never contains secrets; `${ENV_VAR}` placeholders are resolved from the environment on import.
|
|
27
|
+
- `import` supports `--dry-run` to preview the plan and `--prune` to delete resources removed from the directory; without `--prune` nothing is deleted.
|
|
28
|
+
- `atlas actions list | deploy | test | logs` for managing Atlas Actions, with `test` running an Action locally through the `@atlasauth/actions` harness.
|
|
29
|
+
|
|
30
|
+
## 0.1.0
|
|
31
|
+
|
|
32
|
+
First published release.
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
- `atlas` command-line tool for managing an Atlas instance over the Backend API, built on `@atlasauth/backend`.
|
|
36
|
+
- `atlas login`, `logout` and `whoami`, with named profiles (`--profile`) stored in a `0600` config file and `ATLAS_SECRET_KEY` / `ATLAS_API_URL` environment overrides.
|
|
37
|
+
- Commands: `users list | get | create | delete`, `orgs list | get | members`, `api-keys list | create | revoke`, `webhooks list` and `sessions revoke`.
|
|
38
|
+
- Human-readable tables by default, `--json` for raw output, and `--limit` / `--starting-after` pagination on list commands.
|
package/README.md
CHANGED
|
@@ -40,8 +40,14 @@ ATLAS_SECRET_KEY=sk_live_... ATLAS_API_URL=https://api.atlasauth.net atlas users
|
|
|
40
40
|
atlas users list | get <id> | create --email <e> | delete <id>
|
|
41
41
|
atlas orgs list | get <id> | members <id>
|
|
42
42
|
atlas api-keys list | create --subject-type <t> --subject-id <id> | revoke <id>
|
|
43
|
-
atlas webhooks list
|
|
43
|
+
atlas webhooks list | create --url <url> [--events a,b]
|
|
44
44
|
atlas sessions revoke <id>
|
|
45
|
+
atlas config export [--dir <path>] [--format json|yaml]
|
|
46
|
+
atlas config import [--dir <path>] [--format json|yaml] [--dry-run] [--prune]
|
|
47
|
+
atlas init --product <name> [--domain <d>] [--instance-env development|production] ...
|
|
48
|
+
atlas preflight [--instance <id> | --product <name>] [--fail-on error|warning]
|
|
49
|
+
atlas env --product <name> --format dotenv|coolify|vercel
|
|
50
|
+
atlas client rotate <client-id> [--now | --overlap <seconds>]
|
|
45
51
|
```
|
|
46
52
|
|
|
47
53
|
Every command takes `--json` for raw JSON (otherwise a human table). Paginated
|
|
@@ -56,3 +62,70 @@ atlas api-keys create --subject-type user --subject-id user_123 --name ci
|
|
|
56
62
|
|
|
57
63
|
Run `atlas --help` or `atlas <command> --help` for details, `atlas --version`
|
|
58
64
|
for the version.
|
|
65
|
+
|
|
66
|
+
## Secrets go to files
|
|
67
|
+
|
|
68
|
+
Any command that receives a secret (an instance secret key, an OAuth client
|
|
69
|
+
secret, a webhook signing secret, an end-user API key) writes it to a `0600`
|
|
70
|
+
dotenv file under `~/.config/<product>/` (directory `0700`;
|
|
71
|
+
`~/.config/atlasauth/` without `--product`) and prints only the path. An
|
|
72
|
+
existing different file is never overwritten without `--force`.
|
|
73
|
+
`--print-secret` prints it instead, with a warning.
|
|
74
|
+
|
|
75
|
+
## Set up an app (`atlas init`)
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
export ATLAS_PLATFORM_KEY=psk_... # or: atlas login --secret-key psk_...
|
|
79
|
+
atlas init --product acme --domain acme.com \
|
|
80
|
+
--email-provider resend --email-key-file ~/.secrets/resend.key \
|
|
81
|
+
--strategies password,email_code,passkey \
|
|
82
|
+
--client-redirect https://app.acme.com/auth/callback \
|
|
83
|
+
--webhook-url https://app.acme.com/hooks/atlas --yes
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Finds or creates the app + instance, sets the strategies, the email sender
|
|
87
|
+
(`--email managed|development|none`, always on your own provider account; the
|
|
88
|
+
key comes from `--email-key-file`, or stdin with `-`, never argv; managed
|
|
89
|
+
prints the DNS records), the custom
|
|
90
|
+
domain (`auth.<domain>`, prints the CNAME), a first-party OAuth client and a
|
|
91
|
+
webhook endpoint. Re-running only fills gaps. Secrets land in
|
|
92
|
+
`~/.config/acme/production*.env`; public values and file paths in
|
|
93
|
+
`~/.config/acme/atlas.json`.
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
atlas preflight --product acme --fail-on warning # CI gate: exit 1 on findings
|
|
97
|
+
atlas env --product acme --format dotenv # public values + *_FILE paths
|
|
98
|
+
atlas client rotate oc_123 --product acme --overlap 3600
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Config-as-code (`atlas config`)
|
|
102
|
+
|
|
103
|
+
The Auth0 `deploy-cli` equivalent: round-trip an instance's configuration to a
|
|
104
|
+
deterministic directory tree you keep in Git. `export` writes one file per
|
|
105
|
+
resource type with sorted keys and **secrets omitted**; `import` diffs the
|
|
106
|
+
directory against the live instance and applies creates/updates idempotently.
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
atlas config export --dir ./atlas-config # snapshot the instance
|
|
110
|
+
atlas config import --dir ./atlas-config --dry-run # preview the plan
|
|
111
|
+
atlas config import --dir ./atlas-config # apply creates/updates
|
|
112
|
+
atlas config import --dir ./atlas-config --prune # also delete removed resources
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Managed resource types (the same set the Terraform provider manages):
|
|
116
|
+
`instance` (auth config + allowed origins), `oauth_clients`, `oauth_providers`,
|
|
117
|
+
`sso_connections`, `resource_servers`, `jwt_templates`, `roles`,
|
|
118
|
+
`webhook_endpoints`, `billing_plans`, `redirect_urls`, `org_settings_schema`,
|
|
119
|
+
`notification_templates`, `email_templates`, `organization_policies`.
|
|
120
|
+
|
|
121
|
+
Rules that make it safe and repeatable:
|
|
122
|
+
|
|
123
|
+
- **Deterministic.** Keys are sorted, so re-exporting an unchanged instance is a
|
|
124
|
+
byte-for-byte no-op and a round-trip (`export` then `import`) is an empty diff.
|
|
125
|
+
- **No secrets on disk.** The management API never returns a secret on a read,
|
|
126
|
+
so none is ever written. To (re)write a credential at import, put a
|
|
127
|
+
`${ENV_VAR}` placeholder in the file; it is resolved from the environment.
|
|
128
|
+
- **Non-destructive.** `import` never deletes without `--prune`, and a resource
|
|
129
|
+
type with no file is left untouched (only committed types are managed).
|
|
130
|
+
|
|
131
|
+
Ship it on push with the [`atlas-deploy` GitHub Action](../../actions/atlas-deploy).
|
package/dist/args.d.ts
CHANGED
|
@@ -52,9 +52,88 @@ declare const OPTIONS: {
|
|
|
52
52
|
readonly name: {
|
|
53
53
|
readonly type: "string";
|
|
54
54
|
};
|
|
55
|
+
readonly dir: {
|
|
56
|
+
readonly type: "string";
|
|
57
|
+
};
|
|
58
|
+
readonly format: {
|
|
59
|
+
readonly type: "string";
|
|
60
|
+
};
|
|
61
|
+
readonly 'dry-run': {
|
|
62
|
+
readonly type: "boolean";
|
|
63
|
+
};
|
|
64
|
+
readonly prune: {
|
|
65
|
+
readonly type: "boolean";
|
|
66
|
+
};
|
|
67
|
+
readonly trigger: {
|
|
68
|
+
readonly type: "string";
|
|
69
|
+
};
|
|
70
|
+
readonly product: {
|
|
71
|
+
readonly type: "string";
|
|
72
|
+
};
|
|
73
|
+
readonly domain: {
|
|
74
|
+
readonly type: "string";
|
|
75
|
+
};
|
|
76
|
+
readonly 'auth-host': {
|
|
77
|
+
readonly type: "string";
|
|
78
|
+
};
|
|
79
|
+
readonly 'instance-env': {
|
|
80
|
+
readonly type: "string";
|
|
81
|
+
};
|
|
82
|
+
readonly strategies: {
|
|
83
|
+
readonly type: "string";
|
|
84
|
+
};
|
|
85
|
+
readonly 'email-from': {
|
|
86
|
+
readonly type: "string";
|
|
87
|
+
};
|
|
88
|
+
readonly 'email-provider': {
|
|
89
|
+
readonly type: "string";
|
|
90
|
+
};
|
|
91
|
+
readonly 'email-key-file': {
|
|
92
|
+
readonly type: "string";
|
|
93
|
+
};
|
|
94
|
+
readonly 'client-redirect': {
|
|
95
|
+
readonly type: "string";
|
|
96
|
+
readonly multiple: true;
|
|
97
|
+
};
|
|
98
|
+
readonly 'webhook-url': {
|
|
99
|
+
readonly type: "string";
|
|
100
|
+
};
|
|
101
|
+
readonly yes: {
|
|
102
|
+
readonly type: "boolean";
|
|
103
|
+
readonly short: "y";
|
|
104
|
+
};
|
|
105
|
+
readonly force: {
|
|
106
|
+
readonly type: "boolean";
|
|
107
|
+
};
|
|
108
|
+
readonly 'rotate-secret': {
|
|
109
|
+
readonly type: "boolean";
|
|
110
|
+
};
|
|
111
|
+
readonly instance: {
|
|
112
|
+
readonly type: "string";
|
|
113
|
+
};
|
|
114
|
+
readonly 'fail-on': {
|
|
115
|
+
readonly type: "string";
|
|
116
|
+
};
|
|
117
|
+
readonly now: {
|
|
118
|
+
readonly type: "boolean";
|
|
119
|
+
};
|
|
120
|
+
readonly overlap: {
|
|
121
|
+
readonly type: "string";
|
|
122
|
+
};
|
|
123
|
+
readonly 'print-secret': {
|
|
124
|
+
readonly type: "boolean";
|
|
125
|
+
};
|
|
126
|
+
readonly events: {
|
|
127
|
+
readonly type: "string";
|
|
128
|
+
};
|
|
55
129
|
};
|
|
130
|
+
type OptionValue<O> = O extends {
|
|
131
|
+
type: 'boolean';
|
|
132
|
+
} ? boolean : O extends {
|
|
133
|
+
multiple: true;
|
|
134
|
+
} ? string[] : string;
|
|
56
135
|
export type Values = {
|
|
57
|
-
[K in keyof typeof OPTIONS]?: (typeof OPTIONS)[K]
|
|
136
|
+
[K in keyof typeof OPTIONS]?: OptionValue<(typeof OPTIONS)[K]>;
|
|
58
137
|
};
|
|
59
138
|
export interface ParsedArgs {
|
|
60
139
|
positionals: string[];
|
|
@@ -64,6 +143,8 @@ export interface ParsedArgs {
|
|
|
64
143
|
export declare function parse(argv: string[]): ParsedArgs;
|
|
65
144
|
/** A string flag's value, or undefined. */
|
|
66
145
|
export declare function str(values: Values, key: keyof Values): string | undefined;
|
|
146
|
+
/** A repeatable string flag's values (each may also be comma-separated), or []. */
|
|
147
|
+
export declare function list(values: Values, key: keyof Values): string[];
|
|
67
148
|
/** `--limit` as a positive integer, or undefined. Rejects garbage with a clean error. */
|
|
68
149
|
export declare function limit(values: Values): number | undefined;
|
|
69
150
|
export {};
|
package/dist/args.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parse = parse;
|
|
4
4
|
exports.str = str;
|
|
5
|
+
exports.list = list;
|
|
5
6
|
exports.limit = limit;
|
|
6
7
|
const node_util_1 = require("node:util");
|
|
7
8
|
const errors_1 = require("./errors");
|
|
@@ -31,6 +32,36 @@ const OPTIONS = {
|
|
|
31
32
|
'subject-type': { type: 'string' },
|
|
32
33
|
'subject-id': { type: 'string' },
|
|
33
34
|
name: { type: 'string' },
|
|
35
|
+
// config export / import.
|
|
36
|
+
dir: { type: 'string' },
|
|
37
|
+
format: { type: 'string' },
|
|
38
|
+
'dry-run': { type: 'boolean' },
|
|
39
|
+
prune: { type: 'boolean' },
|
|
40
|
+
// actions.
|
|
41
|
+
trigger: { type: 'string' },
|
|
42
|
+
// init / preflight / env / client rotate.
|
|
43
|
+
product: { type: 'string' },
|
|
44
|
+
domain: { type: 'string' },
|
|
45
|
+
'auth-host': { type: 'string' },
|
|
46
|
+
'instance-env': { type: 'string' },
|
|
47
|
+
strategies: { type: 'string' },
|
|
48
|
+
'email-from': { type: 'string' },
|
|
49
|
+
// The customer's own email provider key: from a file (or '-' for stdin), never argv.
|
|
50
|
+
'email-provider': { type: 'string' },
|
|
51
|
+
'email-key-file': { type: 'string' },
|
|
52
|
+
'client-redirect': { type: 'string', multiple: true },
|
|
53
|
+
'webhook-url': { type: 'string' },
|
|
54
|
+
yes: { type: 'boolean', short: 'y' },
|
|
55
|
+
force: { type: 'boolean' },
|
|
56
|
+
'rotate-secret': { type: 'boolean' },
|
|
57
|
+
instance: { type: 'string' },
|
|
58
|
+
'fail-on': { type: 'string' },
|
|
59
|
+
now: { type: 'boolean' },
|
|
60
|
+
overlap: { type: 'string' },
|
|
61
|
+
// Any command that receives a secret: print it instead of writing a 0600 file.
|
|
62
|
+
'print-secret': { type: 'boolean' },
|
|
63
|
+
// webhooks create.
|
|
64
|
+
events: { type: 'string' },
|
|
34
65
|
};
|
|
35
66
|
/** Parse argv, turning parseArgs' own errors (unknown/invalid flag) into clean CliErrors. */
|
|
36
67
|
function parse(argv) {
|
|
@@ -55,6 +86,15 @@ function str(values, key) {
|
|
|
55
86
|
const v = values[key];
|
|
56
87
|
return typeof v === 'string' ? v : undefined;
|
|
57
88
|
}
|
|
89
|
+
/** A repeatable string flag's values (each may also be comma-separated), or []. */
|
|
90
|
+
function list(values, key) {
|
|
91
|
+
const v = values[key];
|
|
92
|
+
const raw = Array.isArray(v) ? v : typeof v === 'string' ? [v] : [];
|
|
93
|
+
return raw
|
|
94
|
+
.flatMap((x) => x.split(','))
|
|
95
|
+
.map((x) => x.trim())
|
|
96
|
+
.filter(Boolean);
|
|
97
|
+
}
|
|
58
98
|
/** `--limit` as a positive integer, or undefined. Rejects garbage with a clean error. */
|
|
59
99
|
function limit(values) {
|
|
60
100
|
const raw = str(values, 'limit');
|
package/dist/args.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ParsedArgs } from '../args';
|
|
2
|
+
import type { RunContext } from '../context';
|
|
3
|
+
/**
|
|
4
|
+
* `atlas actions` — manage tenant Actions (code run in the auth pipeline).
|
|
5
|
+
*
|
|
6
|
+
* list the instance's actions
|
|
7
|
+
* deploy <file> --trigger <t> upload a file's code as a new action
|
|
8
|
+
* test <file> [--trigger <t>] dry-run the file OFFLINE through @atlasauth/actions
|
|
9
|
+
* logs <id> where to find an action's execution history
|
|
10
|
+
*/
|
|
11
|
+
export declare function actions(ctx: RunContext, args: ParsedArgs): Promise<number>;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.actions = actions;
|
|
4
|
+
const node_path_1 = require("node:path");
|
|
5
|
+
const actions_1 = require("@atlasauth/actions");
|
|
6
|
+
const args_1 = require("../args");
|
|
7
|
+
const errors_1 = require("../errors");
|
|
8
|
+
const output_1 = require("../output");
|
|
9
|
+
const shared_1 = require("./shared");
|
|
10
|
+
const COLUMNS = [
|
|
11
|
+
{ header: 'ID', get: (a) => a.id },
|
|
12
|
+
{ header: 'NAME', get: (a) => a.name },
|
|
13
|
+
{ header: 'TRIGGER', get: (a) => a.trigger },
|
|
14
|
+
{ header: 'ENABLED', get: (a) => a.enabled },
|
|
15
|
+
{ header: 'SECRETS', get: (a) => a.secret_names },
|
|
16
|
+
{ header: 'UPDATED', get: (a) => (0, output_1.fmtTime)(a.updated_at) },
|
|
17
|
+
];
|
|
18
|
+
/** Validate a `--trigger` value against the known set, with a clean error. */
|
|
19
|
+
function parseTrigger(raw) {
|
|
20
|
+
if (!raw) {
|
|
21
|
+
throw new errors_1.CliError(`--trigger is required (one of: ${actions_1.ACTION_TRIGGERS.join(', ')}).`);
|
|
22
|
+
}
|
|
23
|
+
if (!actions_1.ACTION_TRIGGERS.includes(raw)) {
|
|
24
|
+
throw new errors_1.CliError(`Unknown trigger '${raw}'. Expected one of: ${actions_1.ACTION_TRIGGERS.join(', ')}.`);
|
|
25
|
+
}
|
|
26
|
+
return raw;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* `atlas actions` — manage tenant Actions (code run in the auth pipeline).
|
|
30
|
+
*
|
|
31
|
+
* list the instance's actions
|
|
32
|
+
* deploy <file> --trigger <t> upload a file's code as a new action
|
|
33
|
+
* test <file> [--trigger <t>] dry-run the file OFFLINE through @atlasauth/actions
|
|
34
|
+
* logs <id> where to find an action's execution history
|
|
35
|
+
*/
|
|
36
|
+
async function actions(ctx, args) {
|
|
37
|
+
const sub = args.positionals[1];
|
|
38
|
+
const json = (0, shared_1.wantsJson)(args.values);
|
|
39
|
+
switch (sub) {
|
|
40
|
+
case 'list': {
|
|
41
|
+
const { client } = (0, shared_1.requireClient)(ctx, args.values);
|
|
42
|
+
const page = await client.actions.list();
|
|
43
|
+
if (json)
|
|
44
|
+
(0, output_1.printJson)(ctx.io, page);
|
|
45
|
+
else
|
|
46
|
+
ctx.io.out((0, output_1.renderTable)(COLUMNS, page.data));
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
49
|
+
case 'deploy': {
|
|
50
|
+
const file = (0, shared_1.requireArg)(args.positionals, 2, 'file');
|
|
51
|
+
const trigger = parseTrigger((0, args_1.str)(args.values, 'trigger'));
|
|
52
|
+
const code = ctx.readFile(file);
|
|
53
|
+
if (!code.trim())
|
|
54
|
+
throw new errors_1.CliError(`'${file}' is empty — nothing to deploy.`);
|
|
55
|
+
const name = (0, args_1.str)(args.values, 'name') || (0, node_path_1.basename)(file).replace(/\.[^.]+$/, '');
|
|
56
|
+
const { client } = (0, shared_1.requireClient)(ctx, args.values);
|
|
57
|
+
const action = await client.actions.create({ name, trigger, code });
|
|
58
|
+
if (json)
|
|
59
|
+
(0, output_1.printJson)(ctx.io, action);
|
|
60
|
+
else {
|
|
61
|
+
ctx.io.out(`Deployed action ${action.id} (${action.name}) for ${action.trigger}.`);
|
|
62
|
+
ctx.io.err(`It is created but NOT yet bound to the ${action.trigger} flow — bind it to run it.`);
|
|
63
|
+
}
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
case 'test': {
|
|
67
|
+
const file = (0, shared_1.requireArg)(args.positionals, 2, 'file');
|
|
68
|
+
// Default to post_login's sample event; --trigger picks another shape.
|
|
69
|
+
const trigger = (0, args_1.str)(args.values, 'trigger')
|
|
70
|
+
? parseTrigger((0, args_1.str)(args.values, 'trigger'))
|
|
71
|
+
: 'post_login';
|
|
72
|
+
const code = ctx.readFile(file);
|
|
73
|
+
if (!code.trim())
|
|
74
|
+
throw new errors_1.CliError(`'${file}' is empty — nothing to test.`);
|
|
75
|
+
// OFFLINE: no network, no client — the local harness mirrors the isolate.
|
|
76
|
+
const result = await (0, actions_1.runScript)(code, (0, actions_1.createTestEvent)(trigger));
|
|
77
|
+
if (json) {
|
|
78
|
+
(0, output_1.printJson)(ctx.io, result);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
ctx.io.out(`Trigger: ${trigger}`);
|
|
82
|
+
ctx.io.out(`Denied: ${result.denied}${result.denyReason ? ` (${result.denyReason})` : ''}`);
|
|
83
|
+
ctx.io.out(`ID claims: ${JSON.stringify(result.idTokenClaims)}`);
|
|
84
|
+
ctx.io.out(`AT claims: ${JSON.stringify(result.accessTokenClaims)}`);
|
|
85
|
+
ctx.io.out(`Metadata: ${JSON.stringify(result.appMetadata)}`);
|
|
86
|
+
if (result.logs.length)
|
|
87
|
+
ctx.io.out(`Logs:\n ${result.logs.join('\n ')}`);
|
|
88
|
+
if (result.error)
|
|
89
|
+
ctx.io.err(`Error: ${result.error}`);
|
|
90
|
+
}
|
|
91
|
+
// A thrown error in the action is a failed dry-run → non-zero so CI catches it.
|
|
92
|
+
return result.error ? 1 : 0;
|
|
93
|
+
}
|
|
94
|
+
case 'logs': {
|
|
95
|
+
const id = (0, shared_1.requireArg)(args.positionals, 2, 'action-id');
|
|
96
|
+
// The Backend API does not expose a per-action execution-log endpoint:
|
|
97
|
+
// each run is written as an audit event (`action.<trigger>`) carrying the
|
|
98
|
+
// outcome, duration and captured logs. Point the user at where to read it
|
|
99
|
+
// rather than pretend an endpoint exists.
|
|
100
|
+
const lines = [
|
|
101
|
+
`Atlas does not expose a live log stream for action ${id}.`,
|
|
102
|
+
'Each execution is recorded as an audit event named `action.<trigger>`',
|
|
103
|
+
'(outcome, duration, deny reason / error, and the action\'s console logs).',
|
|
104
|
+
'Read them in the dashboard audit log, or stream them via a configured',
|
|
105
|
+
'log stream. To see what an action WOULD do right now, dry-run it:',
|
|
106
|
+
` atlas actions test <file> --trigger <trigger>`,
|
|
107
|
+
];
|
|
108
|
+
if (json)
|
|
109
|
+
(0, output_1.printJson)(ctx.io, { object: 'action_logs_info', action_id: id, message: lines.join(' ') });
|
|
110
|
+
else
|
|
111
|
+
ctx.io.out(lines.join('\n'));
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
default:
|
|
115
|
+
throw new errors_1.CliError(sub
|
|
116
|
+
? `Unknown subcommand 'actions ${sub}'. Try: list, deploy, test, logs.`
|
|
117
|
+
: 'actions needs a subcommand: list, deploy, test, logs.');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=actions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/commands/actions.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ exports.apiKeys = apiKeys;
|
|
|
4
4
|
const args_1 = require("../args");
|
|
5
5
|
const errors_1 = require("../errors");
|
|
6
6
|
const output_1 = require("../output");
|
|
7
|
+
const secrets_1 = require("../secrets");
|
|
7
8
|
const shared_1 = require("./shared");
|
|
8
9
|
const COLUMNS = [
|
|
9
10
|
{ header: 'ID', get: (k) => k.id },
|
|
@@ -52,13 +53,27 @@ async function apiKeys(ctx, args) {
|
|
|
52
53
|
subject_id: subjectId,
|
|
53
54
|
name: (0, args_1.str)(args.values, 'name'),
|
|
54
55
|
});
|
|
56
|
+
// The secret is revealed exactly once. By default it goes to a 0600 file
|
|
57
|
+
// and only the path is printed; --print-secret is the explicit opt-out.
|
|
58
|
+
const printSecret = args.values['print-secret'] === true;
|
|
59
|
+
const { secret, ...rest } = key;
|
|
60
|
+
if (printSecret) {
|
|
61
|
+
ctx.io.err('atlas: warning: printing the API key because --print-secret was given. It may end up in your shell history, terminal scrollback or CI logs.');
|
|
62
|
+
if (json)
|
|
63
|
+
(0, output_1.printJson)(ctx.io, key);
|
|
64
|
+
else {
|
|
65
|
+
ctx.io.out(`Created API key ${key.id}.`);
|
|
66
|
+
ctx.io.out(`Secret (shown once): ${secret}`);
|
|
67
|
+
}
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
const { path } = (0, secrets_1.writeSecretFile)((0, secrets_1.productDir)(ctx.env, (0, args_1.str)(args.values, 'product') ?? 'atlasauth'), `api-key-${key.id}.env`, { ATLAS_API_KEY: secret ?? '' }, { force: args.values.force === true, comment: `End-user API key ${key.id} (${subjectType} ${subjectId}).` });
|
|
55
71
|
if (json) {
|
|
56
|
-
(0, output_1.printJson)(ctx.io,
|
|
72
|
+
(0, output_1.printJson)(ctx.io, { ...rest, secret_file: path });
|
|
57
73
|
}
|
|
58
74
|
else {
|
|
59
|
-
// The secret is revealed exactly once — make that unmissable.
|
|
60
75
|
ctx.io.out(`Created API key ${key.id}.`);
|
|
61
|
-
ctx.io.out(`Secret
|
|
76
|
+
ctx.io.out(`Secret written to ${path} (mode 0600). It is shown nowhere else.`);
|
|
62
77
|
}
|
|
63
78
|
return 0;
|
|
64
79
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-keys.js","sourceRoot":"","sources":["../../src/commands/api-keys.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"api-keys.js","sourceRoot":"","sources":["../../src/commands/api-keys.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/auth.js
CHANGED
|
@@ -7,6 +7,7 @@ const backend_1 = require("@atlasauth/backend");
|
|
|
7
7
|
const args_1 = require("../args");
|
|
8
8
|
const errors_1 = require("../errors");
|
|
9
9
|
const output_1 = require("../output");
|
|
10
|
+
const project_1 = require("../project");
|
|
10
11
|
const shared_1 = require("./shared");
|
|
11
12
|
/**
|
|
12
13
|
* `atlas login` — prompt for an API URL + a secret key, PROVE the key works
|
|
@@ -27,10 +28,13 @@ async function login(ctx, args) {
|
|
|
27
28
|
const secretKey = (0, args_1.str)(values, 'secret-key') || (await ctx.prompt.secret('Atlas secret key (sk_...)'));
|
|
28
29
|
if (!secretKey)
|
|
29
30
|
throw new errors_1.CliError('A secret key is required to log in.');
|
|
30
|
-
// Prove the credential before persisting it.
|
|
31
|
-
|
|
31
|
+
// Prove the credential before persisting it. A platform key (psk_, for
|
|
32
|
+
// `atlas init`) is proven against the platform API instead.
|
|
32
33
|
try {
|
|
33
|
-
|
|
34
|
+
if (secretKey.startsWith('psk_'))
|
|
35
|
+
await (0, project_1.httpFor)(ctx, { secretKey, apiUrl }).get('/v1/platform/apps');
|
|
36
|
+
else
|
|
37
|
+
await ctx.makeClient({ secretKey, apiUrl }).users.list({ limit: 1 });
|
|
34
38
|
}
|
|
35
39
|
catch (err) {
|
|
36
40
|
if (err instanceof backend_1.AtlasApiError) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
|