@hardfin/cli 0.0.2-dev.8 → 0.0.2-dev.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/README.md +97 -6
- package/dist/cli.js +2122 -1118
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -7,8 +7,8 @@ It is built for people at a terminal and for agents that call Hardfin on their b
|
|
|
7
7
|
|
|
8
8
|
## Status
|
|
9
9
|
|
|
10
|
-
The CLI is early.
|
|
11
|
-
|
|
10
|
+
The CLI is early. Signing in works against a Hardfin that publishes an authorization
|
|
11
|
+
server, and every command also accepts an API key.
|
|
12
12
|
|
|
13
13
|
## Install
|
|
14
14
|
|
|
@@ -97,6 +97,98 @@ The first one matters because `hardfinhq/api-spec` can sit a release behind the
|
|
|
97
97
|
while its bridge pull request is open. Generating from that document would replace the
|
|
98
98
|
current commands with an earlier API's.
|
|
99
99
|
|
|
100
|
+
## Signing in
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
hardfin login # approve this CLI in a browser
|
|
104
|
+
hardfin status # what the CLI is configured with and signed in as
|
|
105
|
+
hardfin logout # forget this machine, and ask Hardfin to revoke it
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
An API key is still the way to run unattended. `HARDFIN_API_KEY` wins over a stored sign in,
|
|
109
|
+
so CI and an agent sandbox need no browser.
|
|
110
|
+
|
|
111
|
+
### What login does
|
|
112
|
+
|
|
113
|
+
1. Reads `/.well-known/oauth-authorization-server` at the API's host, which names every
|
|
114
|
+
endpoint, including the authorize endpoint on the app host
|
|
115
|
+
2. Opens a loopback listener on `127.0.0.1`, over IPv4, on whatever port the machine hands out
|
|
116
|
+
3. Opens the browser to approve this CLI, with a PKCE challenge and a state value
|
|
117
|
+
4. Prints the URL, and waits at the keyboard as well as on the listener
|
|
118
|
+
5. Checks the state and the `iss` it came back with, then trades the code for tokens
|
|
119
|
+
6. Keeps the refresh token, and nothing else
|
|
120
|
+
|
|
121
|
+
While it waits, the terminal takes two things.
|
|
122
|
+
|
|
123
|
+
| Key | Does |
|
|
124
|
+
| --- | --- |
|
|
125
|
+
| `c` | Copies the URL to the clipboard |
|
|
126
|
+
| A pasted value, then enter | Finishes the sign in without the listener |
|
|
127
|
+
|
|
128
|
+
Paste whichever of these you have: the whole redirect URL from the browser's address bar,
|
|
129
|
+
`code#state`, or the code alone. A browser on another machine never reaches this listener,
|
|
130
|
+
and the redirect it failed to follow is still in the address bar.
|
|
131
|
+
|
|
132
|
+
On WSL the browser is opened through Windows, by `wslview`, then PowerShell, then
|
|
133
|
+
`explorer.exe`, because `xdg-open` reaches nothing outside the distribution.
|
|
134
|
+
|
|
135
|
+
The port changes every time, so Hardfin matches a loopback redirect by everything except its
|
|
136
|
+
port, which is what RFC 8252 asks of an authorization server.
|
|
137
|
+
|
|
138
|
+
### Where the refresh token is kept
|
|
139
|
+
|
|
140
|
+
| Host | Kept in |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| macOS, Windows, and Linux with a secret service | the OS keyring |
|
|
143
|
+
| Everything else, including WSL, containers, and agent sandboxes | `$XDG_STATE_HOME/hardfin/credentials.json`, mode 0600 |
|
|
144
|
+
|
|
145
|
+
`HARDFIN_NO_BROWSER=1` keeps `hardfin login` from opening a tab, which is what a script or a
|
|
146
|
+
headless host wants. `HARDFIN_CREDENTIAL_STORE=file` forces the file. `hardfin status` reports which one holds
|
|
147
|
+
the credential, and where.
|
|
148
|
+
|
|
149
|
+
Access tokens are never written anywhere. One is fetched when a command needs it and lives
|
|
150
|
+
in that process only, so what sits at rest is revocable with `hardfin logout`.
|
|
151
|
+
|
|
152
|
+
A credential is filed under the authorization server it came from, so a local build and
|
|
153
|
+
production never share a sign in.
|
|
154
|
+
|
|
155
|
+
### What it needs configured
|
|
156
|
+
|
|
157
|
+
Nothing. Hardfin registers this CLI as a first-party client, and its key is the same in every
|
|
158
|
+
environment, so `hardfin login` works out of the box.
|
|
159
|
+
|
|
160
|
+
| Setting | Holds | Default |
|
|
161
|
+
| --- | --- | --- |
|
|
162
|
+
| `clientId`, or `HARDFIN_CLIENT_ID` | the client this CLI names itself as | the seeded Hardfin CLI client |
|
|
163
|
+
| `issuerUrl`, or `HARDFIN_ISSUER_URL` | the authorization server | the API's host root |
|
|
164
|
+
|
|
165
|
+
## Diagnosing a problem
|
|
166
|
+
|
|
167
|
+
`hardfin status` prints everything a support request needs, and is the first thing to send.
|
|
168
|
+
|
|
169
|
+
```sh
|
|
170
|
+
hardfin status # for you
|
|
171
|
+
hardfin status --json # for a support request
|
|
172
|
+
hardfin status --offline # no network calls at all
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
| Section | Holds |
|
|
176
|
+
| --- | --- |
|
|
177
|
+
| `cli` | The version, the API version it speaks, Node, and whether a terminal is attached |
|
|
178
|
+
| `host` | The operating system, kernel, build, processor, memory, timezone, shell, and the distribution and WSL details on Linux |
|
|
179
|
+
| `configuration` | Every setting, its value, and the layer it came from |
|
|
180
|
+
| `credential` | Whether you are signed in, where the refresh token is kept, and when it was issued and last renewed |
|
|
181
|
+
| `authorizationServer` | Whether discovery worked, and every endpoint it named |
|
|
182
|
+
| `api` | Whether the API accepted the credential, when the access token expires, and its scopes |
|
|
183
|
+
|
|
184
|
+
Nothing secret is printed. An API key and a refresh token are each reported as a
|
|
185
|
+
`sha256:` fingerprint, which identifies a credential across two machines without disclosing
|
|
186
|
+
it.
|
|
187
|
+
|
|
188
|
+
`refreshExpiresAt` is an estimate. Hardfin expires an unused refresh token after 90 days,
|
|
189
|
+
but the token endpoint reports no expiry, so the CLI applies that rule to the date it last
|
|
190
|
+
renewed. The flag `refreshExpiryIsEstimated` says so in the output.
|
|
191
|
+
|
|
100
192
|
## Local configuration
|
|
101
193
|
|
|
102
194
|
A local build reaches a local server without editing code. Four layers supply the same
|
|
@@ -117,13 +209,12 @@ An exported variable beats `.env` because Node leaves a variable that is already
|
|
|
117
209
|
```json
|
|
118
210
|
{
|
|
119
211
|
"apiUrl": "http://localhost:8080/v2",
|
|
120
|
-
"
|
|
212
|
+
"clientId": "https://hardfin.com/cli/client.json"
|
|
121
213
|
}
|
|
122
214
|
```
|
|
123
215
|
|
|
124
|
-
The
|
|
125
|
-
|
|
126
|
-
`clientId`, and `auth` holding `authorizeUrl`, `tokenUrl`, `deviceUrl`, and `revokeUrl`.
|
|
216
|
+
The authorization server sits at the API's host, so pointing at a local server moves signing
|
|
217
|
+
in with it. The keys are `apiUrl`, `apiKey`, `clientId`, and `issuerUrl`.
|
|
127
218
|
|
|
128
219
|
A key the file does not define fails the command with exit code 2. A typo that was silently
|
|
129
220
|
ignored would look like a setting that never applied.
|