@xano/cli 1.3.4 → 1.3.5-beta.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/README.md +69 -2
- package/dist/base-command.d.ts +12 -1
- package/dist/base-command.js +36 -22
- package/dist/commands/branch/set_live/index.d.ts +14 -0
- package/dist/commands/branch/set_live/index.js +38 -0
- package/dist/commands/ephemeral/push/index.js +6 -1
- package/dist/commands/function/create/index.d.ts +15 -0
- package/dist/commands/function/create/index.js +39 -0
- package/dist/commands/function/edit/index.d.ts +15 -0
- package/dist/commands/function/edit/index.js +39 -0
- package/dist/commands/function/run/index.js +5 -11
- package/dist/commands/policy/catalogue/index.d.ts +16 -0
- package/dist/commands/policy/catalogue/index.js +60 -0
- package/dist/commands/policy/coverage/index.d.ts +17 -0
- package/dist/commands/policy/coverage/index.js +33 -0
- package/dist/commands/policy/create/index.d.ts +18 -0
- package/dist/commands/policy/create/index.js +44 -0
- package/dist/commands/policy/delete/index.d.ts +19 -0
- package/dist/commands/policy/delete/index.js +61 -0
- package/dist/commands/policy/evaluate/index.d.ts +32 -0
- package/dist/commands/policy/evaluate/index.js +71 -0
- package/dist/commands/policy/list/index.d.ts +14 -0
- package/dist/commands/policy/list/index.js +21 -0
- package/dist/commands/policy/parse/index.d.ts +19 -0
- package/dist/commands/policy/parse/index.js +18 -0
- package/dist/commands/policy/publish/index.d.ts +20 -0
- package/dist/commands/policy/publish/index.js +38 -0
- package/dist/commands/policy/runs/index.d.ts +54 -0
- package/dist/commands/policy/runs/index.js +273 -0
- package/dist/commands/policy/status/index.d.ts +21 -0
- package/dist/commands/policy/status/index.js +54 -0
- package/dist/commands/release/create/index.js +4 -0
- package/dist/commands/release/deploy/index.d.ts +19 -0
- package/dist/commands/release/deploy/index.js +68 -6
- package/dist/commands/release/import/index.js +5 -1
- package/dist/commands/release/list/index.d.ts +7 -0
- package/dist/commands/release/list/index.js +46 -9
- package/dist/commands/release/push/index.js +19 -1
- package/dist/commands/sandbox/push/index.js +6 -1
- package/dist/commands/skills/pull/index.d.ts +30 -0
- package/dist/commands/skills/pull/index.js +118 -0
- package/dist/commands/tenant/create/index.d.ts +3 -0
- package/dist/commands/tenant/create/index.js +21 -0
- package/dist/commands/tenant/deploy_release/index.d.ts +40 -0
- package/dist/commands/tenant/deploy_release/index.js +182 -4
- package/dist/commands/tenant/edit/index.d.ts +2 -0
- package/dist/commands/tenant/edit/index.js +39 -4
- package/dist/commands/tenant_deploy_request/bypass/index.d.ts +31 -0
- package/dist/commands/tenant_deploy_request/bypass/index.js +109 -0
- package/dist/commands/tenant_deploy_request/create/index.d.ts +21 -0
- package/dist/commands/tenant_deploy_request/create/index.js +108 -0
- package/dist/commands/tenant_deploy_request/edit/index.d.ts +22 -0
- package/dist/commands/tenant_deploy_request/edit/index.js +103 -0
- package/dist/commands/tenant_deploy_request/get/index.d.ts +25 -0
- package/dist/commands/tenant_deploy_request/get/index.js +113 -0
- package/dist/commands/tenant_deploy_request/list/index.d.ts +20 -0
- package/dist/commands/tenant_deploy_request/list/index.js +122 -0
- package/dist/commands/tenant_deploy_request/revision/index.d.ts +21 -0
- package/dist/commands/tenant_deploy_request/revision/index.js +83 -0
- package/dist/commands/tenant_deploy_request/set_status/index.d.ts +38 -0
- package/dist/commands/tenant_deploy_request/set_status/index.js +159 -0
- package/dist/commands/workspace/pull/index.d.ts +10 -0
- package/dist/commands/workspace/pull/index.js +70 -7
- package/dist/commands/workspace/push/index.d.ts +19 -0
- package/dist/commands/workspace/push/index.js +135 -6
- package/dist/policy-command.d.ts +91 -0
- package/dist/policy-command.js +95 -0
- package/dist/utils/document-parser.d.ts +10 -0
- package/dist/utils/document-parser.js +21 -0
- package/dist/utils/multidoc-push.d.ts +57 -2
- package/dist/utils/multidoc-push.js +102 -33
- package/dist/utils/policy/catalogue.d.ts +85 -0
- package/dist/utils/policy/catalogue.js +196 -0
- package/dist/utils/policy/coverage.d.ts +19 -0
- package/dist/utils/policy/coverage.js +93 -0
- package/dist/utils/policy/errors.d.ts +20 -0
- package/dist/utils/policy/errors.js +93 -0
- package/dist/utils/policy/feedback.d.ts +90 -0
- package/dist/utils/policy/feedback.js +210 -0
- package/dist/utils/policy/findings.d.ts +29 -0
- package/dist/utils/policy/findings.js +82 -0
- package/dist/utils/policy/gate.d.ts +138 -0
- package/dist/utils/policy/gate.js +193 -0
- package/dist/utils/policy/permission.d.ts +7 -0
- package/dist/utils/policy/permission.js +55 -0
- package/dist/utils/policy/push-gate.d.ts +5 -0
- package/dist/utils/policy/push-gate.js +43 -0
- package/dist/utils/policy/release.d.ts +85 -0
- package/dist/utils/policy/release.js +117 -0
- package/dist/utils/policy/request.d.ts +55 -0
- package/dist/utils/policy/request.js +119 -0
- package/dist/utils/policy/runs.d.ts +30 -0
- package/dist/utils/policy/runs.js +101 -0
- package/dist/utils/policy/status.d.ts +55 -0
- package/dist/utils/policy/status.js +127 -0
- package/dist/utils/policy/template.d.ts +66 -0
- package/dist/utils/policy/template.js +152 -0
- package/dist/utils/policy/types.d.ts +295 -0
- package/dist/utils/policy/types.js +1 -0
- package/oclif.manifest.json +5782 -2573
- package/package.json +9 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { POLICY_KEY_PATTERN } from '../document-parser.js';
|
|
2
|
+
/**
|
|
3
|
+
* The refusal of a recipe id given to `--template`: recipes have no create action, so it names the
|
|
4
|
+
* recipe's templates in the order to create them and, when it has rules no template covers, where
|
|
5
|
+
* they are shown.
|
|
6
|
+
*/
|
|
7
|
+
export function recipeRefusal(recipe) {
|
|
8
|
+
const templates = Array.isArray(recipe.templates) ? recipe.templates : [];
|
|
9
|
+
const rules = Array.isArray(recipe.rules) ? recipe.rules.length : 0;
|
|
10
|
+
const steps = templates.length > 0
|
|
11
|
+
? ` Create its templates in order with --template, one policy each: ${templates.join(', ')}.`
|
|
12
|
+
: '';
|
|
13
|
+
const own = rules > 0 ? ` ${rules === 1 ? 'The rule' : `The ${rules} rules`} no template covers ${rules === 1 ? 'goes' : 'go'} in a policy of your own (\`xano policy publish\`).` : '';
|
|
14
|
+
return `"${recipe.id}" is a recipe (${recipe.title}), not a template, and a recipe has no create action.${steps}${own} Run \`xano policy catalogue --recipe ${recipe.id}\` for what to set up first and the rules.`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The policy document for a template: its sparse settings with the `--param` assignments applied, every
|
|
18
|
+
* `needs` path filled (at least one of a rule's when it says `needs_any`), and a key no policy on the
|
|
19
|
+
* branch holds (compared case-insensitively). A taken template key gets a free numeric suffix; a taken or
|
|
20
|
+
* malformed `--key` is refused.
|
|
21
|
+
*/
|
|
22
|
+
export function policyFromTemplate(template, takenKeys, options = {}) {
|
|
23
|
+
const { checks = [], key, keyRule, overrides = [] } = options;
|
|
24
|
+
const taken = new Set(takenKeys.map(value => value.toLowerCase()));
|
|
25
|
+
let chosen = key ?? template.key;
|
|
26
|
+
if (!keyPattern(keyRule).test(chosen))
|
|
27
|
+
throw new Error(keyRefusal(keyRule, chosen));
|
|
28
|
+
if (key !== undefined && taken.has(chosen.toLowerCase()))
|
|
29
|
+
throw new Error(`Policy ${chosen} already exists. Choose a new --key or use policy publish to update it.`);
|
|
30
|
+
for (let suffix = 2; taken.has(chosen.toLowerCase()); suffix++)
|
|
31
|
+
chosen = `${template.key.slice(0, 63 - String(suffix).length)}-${suffix}`;
|
|
32
|
+
const rules = template.rules.map(rule => ({ check: rule.check, params: Array.isArray(rule.params) ? {} : structuredClone(rule.params), title: rule.title }));
|
|
33
|
+
for (const assignment of overrides)
|
|
34
|
+
applyOverride(rules, assignment);
|
|
35
|
+
const missing = template.rules.flatMap((rule, index) => missingNeeds(rule, rules[index].params, index));
|
|
36
|
+
if (missing.length > 0)
|
|
37
|
+
throw new Error(`Fill the template's required settings with --param 'N.path=JSON': ${missing.join(', ')}.${exampleHint(template, checks, missing)}`);
|
|
38
|
+
return { key: chosen, rules, severity: template.severity, statement: template.summary, title: template.title };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* An example for the first unfilled need that has one, as a `--param` to copy
|
|
42
|
+
* (` For example: --param '1.names=["audit_log"]'.`), or '' when none has: the template's own example
|
|
43
|
+
* for the path, else the example its check's catalogue entry gives for that param, as Studio shows it.
|
|
44
|
+
* The rule number is left off for a single-rule template, as `--param` takes it.
|
|
45
|
+
*/
|
|
46
|
+
function exampleHint(template, checks, missing) {
|
|
47
|
+
const examples = template.examples && typeof template.examples === 'object' && !Array.isArray(template.examples) ? template.examples : {};
|
|
48
|
+
for (const entry of missing.flatMap(item => item.split(' or '))) {
|
|
49
|
+
const dot = entry.indexOf('.');
|
|
50
|
+
const path = entry.slice(dot + 1);
|
|
51
|
+
const rule = template.rules[Number(entry.slice(0, dot)) - 1];
|
|
52
|
+
const example = Object.hasOwn(examples, path) ? examples[path] : checkExample(checks.find(check => check.id === rule?.check), path);
|
|
53
|
+
if (example === undefined)
|
|
54
|
+
continue;
|
|
55
|
+
const name = template.rules.length === 1 ? path : entry;
|
|
56
|
+
return ` For example: --param '${name}=${JSON.stringify(example)}'.`;
|
|
57
|
+
}
|
|
58
|
+
return '';
|
|
59
|
+
}
|
|
60
|
+
/** The catalogue's `example` for a param path of a check (`table_selector.has_field` reads a part's), or undefined. */
|
|
61
|
+
function checkExample(check, path) {
|
|
62
|
+
let schemas = check?.params;
|
|
63
|
+
let schema;
|
|
64
|
+
for (const part of path.split('.')) {
|
|
65
|
+
if (!schemas || typeof schemas !== 'object' || !Object.hasOwn(schemas, part))
|
|
66
|
+
return undefined;
|
|
67
|
+
schema = schemas[part];
|
|
68
|
+
schemas = schema?.properties;
|
|
69
|
+
}
|
|
70
|
+
return schema?.example;
|
|
71
|
+
}
|
|
72
|
+
/** The catalogue's key pattern, or the offline copy when the catalogue serves none (or one that does not compile). */
|
|
73
|
+
function keyPattern(rule) {
|
|
74
|
+
if (typeof rule?.pattern !== 'string' || rule.pattern === '')
|
|
75
|
+
return POLICY_KEY_PATTERN;
|
|
76
|
+
try {
|
|
77
|
+
return new RegExp(rule.pattern);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return POLICY_KEY_PATTERN;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** The catalogue's refusal for a malformed key, naming it, or the offline sentence. */
|
|
84
|
+
function keyRefusal(rule, key) {
|
|
85
|
+
return typeof rule?.message === 'string' && rule.message.trim()
|
|
86
|
+
? rule.message.replaceAll('%s', key)
|
|
87
|
+
: 'A policy key must be 1–64 letters, digits, dots, underscores or hyphens, starting with a letter or digit.';
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* A rule's unfilled `needs`, each as `N.path`: every unfilled one, or, for a `needs_any` rule with none
|
|
91
|
+
* filled, one entry naming the alternatives (`1.hosts or 1.providers`).
|
|
92
|
+
*/
|
|
93
|
+
function missingNeeds(rule, params, index) {
|
|
94
|
+
const needs = (rule.needs ?? []).map(path => ({ filled: filled(readPath(params, path)), name: `${index + 1}.${path}` }));
|
|
95
|
+
if (rule.needs_any === true && needs.length > 1)
|
|
96
|
+
return needs.some(need => need.filled) ? [] : [needs.map(need => need.name).join(' or ')];
|
|
97
|
+
return needs.filter(need => !need.filled).map(need => need.name);
|
|
98
|
+
}
|
|
99
|
+
/** The value at a dotted path of a rule's params, or undefined when any step is missing. */
|
|
100
|
+
function readPath(params, path) {
|
|
101
|
+
let value = params;
|
|
102
|
+
for (const part of path.split('.')) {
|
|
103
|
+
if (!value || typeof value !== 'object' || !Object.hasOwn(value, part))
|
|
104
|
+
return undefined;
|
|
105
|
+
value = value[part];
|
|
106
|
+
}
|
|
107
|
+
return value;
|
|
108
|
+
}
|
|
109
|
+
/** Whether a `needs` value is set: not empty, null or blank; `false` and `0` count as set. */
|
|
110
|
+
function filled(value) {
|
|
111
|
+
if (Array.isArray(value))
|
|
112
|
+
return value.some(item => filled(item));
|
|
113
|
+
if (value && typeof value === 'object')
|
|
114
|
+
return Object.keys(value).length > 0;
|
|
115
|
+
return value !== undefined && value !== null && (typeof value !== 'string' || value.trim() !== '');
|
|
116
|
+
}
|
|
117
|
+
/** Apply one `--param [N.]path=JSON` assignment to its rule's params, refusing unsafe paths and non-JSON values. */
|
|
118
|
+
function applyOverride(rules, assignment) {
|
|
119
|
+
const equals = assignment.indexOf('=');
|
|
120
|
+
if (equals < 1)
|
|
121
|
+
throw new Error('Use --param path=JSON or --param N.path=JSON (rule numbers start at 1).');
|
|
122
|
+
const parts = assignment.slice(0, equals).split('.');
|
|
123
|
+
let index = 0;
|
|
124
|
+
if (/^\d+$/.test(parts[0]))
|
|
125
|
+
index = Number(parts.shift()) - 1;
|
|
126
|
+
else if (rules.length !== 1)
|
|
127
|
+
throw new Error('Include the rule number in --param N.path=JSON for a template with multiple rules.');
|
|
128
|
+
if (!Number.isSafeInteger(index) || !rules[index])
|
|
129
|
+
throw new Error(`Rule ${index + 1} does not exist in this template.`);
|
|
130
|
+
if (parts.length === 0 || parts.some(part => !/^[A-Za-z_][A-Za-z0-9_]*$/.test(part) || ['__proto__', 'constructor', 'prototype'].includes(part)))
|
|
131
|
+
throw new Error('Invalid parameter path. Use parameter names separated by dots.');
|
|
132
|
+
let value;
|
|
133
|
+
try {
|
|
134
|
+
value = JSON.parse(assignment.slice(equals + 1), (_key, parsed) => {
|
|
135
|
+
if (typeof parsed === 'number' && !Number.isFinite(parsed))
|
|
136
|
+
throw new Error('Numbers must be finite.');
|
|
137
|
+
return parsed;
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
throw new Error(`The value for ${assignment.slice(0, equals)} must be JSON: a quoted string, finite number, boolean, array or object.`);
|
|
142
|
+
}
|
|
143
|
+
let target = rules[index].params;
|
|
144
|
+
for (const part of parts.slice(0, -1)) {
|
|
145
|
+
if (target[part] === undefined)
|
|
146
|
+
target[part] = {};
|
|
147
|
+
if (!target[part] || typeof target[part] !== 'object' || Array.isArray(target[part]))
|
|
148
|
+
throw new Error(`Cannot set a nested parameter inside ${part}.`);
|
|
149
|
+
target = target[part];
|
|
150
|
+
}
|
|
151
|
+
target[parts.at(-1)] = value;
|
|
152
|
+
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/** The shapes the policy routes answer with. Policy grammar belongs to the platform. */
|
|
2
|
+
export interface PolicyCatalogueEntry {
|
|
3
|
+
description?: string;
|
|
4
|
+
fix_hint?: string;
|
|
5
|
+
id: string;
|
|
6
|
+
/** The check's human name. */
|
|
7
|
+
label: string;
|
|
8
|
+
object_kinds?: string[];
|
|
9
|
+
params?: Record<string, PolicyParamSchema>;
|
|
10
|
+
/** Params of which a rule must set at least one. */
|
|
11
|
+
requires_one_of?: string[];
|
|
12
|
+
/** Goals in a customer's words, each with the complete params (scope params included) that achieve it. */
|
|
13
|
+
uses?: PolicyCheckUse[];
|
|
14
|
+
}
|
|
15
|
+
/** One of a check's `uses`: a goal and a rule's params its check accepts as written. */
|
|
16
|
+
export interface PolicyCheckUse {
|
|
17
|
+
goal: string;
|
|
18
|
+
/** What to know before using it, when the goal alone could mislead. */
|
|
19
|
+
note?: string;
|
|
20
|
+
/** PHP sends an empty map as `[]`. */
|
|
21
|
+
params: Record<string, unknown> | unknown[];
|
|
22
|
+
}
|
|
23
|
+
/** One param as the catalogue describes it: a nested object's parts are its `properties`. */
|
|
24
|
+
export interface PolicyParamSchema {
|
|
25
|
+
/** A value that fits the param, shown as a hint; never filled in. */
|
|
26
|
+
example?: unknown;
|
|
27
|
+
properties?: Record<string, PolicyParamSchema>;
|
|
28
|
+
required?: boolean;
|
|
29
|
+
type?: string;
|
|
30
|
+
}
|
|
31
|
+
/** One rule as a run snapshot records it: the settings the check ran with, plus the check's label. */
|
|
32
|
+
export interface PolicySnapshotRule {
|
|
33
|
+
check?: string;
|
|
34
|
+
id?: string;
|
|
35
|
+
label?: string;
|
|
36
|
+
/** The resolved settings; PHP sends an empty map as `[]`. */
|
|
37
|
+
params?: unknown;
|
|
38
|
+
title?: string;
|
|
39
|
+
}
|
|
40
|
+
/** One policy as a run snapshot records it, including the description it carried at run time. */
|
|
41
|
+
export interface PolicySnapshotPolicy {
|
|
42
|
+
key?: string;
|
|
43
|
+
rules?: PolicySnapshotRule[];
|
|
44
|
+
/** The policy description as written at run time. */
|
|
45
|
+
statement?: string;
|
|
46
|
+
title?: string;
|
|
47
|
+
/** The Version History index this run evaluated. */
|
|
48
|
+
version?: number;
|
|
49
|
+
}
|
|
50
|
+
export interface PolicyRuleResult {
|
|
51
|
+
check_id?: string;
|
|
52
|
+
checked?: number;
|
|
53
|
+
message?: string;
|
|
54
|
+
policy_key?: string;
|
|
55
|
+
status?: string;
|
|
56
|
+
warnings?: string[];
|
|
57
|
+
}
|
|
58
|
+
export interface PolicyFinding {
|
|
59
|
+
/** Stable finding id, used to tell a blocking finding from an advisory one. */
|
|
60
|
+
id?: string;
|
|
61
|
+
message?: string;
|
|
62
|
+
object?: {
|
|
63
|
+
id?: number;
|
|
64
|
+
name?: string;
|
|
65
|
+
type?: string;
|
|
66
|
+
};
|
|
67
|
+
policy_key?: string;
|
|
68
|
+
policy_title?: string;
|
|
69
|
+
rule_id?: string;
|
|
70
|
+
rule_title?: string;
|
|
71
|
+
severity?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A finding as the platform trims it for a caller without `workspace:policy` read (`access:
|
|
75
|
+
* "coverage"`): no rule id, severity, params or `allow`, but the check's label, first description
|
|
76
|
+
* sentence and fix hint, and whether it blocks.
|
|
77
|
+
*/
|
|
78
|
+
export interface CoverageFinding extends PolicyFinding {
|
|
79
|
+
blocking?: boolean;
|
|
80
|
+
/** `null` when the rule can no longer be resolved (a deleted policy, a rule removed since the run). */
|
|
81
|
+
check?: null | {
|
|
82
|
+
description?: string;
|
|
83
|
+
fix_hint?: string;
|
|
84
|
+
label?: string;
|
|
85
|
+
};
|
|
86
|
+
/** Coverage only: the run evaluated a policy the branch no longer holds. */
|
|
87
|
+
deleted?: boolean;
|
|
88
|
+
}
|
|
89
|
+
/** The verdict every `policy_check` carries. */
|
|
90
|
+
export interface PolicyVerdict {
|
|
91
|
+
/** True when an active, blocking policy failed; it decides the exit code whatever the status. */
|
|
92
|
+
blocking?: boolean;
|
|
93
|
+
/** The platform's verdict, including the names of rules that checked no objects. */
|
|
94
|
+
message?: string;
|
|
95
|
+
run_id?: number;
|
|
96
|
+
/**
|
|
97
|
+
* `pass`, `fail` or `error` (a check could not run) for an evaluation; `disabled`,
|
|
98
|
+
* `not_applicable` or `unavailable` when nothing was evaluated. An older platform answers
|
|
99
|
+
* `forbidden` to a caller without `workspace:policy` read, which is reported like any other
|
|
100
|
+
* status it has no headline for.
|
|
101
|
+
*/
|
|
102
|
+
status?: string;
|
|
103
|
+
}
|
|
104
|
+
/** A run's finding counts: every finding, the blocking ones, and the rules that could not run. */
|
|
105
|
+
export interface PolicyCounts {
|
|
106
|
+
/** The findings that do not block; the run summary serves it, a push's feedback does not. */
|
|
107
|
+
advisory?: number;
|
|
108
|
+
blocking: number;
|
|
109
|
+
errors: number;
|
|
110
|
+
findings: number;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* A push's `policy_check`: the verdict with its findings and results, since a push answers no run.
|
|
114
|
+
* The lists hold the first 100 each, in the platform's order; the stored run (`run_id`) has them all.
|
|
115
|
+
*/
|
|
116
|
+
export interface PushPolicyCheck extends PolicyVerdict {
|
|
117
|
+
/**
|
|
118
|
+
* `coverage` for a caller without `workspace:policy` read: the findings are only those on the
|
|
119
|
+
* objects the push carried that the caller may read (the workspace too, for a push that carried
|
|
120
|
+
* the workspace document and a caller with `workspace:settings` read), trimmed (`CoverageFinding`),
|
|
121
|
+
* with `run_id` 0, `results` empty and a `note`. `counts` are about those findings, except
|
|
122
|
+
* `counts.errors` (the branch's); `blocking` is what a reader's push of the same change says, so
|
|
123
|
+
* the exit code is the same whoever pushed.
|
|
124
|
+
*/
|
|
125
|
+
access?: string;
|
|
126
|
+
/** The first blocking findings. */
|
|
127
|
+
blocking_findings?: PolicyFinding[];
|
|
128
|
+
/** What the lists are out of. */
|
|
129
|
+
counts?: PolicyCounts;
|
|
130
|
+
/**
|
|
131
|
+
* A trimmed answer's count of the findings on the objects the push does not list (never named).
|
|
132
|
+
* `basis` `introduced`: those the push introduced (not in the push gate's evaluation of the branch
|
|
133
|
+
* before it on the live branch; elsewhere not in the newest run that still described the branch);
|
|
134
|
+
* `all`: no baseline was known, so every finding there. An older platform sends no `basis`.
|
|
135
|
+
*/
|
|
136
|
+
elsewhere?: {
|
|
137
|
+
basis?: string;
|
|
138
|
+
blocking?: number;
|
|
139
|
+
total?: number;
|
|
140
|
+
};
|
|
141
|
+
/** The first findings, blocking first. */
|
|
142
|
+
findings?: PolicyFinding[];
|
|
143
|
+
/** The platform's sentence on what a trimmed answer leaves out (`access: "coverage"`). */
|
|
144
|
+
note?: string;
|
|
145
|
+
results?: PolicyRuleResult[];
|
|
146
|
+
/** `pushed_objects` beside `access: "coverage"`: the findings are about the pushed objects only. */
|
|
147
|
+
scope?: string;
|
|
148
|
+
/** Every finding, listed or not. */
|
|
149
|
+
total?: number;
|
|
150
|
+
/** Whether either list was cut. */
|
|
151
|
+
truncated?: boolean;
|
|
152
|
+
}
|
|
153
|
+
/** One policy that applies to an object, as the coverage route serves it. */
|
|
154
|
+
export interface ObjectCoveragePolicy {
|
|
155
|
+
blocking?: boolean;
|
|
156
|
+
/** `blocking` or `advisory`. */
|
|
157
|
+
enforcement?: string;
|
|
158
|
+
key?: string;
|
|
159
|
+
/** Why it applies here, one plain sentence per rule. */
|
|
160
|
+
reasons?: string[];
|
|
161
|
+
/**
|
|
162
|
+
* `failing` (a finding of it here), `not_checked` (no run, or the run did not evaluate it as it now
|
|
163
|
+
* stands), `could_not_check` (the run could not check it: a rule of it could not run, or the run
|
|
164
|
+
* stopped on an error before it) or `passing`, which a run that errored on another policy still gives.
|
|
165
|
+
*/
|
|
166
|
+
status?: string;
|
|
167
|
+
title?: string;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* `GET policy/object/coverage`: which active policies apply to one object, and its findings in the
|
|
171
|
+
* branch's newest run, trimmed for anyone who may read the object (`workspace:policy` read is not
|
|
172
|
+
* needed). The same trimmed shape for every caller.
|
|
173
|
+
*/
|
|
174
|
+
export interface ObjectCoverage {
|
|
175
|
+
access?: string;
|
|
176
|
+
findings?: CoverageFinding[];
|
|
177
|
+
note?: string;
|
|
178
|
+
object?: {
|
|
179
|
+
app_id?: number;
|
|
180
|
+
id?: number;
|
|
181
|
+
name?: string;
|
|
182
|
+
type?: string;
|
|
183
|
+
};
|
|
184
|
+
policies?: ObjectCoveragePolicy[];
|
|
185
|
+
/** The branch's newest ended run, `null` before the first. */
|
|
186
|
+
run?: null | {
|
|
187
|
+
started_at?: string;
|
|
188
|
+
status?: string;
|
|
189
|
+
};
|
|
190
|
+
summary?: {
|
|
191
|
+
advisory?: number;
|
|
192
|
+
applies?: number;
|
|
193
|
+
blocking?: number;
|
|
194
|
+
/** The policies that apply whose status is `could_not_check`; an older platform does not send it. */
|
|
195
|
+
could_not_check?: number;
|
|
196
|
+
not_checked?: number;
|
|
197
|
+
passing?: number;
|
|
198
|
+
/**
|
|
199
|
+
* `none_apply`, `findings`, `not_checked`, `check_failed` (only when a policy that applies here
|
|
200
|
+
* could not be checked) or `pass`.
|
|
201
|
+
*/
|
|
202
|
+
state?: string;
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/** A policy's place in its branch's newest run, as the platform serves it on every policy. */
|
|
206
|
+
export interface PolicyCoverage {
|
|
207
|
+
enforcement: null | string;
|
|
208
|
+
/** Whether the newest run evaluated this policy at all. */
|
|
209
|
+
included: boolean;
|
|
210
|
+
/** 0 when the branch has no run. */
|
|
211
|
+
run_id: number;
|
|
212
|
+
/** True only when the newest run evaluated a different version of this policy. */
|
|
213
|
+
stale: boolean;
|
|
214
|
+
version: null | number;
|
|
215
|
+
}
|
|
216
|
+
export interface Policy {
|
|
217
|
+
active: boolean;
|
|
218
|
+
enforcement: string;
|
|
219
|
+
id: number;
|
|
220
|
+
key: string;
|
|
221
|
+
latest_run?: PolicyCoverage;
|
|
222
|
+
rules?: Array<{
|
|
223
|
+
id: string;
|
|
224
|
+
}>;
|
|
225
|
+
title?: string;
|
|
226
|
+
/** When the policy was last written, as served; sent back as `last_updated_at` to refuse acting on a stale read. */
|
|
227
|
+
updated_at?: number | string;
|
|
228
|
+
/** The index of the policy's newest Version History entry; it moves only when the definition changes. */
|
|
229
|
+
version: number;
|
|
230
|
+
}
|
|
231
|
+
/** One stored run as the run list serves it: the verdict and counts, without findings or results. */
|
|
232
|
+
export interface PolicyRunSummary {
|
|
233
|
+
counts: {
|
|
234
|
+
blocking: number;
|
|
235
|
+
errors: number;
|
|
236
|
+
findings: number;
|
|
237
|
+
};
|
|
238
|
+
finished_at?: string;
|
|
239
|
+
id: number;
|
|
240
|
+
objects_checked: number;
|
|
241
|
+
started_at?: string;
|
|
242
|
+
status: string;
|
|
243
|
+
trigger?: string;
|
|
244
|
+
}
|
|
245
|
+
/** One run in full, as `GET run/{id}` serves it. */
|
|
246
|
+
export interface PolicyRun {
|
|
247
|
+
findings?: PolicyFinding[];
|
|
248
|
+
finished_at?: number | string;
|
|
249
|
+
/** 0 for an evaluation that was not stored. */
|
|
250
|
+
id?: number;
|
|
251
|
+
/** How many workspace objects the run inspected. */
|
|
252
|
+
objects_checked?: number;
|
|
253
|
+
/** The snapshot of the policies as they were when the run went out. */
|
|
254
|
+
policies?: PolicySnapshotPolicy[];
|
|
255
|
+
results?: PolicyRuleResult[];
|
|
256
|
+
started_at?: number | string;
|
|
257
|
+
status?: string;
|
|
258
|
+
trigger?: string;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* What `policy evaluate` answers: the run as `GET run/{id}` serves it, whether it was stored, and the verdict.
|
|
262
|
+
* With no active policy on the branch it is no run at all: `id` 0, `status` `not_applicable`, nothing evaluated.
|
|
263
|
+
*/
|
|
264
|
+
export interface PolicyEvaluation extends PolicyRun {
|
|
265
|
+
/** The summary answer's counts (`--summary`). */
|
|
266
|
+
counts?: PolicyCounts;
|
|
267
|
+
/** `blocking_total`: every blocking finding, beside the summary answer's listed ones. */
|
|
268
|
+
policy_check?: PolicyVerdict & {
|
|
269
|
+
blocking_finding_ids?: string[];
|
|
270
|
+
blocking_total?: number;
|
|
271
|
+
};
|
|
272
|
+
stored?: boolean;
|
|
273
|
+
/** The summary answer: every finding, and whether `findings` lists only the first. */
|
|
274
|
+
total?: number;
|
|
275
|
+
truncated?: boolean;
|
|
276
|
+
}
|
|
277
|
+
/** One run without its findings, as `GET run/{id}/summary` serves it. */
|
|
278
|
+
export interface PolicyRunHead extends PolicyRun {
|
|
279
|
+
counts?: PolicyCounts;
|
|
280
|
+
/** The snapshot, each policy with its verdict in this run. */
|
|
281
|
+
policies?: Array<PolicySnapshotPolicy & {
|
|
282
|
+
blocking?: boolean;
|
|
283
|
+
findings?: number;
|
|
284
|
+
objects_checked?: number;
|
|
285
|
+
status?: string;
|
|
286
|
+
}>;
|
|
287
|
+
}
|
|
288
|
+
/** One page of a run's findings, as `GET run/{id}/findings` serves it. */
|
|
289
|
+
export interface PolicyFindingsPage {
|
|
290
|
+
items: PolicyFinding[];
|
|
291
|
+
limit: number;
|
|
292
|
+
offset: number;
|
|
293
|
+
/** The findings that match the filters, listed or not. */
|
|
294
|
+
total: number;
|
|
295
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|