@bussolabs/closeyourit-cli 0.24.1 → 0.24.2
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 +3 -0
- package/dist/base.d.ts +12 -0
- package/dist/base.js +16 -0
- package/dist/lib/api.d.ts +12 -0
- package/dist/lib/api.js +25 -3
- package/oclif.manifest.json +8091 -6092
- package/opencli.json +1493 -2
- package/package.json +106 -1
package/README.md
CHANGED
|
@@ -272,6 +272,9 @@ CLOSEYOURIT_TOKEN=cyi_u_… CLOSEYOURIT_API_URL=https://www.closeyour.it \
|
|
|
272
272
|
| `workload promote <action-id> --project <id\|key> [--title] [--description] [--kind] [--status] [--priority]` | Generate a ticket from the action and link it back. |
|
|
273
273
|
|
|
274
274
|
Every command accepts `--json` for machine-readable output and `--help` for usage details.
|
|
275
|
+
Every command also accepts `--yes`: the server refuses a write that goes through a dangerous
|
|
276
|
+
permission (deleting a project, importing or deleting secrets, …) with `R422-CONFIRM-001` until you
|
|
277
|
+
confirm it, and `--yes` is that confirmation. Reads never need it.
|
|
275
278
|
`--project` accepts either a project UUID or its key (matched case-insensitively).
|
|
276
279
|
|
|
277
280
|
`kb publish` needs a backend exposing the atomic Knowledge publication route; an older one fails with
|
package/dist/base.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Command, type Interfaces } from '@oclif/core';
|
|
2
|
+
import type { ArgOutput, FlagOutput, Input, ParserOutput } from '@oclif/core/lib/interfaces/parser';
|
|
2
3
|
import { type CliConfig } from './lib/config';
|
|
3
4
|
import { CliApi } from './lib/api';
|
|
4
5
|
import { type TicketLookup } from './lib/ticket-lookup';
|
|
@@ -28,9 +29,20 @@ export declare function paginationError(opts: {
|
|
|
28
29
|
}): string | undefined;
|
|
29
30
|
export declare abstract class BaseCommand extends Command {
|
|
30
31
|
static enableJsonFlag: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* `--yes` on every command (CYCL-53): the server asks an explicit confirmation for writes that pass
|
|
34
|
+
* through a dangerous permission key (`R422-CONFIRM-001`, CYRA-728). Which keys are dangerous is
|
|
35
|
+
* the server's catalogue, not ours, so the flag is global instead of being sprinkled on the
|
|
36
|
+
* commands we believe are risky today. Harmless elsewhere: the parameter is simply ignored.
|
|
37
|
+
*/
|
|
38
|
+
static baseFlags: {
|
|
39
|
+
yes: Interfaces.BooleanFlag<boolean>;
|
|
40
|
+
};
|
|
31
41
|
protected cfg: CliConfig;
|
|
32
42
|
protected api: CliApi;
|
|
33
43
|
init(): Promise<void>;
|
|
44
|
+
/** Parse as oclif does, then hand `--yes` to the api client before any request leaves. */
|
|
45
|
+
protected parse<F extends FlagOutput, B extends FlagOutput, A extends ArgOutput>(options?: Input<F, B, A>, argv?: string[]): Promise<ParserOutput<F, B, A>>;
|
|
34
46
|
/**
|
|
35
47
|
* Resolve a project reference (UUID passes through; otherwise matched by key, case-insensitive).
|
|
36
48
|
* Walks every page of `/cli/v1/projects`: a key can live past the first page, so a single-page
|
package/dist/base.js
CHANGED
|
@@ -38,6 +38,15 @@ function paginationError(opts) {
|
|
|
38
38
|
}
|
|
39
39
|
class BaseCommand extends core_1.Command {
|
|
40
40
|
static enableJsonFlag = true;
|
|
41
|
+
/**
|
|
42
|
+
* `--yes` on every command (CYCL-53): the server asks an explicit confirmation for writes that pass
|
|
43
|
+
* through a dangerous permission key (`R422-CONFIRM-001`, CYRA-728). Which keys are dangerous is
|
|
44
|
+
* the server's catalogue, not ours, so the flag is global instead of being sprinkled on the
|
|
45
|
+
* commands we believe are risky today. Harmless elsewhere: the parameter is simply ignored.
|
|
46
|
+
*/
|
|
47
|
+
static baseFlags = {
|
|
48
|
+
yes: core_1.Flags.boolean({ description: 'Confirm a dangerous action the server would otherwise refuse (R422-CONFIRM-001)', default: false }),
|
|
49
|
+
};
|
|
41
50
|
cfg;
|
|
42
51
|
api;
|
|
43
52
|
async init() {
|
|
@@ -45,6 +54,13 @@ class BaseCommand extends core_1.Command {
|
|
|
45
54
|
this.cfg = (0, config_1.loadConfig)();
|
|
46
55
|
this.api = new api_1.CliApi(this.cfg);
|
|
47
56
|
}
|
|
57
|
+
/** Parse as oclif does, then hand `--yes` to the api client before any request leaves. */
|
|
58
|
+
async parse(options, argv) {
|
|
59
|
+
const parsed = await super.parse(options, argv);
|
|
60
|
+
if (this.api)
|
|
61
|
+
this.api.confirm = parsed.flags.yes === true;
|
|
62
|
+
return parsed;
|
|
63
|
+
}
|
|
48
64
|
/**
|
|
49
65
|
* Resolve a project reference (UUID passes through; otherwise matched by key, case-insensitive).
|
|
50
66
|
* Walks every page of `/cli/v1/projects`: a key can live past the first page, so a single-page
|
package/dist/lib/api.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface UploadFile {
|
|
|
23
23
|
data: Blob;
|
|
24
24
|
}
|
|
25
25
|
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
26
|
+
/** Error code the server answers when a dangerous write arrives without the confirm gesture (CYRA-728). */
|
|
27
|
+
export declare const CONFIRMATION_REQUIRED_CODE = "R422-CONFIRM-001";
|
|
26
28
|
export declare class CliApi {
|
|
27
29
|
private readonly config;
|
|
28
30
|
/**
|
|
@@ -32,6 +34,14 @@ export declare class CliApi {
|
|
|
32
34
|
* commands (CYCL-11). The instance is per-command, so this is that command's last response.
|
|
33
35
|
*/
|
|
34
36
|
lastMeta?: Record<string, unknown>;
|
|
37
|
+
/**
|
|
38
|
+
* The user confirmed dangerous actions (`--yes`, CYCL-53). The server (CYRA-728) refuses any
|
|
39
|
+
* write through a `dangerous` permission key without the `confirm` parameter and answers
|
|
40
|
+
* `R422-CONFIRM-001`: not a permission problem, a missing gesture. `BaseCommand.parse` sets it;
|
|
41
|
+
* `request()` then adds `confirm=1` to every writing call — in the query string, so DELETE
|
|
42
|
+
* without a body is covered too. Reads never carry it: looking is not executing.
|
|
43
|
+
*/
|
|
44
|
+
confirm: boolean;
|
|
35
45
|
constructor(config: CliConfig);
|
|
36
46
|
request<T = unknown>(method: HttpMethod, path: string, opts?: RequestOptions): Promise<Envelope<T>>;
|
|
37
47
|
/**
|
|
@@ -39,6 +49,8 @@ export declare class CliApi {
|
|
|
39
49
|
* The boundary Content-Type is derived by fetch from the FormData body — never set it by hand.
|
|
40
50
|
*/
|
|
41
51
|
upload<T = unknown>(method: 'POST' | 'PUT', path: string, files: UploadFile[], opts?: RequestOptions): Promise<Envelope<T>>;
|
|
52
|
+
/** Add `confirm=1` to a writing request when the user passed `--yes`; reads are left alone. */
|
|
53
|
+
private withConfirmation;
|
|
42
54
|
private resolveUrl;
|
|
43
55
|
/** Build the shared Accept + Authorization headers; throws (before any fetch) if an authed call has no token. */
|
|
44
56
|
private authHeaders;
|
package/dist/lib/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CliApi = exports.ApiRequestError = void 0;
|
|
3
|
+
exports.CliApi = exports.CONFIRMATION_REQUIRED_CODE = exports.ApiRequestError = void 0;
|
|
4
4
|
const error_codes_1 = require("../errors/error-codes");
|
|
5
5
|
/** Error carrying the HTTP status and the structured code from the backend envelope (R/G prefix) or a local C-prefix fallback. */
|
|
6
6
|
class ApiRequestError extends Error {
|
|
@@ -16,6 +16,9 @@ class ApiRequestError extends Error {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
exports.ApiRequestError = ApiRequestError;
|
|
19
|
+
/** Error code the server answers when a dangerous write arrives without the confirm gesture (CYRA-728). */
|
|
20
|
+
exports.CONFIRMATION_REQUIRED_CODE = 'R422-CONFIRM-001';
|
|
21
|
+
const READ_METHODS = new Set(['GET', 'HEAD', 'OPTIONS']);
|
|
19
22
|
class CliApi {
|
|
20
23
|
config;
|
|
21
24
|
/**
|
|
@@ -25,13 +28,21 @@ class CliApi {
|
|
|
25
28
|
* commands (CYCL-11). The instance is per-command, so this is that command's last response.
|
|
26
29
|
*/
|
|
27
30
|
lastMeta;
|
|
31
|
+
/**
|
|
32
|
+
* The user confirmed dangerous actions (`--yes`, CYCL-53). The server (CYRA-728) refuses any
|
|
33
|
+
* write through a `dangerous` permission key without the `confirm` parameter and answers
|
|
34
|
+
* `R422-CONFIRM-001`: not a permission problem, a missing gesture. `BaseCommand.parse` sets it;
|
|
35
|
+
* `request()` then adds `confirm=1` to every writing call — in the query string, so DELETE
|
|
36
|
+
* without a body is covered too. Reads never carry it: looking is not executing.
|
|
37
|
+
*/
|
|
38
|
+
confirm = false;
|
|
28
39
|
constructor(config) {
|
|
29
40
|
this.config = config;
|
|
30
41
|
}
|
|
31
42
|
async request(method, path, opts = {}) {
|
|
32
43
|
const headers = this.authHeaders(opts.auth !== false);
|
|
33
44
|
headers['Content-Type'] = 'application/json';
|
|
34
|
-
const url = this.resolveUrl(path);
|
|
45
|
+
const url = this.resolveUrl(this.withConfirmation(method, path));
|
|
35
46
|
let res;
|
|
36
47
|
try {
|
|
37
48
|
res = await fetch(url, {
|
|
@@ -70,6 +81,12 @@ class CliApi {
|
|
|
70
81
|
}
|
|
71
82
|
return this.handleResponse(res);
|
|
72
83
|
}
|
|
84
|
+
/** Add `confirm=1` to a writing request when the user passed `--yes`; reads are left alone. */
|
|
85
|
+
withConfirmation(method, path) {
|
|
86
|
+
if (!this.confirm || READ_METHODS.has(method))
|
|
87
|
+
return path;
|
|
88
|
+
return `${path}${path.includes('?') ? '&' : '?'}confirm=1`;
|
|
89
|
+
}
|
|
73
90
|
resolveUrl(path) {
|
|
74
91
|
return this.config.apiUrl.replace(/\/+$/, '') + path;
|
|
75
92
|
}
|
|
@@ -102,7 +119,12 @@ class CliApi {
|
|
|
102
119
|
if (!res.ok) {
|
|
103
120
|
const envelope = (json ?? {});
|
|
104
121
|
const error = envelope.error ?? {};
|
|
105
|
-
|
|
122
|
+
let message = error.message ?? res.statusText ?? `Request failed (${res.status})`;
|
|
123
|
+
// The server names the gesture it wants but not the flag that makes it: say it here, once.
|
|
124
|
+
if (error.code === exports.CONFIRMATION_REQUIRED_CODE && !message.includes('--yes')) {
|
|
125
|
+
message = `${message} Re-run with --yes to confirm this dangerous action.`;
|
|
126
|
+
}
|
|
127
|
+
throw new ApiRequestError(res.status, error.code ?? `C${res.status}-API-000`, message, error.details);
|
|
106
128
|
}
|
|
107
129
|
const envelope = (json ?? {});
|
|
108
130
|
this.lastMeta = envelope.meta;
|