@xano/cli 1.3.1-beta.0 → 1.3.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 +5 -269
- package/dist/base-command.d.ts +1 -12
- package/dist/base-command.js +22 -36
- package/dist/commands/branch/set_live/index.d.ts +0 -22
- package/dist/commands/branch/set_live/index.js +1 -60
- package/dist/commands/ephemeral/push/index.js +1 -6
- package/dist/commands/function/create/index.d.ts +0 -15
- package/dist/commands/function/create/index.js +0 -40
- package/dist/commands/function/edit/index.d.ts +0 -15
- package/dist/commands/function/edit/index.js +0 -40
- package/dist/commands/function/run/index.d.ts +1 -0
- package/dist/commands/function/run/index.js +10 -2
- package/dist/commands/release/create/index.js +0 -7
- package/dist/commands/release/deploy/index.d.ts +0 -28
- package/dist/commands/release/deploy/index.js +6 -90
- package/dist/commands/release/import/index.js +1 -5
- package/dist/commands/release/list/index.d.ts +0 -7
- package/dist/commands/release/list/index.js +10 -54
- package/dist/commands/release/push/index.js +1 -19
- package/dist/commands/sandbox/push/index.js +1 -6
- package/dist/commands/tenant/create/index.d.ts +0 -3
- package/dist/commands/tenant/create/index.js +0 -21
- package/dist/commands/tenant/deploy_release/index.d.ts +0 -40
- package/dist/commands/tenant/deploy_release/index.js +4 -186
- package/dist/commands/tenant/edit/index.d.ts +0 -2
- package/dist/commands/tenant/edit/index.js +4 -39
- package/dist/commands/workspace/pull/index.d.ts +0 -10
- package/dist/commands/workspace/pull/index.js +7 -70
- package/dist/commands/workspace/push/index.d.ts +0 -19
- package/dist/commands/workspace/push/index.js +5 -124
- package/dist/utils/document-parser.d.ts +0 -10
- package/dist/utils/document-parser.js +0 -21
- package/dist/utils/multidoc-push.d.ts +2 -55
- package/dist/utils/multidoc-push.js +27 -103
- package/oclif.manifest.json +3658 -6647
- package/package.json +1 -7
- package/dist/commands/policy/catalogue/index.d.ts +0 -15
- package/dist/commands/policy/catalogue/index.js +0 -29
- package/dist/commands/policy/create/index.d.ts +0 -18
- package/dist/commands/policy/create/index.js +0 -39
- package/dist/commands/policy/delete/index.d.ts +0 -19
- package/dist/commands/policy/delete/index.js +0 -61
- package/dist/commands/policy/evaluate/index.d.ts +0 -32
- package/dist/commands/policy/evaluate/index.js +0 -71
- package/dist/commands/policy/list/index.d.ts +0 -14
- package/dist/commands/policy/list/index.js +0 -21
- package/dist/commands/policy/parse/index.d.ts +0 -19
- package/dist/commands/policy/parse/index.js +0 -18
- package/dist/commands/policy/publish/index.d.ts +0 -20
- package/dist/commands/policy/publish/index.js +0 -38
- package/dist/commands/policy/runs/index.d.ts +0 -54
- package/dist/commands/policy/runs/index.js +0 -273
- package/dist/commands/policy/status/index.d.ts +0 -21
- package/dist/commands/policy/status/index.js +0 -54
- package/dist/commands/skills/pull/index.d.ts +0 -30
- package/dist/commands/skills/pull/index.js +0 -118
- package/dist/commands/tenant_deploy_request/bypass/index.d.ts +0 -31
- package/dist/commands/tenant_deploy_request/bypass/index.js +0 -109
- package/dist/commands/tenant_deploy_request/create/index.d.ts +0 -21
- package/dist/commands/tenant_deploy_request/create/index.js +0 -108
- package/dist/commands/tenant_deploy_request/edit/index.d.ts +0 -22
- package/dist/commands/tenant_deploy_request/edit/index.js +0 -103
- package/dist/commands/tenant_deploy_request/get/index.d.ts +0 -25
- package/dist/commands/tenant_deploy_request/get/index.js +0 -116
- package/dist/commands/tenant_deploy_request/list/index.d.ts +0 -20
- package/dist/commands/tenant_deploy_request/list/index.js +0 -122
- package/dist/commands/tenant_deploy_request/revision/index.d.ts +0 -21
- package/dist/commands/tenant_deploy_request/revision/index.js +0 -83
- package/dist/commands/tenant_deploy_request/set_status/index.d.ts +0 -38
- package/dist/commands/tenant_deploy_request/set_status/index.js +0 -159
- package/dist/policy-command.d.ts +0 -90
- package/dist/policy-command.js +0 -94
- package/dist/utils/policy/catalogue.d.ts +0 -7
- package/dist/utils/policy/catalogue.js +0 -72
- package/dist/utils/policy/errors.d.ts +0 -12
- package/dist/utils/policy/errors.js +0 -61
- package/dist/utils/policy/feedback.d.ts +0 -68
- package/dist/utils/policy/feedback.js +0 -165
- package/dist/utils/policy/findings.d.ts +0 -23
- package/dist/utils/policy/findings.js +0 -65
- package/dist/utils/policy/gate.d.ts +0 -161
- package/dist/utils/policy/gate.js +0 -201
- package/dist/utils/policy/goal.d.ts +0 -46
- package/dist/utils/policy/goal.js +0 -95
- package/dist/utils/policy/permission.d.ts +0 -23
- package/dist/utils/policy/permission.js +0 -84
- package/dist/utils/policy/push-gate.d.ts +0 -5
- package/dist/utils/policy/push-gate.js +0 -29
- package/dist/utils/policy/release.d.ts +0 -85
- package/dist/utils/policy/release.js +0 -115
- package/dist/utils/policy/request.d.ts +0 -55
- package/dist/utils/policy/request.js +0 -115
- package/dist/utils/policy/runs.d.ts +0 -30
- package/dist/utils/policy/runs.js +0 -101
- package/dist/utils/policy/status.d.ts +0 -47
- package/dist/utils/policy/status.js +0 -117
- package/dist/utils/policy/types.d.ts +0 -185
- package/dist/utils/policy/types.js +0 -1
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { POLICY_KEY_PATTERN } from '../document-parser.js';
|
|
2
|
-
/**
|
|
3
|
-
* The policy document for a goal: its sparse settings with the `--param` assignments applied, every
|
|
4
|
-
* `needs` path filled, and a key no policy on the branch holds (compared case-insensitively). A taken
|
|
5
|
-
* goal key gets a free numeric suffix; a taken or malformed `--key` is refused.
|
|
6
|
-
*/
|
|
7
|
-
export function policyFromGoal(goal, takenKeys, options = {}) {
|
|
8
|
-
const { key, keyRule, overrides = [] } = options;
|
|
9
|
-
const taken = new Set(takenKeys.map(value => value.toLowerCase()));
|
|
10
|
-
let chosen = key ?? goal.key;
|
|
11
|
-
if (!keyPattern(keyRule).test(chosen))
|
|
12
|
-
throw new Error(keyRefusal(keyRule, chosen));
|
|
13
|
-
if (key !== undefined && taken.has(chosen.toLowerCase()))
|
|
14
|
-
throw new Error(`Policy ${chosen} already exists. Choose a new --key or use policy publish to update it.`);
|
|
15
|
-
for (let suffix = 2; taken.has(chosen.toLowerCase()); suffix++)
|
|
16
|
-
chosen = `${goal.key.slice(0, 63 - String(suffix).length)}-${suffix}`;
|
|
17
|
-
const rules = goal.rules.map(rule => ({ check: rule.check, params: Array.isArray(rule.params) ? {} : structuredClone(rule.params), title: rule.title }));
|
|
18
|
-
for (const assignment of overrides)
|
|
19
|
-
applyOverride(rules, assignment);
|
|
20
|
-
const missing = goal.rules.flatMap((rule, index) => (rule.needs ?? []).filter(path => !filled(readPath(rules[index].params, path))).map(path => `${index + 1}.${path}`));
|
|
21
|
-
if (missing.length > 0)
|
|
22
|
-
throw new Error(`Fill the goal's required settings with --param 'N.path=JSON': ${missing.join(', ')}.`);
|
|
23
|
-
return { key: chosen, rules, severity: goal.severity, statement: goal.summary, title: goal.goal };
|
|
24
|
-
}
|
|
25
|
-
/** The catalogue's key pattern, or the offline copy when the catalogue serves none (or one that does not compile). */
|
|
26
|
-
function keyPattern(rule) {
|
|
27
|
-
if (typeof rule?.pattern !== 'string' || rule.pattern === '')
|
|
28
|
-
return POLICY_KEY_PATTERN;
|
|
29
|
-
try {
|
|
30
|
-
return new RegExp(rule.pattern);
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
return POLICY_KEY_PATTERN;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
/** The catalogue's refusal for a malformed key, naming it, or the offline sentence. */
|
|
37
|
-
function keyRefusal(rule, key) {
|
|
38
|
-
return typeof rule?.message === 'string' && rule.message.trim()
|
|
39
|
-
? rule.message.replaceAll('%s', key)
|
|
40
|
-
: 'A policy key must be 1–64 letters, digits, dots, underscores or hyphens, starting with a letter or digit.';
|
|
41
|
-
}
|
|
42
|
-
/** The value at a dotted path of a rule's params, or undefined when any step is missing. */
|
|
43
|
-
function readPath(params, path) {
|
|
44
|
-
let value = params;
|
|
45
|
-
for (const part of path.split('.')) {
|
|
46
|
-
if (!value || typeof value !== 'object' || !Object.hasOwn(value, part))
|
|
47
|
-
return undefined;
|
|
48
|
-
value = value[part];
|
|
49
|
-
}
|
|
50
|
-
return value;
|
|
51
|
-
}
|
|
52
|
-
/** Whether a `needs` value is set: not empty, null or blank; `false` and `0` count as set. */
|
|
53
|
-
function filled(value) {
|
|
54
|
-
if (Array.isArray(value))
|
|
55
|
-
return value.some(item => filled(item));
|
|
56
|
-
if (value && typeof value === 'object')
|
|
57
|
-
return Object.keys(value).length > 0;
|
|
58
|
-
return value !== undefined && value !== null && (typeof value !== 'string' || value.trim() !== '');
|
|
59
|
-
}
|
|
60
|
-
/** Apply one `--param [N.]path=JSON` assignment to its rule's params, refusing unsafe paths and non-JSON values. */
|
|
61
|
-
function applyOverride(rules, assignment) {
|
|
62
|
-
const equals = assignment.indexOf('=');
|
|
63
|
-
if (equals < 1)
|
|
64
|
-
throw new Error('Use --param path=JSON or --param N.path=JSON (rule numbers start at 1).');
|
|
65
|
-
const parts = assignment.slice(0, equals).split('.');
|
|
66
|
-
let index = 0;
|
|
67
|
-
if (/^\d+$/.test(parts[0]))
|
|
68
|
-
index = Number(parts.shift()) - 1;
|
|
69
|
-
else if (rules.length !== 1)
|
|
70
|
-
throw new Error('Include the rule number in --param N.path=JSON for a goal with multiple rules.');
|
|
71
|
-
if (!Number.isSafeInteger(index) || !rules[index])
|
|
72
|
-
throw new Error(`Rule ${index + 1} does not exist in this goal.`);
|
|
73
|
-
if (parts.length === 0 || parts.some(part => !/^[A-Za-z_][A-Za-z0-9_]*$/.test(part) || ['__proto__', 'constructor', 'prototype'].includes(part)))
|
|
74
|
-
throw new Error('Invalid parameter path. Use parameter names separated by dots.');
|
|
75
|
-
let value;
|
|
76
|
-
try {
|
|
77
|
-
value = JSON.parse(assignment.slice(equals + 1), (_key, parsed) => {
|
|
78
|
-
if (typeof parsed === 'number' && !Number.isFinite(parsed))
|
|
79
|
-
throw new Error('Numbers must be finite.');
|
|
80
|
-
return parsed;
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
throw new Error(`The value for ${assignment.slice(0, equals)} must be JSON: a quoted string, finite number, boolean, array or object.`);
|
|
85
|
-
}
|
|
86
|
-
let target = rules[index].params;
|
|
87
|
-
for (const part of parts.slice(0, -1)) {
|
|
88
|
-
if (target[part] === undefined)
|
|
89
|
-
target[part] = {};
|
|
90
|
-
if (!target[part] || typeof target[part] !== 'object' || Array.isArray(target[part]))
|
|
91
|
-
throw new Error(`Cannot set a nested parameter inside ${part}.`);
|
|
92
|
-
target = target[part];
|
|
93
|
-
}
|
|
94
|
-
target[parts.at(-1)] = value;
|
|
95
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The refusal of a change that weakens a policy active and mandatory on the branch (demotes,
|
|
3
|
-
* deactivates or deletes it, or loosens one of its rules; for a set-live, a live policy the branch
|
|
4
|
-
* lacks) from a caller without the `workspace:policy` update permission. It is a permission refusal,
|
|
5
|
-
* not a blocking finding, so a command exits 1 on it. `payload.policies` names the policies.
|
|
6
|
-
*/
|
|
7
|
-
export declare const WEAKENING_REFUSAL = "policy_weakening_permission_required";
|
|
8
|
-
/** Guidance appended to a refused policy request, given the HTTP status and the refusal's payload. */
|
|
9
|
-
export declare function policyPermissionGuidance(status: number, payload: unknown): string;
|
|
10
|
-
/**
|
|
11
|
-
* Guidance for a `workspace push` (or its preview) refused because it would change policies, or
|
|
12
|
-
* because its policy files weaken a mandatory policy of the live branch, or `undefined` for any
|
|
13
|
-
* other refusal.
|
|
14
|
-
*/
|
|
15
|
-
export declare function policyFilePushGuidance(payload: unknown): string | undefined;
|
|
16
|
-
/**
|
|
17
|
-
* Guidance for a change refused with `policy_weakening_permission_required`. The platform's sentence
|
|
18
|
-
* already names the policies and what was left alone; this says why (a delete of a mandatory policy,
|
|
19
|
-
* or a check that could not read the policies and so fails closed), that `--policy-override` does
|
|
20
|
-
* not stand in for the permission when the command has that flag (`overrideFlag`), and how to go on:
|
|
21
|
-
* `ways` are the command's own, before the fallback of asking someone who holds the permission.
|
|
22
|
-
*/
|
|
23
|
-
export declare function policyWeakeningGuidance(payload: unknown, ways?: string[], overrideFlag?: boolean): string;
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
const TOKEN_SETTINGS = 'Instance settings → Metadata API & MCP Server → Manage Access Tokens';
|
|
2
|
-
/**
|
|
3
|
-
* The refusal of a change that weakens a policy active and mandatory on the branch (demotes,
|
|
4
|
-
* deactivates or deletes it, or loosens one of its rules; for a set-live, a live policy the branch
|
|
5
|
-
* lacks) from a caller without the `workspace:policy` update permission. It is a permission refusal,
|
|
6
|
-
* not a blocking finding, so a command exits 1 on it. `payload.policies` names the policies.
|
|
7
|
-
*/
|
|
8
|
-
export const WEAKENING_REFUSAL = 'policy_weakening_permission_required';
|
|
9
|
-
function refusalOf(payload) {
|
|
10
|
-
return payload && typeof payload === 'object' && !Array.isArray(payload) ? payload : {};
|
|
11
|
-
}
|
|
12
|
-
/** `workspace:policy create`, or just `workspace:policy` when the refusal names no level. */
|
|
13
|
-
function permissionAt(refusal) {
|
|
14
|
-
return `\`workspace:policy\`${typeof refusal.level === 'string' && refusal.level ? ` ${refusal.level}` : ''}`;
|
|
15
|
-
}
|
|
16
|
-
/** Guidance appended to a refused policy request, given the HTTP status and the refusal's payload. */
|
|
17
|
-
export function policyPermissionGuidance(status, payload) {
|
|
18
|
-
if (status === 401) {
|
|
19
|
-
return `\nThe Metadata API token was not accepted: it is missing, expired or revoked. Check the active profile (xano profile list) or create a new token: ${TOKEN_SETTINGS}.`;
|
|
20
|
-
}
|
|
21
|
-
const refusal = refusalOf(payload);
|
|
22
|
-
switch (refusal.code) {
|
|
23
|
-
case 'policy_feature_disabled': {
|
|
24
|
-
return '\nThe Policies feature is turned off for this instance, so no token or permission can reach it. Ask your Xano contact to enable Policies.';
|
|
25
|
-
}
|
|
26
|
-
case 'policy_permission_required': {
|
|
27
|
-
return `\nYour role on this workspace lacks the ${permissionAt(refusal)} permission. Your token is fine — reissuing it will not help. Ask an instance admin to grant it.${refusal.level === 'read' ? '' : ' Reading policies and running checks need only read.'}`;
|
|
28
|
-
}
|
|
29
|
-
case 'policy_scope_required': {
|
|
30
|
-
return `\nThis Metadata API token was created without the ${permissionAt(refusal)} scope. Create a token that has it: ${TOKEN_SETTINGS}.`;
|
|
31
|
-
}
|
|
32
|
-
case WEAKENING_REFUSAL: {
|
|
33
|
-
return policyWeakeningGuidance(payload);
|
|
34
|
-
}
|
|
35
|
-
default: {
|
|
36
|
-
return '';
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Guidance for a `workspace push` (or its preview) refused because it would change policies, or
|
|
42
|
-
* because its policy files weaken a mandatory policy of the live branch, or `undefined` for any
|
|
43
|
-
* other refusal.
|
|
44
|
-
*/
|
|
45
|
-
export function policyFilePushGuidance(payload) {
|
|
46
|
-
const refusal = refusalOf(payload);
|
|
47
|
-
if (refusal.code === WEAKENING_REFUSAL) {
|
|
48
|
-
return policyWeakeningGuidance(payload, [
|
|
49
|
-
'To push everything else, leave the policy files out: xano workspace push -e "policies/*"',
|
|
50
|
-
'To discard your local policy edits, pull again: xano workspace pull',
|
|
51
|
-
], true);
|
|
52
|
-
}
|
|
53
|
-
if (!Array.isArray(refusal.policies) || refusal.policies.length === 0)
|
|
54
|
-
return undefined;
|
|
55
|
-
const remedy = {
|
|
56
|
-
policy_permission_required: '\n - To change a policy, ask someone with that permission to push it or to run xano policy publish.',
|
|
57
|
-
policy_scope_required: `\n - To change a policy yourself, create a token with that scope: ${TOKEN_SETTINGS}.`,
|
|
58
|
-
}[String(refusal.code)];
|
|
59
|
-
if (!remedy)
|
|
60
|
-
return undefined;
|
|
61
|
-
return (`\nThis push contains policy files that differ from the policies on the branch, and changing them needs the ${permissionAt(refusal)} ${refusal.code === 'policy_scope_required' ? 'scope on your token' : 'permission'}.` +
|
|
62
|
-
'\nNothing was imported. Policy files that are unchanged never cause this.' +
|
|
63
|
-
'\n - To push everything else, leave the policy files out: xano workspace push -e "policies/*"' +
|
|
64
|
-
'\n - To discard your local policy edits, pull again: xano workspace pull' +
|
|
65
|
-
remedy);
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Guidance for a change refused with `policy_weakening_permission_required`. The platform's sentence
|
|
69
|
-
* already names the policies and what was left alone; this says why (a delete of a mandatory policy,
|
|
70
|
-
* or a check that could not read the policies and so fails closed), that `--policy-override` does
|
|
71
|
-
* not stand in for the permission when the command has that flag (`overrideFlag`), and how to go on:
|
|
72
|
-
* `ways` are the command's own, before the fallback of asking someone who holds the permission.
|
|
73
|
-
*/
|
|
74
|
-
export function policyWeakeningGuidance(payload, ways = [], overrideFlag = false) {
|
|
75
|
-
const refusal = refusalOf(payload);
|
|
76
|
-
const permission = `${permissionAt({ level: refusal.level ?? 'update' })} permission`;
|
|
77
|
-
const why = refusal.unavailable === true
|
|
78
|
-
? `The policies could not be read to check this, so only someone with the ${permission} may proceed.`
|
|
79
|
-
: refusal.gate === 'delete'
|
|
80
|
-
? `Deleting a policy that is active and mandatory weakens it, so it needs the ${permission}, not only delete.`
|
|
81
|
-
: `Weakening means demoting, deactivating or deleting a mandatory policy, or loosening one of its rules, and it needs the ${permission}.`;
|
|
82
|
-
return (`\n${why}${overrideFlag ? ' --policy-override does not stand in for it.' : ''}` +
|
|
83
|
-
[...ways, `${ways.length > 0 ? 'Or ask' : 'Ask'} someone who holds that permission to make this change, or an instance admin to grant it to your role.`].map(way => `\n - ${way}`).join(''));
|
|
84
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { findingLine } from './findings.js';
|
|
2
|
-
/**
|
|
3
|
-
* One blocking finding of a refused push: its rule, policy, object and message (a finding's message
|
|
4
|
-
* rarely names its object), and whether the push introduced it or changed its object.
|
|
5
|
-
*/
|
|
6
|
-
function refusedFindingLine(finding) {
|
|
7
|
-
const reason = typeof finding.gate_reason === 'string' && finding.gate_reason.trim() ? ` (${finding.gate_reason.trim()})` : '';
|
|
8
|
-
return `${findingLine(finding, new Map())}${reason}`;
|
|
9
|
-
}
|
|
10
|
-
/** Preserve a gate refusal through shared push and operational-error wrappers. */
|
|
11
|
-
export class PushPolicyGateError extends Error {
|
|
12
|
-
payload;
|
|
13
|
-
constructor(payload) {
|
|
14
|
-
const count = (key) => typeof payload[key] === 'number' ? payload[key] : 0;
|
|
15
|
-
const findings = Array.isArray(payload.findings) ? payload.findings.slice(0, 100) : [];
|
|
16
|
-
const lines = findings.flatMap(finding => finding && typeof finding === 'object' ? [refusedFindingLine(finding)] : []);
|
|
17
|
-
const guidance = payload.can_override === true && payload.override_denied !== true
|
|
18
|
-
? 'To proceed with an audited reason, retry with --policy-override "reason".'
|
|
19
|
-
: 'Fix the findings or ask someone with workspace:policy update permission to override with a reason.';
|
|
20
|
-
const total = count('total');
|
|
21
|
-
super([
|
|
22
|
-
`Push refused: ${total} blocking policy finding${total === 1 ? '' : 's'} (${count('introduced')} introduced, ${count('changed')} on changed objects). Nothing was imported.`,
|
|
23
|
-
...lines,
|
|
24
|
-
...(payload.truncated ? ['Only the first findings are listed.'] : []),
|
|
25
|
-
guidance,
|
|
26
|
-
].join('\n'));
|
|
27
|
-
this.payload = payload;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import type { PolicyRunHead } from './types.js';
|
|
2
|
-
import { type PolicyRequestHost, type PolicyRequestRoute } from './request.js';
|
|
3
|
-
/**
|
|
4
|
-
* One release's stored check as `GET release/policy_check` lists it, the read behind Studio's
|
|
5
|
-
* Policies column: the run, its status, when it finished, its finding counts and how many policies
|
|
6
|
-
* the release ships. A release without a stored run is not listed at all.
|
|
7
|
-
*/
|
|
8
|
-
export interface ReleasePolicyCheck {
|
|
9
|
-
counts?: {
|
|
10
|
-
advisory?: number;
|
|
11
|
-
blocking?: number;
|
|
12
|
-
errors?: number;
|
|
13
|
-
findings?: number;
|
|
14
|
-
};
|
|
15
|
-
finished_at?: string;
|
|
16
|
-
/** How many policies the release ships, inactive ones included. */
|
|
17
|
-
policies?: number;
|
|
18
|
-
release_id?: number;
|
|
19
|
-
run_id?: number;
|
|
20
|
-
/** `pass`, `fail` (a rule found something, advisory or not) or `error` (a rule could not run). */
|
|
21
|
-
status?: string;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* The stored checks of these releases, by release id, or `null` when they could not be read: the
|
|
25
|
-
* Policies feature is off, the credential lacks `workspace:policy` read, the platform has no such
|
|
26
|
-
* route, or the request failed. A release the answer leaves out has no stored check. The read
|
|
27
|
-
* stores nothing and never checks a release on demand.
|
|
28
|
-
*/
|
|
29
|
-
export declare function readReleasePolicyChecks(host: Omit<PolicyRequestHost, 'error'>, route: Omit<PolicyRequestRoute, 'label' | 'path'>, releaseIds: number[]): Promise<Map<number, ReleasePolicyCheck> | null>;
|
|
30
|
-
/**
|
|
31
|
-
* A release's stored check as a tag on its list line, worded as Studio's Policies column: the
|
|
32
|
-
* findings it holds (`2 blocking, 1 advisory`, or `11 advisory`), `passed` when it holds none,
|
|
33
|
-
* `none shipped` when the release carries no policies, `could not check` when a rule could not
|
|
34
|
-
* run, and `not checked` for a release with no stored check. The tag is the release's own check,
|
|
35
|
-
* its code against the policies it ships; whether a deploy is held is each tenant's question
|
|
36
|
-
* (`tenant deploy_release --check`), so it never says blocked.
|
|
37
|
-
*/
|
|
38
|
-
export declare function releasePolicyCheckTag(check: null | ReleasePolicyCheck | undefined): string;
|
|
39
|
-
/**
|
|
40
|
-
* The policy check a release cut stored (`policy_run` on the create, multidoc push and import
|
|
41
|
-
* answers): whether one was recorded (`recorded`, or `disabled`, `skipped` or `error` with a
|
|
42
|
-
* message), the run, its verdict and how many of its findings block. `null` for a credential that
|
|
43
|
-
* cannot read policies; absent from a platform that does not check releases.
|
|
44
|
-
*/
|
|
45
|
-
export interface ReleasePolicyRun {
|
|
46
|
-
advisory?: number;
|
|
47
|
-
blocking?: number;
|
|
48
|
-
message?: string;
|
|
49
|
-
run_id?: number;
|
|
50
|
-
/** `pass`, `fail` or `error`; empty when nothing was recorded. */
|
|
51
|
-
run_status?: string;
|
|
52
|
-
status?: string;
|
|
53
|
-
}
|
|
54
|
-
/** A release's stored run, as `GET release/{id}/policy_run` serves it: a run summary plus the release's own keys. */
|
|
55
|
-
export interface ReleaseRunHead extends PolicyRunHead {
|
|
56
|
-
release?: {
|
|
57
|
-
branch?: {
|
|
58
|
-
id?: number;
|
|
59
|
-
label?: string;
|
|
60
|
-
};
|
|
61
|
-
id?: number;
|
|
62
|
-
};
|
|
63
|
-
/** Every policy the release carries, inactive ones included. */
|
|
64
|
-
shipped?: Array<{
|
|
65
|
-
active?: boolean;
|
|
66
|
-
enforcement?: string;
|
|
67
|
-
key?: string;
|
|
68
|
-
title?: string;
|
|
69
|
-
}>;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* The cut's policy check as summary lines under a release's own (indented), or none when the answer
|
|
73
|
-
* carries none. A cut is never refused: blocking findings are judged per tenant at deploy, so the
|
|
74
|
-
* lines point at the deploy preview and the release's findings.
|
|
75
|
-
*/
|
|
76
|
-
export declare function releasePolicyRunLines(policyRun: unknown, releaseName?: string, releaseId?: number): string[];
|
|
77
|
-
/** The release's own facts about its check: where it was cut from and the policies it ships. */
|
|
78
|
-
export declare function releaseRunLines(releaseName: string, releaseId: number, run: ReleaseRunHead): string[];
|
|
79
|
-
/**
|
|
80
|
-
* A `release import` the platform refused for the policies the archive carries, as one message with
|
|
81
|
-
* its remedy, or `null` for any other failure. An archive that says it carries policies needs the
|
|
82
|
-
* `workspace:policy` create and update permission to import (`policy_permission_required` for the
|
|
83
|
-
* role, `policy_scope_required` for the token), and nothing is stored without it.
|
|
84
|
-
*/
|
|
85
|
-
export declare function releaseImportRefusal(text: string, status: number, url: string): null | string;
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { describePolicyError } from './errors.js';
|
|
2
|
-
import { quoted } from './gate.js';
|
|
3
|
-
import { policyPermissionGuidance } from './permission.js';
|
|
4
|
-
import { policyRequest } from './request.js';
|
|
5
|
-
/** The most releases one `release/policy_check` request may name (the platform refuses more). */
|
|
6
|
-
const CHECKS_PER_REQUEST = 200;
|
|
7
|
-
/** A request host's `error` that throws instead of exiting, for a read that may fail quietly. */
|
|
8
|
-
function fail(message) {
|
|
9
|
-
throw new Error(message);
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* The stored checks of these releases, by release id, or `null` when they could not be read: the
|
|
13
|
-
* Policies feature is off, the credential lacks `workspace:policy` read, the platform has no such
|
|
14
|
-
* route, or the request failed. A release the answer leaves out has no stored check. The read
|
|
15
|
-
* stores nothing and never checks a release on demand.
|
|
16
|
-
*/
|
|
17
|
-
export async function readReleasePolicyChecks(host, route, releaseIds) {
|
|
18
|
-
const ids = [...new Set(releaseIds.filter(id => Number.isSafeInteger(id) && id > 0))];
|
|
19
|
-
const checks = new Map();
|
|
20
|
-
if (ids.length === 0)
|
|
21
|
-
return checks;
|
|
22
|
-
const request = policyRequest({ ...host, error: fail }, { ...route, label: 'Release policy check', path: '' });
|
|
23
|
-
try {
|
|
24
|
-
for (let start = 0; start < ids.length; start += CHECKS_PER_REQUEST) {
|
|
25
|
-
const batch = ids.slice(start, start + CHECKS_PER_REQUEST).map(String);
|
|
26
|
-
// Each batch is one request; the list is far shorter than a batch in practice.
|
|
27
|
-
// eslint-disable-next-line no-await-in-loop
|
|
28
|
-
const answer = await request('/release/policy_check', 'GET', undefined, { release_id: batch });
|
|
29
|
-
const items = answer && typeof answer === 'object' ? answer.items : undefined;
|
|
30
|
-
if (!Array.isArray(items))
|
|
31
|
-
return null;
|
|
32
|
-
for (const item of items) {
|
|
33
|
-
if (item && typeof item === 'object' && typeof item.release_id === 'number')
|
|
34
|
-
checks.set(item.release_id, item);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
return checks;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* A release's stored check as a tag on its list line, worded as Studio's Policies column: the
|
|
45
|
-
* findings it holds (`2 blocking, 1 advisory`, or `11 advisory`), `passed` when it holds none,
|
|
46
|
-
* `none shipped` when the release carries no policies, `could not check` when a rule could not
|
|
47
|
-
* run, and `not checked` for a release with no stored check. The tag is the release's own check,
|
|
48
|
-
* its code against the policies it ships; whether a deploy is held is each tenant's question
|
|
49
|
-
* (`tenant deploy_release --check`), so it never says blocked.
|
|
50
|
-
*/
|
|
51
|
-
export function releasePolicyCheckTag(check) {
|
|
52
|
-
return `[policies: ${releasePolicyCheckLabel(check)}]`;
|
|
53
|
-
}
|
|
54
|
-
function releasePolicyCheckLabel(check) {
|
|
55
|
-
if (!check)
|
|
56
|
-
return 'not checked';
|
|
57
|
-
const findings = Math.max(0, check.counts?.findings ?? 0);
|
|
58
|
-
const blocking = Math.max(0, check.counts?.blocking ?? 0);
|
|
59
|
-
const advisory = Math.max(0, check.counts?.advisory ?? findings - blocking);
|
|
60
|
-
const counts = [blocking > 0 ? `${blocking} blocking` : '', advisory > 0 ? `${advisory} advisory` : ''].filter(Boolean);
|
|
61
|
-
if (check.status === 'error')
|
|
62
|
-
return ['could not check', ...counts].join(', ');
|
|
63
|
-
if (counts.length > 0)
|
|
64
|
-
return counts.join(', ');
|
|
65
|
-
return (check.policies ?? 0) > 0 ? 'passed' : 'none shipped';
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* The cut's policy check as summary lines under a release's own (indented), or none when the answer
|
|
69
|
-
* carries none. A cut is never refused: blocking findings are judged per tenant at deploy, so the
|
|
70
|
-
* lines point at the deploy preview and the release's findings.
|
|
71
|
-
*/
|
|
72
|
-
export function releasePolicyRunLines(policyRun, releaseName, releaseId) {
|
|
73
|
-
if (!policyRun || typeof policyRun !== 'object')
|
|
74
|
-
return [];
|
|
75
|
-
const check = policyRun;
|
|
76
|
-
const status = check.status?.trim() || 'unknown';
|
|
77
|
-
if (status !== 'recorded') {
|
|
78
|
-
return [` Policy check ${status}: ${check.message?.trim() || 'no message returned.'}`];
|
|
79
|
-
}
|
|
80
|
-
const blocking = check.blocking ?? 0;
|
|
81
|
-
const advisory = check.advisory ?? 0;
|
|
82
|
-
const findings = blocking + advisory === 0 ? 'no findings' : `${blocking} blocking, ${advisory} advisory ${blocking + advisory === 1 ? 'finding' : 'findings'}`;
|
|
83
|
-
const lines = [` Policy check: ${check.run_status || 'recorded'} (run ${check.run_id ?? '?'}), ${findings}`];
|
|
84
|
-
if (check.message?.trim())
|
|
85
|
-
lines.push(` ${check.message.trim()}`);
|
|
86
|
-
const name = releaseName?.trim() ? quoted(releaseName.trim()) : '<release_name>';
|
|
87
|
-
const target = releaseName?.trim() || !releaseId ? `--release ${name}` : `--release-id ${releaseId}`;
|
|
88
|
-
if (blocking + advisory > 0)
|
|
89
|
-
lines.push(` Findings: xano policy runs ${target}`);
|
|
90
|
-
if (blocking > 0 && releaseName?.trim())
|
|
91
|
-
lines.push(` Its blocking findings block a deploy to a standard or run tenant: xano tenant deploy_release <tenant> --release ${name} --check`);
|
|
92
|
-
return lines;
|
|
93
|
-
}
|
|
94
|
-
/** The release's own facts about its check: where it was cut from and the policies it ships. */
|
|
95
|
-
export function releaseRunLines(releaseName, releaseId, run) {
|
|
96
|
-
const shipped = run.shipped ?? [];
|
|
97
|
-
const keys = shipped.map(policy => policy.key ?? '').filter(Boolean);
|
|
98
|
-
const from = run.release?.branch?.label?.trim();
|
|
99
|
-
return [
|
|
100
|
-
`Release ${releaseName} (ID ${releaseId}): ships ${keys.length} ${keys.length === 1 ? 'policy' : 'policies'}${keys.length > 0 ? ` (${keys.join(', ')})` : ''}${from ? `; checked as cut from branch ${from}` : ''}`,
|
|
101
|
-
];
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* A `release import` the platform refused for the policies the archive carries, as one message with
|
|
105
|
-
* its remedy, or `null` for any other failure. An archive that says it carries policies needs the
|
|
106
|
-
* `workspace:policy` create and update permission to import (`policy_permission_required` for the
|
|
107
|
-
* role, `policy_scope_required` for the token), and nothing is stored without it.
|
|
108
|
-
*/
|
|
109
|
-
export function releaseImportRefusal(text, status, url) {
|
|
110
|
-
const { message, payload } = describePolicyError(text, status, url);
|
|
111
|
-
const code = payload && typeof payload === 'object' ? payload.code : undefined;
|
|
112
|
-
if (typeof code !== 'string' || !code.startsWith('policy_'))
|
|
113
|
-
return null;
|
|
114
|
-
return `${message}${policyPermissionGuidance(status, payload)}`;
|
|
115
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { ProfileConfig } from '../../base-command.js';
|
|
2
|
-
import type { Policy } from './types.js';
|
|
3
|
-
/** Query params; a list is sent as PHP reads one (`policy[0]=A&policy[1]=B`). */
|
|
4
|
-
export type PolicyQuery = Record<string, string | string[]>;
|
|
5
|
-
/** One request against a policy-family route: a path under it, a method, a JSON body and query params. */
|
|
6
|
-
export type PolicyRequest = (path?: string, method?: string, body?: unknown, query?: PolicyQuery) => Promise<unknown>;
|
|
7
|
-
/** What a request needs from the command that makes it. */
|
|
8
|
-
export interface PolicyRequestHost {
|
|
9
|
-
error(message: string): never;
|
|
10
|
-
logToStderr(message: string): void;
|
|
11
|
-
verboseFetch(url: string, options: RequestInit, verbose: boolean, authToken?: string): Promise<Response>;
|
|
12
|
-
}
|
|
13
|
-
export interface PolicyRequestRoute {
|
|
14
|
-
branch: string;
|
|
15
|
-
/** How a failure introduces itself: `Policy request failed (403): …`. */
|
|
16
|
-
label: string;
|
|
17
|
-
/** The route under the workspace, e.g. `/policy`. */
|
|
18
|
-
path: string;
|
|
19
|
-
profile: ProfileConfig;
|
|
20
|
-
verbose: boolean;
|
|
21
|
-
workspace: string;
|
|
22
|
-
}
|
|
23
|
-
/** The route the `policy *` commands request. */
|
|
24
|
-
export declare const POLICY_ROUTE: Pick<PolicyRequestRoute, 'label' | 'path'>;
|
|
25
|
-
/** The workspace and branch a command targets: its flags first, then the profile. `-b ''` selects live. */
|
|
26
|
-
export declare function policyScope(flags: {
|
|
27
|
-
branch?: string;
|
|
28
|
-
workspace?: string;
|
|
29
|
-
}, profile: ProfileConfig): {
|
|
30
|
-
branch: string;
|
|
31
|
-
workspace: string;
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* A request against a route gated by `workspace:policy`: failures are folded to the platform's code,
|
|
35
|
-
* message and position, the token is redacted, and a coded refusal says what to do about it.
|
|
36
|
-
*/
|
|
37
|
-
export declare function policyRequest(host: PolicyRequestHost, route: PolicyRequestRoute): PolicyRequest;
|
|
38
|
-
/** What the policy list route answers this credential: it lists, the Policies feature is off, or it may not. */
|
|
39
|
-
export type PolicyListing = 'feature_off' | 'listed' | 'refused';
|
|
40
|
-
/**
|
|
41
|
-
* Whether this credential can list the branch's policies. An export leaves out the policies its
|
|
42
|
-
* credential cannot read, and every policy while the Policies feature is off, without refusing, so
|
|
43
|
-
* this tells an export without policies from one that withheld them, and names the feature when
|
|
44
|
-
* the platform's refusal does (`policy_feature_disabled`). Any other failure answers `refused`.
|
|
45
|
-
*/
|
|
46
|
-
export declare function policyListing(host: Omit<PolicyRequestHost, 'error'>, route: Omit<PolicyRequestRoute, 'label' | 'path'>): Promise<PolicyListing>;
|
|
47
|
-
/** The `items` of a list envelope, as every policy list route answers. */
|
|
48
|
-
export declare function listItems<T>(data: unknown): T[];
|
|
49
|
-
/**
|
|
50
|
-
* Every policy on the target branch. The list route pages them (`page`, `nextPage`), so each page is
|
|
51
|
-
* read in turn until the route names no next one.
|
|
52
|
-
*/
|
|
53
|
-
export declare function listAllPolicies(request: PolicyRequest): Promise<Policy[]>;
|
|
54
|
-
/** Whether two policy keys name the same policy: keys are unique on a branch without regard to case. */
|
|
55
|
-
export declare function sameKey(key: string | undefined, other: string): boolean;
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { describePolicyError, policyCodeGuidance } from './errors.js';
|
|
2
|
-
import { policyPermissionGuidance } from './permission.js';
|
|
3
|
-
/** The route the `policy *` commands request. */
|
|
4
|
-
export const POLICY_ROUTE = { label: 'Policy', path: '/policy' };
|
|
5
|
-
/** The workspace and branch a command targets: its flags first, then the profile. `-b ''` selects live. */
|
|
6
|
-
export function policyScope(flags, profile) {
|
|
7
|
-
// A workspace from profile.yaml or the credentials file can arrive from YAML as a number.
|
|
8
|
-
return { branch: flags.branch ?? profile.branch ?? '', workspace: String(flags.workspace || profile.workspace || '') };
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* A request against a route gated by `workspace:policy`: failures are folded to the platform's code,
|
|
12
|
-
* message and position, the token is redacted, and a coded refusal says what to do about it.
|
|
13
|
-
*/
|
|
14
|
-
export function policyRequest(host, route) {
|
|
15
|
-
const { branch, label, profile, verbose, workspace } = route;
|
|
16
|
-
const base = `${profile.instance_origin}/api:meta/workspace/${workspace}${route.path}`;
|
|
17
|
-
return async (path = '', method = 'GET', body, query = {}) => {
|
|
18
|
-
const url = `${base}${path}?${queryString({ branch, ...query })}`;
|
|
19
|
-
const response = await host.verboseFetch(url, {
|
|
20
|
-
body: body === undefined ? undefined : JSON.stringify(body),
|
|
21
|
-
headers: {
|
|
22
|
-
accept: 'application/json',
|
|
23
|
-
Authorization: `Bearer ${profile.access_token}`,
|
|
24
|
-
...(body === undefined ? {} : { 'Content-Type': 'application/json' }),
|
|
25
|
-
},
|
|
26
|
-
method,
|
|
27
|
-
}, verbose, profile.access_token);
|
|
28
|
-
if (!response.ok) {
|
|
29
|
-
const text = (await response.text()).replaceAll(profile.access_token, '[REDACTED]');
|
|
30
|
-
if (verbose && text)
|
|
31
|
-
host.logToStderr(text);
|
|
32
|
-
const { message, payload } = describePolicyError(text, response.status, url);
|
|
33
|
-
const guidance = `${policyPermissionGuidance(response.status, payload)}${policyCodeGuidance(payload)}`;
|
|
34
|
-
host.error(`${label} request failed (${response.status}): ${message}${guidance}`);
|
|
35
|
-
}
|
|
36
|
-
// The DELETE route can answer with no body at all; every other route sends JSON.
|
|
37
|
-
const text = await response.text();
|
|
38
|
-
if (text.trim() === '')
|
|
39
|
-
return {};
|
|
40
|
-
try {
|
|
41
|
-
return JSON.parse(text);
|
|
42
|
-
}
|
|
43
|
-
catch {
|
|
44
|
-
return host.error(`${label} request to ${path || '/'} returned a ${response.status} that is not JSON.`);
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
function queryString(query) {
|
|
49
|
-
const params = new URLSearchParams();
|
|
50
|
-
for (const [name, value] of Object.entries(query)) {
|
|
51
|
-
if (Array.isArray(value))
|
|
52
|
-
for (const [index, item] of value.entries())
|
|
53
|
-
params.append(`${name}[${index}]`, item);
|
|
54
|
-
else
|
|
55
|
-
params.append(name, value);
|
|
56
|
-
}
|
|
57
|
-
return params;
|
|
58
|
-
}
|
|
59
|
-
/** A request host's `error` for a caller that asks rather than fails: it throws instead of exiting. */
|
|
60
|
-
function fail(message) {
|
|
61
|
-
throw new Error(message);
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Whether this credential can list the branch's policies. An export leaves out the policies its
|
|
65
|
-
* credential cannot read, and every policy while the Policies feature is off, without refusing, so
|
|
66
|
-
* this tells an export without policies from one that withheld them, and names the feature when
|
|
67
|
-
* the platform's refusal does (`policy_feature_disabled`). Any other failure answers `refused`.
|
|
68
|
-
*/
|
|
69
|
-
export async function policyListing(host, route) {
|
|
70
|
-
let refusal;
|
|
71
|
-
const verboseFetch = async (...args) => {
|
|
72
|
-
const response = await host.verboseFetch(...args);
|
|
73
|
-
if (!response.ok)
|
|
74
|
-
refusal = await response.clone().json().catch(() => null);
|
|
75
|
-
return response;
|
|
76
|
-
};
|
|
77
|
-
const list = policyRequest({ ...host, error: fail, verboseFetch }, { ...route, ...POLICY_ROUTE });
|
|
78
|
-
return list().then(() => 'listed', () => refusalCode(refusal) === 'policy_feature_disabled' ? 'feature_off' : 'refused');
|
|
79
|
-
}
|
|
80
|
-
/** The `payload.code` of a refusal body, if it carries one. */
|
|
81
|
-
function refusalCode(body) {
|
|
82
|
-
const payload = body && typeof body === 'object' ? body.payload : undefined;
|
|
83
|
-
return payload && typeof payload === 'object' ? payload.code : undefined;
|
|
84
|
-
}
|
|
85
|
-
/** The `items` of a list envelope, as every policy list route answers. */
|
|
86
|
-
export function listItems(data) {
|
|
87
|
-
if (data && typeof data === 'object' && 'items' in data && Array.isArray(data.items))
|
|
88
|
-
return data.items;
|
|
89
|
-
throw new Error('The platform answered a list request without an items array.');
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Every policy on the target branch. The list route pages them (`page`, `nextPage`), so each page is
|
|
93
|
-
* read in turn until the route names no next one.
|
|
94
|
-
*/
|
|
95
|
-
export async function listAllPolicies(request) {
|
|
96
|
-
const policies = [];
|
|
97
|
-
let page = 1;
|
|
98
|
-
while (true) {
|
|
99
|
-
// Each page number comes from the previous response.
|
|
100
|
-
// eslint-disable-next-line no-await-in-loop
|
|
101
|
-
const listed = await request('', 'GET', undefined, { page: String(page) });
|
|
102
|
-
policies.push(...listItems(listed));
|
|
103
|
-
const { nextPage } = listed;
|
|
104
|
-
if (nextPage === undefined || nextPage === null)
|
|
105
|
-
return policies;
|
|
106
|
-
if (typeof nextPage !== 'number' || !Number.isSafeInteger(nextPage) || nextPage <= page) {
|
|
107
|
-
throw new Error('The platform returned an invalid next policy page.');
|
|
108
|
-
}
|
|
109
|
-
page = nextPage;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
/** Whether two policy keys name the same policy: keys are unique on a branch without regard to case. */
|
|
113
|
-
export function sameKey(key, other) {
|
|
114
|
-
return typeof key === 'string' && key.toLowerCase() === other.toLowerCase();
|
|
115
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { PolicyRun, PolicyRunHead, PolicyRunSummary } from './types.js';
|
|
2
|
-
/** The retained runs, as the run list summarises them, in a table, header first. */
|
|
3
|
-
export declare function policyRunTable(runs: PolicyRunSummary[]): string[];
|
|
4
|
-
/** Where a page of a run's findings sits among the findings that match its filters. */
|
|
5
|
-
export interface PolicyRunPage {
|
|
6
|
-
/** Whether a filter narrowed the findings. */
|
|
7
|
-
filtered: boolean;
|
|
8
|
-
/** The command that reads this run's next page; `xano policy runs <id>` unless another is named. */
|
|
9
|
-
next?: string;
|
|
10
|
-
offset: number;
|
|
11
|
-
/** The findings that match, listed or not. */
|
|
12
|
-
total: number;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* One stored run. A run records its findings, results and the enforcement each policy had;
|
|
16
|
-
* `policy_check.blocking` is the gate's verdict at the time and is not stored. With `page`, the
|
|
17
|
-
* run's findings are one page of them (`GET run/{id}/findings`) and its counts are the summary's.
|
|
18
|
-
*/
|
|
19
|
-
export declare function policyRunSummary(run: PolicyRunHead, page?: PolicyRunPage): string[];
|
|
20
|
-
/**
|
|
21
|
-
* The resolved settings a check ran with, as `settings: name=value, …`, sorted by name so output
|
|
22
|
-
* is stable. Values that resolved to nothing are already omitted by the platform.
|
|
23
|
-
*/
|
|
24
|
-
export declare function policySettings(params: unknown): string;
|
|
25
|
-
/**
|
|
26
|
-
* What a stored run recorded about the policies it evaluated: each policy's description as written
|
|
27
|
-
* then, and each rule's name, settings and how many objects it inspected. Empty for a run that
|
|
28
|
-
* evaluated no policy.
|
|
29
|
-
*/
|
|
30
|
-
export declare function policyRunDetail(run?: PolicyRun): string[];
|