@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,7 +1,5 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import BaseCommand from '../../../base-command.js';
|
|
3
|
-
import { BLANK_POLICY_OVERRIDE, blankPolicyOverride, gateOverrideHint, gateRefusal, liveGateLines, quoted, weakeningRefusal, } from '../../../utils/policy/gate.js';
|
|
4
|
-
import { policyWeakeningGuidance } from '../../../utils/policy/permission.js';
|
|
5
3
|
export default class BranchSetLive extends BaseCommand {
|
|
6
4
|
static args = {
|
|
7
5
|
branch_label: Args.string({
|
|
@@ -9,7 +7,7 @@ export default class BranchSetLive extends BaseCommand {
|
|
|
9
7
|
required: true,
|
|
10
8
|
}),
|
|
11
9
|
};
|
|
12
|
-
static description = '[IMPORTANT] ALWAYS confirm with the user before changing the live branch. Sets a branch as the live (active) branch for API requests.
|
|
10
|
+
static description = '[IMPORTANT] ALWAYS confirm with the user before changing the live branch. Sets a branch as the live (active) branch for API requests.';
|
|
13
11
|
static examples = [
|
|
14
12
|
`$ xano branch set-live staging
|
|
15
13
|
Are you sure you want to set 'staging' as the live branch? (y/N) y
|
|
@@ -26,7 +24,6 @@ Branch 'v1' is now live
|
|
|
26
24
|
"live": true
|
|
27
25
|
}
|
|
28
26
|
`,
|
|
29
|
-
`$ xano branch set_live rollback --force --policy-override "Rollback approved; finding tracked in JIRA-12"`,
|
|
30
27
|
];
|
|
31
28
|
static flags = {
|
|
32
29
|
...BaseCommand.baseFlags,
|
|
@@ -43,27 +40,14 @@ Branch 'v1' is now live
|
|
|
43
40
|
options: ['summary', 'json'],
|
|
44
41
|
required: false,
|
|
45
42
|
}),
|
|
46
|
-
'policy-override': Flags.string({ description: 'Set the branch live past a blocking set-live policy gate with an audited reason (requires workspace:policy update)' }),
|
|
47
43
|
workspace: Flags.integer({
|
|
48
44
|
char: 'w',
|
|
49
45
|
description: 'Workspace ID (uses profile workspace if not provided)',
|
|
50
46
|
required: false,
|
|
51
47
|
}),
|
|
52
48
|
};
|
|
53
|
-
/** Set once the platform refuses for a weakened mandatory policy: already explained, it exits 1 as it is. */
|
|
54
|
-
refusedByPermission = false;
|
|
55
|
-
/** Set once the set-live policy gate refuses, the one failure that exits 2. */
|
|
56
|
-
refusedByPolicyGate = false;
|
|
57
|
-
/** Exit 2 is the set-live gate's refusal; every other failure, flag errors included, exits 1. */
|
|
58
|
-
async catch(error) {
|
|
59
|
-
if (this.refusedByPolicyGate)
|
|
60
|
-
return super.catch(error);
|
|
61
|
-
return this.catchAsOperational(error);
|
|
62
|
-
}
|
|
63
49
|
async run() {
|
|
64
50
|
const { args, flags } = await this.parse(BranchSetLive);
|
|
65
|
-
if (blankPolicyOverride(flags['policy-override']))
|
|
66
|
-
this.error(BLANK_POLICY_OVERRIDE);
|
|
67
51
|
const { profile } = this.resolveProfile(flags);
|
|
68
52
|
// Get workspace ID from flag or profile
|
|
69
53
|
const workspaceId = flags.workspace || profile.workspace;
|
|
@@ -82,26 +66,16 @@ Branch 'v1' is now live
|
|
|
82
66
|
}
|
|
83
67
|
// Construct the API URL
|
|
84
68
|
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/branch/${encodeURIComponent(branchLabel)}/live`;
|
|
85
|
-
// A reason from someone with workspace:policy update sets the branch live past a blocking gate.
|
|
86
|
-
const overrideReason = flags['policy-override']?.trim();
|
|
87
69
|
// Set branch as live via the API
|
|
88
70
|
try {
|
|
89
71
|
const response = await this.verboseFetch(apiUrl, {
|
|
90
|
-
...(overrideReason ? { body: JSON.stringify({ override_reason: overrideReason }) } : {}),
|
|
91
72
|
headers: {
|
|
92
73
|
'accept': 'application/json',
|
|
93
74
|
'Authorization': `Bearer ${profile.access_token}`,
|
|
94
|
-
...(overrideReason ? { 'Content-Type': 'application/json' } : {}),
|
|
95
75
|
},
|
|
96
76
|
method: 'POST',
|
|
97
77
|
}, flags.verbose, profile.access_token);
|
|
98
78
|
if (!response.ok) {
|
|
99
|
-
const refused = await gateRefusal(response);
|
|
100
|
-
if (refused)
|
|
101
|
-
this.refuseSetLive(refused, flags, branchLabel);
|
|
102
|
-
const weakening = await weakeningRefusal(response);
|
|
103
|
-
if (weakening)
|
|
104
|
-
this.refuseWeakening(weakening, flags, branchLabel);
|
|
105
79
|
const errorText = await response.text();
|
|
106
80
|
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
107
81
|
}
|
|
@@ -115,8 +89,6 @@ Branch 'v1' is now live
|
|
|
115
89
|
}
|
|
116
90
|
}
|
|
117
91
|
catch (error) {
|
|
118
|
-
if (this.refusedByPolicyGate || this.refusedByPermission)
|
|
119
|
-
throw error;
|
|
120
92
|
if (error instanceof Error) {
|
|
121
93
|
this.error(`Failed to set branch as live: ${error.message}`);
|
|
122
94
|
}
|
|
@@ -139,35 +111,4 @@ Branch 'v1' is now live
|
|
|
139
111
|
});
|
|
140
112
|
});
|
|
141
113
|
}
|
|
142
|
-
/**
|
|
143
|
-
* The set-live gate refused: the verdict on stdout (under `-o json`, `{set_live: false, message,
|
|
144
|
-
* policy_gate}`), then the platform's message and how to proceed, exiting 2.
|
|
145
|
-
*/
|
|
146
|
-
refuseSetLive(refused, flags, branchLabel) {
|
|
147
|
-
if (flags.output === 'json') {
|
|
148
|
-
this.log(JSON.stringify({ message: refused.message, policy_gate: refused.answer, set_live: false }, null, 2));
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
for (const line of liveGateLines(refused.answer, 'branch'))
|
|
152
|
-
this.log(line);
|
|
153
|
-
}
|
|
154
|
-
const workspace = flags.workspace ? ` -w ${flags.workspace}` : '';
|
|
155
|
-
const hint = gateOverrideHint(refused.answer, `xano branch set_live ${quoted(branchLabel)}${workspace} --policy-override "<why>"`);
|
|
156
|
-
this.refusedByPolicyGate = true;
|
|
157
|
-
this.error(`${refused.message}${hint}`, { exit: 2 });
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* The branch weakens a mandatory policy of the live branch (or lacks one), and the credential lacks
|
|
161
|
-
* `workspace:policy` update. That is a permission refusal, not a blocking finding: it exits 1 (under
|
|
162
|
-
* `-o json` as `{error}`) with the platform's sentence and how to go on. The live branch is unchanged.
|
|
163
|
-
*/
|
|
164
|
-
refuseWeakening(refused, flags, branchLabel) {
|
|
165
|
-
const workspace = flags.workspace ? ` -w ${flags.workspace}` : '';
|
|
166
|
-
this.refusedByPermission = true;
|
|
167
|
-
const again = `xano branch set_live ${quoted(branchLabel)}${workspace}`;
|
|
168
|
-
const way = refused.payload.unavailable === true
|
|
169
|
-
? `The check may read them next time: ${again}`
|
|
170
|
-
: `To set it live yourself, give ${quoted(branchLabel)} the live branch's version of those policies, then run: ${again}`;
|
|
171
|
-
this.error(`${refused.message}${policyWeakeningGuidance(refused.payload, [way], true)}`);
|
|
172
|
-
}
|
|
173
114
|
}
|
|
@@ -4,7 +4,6 @@ import { resolve } from 'node:path';
|
|
|
4
4
|
import BaseCommand from '../../../base-command.js';
|
|
5
5
|
import { isAwaited, waitForMicroservices, } from '../../../utils/microservice-wait.js';
|
|
6
6
|
import { executePush } from '../../../utils/multidoc-push.js';
|
|
7
|
-
import { policiesSkippedNotice } from '../../../utils/policy/feedback.js';
|
|
8
7
|
/** Status glyph for one microservice row in the `--wait` progress block. */
|
|
9
8
|
const icon = (e) => {
|
|
10
9
|
if (!isAwaited(e))
|
|
@@ -169,17 +168,13 @@ Skip preview and push immediately
|
|
|
169
168
|
truncate: flags.truncate,
|
|
170
169
|
verbose: flags.verbose,
|
|
171
170
|
};
|
|
172
|
-
|
|
171
|
+
await executePush({
|
|
173
172
|
accessToken: profile.access_token,
|
|
174
173
|
branch: '',
|
|
175
174
|
command: this,
|
|
176
175
|
inputDir,
|
|
177
176
|
verboseFetch: this.verboseFetch.bind(this),
|
|
178
177
|
}, target, pushFlags);
|
|
179
|
-
// When the platform leaves policy files out, it says so once.
|
|
180
|
-
const skipped = policiesSkippedNotice(result.response ?? result.preview);
|
|
181
|
-
if (skipped)
|
|
182
|
-
this.warn(skipped);
|
|
183
178
|
// --wait: after a real push, poll the tenant's live microservice status until
|
|
184
179
|
// every auto-deployed microservice (tenant_deploy="auto") is ready or the
|
|
185
180
|
// wait times out. Skipped on --dry-run (nothing was deployed).
|
|
@@ -7,28 +7,13 @@ export default class FunctionCreate extends BaseCommand {
|
|
|
7
7
|
edit: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
8
|
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
9
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
-
'policy-override': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
10
|
stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
11
|
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
12
|
config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
13
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
14
|
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
15
|
};
|
|
17
|
-
/** Set once the publish policy gate refuses, the one failure that exits 2. */
|
|
18
|
-
private refusedByPolicyGate;
|
|
19
|
-
/** Exit 2 is the publish gate's refusal; every other failure, flag errors included, exits 1. */
|
|
20
|
-
protected catch(error: Error & {
|
|
21
|
-
oclif?: {
|
|
22
|
-
exit?: number;
|
|
23
|
-
};
|
|
24
|
-
}): Promise<void>;
|
|
25
16
|
run(): Promise<void>;
|
|
26
17
|
private editFile;
|
|
27
18
|
private readStdin;
|
|
28
|
-
/**
|
|
29
|
-
* The live-branch publish gate refused the new function: the verdict on stdout (under `-o json`,
|
|
30
|
-
* `{created: false, message, policy_gate}`), then the platform's message and how to proceed,
|
|
31
|
-
* exiting 2.
|
|
32
|
-
*/
|
|
33
|
-
private refusePublish;
|
|
34
19
|
}
|
|
@@ -4,7 +4,6 @@ import * as fs from 'node:fs';
|
|
|
4
4
|
import * as os from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import BaseCommand from '../../../base-command.js';
|
|
7
|
-
import { BLANK_POLICY_OVERRIDE, blankPolicyOverride, gateRefusal, publishRefusal, quoted } from '../../../utils/policy/gate.js';
|
|
8
7
|
export default class FunctionCreate extends BaseCommand {
|
|
9
8
|
static args = {};
|
|
10
9
|
static description = 'Create a new function in a workspace';
|
|
@@ -37,7 +36,6 @@ Name: my_function
|
|
|
37
36
|
...
|
|
38
37
|
}
|
|
39
38
|
`,
|
|
40
|
-
`$ xano function:create -f function.xs --policy-override "Exception approved; finding tracked in JIRA-12"`,
|
|
41
39
|
];
|
|
42
40
|
static flags = {
|
|
43
41
|
...BaseCommand.baseFlags,
|
|
@@ -61,7 +59,6 @@ Name: my_function
|
|
|
61
59
|
options: ['summary', 'json'],
|
|
62
60
|
required: false,
|
|
63
61
|
}),
|
|
64
|
-
'policy-override': Flags.string({ description: 'Create the function past a blocking live-branch publish policy gate with an audited reason (requires workspace:policy update)' }),
|
|
65
62
|
stdin: Flags.boolean({
|
|
66
63
|
char: 's',
|
|
67
64
|
default: false,
|
|
@@ -75,18 +72,8 @@ Name: my_function
|
|
|
75
72
|
required: false,
|
|
76
73
|
}),
|
|
77
74
|
};
|
|
78
|
-
/** Set once the publish policy gate refuses, the one failure that exits 2. */
|
|
79
|
-
refusedByPolicyGate = false;
|
|
80
|
-
/** Exit 2 is the publish gate's refusal; every other failure, flag errors included, exits 1. */
|
|
81
|
-
async catch(error) {
|
|
82
|
-
if (this.refusedByPolicyGate)
|
|
83
|
-
return super.catch(error);
|
|
84
|
-
return this.catchAsOperational(error);
|
|
85
|
-
}
|
|
86
75
|
async run() {
|
|
87
76
|
const { flags } = await this.parse(FunctionCreate);
|
|
88
|
-
if (blankPolicyOverride(flags['policy-override']))
|
|
89
|
-
this.error(BLANK_POLICY_OVERRIDE);
|
|
90
77
|
const { profile, profileName } = this.resolveProfile(flags);
|
|
91
78
|
// Determine workspace_id from flag or profile
|
|
92
79
|
let workspaceId;
|
|
@@ -146,10 +133,6 @@ Name: my_function
|
|
|
146
133
|
const queryParams = new URLSearchParams({
|
|
147
134
|
include_xanoscript: 'false',
|
|
148
135
|
});
|
|
149
|
-
// A reason from someone with workspace:policy update saves past a blocking publish gate.
|
|
150
|
-
const overrideReason = flags['policy-override']?.trim();
|
|
151
|
-
if (overrideReason)
|
|
152
|
-
queryParams.set('override_reason', overrideReason);
|
|
153
136
|
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/function?${queryParams.toString()}`;
|
|
154
137
|
// Create function via API
|
|
155
138
|
try {
|
|
@@ -163,9 +146,6 @@ Name: my_function
|
|
|
163
146
|
method: 'POST',
|
|
164
147
|
}, flags.verbose, profile.access_token);
|
|
165
148
|
if (!response.ok) {
|
|
166
|
-
const refused = await gateRefusal(response);
|
|
167
|
-
if (refused)
|
|
168
|
-
this.refusePublish(refused, flags);
|
|
169
149
|
const errorText = await response.text();
|
|
170
150
|
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
171
151
|
}
|
|
@@ -186,8 +166,6 @@ Name: my_function
|
|
|
186
166
|
}
|
|
187
167
|
}
|
|
188
168
|
catch (error) {
|
|
189
|
-
if (this.refusedByPolicyGate)
|
|
190
|
-
throw error;
|
|
191
169
|
if (error instanceof Error) {
|
|
192
170
|
this.error(`Failed to create function: ${error.message}`);
|
|
193
171
|
}
|
|
@@ -261,22 +239,4 @@ Name: my_function
|
|
|
261
239
|
process.stdin.resume();
|
|
262
240
|
});
|
|
263
241
|
}
|
|
264
|
-
/**
|
|
265
|
-
* The live-branch publish gate refused the new function: the verdict on stdout (under `-o json`,
|
|
266
|
-
* `{created: false, message, policy_gate}`), then the platform's message and how to proceed,
|
|
267
|
-
* exiting 2.
|
|
268
|
-
*/
|
|
269
|
-
refusePublish(refused, flags) {
|
|
270
|
-
const workspace = flags.workspace ? ` -w ${quoted(flags.workspace)}` : '';
|
|
271
|
-
const source = flags.file ? ` -f ${quoted(flags.file)}` : ' --stdin';
|
|
272
|
-
const { lines, message } = publishRefusal(refused, {
|
|
273
|
-
json: flags.output === 'json',
|
|
274
|
-
outcome: 'created',
|
|
275
|
-
rerun: `xano function create${workspace}${source} --policy-override "<why>"`,
|
|
276
|
-
});
|
|
277
|
-
for (const line of lines)
|
|
278
|
-
this.log(line);
|
|
279
|
-
this.refusedByPolicyGate = true;
|
|
280
|
-
this.error(message, { exit: 2 });
|
|
281
|
-
}
|
|
282
242
|
}
|
|
@@ -9,7 +9,6 @@ export default class FunctionEdit extends BaseCommand {
|
|
|
9
9
|
edit: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
10
|
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
11
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
-
'policy-override': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
12
|
publish: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
13
|
stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
14
|
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -17,24 +16,10 @@ export default class FunctionEdit extends BaseCommand {
|
|
|
17
16
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
17
|
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
19
18
|
};
|
|
20
|
-
/** Set once the publish policy gate refuses, the one failure that exits 2. */
|
|
21
|
-
private refusedByPolicyGate;
|
|
22
|
-
/** Exit 2 is the publish gate's refusal; every other failure, flag errors included, exits 1. */
|
|
23
|
-
protected catch(error: Error & {
|
|
24
|
-
oclif?: {
|
|
25
|
-
exit?: number;
|
|
26
|
-
};
|
|
27
|
-
}): Promise<void>;
|
|
28
19
|
run(): Promise<void>;
|
|
29
20
|
private editFile;
|
|
30
21
|
private editFunctionContent;
|
|
31
22
|
private fetchFunctionCode;
|
|
32
23
|
private promptForFunctionId;
|
|
33
24
|
private readStdin;
|
|
34
|
-
/**
|
|
35
|
-
* The live-branch publish gate refused the update: the verdict on stdout (under `-o json`,
|
|
36
|
-
* `{updated: false, message, policy_gate}`), then the platform's message and how to proceed,
|
|
37
|
-
* exiting 2.
|
|
38
|
-
*/
|
|
39
|
-
private refusePublish;
|
|
40
25
|
}
|
|
@@ -5,7 +5,6 @@ import * as fs from 'node:fs';
|
|
|
5
5
|
import * as os from 'node:os';
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
import BaseCommand, { buildUserAgent } from '../../../base-command.js';
|
|
8
|
-
import { BLANK_POLICY_OVERRIDE, blankPolicyOverride, gateRefusal, publishRefusal, quoted } from '../../../utils/policy/gate.js';
|
|
9
8
|
export default class FunctionEdit extends BaseCommand {
|
|
10
9
|
static args = {
|
|
11
10
|
function_id: Args.string({
|
|
@@ -60,7 +59,6 @@ Name: my_function
|
|
|
60
59
|
...
|
|
61
60
|
}
|
|
62
61
|
`,
|
|
63
|
-
`$ xano function:edit 163 -f function.xs --policy-override "Exception approved; finding tracked in JIRA-12"`,
|
|
64
62
|
];
|
|
65
63
|
static flags = {
|
|
66
64
|
...BaseCommand.baseFlags,
|
|
@@ -83,7 +81,6 @@ Name: my_function
|
|
|
83
81
|
options: ['summary', 'json'],
|
|
84
82
|
required: false,
|
|
85
83
|
}),
|
|
86
|
-
'policy-override': Flags.string({ description: 'Publish past a blocking live-branch publish policy gate with an audited reason (requires workspace:policy update)' }),
|
|
87
84
|
publish: Flags.boolean({
|
|
88
85
|
default: true,
|
|
89
86
|
description: 'Publish the function after editing',
|
|
@@ -102,18 +99,8 @@ Name: my_function
|
|
|
102
99
|
required: false,
|
|
103
100
|
}),
|
|
104
101
|
};
|
|
105
|
-
/** Set once the publish policy gate refuses, the one failure that exits 2. */
|
|
106
|
-
refusedByPolicyGate = false;
|
|
107
|
-
/** Exit 2 is the publish gate's refusal; every other failure, flag errors included, exits 1. */
|
|
108
|
-
async catch(error) {
|
|
109
|
-
if (this.refusedByPolicyGate)
|
|
110
|
-
return super.catch(error);
|
|
111
|
-
return this.catchAsOperational(error);
|
|
112
|
-
}
|
|
113
102
|
async run() {
|
|
114
103
|
const { args, flags } = await this.parse(FunctionEdit);
|
|
115
|
-
if (blankPolicyOverride(flags['policy-override']))
|
|
116
|
-
this.error(BLANK_POLICY_OVERRIDE);
|
|
117
104
|
const { profile, profileName } = this.resolveProfile(flags);
|
|
118
105
|
// Validate flag combinations
|
|
119
106
|
if (flags.edit && !flags.file) {
|
|
@@ -188,10 +175,6 @@ Name: my_function
|
|
|
188
175
|
include_xanoscript: 'false',
|
|
189
176
|
publish: flags.publish ? 'true' : 'false',
|
|
190
177
|
});
|
|
191
|
-
// A reason from someone with workspace:policy update publishes past a blocking publish gate.
|
|
192
|
-
const overrideReason = flags['policy-override']?.trim();
|
|
193
|
-
if (overrideReason)
|
|
194
|
-
queryParams.set('override_reason', overrideReason);
|
|
195
178
|
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/function/${functionId}?${queryParams.toString()}`;
|
|
196
179
|
// Update function via API
|
|
197
180
|
try {
|
|
@@ -205,9 +188,6 @@ Name: my_function
|
|
|
205
188
|
method: 'PUT',
|
|
206
189
|
}, flags.verbose, profile.access_token);
|
|
207
190
|
if (!response.ok) {
|
|
208
|
-
const refused = await gateRefusal(response);
|
|
209
|
-
if (refused)
|
|
210
|
-
this.refusePublish(refused, flags, functionId);
|
|
211
191
|
const errorText = await response.text();
|
|
212
192
|
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
213
193
|
}
|
|
@@ -228,8 +208,6 @@ Name: my_function
|
|
|
228
208
|
}
|
|
229
209
|
}
|
|
230
210
|
catch (error) {
|
|
231
|
-
if (this.refusedByPolicyGate)
|
|
232
|
-
throw error;
|
|
233
211
|
if (error instanceof Error) {
|
|
234
212
|
this.error(`Failed to update function: ${error.message}`);
|
|
235
213
|
}
|
|
@@ -450,22 +428,4 @@ Name: my_function
|
|
|
450
428
|
process.stdin.resume();
|
|
451
429
|
});
|
|
452
430
|
}
|
|
453
|
-
/**
|
|
454
|
-
* The live-branch publish gate refused the update: the verdict on stdout (under `-o json`,
|
|
455
|
-
* `{updated: false, message, policy_gate}`), then the platform's message and how to proceed,
|
|
456
|
-
* exiting 2.
|
|
457
|
-
*/
|
|
458
|
-
refusePublish(refused, flags, functionId) {
|
|
459
|
-
const workspace = flags.workspace ? ` -w ${quoted(flags.workspace)}` : '';
|
|
460
|
-
const source = flags.file ? ` -f ${quoted(flags.file)}` : flags.stdin ? ' --stdin' : '';
|
|
461
|
-
const { lines, message } = publishRefusal(refused, {
|
|
462
|
-
json: flags.output === 'json',
|
|
463
|
-
outcome: 'updated',
|
|
464
|
-
rerun: `xano function edit ${quoted(functionId)}${workspace}${source} --policy-override "<why>"`,
|
|
465
|
-
});
|
|
466
|
-
for (const line of lines)
|
|
467
|
-
this.log(line);
|
|
468
|
-
this.refusedByPolicyGate = true;
|
|
469
|
-
this.error(message, { exit: 2 });
|
|
470
|
-
}
|
|
471
431
|
}
|
|
@@ -15,6 +15,7 @@ export default class FunctionRun extends BaseCommand {
|
|
|
15
15
|
'no-input-check': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
16
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
17
|
stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
tenant: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
19
|
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
20
|
config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
21
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -19,6 +19,8 @@ export default class FunctionRun extends BaseCommand {
|
|
|
19
19
|
`$ xano function:run calcScore --branch dev --logs`,
|
|
20
20
|
`$ xano function:run calcScore --datasource test
|
|
21
21
|
# Runs against the 'test' data source instead of 'live'`,
|
|
22
|
+
`$ xano function:run calcScore --tenant my-tenant
|
|
23
|
+
# Runs the function on the tenant instead of the workspace`,
|
|
22
24
|
];
|
|
23
25
|
static flags = {
|
|
24
26
|
...BaseCommand.baseFlags,
|
|
@@ -70,6 +72,11 @@ export default class FunctionRun extends BaseCommand {
|
|
|
70
72
|
exclusive: ['json'],
|
|
71
73
|
required: false,
|
|
72
74
|
}),
|
|
75
|
+
tenant: Flags.string({
|
|
76
|
+
char: 't',
|
|
77
|
+
description: 'Tenant name to run the function on (defaults to the workspace)',
|
|
78
|
+
required: false,
|
|
79
|
+
}),
|
|
73
80
|
workspace: Flags.string({
|
|
74
81
|
char: 'w',
|
|
75
82
|
description: 'Workspace ID (optional if set in profile)',
|
|
@@ -107,8 +114,9 @@ export default class FunctionRun extends BaseCommand {
|
|
|
107
114
|
input = await this.promptForMissing(input, missingRequired);
|
|
108
115
|
}
|
|
109
116
|
}
|
|
110
|
-
// 3) Execute via the meta run endpoint.
|
|
111
|
-
const
|
|
117
|
+
// 3) Execute via the meta run endpoint, scoped to the tenant when one is given.
|
|
118
|
+
const tenantPath = flags.tenant ? `/tenant/${encodeURIComponent(flags.tenant)}` : '';
|
|
119
|
+
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}${tenantPath}/function/run`;
|
|
112
120
|
const body = { input, name: functionName };
|
|
113
121
|
if (branch)
|
|
114
122
|
body.branch = branch;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import BaseCommand from '../../../base-command.js';
|
|
3
|
-
import { releasePolicyRunLines } from '../../../utils/policy/release.js';
|
|
4
3
|
export default class ReleaseCreate extends BaseCommand {
|
|
5
4
|
static args = {
|
|
6
5
|
name: Args.string({
|
|
@@ -12,10 +11,6 @@ export default class ReleaseCreate extends BaseCommand {
|
|
|
12
11
|
static examples = [
|
|
13
12
|
`$ xano release create "v1.0" --branch main
|
|
14
13
|
Created release: v1.0 - ID: 10
|
|
15
|
-
Branch: main
|
|
16
|
-
Policy check: fail (run 1712), 2 blocking, 1 advisory findings
|
|
17
|
-
Findings: xano policy runs --release v1.0
|
|
18
|
-
Its blocking findings block a deploy to a standard or run tenant: xano tenant deploy_release <tenant> --release v1.0 --check
|
|
19
14
|
`,
|
|
20
15
|
`$ xano release create "v1.1-hotfix" --branch main --hotfix --description "Critical fix" -o json`,
|
|
21
16
|
];
|
|
@@ -95,8 +90,6 @@ Created release: v1.0 - ID: 10
|
|
|
95
90
|
this.log(` Branch: ${release.branch}`);
|
|
96
91
|
if (release.hotfix)
|
|
97
92
|
this.log(` Hotfix: true`);
|
|
98
|
-
for (const line of releasePolicyRunLines(release.policy_run, release.name ?? args.name))
|
|
99
|
-
this.log(line);
|
|
100
93
|
}
|
|
101
94
|
}
|
|
102
95
|
catch (error) {
|
|
@@ -9,40 +9,12 @@ export default class ReleaseDeploy extends BaseCommand {
|
|
|
9
9
|
branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
11
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
-
'policy-override': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
12
|
set_live: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
13
|
workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
14
|
config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
15
|
profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
16
|
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
17
|
};
|
|
19
|
-
/** Set once the platform refuses set live for a weakened mandatory policy: already explained, it exits 1 as it is. */
|
|
20
|
-
private refusedByPermission;
|
|
21
|
-
/** Set once the set-live policy gate refuses, the one failure that exits 2. */
|
|
22
|
-
private refusedByPolicyGate;
|
|
23
|
-
/** Exit 2 is the set-live gate's refusal; every other failure, flag errors included, exits 1. */
|
|
24
|
-
protected catch(error: Error & {
|
|
25
|
-
oclif?: {
|
|
26
|
-
exit?: number;
|
|
27
|
-
};
|
|
28
|
-
}): Promise<void>;
|
|
29
18
|
run(): Promise<void>;
|
|
30
19
|
private confirm;
|
|
31
|
-
/** The set-live verdict a successful deploy answered with --set_live (`pass`, `overridden`, ...). */
|
|
32
|
-
private logPolicyOutcome;
|
|
33
|
-
/** Stops the command when set live was refused after the branch was created: by the gate (exit 2) or for a weakened mandatory policy (exit 1). */
|
|
34
|
-
private refuseIfSetLiveRefused;
|
|
35
|
-
/**
|
|
36
|
-
* The set-live gate refused after the branch was created: the verdict, the refusal, and how to
|
|
37
|
-
* proceed, exiting 2. Under `-o json` the refusal is `{branch_created, set_live, branch, message,
|
|
38
|
-
* policy_gate}`.
|
|
39
|
-
*/
|
|
40
|
-
private refuseSetLive;
|
|
41
|
-
/**
|
|
42
|
-
* Set live was refused after the branch was created because the release weakens (or lacks) a
|
|
43
|
-
* mandatory policy of the live branch, and the credential lacks `workspace:policy` update. That is a
|
|
44
|
-
* permission refusal, not a blocking finding: it exits 1 (under `-o json` as `{error}`) with the
|
|
45
|
-
* platform's sentence, which names the branch, and how to go on.
|
|
46
|
-
*/
|
|
47
|
-
private refuseWeakening;
|
|
48
20
|
}
|