@kutrion/cli 0.0.0-stage → 1.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +139 -2
  2. package/dist/index.js +21937 -0
  3. package/package.json +34 -4
package/README.md CHANGED
@@ -1,3 +1,140 @@
1
- # Temporary Holding Version
1
+ # Kutrion CLI (`kt`)
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Vaults, credentials and SSH/SFTP/RDP brokering from the terminal. The published package is a single
4
+ self-contained bundle (the shared client, `ws` and `@noble/post-quantum` are inlined at build time),
5
+ so it installs with no transitive dependencies.
6
+
7
+ ## Install
8
+
9
+ Download the CLI tarball from https://kutrion.com/downloads, then install it with npm from the folder
10
+ you saved it in. It needs Node 18 or newer and pulls in no dependencies:
11
+
12
+ ```sh
13
+ node -v # must report v18 or newer
14
+ npm i -g ./kutrion-cli-<version>.tgz # the leading ./ is required; use the file name you downloaded
15
+ kt --version
16
+ ```
17
+
18
+ `npm i -g @kutrion/cli` does not work: the package is not on the public npm registry.
19
+
20
+ ## First login
21
+
22
+ ```sh
23
+ kt --base https://kutrion.com login --email you@example.com
24
+ ```
25
+
26
+ `login` prompts for the password (and a 2FA code when the account has one), so neither lands in shell
27
+ history; `--password` and `--code` exist for scripts. A successful login saves the server to
28
+ `~/.config/kutrion/config.json`, so every command after it needs no `--base`:
29
+
30
+ ```sh
31
+ kt whoami
32
+ kt vaults
33
+ kt get <vaultId> <credId>
34
+ kt conn add --name web-01 --host 10.0.0.5 --username deploy --cred <credId>
35
+ kt ssh <connId>
36
+ kt --help
37
+ ```
38
+
39
+ Use the address exactly as written. The CLI does not follow a redirect on a login: a redirected POST
40
+ is re-sent without its body, so `kt` stops and prints the address the server pointed to instead.
41
+
42
+ `--base <url>` (or `KT_API_BASE`) points at a server; the token is stored in the OS keychain. There
43
+ is no default: unconfigured, `kt` exits non-zero rather than guessing an address to send credentials
44
+ to. `login` also refuses a plaintext `http://` server unless it is loopback. On a machine with no
45
+ keychain, `KT_TOKEN_STORE=file` keeps the token in `~/.config/kutrion/token` (mode 0600).
46
+
47
+ Precedence is `--base`, then `KT_API_BASE`, then the saved server, and only `login` writes it:
48
+ `--base` on any other command is a one-off that reads a different server without changing the saved
49
+ one. To switch servers, log in again; each server's token is filed under its own URL, so sessions are
50
+ never crossed and logging into one does not end the other. `logout` clears the token for the current
51
+ server and leaves the saved URL, so the next `login` needs no flag either.
52
+
53
+ Environment variables set under the names earlier CLI releases used are still read when the `KT_`
54
+ name is not set, so an existing shell profile or assistant config keeps working.
55
+
56
+ ## Connect an AI assistant (`kt mcp install`)
57
+
58
+ Once logged in, wire an assistant to Kutrion through the CLI's MCP bridge. Your organisation's plan
59
+ needs agent access:
60
+
61
+ ```sh
62
+ kt mcp install --client claude-code # or claude-desktop, cursor, copilot
63
+ kt mcp status # each client's agent, and which clients are wired
64
+ kt mcp uninstall --client claude-code # revoke the agent and remove the config entry
65
+ ```
66
+
67
+ `install` mints an agent for that client, keeps its credential in the OS keychain, writes the
68
+ client's config to launch `kt mcp`, and starts the bridge once to check that it launches. The config
69
+ holds the server address and the client name, never a credential. Follow the next step it prints for
70
+ that client to load the new server.
71
+
72
+ ## Job files in CI (`kt run`)
73
+
74
+ `kt run <file>` executes a declarative job file through the broker. Paired with `kt ci-login`, which
75
+ exchanges the pipeline's own OIDC token for a short-lived principal, a CI job needs no stored
76
+ Kutrion credential and the job file in the repo holds no secret: connections are referenced by name
77
+ and resolved against the caller at run time. A literal `password:`/`value:`/`token:` key anywhere in
78
+ the file is rejected rather than used, and no step type names a vault entry at all — the credential
79
+ a connection uses is the server's business, and a command that tries to interpolate one is refused.
80
+
81
+ ```yaml
82
+ name: deploy smoke
83
+ connections:
84
+ web: prod-web-01 # a connection name, or its id
85
+ steps:
86
+ - name: nginx is up
87
+ exec: { connection: web, command: "systemctl is-active nginx" }
88
+ expect: { exit_code: 0, stdout_contains: active }
89
+
90
+ - name: pull the config
91
+ get: { connection: web, remote: /etc/nginx/nginx.conf, local: ./nginx.conf }
92
+
93
+ - name: publish the healthcheck
94
+ put: { connection: web, local: ./health.sh, remote: /usr/local/bin/health.sh }
95
+
96
+ - name: mirror the artifacts
97
+ sync:
98
+ from: { connection: web, path: /var/artifacts }
99
+ to: { connection: web, path: /backup/artifacts }
100
+ mirror: true
101
+ ```
102
+
103
+ Each step carries exactly one action (`exec`, `get`, `put`, `sync`). `expect` applies to `exec` and
104
+ supports `exit_code`, `stdout_contains`, `stderr_contains`, `stdout_not_contains` and
105
+ `stdout_matches`; a step that asserts nothing still requires exit code 0. The run stops at the first
106
+ failed step and reports the rest as skipped, unless that step sets `continue_on_error: true`.
107
+
108
+ There is no `rotate` step. It was accepted once and is withdrawn: rotating changes a stored
109
+ credential, so a job file naming the wrong one can lock every human out of that system. A file that
110
+ still carries one is refused with that reason rather than silently ignored. Rotate with
111
+ `kt rotation run` or from the web app, where a person is present.
112
+
113
+ ```sh
114
+ export KT_AGENT_TOKEN=$(kt ci-login --trust $KT_OIDC_TRUST_ID) # exchange the pipeline's OIDC token
115
+ kt run kutrion.yml # console reporter, exits non-zero on failure
116
+ kt run kutrion.yml --reporter junit --out report.xml
117
+ kt run kutrion.yml --dry-run # validate and list the steps, touch nothing
118
+ ```
119
+
120
+ On GitLab, the job's OIDC token comes from an `id_tokens:` block that exposes it as `KT_ID_TOKEN`,
121
+ with the audience your trust is registered for. On GitHub Actions, give the job
122
+ `permissions: id-token: write` and `ci-login` requests the token itself.
123
+
124
+ **How a pipeline authenticates.** With `KT_AGENT_TOKEN` set — or `--token <vta_…>` — `kt run` runs
125
+ as that pipeline principal and sends its steps to the server's agent endpoint (`/mcp`) rather than to
126
+ the REST API. It has to: a principal from `ci-login` is an opaque `vta_` token, and every REST route
127
+ verifies a JWT, so an exchanged principal authenticates nothing there. Routing through the agent
128
+ endpoint is also what subjects each step to the organisation's agent tool policy and records it in
129
+ the flight recorder against the pipeline's identity. Without that variable `kt run` uses your own
130
+ stored session over REST, unchanged. `--dry-run` needs neither.
131
+
132
+ Two things differ on the pipeline path. A `get` step receives the file as broker-redacted UTF-8 text
133
+ capped at 1MB rather than raw bytes, and the step says so in its output — do not use it to move a
134
+ binary. And a step the organisation gates on a human approval is refused rather than waited on, since
135
+ a pipeline has nobody to ask.
136
+
137
+ Reporters are `console`, `junit` and `json`. The JUnit document is standard `<testsuites>` XML; a
138
+ GitLab job renders it once the job declares `artifacts:reports:junit`, and GitHub needs a reporting
139
+ action — the file alone is not picked up. With `--out` the report is written to a file and progress
140
+ goes to stderr, so the console stays readable while a machine consumes the file.