@ciphrix/cli 0.1.0 → 0.1.1
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 +1 -1
- package/dist/cli.js +27 -3
- package/dist/commands/asset.d.ts +4 -1
- package/dist/commands/asset.js +15 -8
- package/dist/commands/context.js +9 -7
- package/dist/commands/control.d.ts +2 -1
- package/dist/commands/control.js +16 -1
- package/dist/commands/framework.d.ts +3 -1
- package/dist/commands/framework.js +18 -3
- package/dist/commands/policy.js +1 -1
- package/dist/commands/test.d.ts +3 -1
- package/dist/commands/test.js +15 -1
- package/dist/commands/vendor.d.ts +4 -1
- package/dist/commands/vendor.js +7 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/toolSurface.d.ts +8 -0
- package/dist/toolSurface.js +45 -0
- package/dist/upload.d.ts +1 -1
- package/dist/upload.js +2 -2
- package/package.json +1 -1
- package/skills/ciphrix/references/commands.md +30 -17
package/README.md
CHANGED
|
@@ -164,7 +164,7 @@ one command. Installed help is authoritative. The complete generated reference i
|
|
|
164
164
|
- Destructive and consequential actions require confirmation unless `--yes` is explicitly supplied.
|
|
165
165
|
- JSON output is undecorated and suitable for programs and agents.
|
|
166
166
|
- Requests time out, responses are size-limited, and local evidence uploads reject symbolic links and
|
|
167
|
-
files over
|
|
167
|
+
files over 25 MiB.
|
|
168
168
|
|
|
169
169
|
Please report vulnerabilities privately as described in [SECURITY.md](SECURITY.md).
|
|
170
170
|
|
package/dist/cli.js
CHANGED
|
@@ -305,6 +305,8 @@ export const createProgram = (io = createDefaultIO()) => {
|
|
|
305
305
|
.requiredOption('--type <type>', 'item type: native_doc or check')
|
|
306
306
|
.option('--run <id>', 'a specific run')
|
|
307
307
|
.option('--search <text>', 'filter by item name')
|
|
308
|
+
.option('--page <n>', 'page number')
|
|
309
|
+
.option('--limit <n>', 'page size')
|
|
308
310
|
.option('--api-url <url>', 'override the API base URL for this command')
|
|
309
311
|
.option('--json', 'output raw JSON')
|
|
310
312
|
.action(async (name, options) => {
|
|
@@ -314,6 +316,8 @@ export const createProgram = (io = createDefaultIO()) => {
|
|
|
314
316
|
runId: readStringOption(options, 'run'),
|
|
315
317
|
itemType: readStringOption(options, 'type') ?? 'native_doc',
|
|
316
318
|
search: readStringOption(options, 'search'),
|
|
319
|
+
page: readNumberOption(options, 'page'),
|
|
320
|
+
limit: readNumberOption(options, 'limit'),
|
|
317
321
|
apiUrl: readStringOption(options, 'apiUrl'),
|
|
318
322
|
json: readBooleanOption(options, 'json'),
|
|
319
323
|
});
|
|
@@ -454,6 +458,8 @@ export const createProgram = (io = createDefaultIO()) => {
|
|
|
454
458
|
.description('List items that can be mapped to a clause')
|
|
455
459
|
.requiredOption('--type <type>', 'item type: test or document')
|
|
456
460
|
.option('--search <text>', 'filter by item name')
|
|
461
|
+
.option('--page <n>', 'page number')
|
|
462
|
+
.option('--limit <n>', 'page size')
|
|
457
463
|
.option('--api-url <url>', 'override the API base URL for this command')
|
|
458
464
|
.option('--json', 'output raw JSON')
|
|
459
465
|
.action(async (frameworkName, clause, options) => {
|
|
@@ -463,6 +469,8 @@ export const createProgram = (io = createDefaultIO()) => {
|
|
|
463
469
|
clause,
|
|
464
470
|
itemType: readStringOption(options, 'type') ?? 'test',
|
|
465
471
|
search: readStringOption(options, 'search'),
|
|
472
|
+
page: readNumberOption(options, 'page'),
|
|
473
|
+
limit: readNumberOption(options, 'limit'),
|
|
466
474
|
apiUrl: readStringOption(options, 'apiUrl'),
|
|
467
475
|
json: readBooleanOption(options, 'json'),
|
|
468
476
|
});
|
|
@@ -523,10 +531,13 @@ export const createProgram = (io = createDefaultIO()) => {
|
|
|
523
531
|
.command('list')
|
|
524
532
|
.description('List assets with their code, status and classification')
|
|
525
533
|
.option('--name <text>', 'filter by name')
|
|
526
|
-
.option('--category <
|
|
534
|
+
.option('--category <csv>', 'filter by category')
|
|
535
|
+
.option('--sub-category <csv>', 'filter by sub-category')
|
|
527
536
|
.option('--status <csv>', 'filter by status')
|
|
528
|
-
.option('--business-impact <
|
|
529
|
-
.option('--data-classification <
|
|
537
|
+
.option('--business-impact <csv>', 'filter by business impact')
|
|
538
|
+
.option('--data-classification <csv>', 'filter by data classification')
|
|
539
|
+
.option('--source <csv>', 'filter by discovery source (provider, e.g. aws, azure, gcp)')
|
|
540
|
+
.option('--technical-owner-email <email>', 'filter by technical owner email')
|
|
530
541
|
.option('--page <n>', 'page number')
|
|
531
542
|
.option('--limit <n>', 'page size')
|
|
532
543
|
.option('--api-url <url>', 'override the API base URL for this command')
|
|
@@ -536,9 +547,12 @@ export const createProgram = (io = createDefaultIO()) => {
|
|
|
536
547
|
io,
|
|
537
548
|
name: readStringOption(options, 'name'),
|
|
538
549
|
category: readStringOption(options, 'category'),
|
|
550
|
+
subCategory: readStringOption(options, 'subCategory'),
|
|
539
551
|
status: readStringOption(options, 'status'),
|
|
540
552
|
businessImpact: readStringOption(options, 'businessImpact'),
|
|
541
553
|
dataClassification: readStringOption(options, 'dataClassification'),
|
|
554
|
+
source: readStringOption(options, 'source'),
|
|
555
|
+
technicalOwnerEmail: readStringOption(options, 'technicalOwnerEmail'),
|
|
542
556
|
page: readNumberOption(options, 'page'),
|
|
543
557
|
limit: readNumberOption(options, 'limit'),
|
|
544
558
|
apiUrl: readStringOption(options, 'apiUrl'),
|
|
@@ -756,7 +770,10 @@ export const createProgram = (io = createDefaultIO()) => {
|
|
|
756
770
|
.description('Create a vendor')
|
|
757
771
|
.requiredOption('--name <name>', 'vendor name')
|
|
758
772
|
.option('--category <value>', 'category')
|
|
773
|
+
.option('--subcategory <value>', 'sub-category')
|
|
759
774
|
.option('--criticality <value>', 'criticality')
|
|
775
|
+
.option('--data-sensitivity <value>', 'data sensitivity')
|
|
776
|
+
.option('--service-availability <value>', 'service availability')
|
|
760
777
|
.option('--description <text>', 'description')
|
|
761
778
|
.option('--api-url <url>', 'override the API base URL for this command')
|
|
762
779
|
.option('--json', 'output raw JSON')
|
|
@@ -765,7 +782,10 @@ export const createProgram = (io = createDefaultIO()) => {
|
|
|
765
782
|
io,
|
|
766
783
|
name: readStringOption(options, 'name') ?? '',
|
|
767
784
|
category: readStringOption(options, 'category'),
|
|
785
|
+
subcategory: readStringOption(options, 'subcategory'),
|
|
768
786
|
criticality: readStringOption(options, 'criticality'),
|
|
787
|
+
dataSensitivity: readStringOption(options, 'dataSensitivity'),
|
|
788
|
+
serviceAvailability: readStringOption(options, 'serviceAvailability'),
|
|
769
789
|
description: readStringOption(options, 'description'),
|
|
770
790
|
apiUrl: readStringOption(options, 'apiUrl'),
|
|
771
791
|
json: readBooleanOption(options, 'json'),
|
|
@@ -836,6 +856,7 @@ export const createProgram = (io = createDefaultIO()) => {
|
|
|
836
856
|
.option('--domain <value>', 'filter by control domain')
|
|
837
857
|
.option('--status <csv>', 'filter by status')
|
|
838
858
|
.option('--applicability <value>', 'filter by applicability (in_scope|out_of_scope)')
|
|
859
|
+
.option('--owner <csv>', 'filter by owner user id')
|
|
839
860
|
.option('--page <n>', 'page number')
|
|
840
861
|
.option('--limit <n>', 'page size')
|
|
841
862
|
.option('--api-url <url>', 'override the API base URL for this command')
|
|
@@ -847,6 +868,7 @@ export const createProgram = (io = createDefaultIO()) => {
|
|
|
847
868
|
domain: readStringOption(options, 'domain'),
|
|
848
869
|
status: readStringOption(options, 'status'),
|
|
849
870
|
applicability: readStringOption(options, 'applicability'),
|
|
871
|
+
ownerId: readStringOption(options, 'owner'),
|
|
850
872
|
page: readNumberOption(options, 'page'),
|
|
851
873
|
limit: readNumberOption(options, 'limit'),
|
|
852
874
|
apiUrl: readStringOption(options, 'apiUrl'),
|
|
@@ -914,6 +936,7 @@ export const createProgram = (io = createDefaultIO()) => {
|
|
|
914
936
|
.option('--justification <text>', 'why the applicability changed')
|
|
915
937
|
.option('--design-requirements <state>', 'not_assessed | not_needed | not_met | partial | met')
|
|
916
938
|
.option('--notes <text>', 'notes (Markdown)')
|
|
939
|
+
.option('--description <text>', 'description (custom controls only)')
|
|
917
940
|
.option('--rename <text>', 'new name (custom controls only)')
|
|
918
941
|
.option('--yes', 'apply without prompting')
|
|
919
942
|
.option('--api-url <url>', 'override the API base URL for this command')
|
|
@@ -928,6 +951,7 @@ export const createProgram = (io = createDefaultIO()) => {
|
|
|
928
951
|
['justification', 'justification'],
|
|
929
952
|
['designRequirements', 'designRequirements'],
|
|
930
953
|
['notes', 'notes'],
|
|
954
|
+
['description', 'description'],
|
|
931
955
|
['rename', 'name'],
|
|
932
956
|
]) {
|
|
933
957
|
const value = readStringOption(options, flag);
|
package/dist/commands/asset.d.ts
CHANGED
|
@@ -6,12 +6,15 @@ export interface AssetCommonOptions {
|
|
|
6
6
|
json?: boolean | undefined;
|
|
7
7
|
credentialStore?: CredentialStore | undefined;
|
|
8
8
|
}
|
|
9
|
-
export declare const assetListCommand: ({ io, apiUrl, json, credentialStore, name, category, status, businessImpact, dataClassification, page, limit, }: AssetCommonOptions & {
|
|
9
|
+
export declare const assetListCommand: ({ io, apiUrl, json, credentialStore, name, category, subCategory, status, businessImpact, dataClassification, source, technicalOwnerEmail, page, limit, }: AssetCommonOptions & {
|
|
10
10
|
name?: string | undefined;
|
|
11
11
|
category?: string | undefined;
|
|
12
|
+
subCategory?: string | undefined;
|
|
12
13
|
status?: string | undefined;
|
|
13
14
|
businessImpact?: string | undefined;
|
|
14
15
|
dataClassification?: string | undefined;
|
|
16
|
+
source?: string | undefined;
|
|
17
|
+
technicalOwnerEmail?: string | undefined;
|
|
15
18
|
page?: number | undefined;
|
|
16
19
|
limit?: number | undefined;
|
|
17
20
|
}) => Promise<void>;
|
package/dist/commands/asset.js
CHANGED
|
@@ -2,22 +2,29 @@ import { applyTool } from '../actions.js';
|
|
|
2
2
|
import { writeLine, writeNextHint, writePageFooter, writeTable, clip } from '../io.js';
|
|
3
3
|
import { asRecord, asText, callTool, errorMessage, resolveToolContext } from '../toolSurface.js';
|
|
4
4
|
const text = (value, fallback = '-') => typeof value === 'string' ? value : typeof value === 'number' ? String(value) : fallback;
|
|
5
|
-
export const assetListCommand = async ({ io, apiUrl, json = false, credentialStore, name, category, status, businessImpact, dataClassification, page, limit, }) => {
|
|
5
|
+
export const assetListCommand = async ({ io, apiUrl, json = false, credentialStore, name, category, subCategory, status, businessImpact, dataClassification, source, technicalOwnerEmail, page, limit, }) => {
|
|
6
6
|
const ctx = await resolveToolContext(apiUrl, credentialStore);
|
|
7
|
+
const csv = (value) => value
|
|
8
|
+
.split(',')
|
|
9
|
+
.map((entry) => entry.trim())
|
|
10
|
+
.filter(Boolean);
|
|
7
11
|
const input = {};
|
|
8
12
|
if (name)
|
|
9
13
|
input.name = name;
|
|
10
14
|
if (category)
|
|
11
|
-
input.category =
|
|
15
|
+
input.category = csv(category);
|
|
16
|
+
if (subCategory)
|
|
17
|
+
input.subCategory = csv(subCategory);
|
|
12
18
|
if (status)
|
|
13
|
-
input.status = status
|
|
14
|
-
.split(',')
|
|
15
|
-
.map((value) => value.trim())
|
|
16
|
-
.filter(Boolean);
|
|
19
|
+
input.status = csv(status);
|
|
17
20
|
if (businessImpact)
|
|
18
|
-
input.businessImpact =
|
|
21
|
+
input.businessImpact = csv(businessImpact);
|
|
19
22
|
if (dataClassification)
|
|
20
|
-
input.dataClassification =
|
|
23
|
+
input.dataClassification = csv(dataClassification);
|
|
24
|
+
if (source)
|
|
25
|
+
input.source = csv(source);
|
|
26
|
+
if (technicalOwnerEmail)
|
|
27
|
+
input.technicalOwnerEmail = technicalOwnerEmail;
|
|
21
28
|
if (page)
|
|
22
29
|
input.page = page;
|
|
23
30
|
if (limit)
|
package/dist/commands/context.js
CHANGED
|
@@ -68,15 +68,17 @@ export const contextSetCommand = async ({ io, apiUrl, json = false, target, valu
|
|
|
68
68
|
if (!questionId)
|
|
69
69
|
throw new Error('A question id is required, for example business.company_size');
|
|
70
70
|
const ctx = await resolveToolContext(apiUrl, credentialStore);
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
const result = await applyTool({
|
|
72
|
+
ctx,
|
|
73
|
+
io,
|
|
74
|
+
toolName: 'set_context_answer',
|
|
75
|
+
input: { store, questionId, value: parseValue(value) },
|
|
76
|
+
fallback: 'Could not save the answer.',
|
|
75
77
|
});
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
+
if (!result)
|
|
79
|
+
return;
|
|
78
80
|
if (json) {
|
|
79
|
-
writeLine(io.stdout, JSON.stringify(
|
|
81
|
+
writeLine(io.stdout, JSON.stringify(result.data, null, 2));
|
|
80
82
|
return;
|
|
81
83
|
}
|
|
82
84
|
writeLine(io.stdout, `${io.theme.green('✓')} ${store}.${questionId} saved`);
|
|
@@ -9,11 +9,12 @@ export interface ControlCommonOptions {
|
|
|
9
9
|
export interface ControlReadOptions extends ControlCommonOptions {
|
|
10
10
|
name: string;
|
|
11
11
|
}
|
|
12
|
-
export declare const controlListCommand: ({ io, apiUrl, json, credentialStore, search, domain, status, applicability, page, limit, }: ControlCommonOptions & {
|
|
12
|
+
export declare const controlListCommand: ({ io, apiUrl, json, credentialStore, search, domain, status, applicability, ownerId, page, limit, }: ControlCommonOptions & {
|
|
13
13
|
search?: string | undefined;
|
|
14
14
|
domain?: string | undefined;
|
|
15
15
|
status?: string | undefined;
|
|
16
16
|
applicability?: string | undefined;
|
|
17
|
+
ownerId?: string | undefined;
|
|
17
18
|
page?: number | undefined;
|
|
18
19
|
limit?: number | undefined;
|
|
19
20
|
}) => Promise<void>;
|
package/dist/commands/control.js
CHANGED
|
@@ -2,7 +2,7 @@ import { applyTool } from '../actions.js';
|
|
|
2
2
|
import { writeLine, writeNextHint, writePageFooter, writeTable } from '../io.js';
|
|
3
3
|
import { asRecord, asText, callTool, errorMessage, resolveToolContext } from '../toolSurface.js';
|
|
4
4
|
const text = (value, fallback = '-') => typeof value === 'string' ? value : typeof value === 'number' ? String(value) : fallback;
|
|
5
|
-
export const controlListCommand = async ({ io, apiUrl, json = false, credentialStore, search, domain, status, applicability, page, limit, }) => {
|
|
5
|
+
export const controlListCommand = async ({ io, apiUrl, json = false, credentialStore, search, domain, status, applicability, ownerId, page, limit, }) => {
|
|
6
6
|
const ctx = await resolveToolContext(apiUrl, credentialStore);
|
|
7
7
|
const input = {};
|
|
8
8
|
if (search)
|
|
@@ -16,6 +16,11 @@ export const controlListCommand = async ({ io, apiUrl, json = false, credentialS
|
|
|
16
16
|
.filter(Boolean);
|
|
17
17
|
if (applicability)
|
|
18
18
|
input.applicability = [applicability];
|
|
19
|
+
if (ownerId)
|
|
20
|
+
input.ownerId = ownerId
|
|
21
|
+
.split(',')
|
|
22
|
+
.map((value) => value.trim())
|
|
23
|
+
.filter(Boolean);
|
|
19
24
|
if (page)
|
|
20
25
|
input.page = page;
|
|
21
26
|
if (limit)
|
|
@@ -145,6 +150,16 @@ export const controlAvailableItemsCommand = async ({ io, name, itemType, apiUrl,
|
|
|
145
150
|
const record = asRecord(item);
|
|
146
151
|
return [text(record.name, text(record.id)), text(record.status)];
|
|
147
152
|
}));
|
|
153
|
+
const total = typeof data.total === 'number' ? data.total : items.length;
|
|
154
|
+
const currentPage = typeof data.page === 'number' ? data.page : 1;
|
|
155
|
+
const pageSize = typeof data.limit === 'number' ? data.limit : 25;
|
|
156
|
+
writePageFooter(io, {
|
|
157
|
+
shown: items.length,
|
|
158
|
+
total,
|
|
159
|
+
page: currentPage,
|
|
160
|
+
limit: pageSize,
|
|
161
|
+
hasMore: data.hasMore === true || currentPage * pageSize < total,
|
|
162
|
+
});
|
|
148
163
|
};
|
|
149
164
|
export const controlUpdateCommand = async ({ io, name, apiUrl, json = false, yes = false, confirm, credentialStore, changes, }) => {
|
|
150
165
|
if (Object.keys(changes).length === 0) {
|
|
@@ -24,9 +24,11 @@ export declare const frameworkClausesCommand: ({ io, framework, apiUrl, json, cr
|
|
|
24
24
|
}) => Promise<void>;
|
|
25
25
|
export declare const clauseGetCommand: ({ io, framework, clause, apiUrl, json, credentialStore, }: ClauseTargetOptions) => Promise<void>;
|
|
26
26
|
export declare const clauseItemsCommand: ({ io, framework, clause, apiUrl, json, credentialStore, }: ClauseTargetOptions) => Promise<void>;
|
|
27
|
-
export declare const clauseAvailableItemsCommand: ({ io, framework, clause, itemType, apiUrl, json, credentialStore, search, }: ClauseTargetOptions & {
|
|
27
|
+
export declare const clauseAvailableItemsCommand: ({ io, framework, clause, itemType, apiUrl, json, credentialStore, search, page, limit, }: ClauseTargetOptions & {
|
|
28
28
|
itemType: string;
|
|
29
29
|
search?: string | undefined;
|
|
30
|
+
page?: number | undefined;
|
|
31
|
+
limit?: number | undefined;
|
|
30
32
|
}) => Promise<void>;
|
|
31
33
|
export declare const clauseUpdateCommand: ({ io, framework, clause, changes, apiUrl, json, yes, credentialStore, }: ClauseTargetOptions & {
|
|
32
34
|
changes: Record<string, unknown>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { writeLine, writeNextHint, writeTable } from '../io.js';
|
|
1
|
+
import { writeLine, writeNextHint, writePageFooter, writeTable } from '../io.js';
|
|
2
2
|
import { asRecord, callTool, errorMessage, resolveToolContext, asText } from '../toolSurface.js';
|
|
3
3
|
const text = (value, fallback = '-') => typeof value === 'string' ? value : typeof value === 'number' ? String(value) : fallback;
|
|
4
4
|
export const frameworkListCommand = async ({ io, apiUrl, json = false, credentialStore, }) => {
|
|
@@ -118,11 +118,15 @@ export const clauseItemsCommand = async ({ io, framework, clause, apiUrl, json =
|
|
|
118
118
|
return [text(record.name, text(record.id)), text(record.itemType ?? record.type)];
|
|
119
119
|
}));
|
|
120
120
|
};
|
|
121
|
-
export const clauseAvailableItemsCommand = async ({ io, framework, clause, itemType, apiUrl, json = false, credentialStore, search, }) => {
|
|
121
|
+
export const clauseAvailableItemsCommand = async ({ io, framework, clause, itemType, apiUrl, json = false, credentialStore, search, page, limit, }) => {
|
|
122
122
|
const ctx = await resolveToolContext(apiUrl, credentialStore);
|
|
123
123
|
const input = { framework, clause, itemType };
|
|
124
124
|
if (search)
|
|
125
125
|
input.search = search;
|
|
126
|
+
if (page)
|
|
127
|
+
input.page = page;
|
|
128
|
+
if (limit)
|
|
129
|
+
input.limit = limit;
|
|
126
130
|
const envelope = await callTool(ctx, 'list_clause_items_available', input);
|
|
127
131
|
if (envelope.status !== 'ok')
|
|
128
132
|
throw new Error(errorMessage(envelope, 'Could not read available items.'));
|
|
@@ -130,13 +134,24 @@ export const clauseAvailableItemsCommand = async ({ io, framework, clause, itemT
|
|
|
130
134
|
writeLine(io.stdout, JSON.stringify(envelope.data, null, 2));
|
|
131
135
|
return;
|
|
132
136
|
}
|
|
133
|
-
const
|
|
137
|
+
const data = asRecord(envelope.data);
|
|
138
|
+
const items = data.items;
|
|
134
139
|
const list = Array.isArray(items) ? items : [];
|
|
135
140
|
writeLine(io.stdout, `${io.theme.bold(`Available ${itemType}s`)} ${io.theme.dim(`(${list.length})`)}`);
|
|
136
141
|
for (const item of list) {
|
|
137
142
|
const record = asRecord(item);
|
|
138
143
|
writeLine(io.stdout, ` ${text(record.name, text(record.id))}`);
|
|
139
144
|
}
|
|
145
|
+
const total = typeof data.total === 'number' ? data.total : list.length;
|
|
146
|
+
const currentPage = typeof data.page === 'number' ? data.page : 1;
|
|
147
|
+
const pageSize = typeof data.limit === 'number' ? data.limit : 25;
|
|
148
|
+
writePageFooter(io, {
|
|
149
|
+
shown: list.length,
|
|
150
|
+
total,
|
|
151
|
+
page: currentPage,
|
|
152
|
+
limit: pageSize,
|
|
153
|
+
hasMore: data.hasMore === true || currentPage * pageSize < total,
|
|
154
|
+
});
|
|
140
155
|
};
|
|
141
156
|
export const clauseUpdateCommand = async ({ io, framework, clause, changes, apiUrl, json = false, yes = false, credentialStore, }) => {
|
|
142
157
|
const { applyTool } = await import('../actions.js');
|
package/dist/commands/policy.js
CHANGED
|
@@ -20,7 +20,7 @@ export const policyListCommand = async ({ io, apiUrl, json = false, name, status
|
|
|
20
20
|
if (envelope.status !== 'ok')
|
|
21
21
|
throw new Error(errorMessage(envelope, 'Could not list documents.'));
|
|
22
22
|
if (json) {
|
|
23
|
-
writeLine(io.stdout, JSON.stringify(envelope, null, 2));
|
|
23
|
+
writeLine(io.stdout, JSON.stringify(envelope.data, null, 2));
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
26
|
const data = asRecord(envelope.data);
|
package/dist/commands/test.d.ts
CHANGED
|
@@ -41,9 +41,11 @@ export interface TestAttachOptions extends TestReadOptions {
|
|
|
41
41
|
unlink?: boolean | undefined;
|
|
42
42
|
}
|
|
43
43
|
export declare const testAttachCommand: ({ io, name, runId, apiUrl, json, credentialStore, itemType, itemId, uploadIds, file, unlink, }: TestAttachOptions) => Promise<void>;
|
|
44
|
-
export declare const testAvailableItemsCommand: ({ io, name, runId, itemType, apiUrl, json, credentialStore, search, }: TestReadOptions & {
|
|
44
|
+
export declare const testAvailableItemsCommand: ({ io, name, runId, itemType, apiUrl, json, credentialStore, search, page, limit, }: TestReadOptions & {
|
|
45
45
|
itemType: string;
|
|
46
46
|
search?: string | undefined;
|
|
47
|
+
page?: number | undefined;
|
|
48
|
+
limit?: number | undefined;
|
|
47
49
|
}) => Promise<void>;
|
|
48
50
|
export declare const testLinksCommand: ({ io, name, apiUrl, json, credentialStore, }: TestReadOptions) => Promise<void>;
|
|
49
51
|
export declare const testUpdateCommand: ({ io, name, apiUrl, json, yes, confirm, credentialStore, changes, }: TestReadOptions & {
|
package/dist/commands/test.js
CHANGED
|
@@ -235,13 +235,17 @@ export const testAttachCommand = async ({ io, name, runId, apiUrl, json = false,
|
|
|
235
235
|
const job = asText(data.aiTaskId);
|
|
236
236
|
writeLine(io.stdout, `${io.theme.green('✓')} ${unlink ? 'unlinked' : 'linked'} ${resolvedItemType} on run ${text(data.runId)}${job ? io.theme.dim(` · job ${job}`) : ''}`);
|
|
237
237
|
};
|
|
238
|
-
export const testAvailableItemsCommand = async ({ io, name, runId, itemType, apiUrl, json = false, credentialStore, search, }) => {
|
|
238
|
+
export const testAvailableItemsCommand = async ({ io, name, runId, itemType, apiUrl, json = false, credentialStore, search, page, limit, }) => {
|
|
239
239
|
const ctx = await resolveToolContext(apiUrl, credentialStore);
|
|
240
240
|
const input = { name, itemType };
|
|
241
241
|
if (runId)
|
|
242
242
|
input.runId = runId;
|
|
243
243
|
if (search)
|
|
244
244
|
input.search = search;
|
|
245
|
+
if (page)
|
|
246
|
+
input.page = page;
|
|
247
|
+
if (limit)
|
|
248
|
+
input.limit = limit;
|
|
245
249
|
const envelope = await callTool(ctx, 'list_test_items_available', input);
|
|
246
250
|
if (envelope.status !== 'ok')
|
|
247
251
|
throw new Error(errorMessage(envelope, 'Could not read available items.'));
|
|
@@ -264,6 +268,16 @@ export const testAvailableItemsCommand = async ({ io, name, runId, itemType, api
|
|
|
264
268
|
text(record.status),
|
|
265
269
|
];
|
|
266
270
|
}));
|
|
271
|
+
const total = typeof data.total === 'number' ? data.total : items.length;
|
|
272
|
+
const currentPage = typeof data.page === 'number' ? data.page : 1;
|
|
273
|
+
const pageSize = typeof data.limit === 'number' ? data.limit : 25;
|
|
274
|
+
writePageFooter(io, {
|
|
275
|
+
shown: items.length,
|
|
276
|
+
total,
|
|
277
|
+
page: currentPage,
|
|
278
|
+
limit: pageSize,
|
|
279
|
+
hasMore: data.hasMore === true || currentPage * pageSize < total,
|
|
280
|
+
});
|
|
267
281
|
};
|
|
268
282
|
export const testLinksCommand = async ({ io, name, apiUrl, json = false, credentialStore, }) => {
|
|
269
283
|
const ctx = await resolveToolContext(apiUrl, credentialStore);
|
|
@@ -22,10 +22,13 @@ export declare const vendorListCommand: ({ io, apiUrl, json, credentialStore, na
|
|
|
22
22
|
limit?: number | undefined;
|
|
23
23
|
}) => Promise<void>;
|
|
24
24
|
export declare const vendorGetCommand: ({ io, name, apiUrl, json, credentialStore, }: VendorReadOptions) => Promise<void>;
|
|
25
|
-
export declare const vendorCreateCommand: ({ io, apiUrl, json, credentialStore, name, category, criticality, description, }: VendorCommonOptions & {
|
|
25
|
+
export declare const vendorCreateCommand: ({ io, apiUrl, json, credentialStore, name, category, subcategory, criticality, dataSensitivity, serviceAvailability, description, }: VendorCommonOptions & {
|
|
26
26
|
name: string;
|
|
27
27
|
category?: string | undefined;
|
|
28
|
+
subcategory?: string | undefined;
|
|
28
29
|
criticality?: string | undefined;
|
|
30
|
+
dataSensitivity?: string | undefined;
|
|
31
|
+
serviceAvailability?: string | undefined;
|
|
29
32
|
description?: string | undefined;
|
|
30
33
|
}) => Promise<void>;
|
|
31
34
|
export interface VendorUpdateOptions extends VendorReadOptions {
|
package/dist/commands/vendor.js
CHANGED
|
@@ -78,13 +78,19 @@ export const vendorGetCommand = async ({ io, name, apiUrl, json = false, credent
|
|
|
78
78
|
writeLine(io.stdout, ` ${io.theme.dim(`${label}:`)} ${text(value)}`);
|
|
79
79
|
}
|
|
80
80
|
};
|
|
81
|
-
export const vendorCreateCommand = async ({ io, apiUrl, json = false, credentialStore, name, category, criticality, description, }) => {
|
|
81
|
+
export const vendorCreateCommand = async ({ io, apiUrl, json = false, credentialStore, name, category, subcategory, criticality, dataSensitivity, serviceAvailability, description, }) => {
|
|
82
82
|
const ctx = await resolveToolContext(apiUrl, credentialStore);
|
|
83
83
|
const input = { name };
|
|
84
84
|
if (category)
|
|
85
85
|
input.category = category;
|
|
86
|
+
if (subcategory)
|
|
87
|
+
input.subcategory = subcategory;
|
|
86
88
|
if (criticality)
|
|
87
89
|
input.criticality = criticality;
|
|
90
|
+
if (dataSensitivity)
|
|
91
|
+
input.dataSensitivity = dataSensitivity;
|
|
92
|
+
if (serviceAvailability)
|
|
93
|
+
input.serviceAvailability = serviceAvailability;
|
|
88
94
|
if (description)
|
|
89
95
|
input.description = description;
|
|
90
96
|
const result = await applyTool({
|
package/dist/constants.d.ts
CHANGED
package/dist/constants.js
CHANGED
package/dist/toolSurface.d.ts
CHANGED
|
@@ -17,4 +17,12 @@ export interface CallToolOptions {
|
|
|
17
17
|
confirmationToken?: string | undefined;
|
|
18
18
|
idempotencyKey?: string | undefined;
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* The tool surface requires an idempotency key on every write and rejects a write without one. Writes
|
|
22
|
+
* must go through `applyTool`, which supplies the key and handles the preflight/confirmation contract.
|
|
23
|
+
* This set is the CLI-side mirror of the tool surface's write effects, so a write cannot be issued as a
|
|
24
|
+
* bare read-style call again. Keep it in step with the write tools the CLI exposes (ideally derived from
|
|
25
|
+
* the manifest once the CLI consumes it).
|
|
26
|
+
*/
|
|
27
|
+
export declare const WRITE_TOOL_NAMES: ReadonlySet<string>;
|
|
20
28
|
export declare const callTool: (ctx: ToolContext, toolName: string, input: unknown, options?: CallToolOptions) => Promise<Record<string, unknown>>;
|
package/dist/toolSurface.js
CHANGED
|
@@ -34,7 +34,52 @@ export const resolveToolContext = async (apiUrl, store) => {
|
|
|
34
34
|
throw new Error('Not signed in. Run `ciphrix login` first.');
|
|
35
35
|
return { baseUrl, client: createApiClient(baseUrl), token: credential.token };
|
|
36
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* The tool surface requires an idempotency key on every write and rejects a write without one. Writes
|
|
39
|
+
* must go through `applyTool`, which supplies the key and handles the preflight/confirmation contract.
|
|
40
|
+
* This set is the CLI-side mirror of the tool surface's write effects, so a write cannot be issued as a
|
|
41
|
+
* bare read-style call again. Keep it in step with the write tools the CLI exposes (ideally derived from
|
|
42
|
+
* the manifest once the CLI consumes it).
|
|
43
|
+
*/
|
|
44
|
+
export const WRITE_TOOL_NAMES = new Set([
|
|
45
|
+
'set_context_answer',
|
|
46
|
+
'reset_context',
|
|
47
|
+
'create_document',
|
|
48
|
+
'edit_document_content',
|
|
49
|
+
'create_document_version',
|
|
50
|
+
'update_document',
|
|
51
|
+
'submit_document',
|
|
52
|
+
'approve_document',
|
|
53
|
+
'delete_document',
|
|
54
|
+
'create_test_run',
|
|
55
|
+
'set_test_run_status',
|
|
56
|
+
'delete_test_run',
|
|
57
|
+
'attach_run_item',
|
|
58
|
+
'update_test',
|
|
59
|
+
'delete_test',
|
|
60
|
+
'update_clause',
|
|
61
|
+
'link_clause_item',
|
|
62
|
+
'update_control',
|
|
63
|
+
'link_control_item',
|
|
64
|
+
'create_vendor',
|
|
65
|
+
'update_vendor',
|
|
66
|
+
'delete_vendor',
|
|
67
|
+
'link_vendor_file',
|
|
68
|
+
'create_risk',
|
|
69
|
+
'update_risk',
|
|
70
|
+
'delete_risk',
|
|
71
|
+
'link_risk_control',
|
|
72
|
+
'link_risk_file',
|
|
73
|
+
'set_check_enabled',
|
|
74
|
+
'create_asset',
|
|
75
|
+
'update_asset',
|
|
76
|
+
'delete_asset',
|
|
77
|
+
'set_asset_tag',
|
|
78
|
+
]);
|
|
37
79
|
export const callTool = async (ctx, toolName, input, options = {}) => {
|
|
80
|
+
if (WRITE_TOOL_NAMES.has(toolName) && !options.idempotencyKey) {
|
|
81
|
+
throw new Error(`Refusing to call the write tool '${toolName}' without an idempotency key. Use applyTool.`);
|
|
82
|
+
}
|
|
38
83
|
const body = { input };
|
|
39
84
|
if (options.confirmationToken)
|
|
40
85
|
body.confirmationToken = options.confirmationToken;
|
package/dist/upload.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ToolContext } from './toolSurface.js';
|
|
2
|
-
/** Maximum evidence file size read and staged by the CLI (
|
|
2
|
+
/** Maximum evidence file size read and staged by the CLI (25 MiB, matching the tool surface). */
|
|
3
3
|
export declare const DEFAULT_MAX_UPLOAD_BYTES: number;
|
|
4
4
|
export interface UploadLimits {
|
|
5
5
|
maxUploadBytes?: number;
|
package/dist/upload.js
CHANGED
|
@@ -19,8 +19,8 @@ const MIME_TYPES = {
|
|
|
19
19
|
'.xls': 'application/vnd.ms-excel',
|
|
20
20
|
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
21
21
|
};
|
|
22
|
-
/** Maximum evidence file size read and staged by the CLI (
|
|
23
|
-
export const DEFAULT_MAX_UPLOAD_BYTES =
|
|
22
|
+
/** Maximum evidence file size read and staged by the CLI (25 MiB, matching the tool surface). */
|
|
23
|
+
export const DEFAULT_MAX_UPLOAD_BYTES = 25 * 1024 * 1024;
|
|
24
24
|
const readUploadFile = async (filePath, maxBytes) => {
|
|
25
25
|
const initialStat = await lstat(filePath);
|
|
26
26
|
if (initialStat.isSymbolicLink() || !initialStat.isFile()) {
|
package/package.json
CHANGED
|
@@ -340,6 +340,8 @@ Options:
|
|
|
340
340
|
--type <type> item type: native_doc or check
|
|
341
341
|
--run <id> a specific run
|
|
342
342
|
--search <text> filter by item name
|
|
343
|
+
--page <n> page number
|
|
344
|
+
--limit <n> page size
|
|
343
345
|
--api-url <url> override the API base URL for this command
|
|
344
346
|
--json output raw JSON
|
|
345
347
|
-h, --help display help for command
|
|
@@ -485,6 +487,8 @@ List items that can be mapped to a clause
|
|
|
485
487
|
Options:
|
|
486
488
|
--type <type> item type: test or document
|
|
487
489
|
--search <text> filter by item name
|
|
490
|
+
--page <n> page number
|
|
491
|
+
--limit <n> page size
|
|
488
492
|
--api-url <url> override the API base URL for this command
|
|
489
493
|
--json output raw JSON
|
|
490
494
|
-h, --help display help for command
|
|
@@ -560,16 +564,20 @@ Usage: ciphrix asset list [options]
|
|
|
560
564
|
List assets with their code, status and classification
|
|
561
565
|
|
|
562
566
|
Options:
|
|
563
|
-
--name <text>
|
|
564
|
-
--category <
|
|
565
|
-
--
|
|
566
|
-
--
|
|
567
|
-
--
|
|
568
|
-
--
|
|
569
|
-
--
|
|
570
|
-
|
|
571
|
-
--
|
|
572
|
-
|
|
567
|
+
--name <text> filter by name
|
|
568
|
+
--category <csv> filter by category
|
|
569
|
+
--sub-category <csv> filter by sub-category
|
|
570
|
+
--status <csv> filter by status
|
|
571
|
+
--business-impact <csv> filter by business impact
|
|
572
|
+
--data-classification <csv> filter by data classification
|
|
573
|
+
--source <csv> filter by discovery source (provider, e.g.
|
|
574
|
+
aws, azure, gcp)
|
|
575
|
+
--technical-owner-email <email> filter by technical owner email
|
|
576
|
+
--page <n> page number
|
|
577
|
+
--limit <n> page size
|
|
578
|
+
--api-url <url> override the API base URL for this command
|
|
579
|
+
--json output raw JSON
|
|
580
|
+
-h, --help display help for command
|
|
573
581
|
```
|
|
574
582
|
|
|
575
583
|
## `ciphrix asset get`
|
|
@@ -766,13 +774,16 @@ Usage: ciphrix vendor create [options]
|
|
|
766
774
|
Create a vendor
|
|
767
775
|
|
|
768
776
|
Options:
|
|
769
|
-
--name <name>
|
|
770
|
-
--category <value>
|
|
771
|
-
--
|
|
772
|
-
--
|
|
773
|
-
--
|
|
774
|
-
--
|
|
775
|
-
|
|
777
|
+
--name <name> vendor name
|
|
778
|
+
--category <value> category
|
|
779
|
+
--subcategory <value> sub-category
|
|
780
|
+
--criticality <value> criticality
|
|
781
|
+
--data-sensitivity <value> data sensitivity
|
|
782
|
+
--service-availability <value> service availability
|
|
783
|
+
--description <text> description
|
|
784
|
+
--api-url <url> override the API base URL for this command
|
|
785
|
+
--json output raw JSON
|
|
786
|
+
-h, --help display help for command
|
|
776
787
|
```
|
|
777
788
|
|
|
778
789
|
**Effect:** Creates a vendor; the CLI prompts if the API requests confirmation.
|
|
@@ -898,6 +909,7 @@ Options:
|
|
|
898
909
|
--domain <value> filter by control domain
|
|
899
910
|
--status <csv> filter by status
|
|
900
911
|
--applicability <value> filter by applicability (in_scope|out_of_scope)
|
|
912
|
+
--owner <csv> filter by owner user id
|
|
901
913
|
--page <n> page number
|
|
902
914
|
--limit <n> page size
|
|
903
915
|
--api-url <url> override the API base URL for this command
|
|
@@ -965,6 +977,7 @@ Options:
|
|
|
965
977
|
--design-requirements <state> not_assessed | not_needed | not_met | partial |
|
|
966
978
|
met
|
|
967
979
|
--notes <text> notes (Markdown)
|
|
980
|
+
--description <text> description (custom controls only)
|
|
968
981
|
--rename <text> new name (custom controls only)
|
|
969
982
|
--yes apply without prompting
|
|
970
983
|
--api-url <url> override the API base URL for this command
|