@uipath/guardrails-tool 1.202.1-preview.220 → 1.202.1-preview.239
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/dist/tool.js +225 -8
- package/package.json +2 -2
package/dist/tool.js
CHANGED
|
@@ -2100,7 +2100,7 @@ var require_commander = __commonJS(function(exports) {
|
|
|
2100
2100
|
var package_default = {
|
|
2101
2101
|
name: "@uipath/guardrails-tool",
|
|
2102
2102
|
license: "SEE LICENSE IN LICENSE.txt",
|
|
2103
|
-
version: "1.202.1-preview.
|
|
2103
|
+
version: "1.202.1-preview.239",
|
|
2104
2104
|
description: "CLI plugin for UiPath AI Trust Layer guardrail configurations.",
|
|
2105
2105
|
private: false,
|
|
2106
2106
|
repository: {
|
|
@@ -4433,7 +4433,165 @@ class FilterImplicitLimitError extends Error {
|
|
|
4433
4433
|
this.instructions = "Pass --limit <n> to choose how many records the filter applies to. " + "To filter over all records, pass the command's maximum accepted --limit (see the option's description in --help).";
|
|
4434
4434
|
}
|
|
4435
4435
|
}
|
|
4436
|
-
function
|
|
4436
|
+
function countRecords(data) {
|
|
4437
|
+
if (Array.isArray(data))
|
|
4438
|
+
return data.length;
|
|
4439
|
+
return data == null ? 0 : 1;
|
|
4440
|
+
}
|
|
4441
|
+
function availableFields(data) {
|
|
4442
|
+
const records = Array.isArray(data) ? data : [data];
|
|
4443
|
+
const keys = new Set;
|
|
4444
|
+
for (const record of records) {
|
|
4445
|
+
if (record && typeof record === "object" && !Array.isArray(record)) {
|
|
4446
|
+
for (const key of Object.keys(record))
|
|
4447
|
+
keys.add(key);
|
|
4448
|
+
}
|
|
4449
|
+
}
|
|
4450
|
+
return [...keys];
|
|
4451
|
+
}
|
|
4452
|
+
function decodeQuotedIdentifier(whole, inner) {
|
|
4453
|
+
const [error, decoded] = catchError(() => JSON.parse(whole));
|
|
4454
|
+
if (!error && typeof decoded === "string")
|
|
4455
|
+
return decoded;
|
|
4456
|
+
return inner.replace(/\\(.)/g, "$1");
|
|
4457
|
+
}
|
|
4458
|
+
function referencedFields(filter) {
|
|
4459
|
+
const top = new Set;
|
|
4460
|
+
const nested = new Set;
|
|
4461
|
+
const withoutValueLiterals = filter.replace(/'(?:\\.|[^'\\])*'/g, " ").replace(/`(?:\\.|[^`\\])*`/g, " ");
|
|
4462
|
+
const isPathTail = (text, index) => text[index - 1] === "." && /[A-Za-z0-9_"]/.test(text[index - 2] ?? "");
|
|
4463
|
+
const quoted = [];
|
|
4464
|
+
const withoutLiterals = withoutValueLiterals.replace(/"((?:\\.|[^"\\])*)"/g, (whole, name, index) => {
|
|
4465
|
+
const isAlias = /^\s*:/.test(withoutValueLiterals.slice(index + whole.length));
|
|
4466
|
+
if (!isAlias) {
|
|
4467
|
+
quoted.push({
|
|
4468
|
+
name: decodeQuotedIdentifier(whole, name),
|
|
4469
|
+
index,
|
|
4470
|
+
tail: isPathTail(withoutValueLiterals, index)
|
|
4471
|
+
});
|
|
4472
|
+
}
|
|
4473
|
+
return `"${" ".repeat(whole.length - 2)}"`;
|
|
4474
|
+
});
|
|
4475
|
+
const descent = /[A-Za-z0-9_"]\s*[.[]/.exec(withoutLiterals);
|
|
4476
|
+
const rootEnd = descent ? descent.index + 1 : Number.POSITIVE_INFINITY;
|
|
4477
|
+
const place = (name, index, tail) => {
|
|
4478
|
+
if (tail || index >= rootEnd)
|
|
4479
|
+
nested.add(name);
|
|
4480
|
+
else
|
|
4481
|
+
top.add(name);
|
|
4482
|
+
};
|
|
4483
|
+
for (const entry of quoted)
|
|
4484
|
+
place(entry.name, entry.index, entry.tail);
|
|
4485
|
+
const identifiers = withoutLiterals.matchAll(/([A-Za-z_][A-Za-z0-9_]*)(\s*[:(])?/g);
|
|
4486
|
+
const reserved = new Set(["true", "false", "null", "and", "or", "not"]);
|
|
4487
|
+
for (const match of identifiers) {
|
|
4488
|
+
const [, name, trailing] = match;
|
|
4489
|
+
if (trailing || reserved.has(name))
|
|
4490
|
+
continue;
|
|
4491
|
+
place(name, match.index, isPathTail(withoutLiterals, match.index));
|
|
4492
|
+
}
|
|
4493
|
+
return {
|
|
4494
|
+
top: [...top],
|
|
4495
|
+
nested: [...nested].filter((name) => !top.has(name)),
|
|
4496
|
+
hasPredicate: /\[\s*\?/.test(withoutValueLiterals)
|
|
4497
|
+
};
|
|
4498
|
+
}
|
|
4499
|
+
function appearsBelowTopLevel(data, name) {
|
|
4500
|
+
let budget = 2000;
|
|
4501
|
+
const visit = (value, depth) => {
|
|
4502
|
+
if (budget-- <= 0 || depth > 4)
|
|
4503
|
+
return false;
|
|
4504
|
+
if (value === null || typeof value !== "object")
|
|
4505
|
+
return false;
|
|
4506
|
+
if (Array.isArray(value))
|
|
4507
|
+
return value.some((entry) => visit(entry, depth));
|
|
4508
|
+
const record = value;
|
|
4509
|
+
if (depth > 0 && Object.hasOwn(record, name))
|
|
4510
|
+
return true;
|
|
4511
|
+
return Object.values(record).some((entry) => visit(entry, depth + 1));
|
|
4512
|
+
};
|
|
4513
|
+
return visit(data, 0);
|
|
4514
|
+
}
|
|
4515
|
+
function alwaysNullKeys(records) {
|
|
4516
|
+
const objects = records.filter((r) => r != null && typeof r === "object" && !Array.isArray(r));
|
|
4517
|
+
if (objects.length === 0 || objects.length !== records.length)
|
|
4518
|
+
return [];
|
|
4519
|
+
const keys = [...new Set(objects.flatMap((o) => Object.keys(o)))];
|
|
4520
|
+
if (keys.length === 0)
|
|
4521
|
+
return [];
|
|
4522
|
+
const nullKeys = keys.filter((key) => objects.every((record) => record[key] === null));
|
|
4523
|
+
return nullKeys.length === keys.length ? nullKeys : [];
|
|
4524
|
+
}
|
|
4525
|
+
function carriesOnlyNulls(value) {
|
|
4526
|
+
if (value === null)
|
|
4527
|
+
return true;
|
|
4528
|
+
if (Array.isArray(value)) {
|
|
4529
|
+
return value.length > 0 && value.every(carriesOnlyNulls);
|
|
4530
|
+
}
|
|
4531
|
+
if (typeof value === "object" && value !== undefined) {
|
|
4532
|
+
const values = Object.values(value);
|
|
4533
|
+
return values.length > 0 && values.every(carriesOnlyNulls);
|
|
4534
|
+
}
|
|
4535
|
+
return false;
|
|
4536
|
+
}
|
|
4537
|
+
function nameList(names, cap2 = 12) {
|
|
4538
|
+
const shown = names.slice(0, cap2).map((n) => `\`${n}\``);
|
|
4539
|
+
const rest = names.length - shown.length;
|
|
4540
|
+
return shown.join(", ") + (rest > 0 ? `, and ${rest} more` : "");
|
|
4541
|
+
}
|
|
4542
|
+
function buildFilterWarning(filter, data, outcome) {
|
|
4543
|
+
const present = availableFields(data);
|
|
4544
|
+
const refs = referencedFields(filter);
|
|
4545
|
+
const unknown = refs.top.filter((name) => !present.includes(name) && !appearsBelowTopLevel(data, name));
|
|
4546
|
+
const unchecked = refs.nested.filter((name) => !present.includes(name));
|
|
4547
|
+
const count = countRecords(data);
|
|
4548
|
+
const scope = `${count} record(s)`;
|
|
4549
|
+
const isNotAField = (names) => `${nameList(names)} ${names.length === 1 ? "is not a field" : "are not fields"} on the ${scope} it read`;
|
|
4550
|
+
const soundness = unchecked.length > 0 ? `${nameList(unchecked)} ${unchecked.length === 1 ? "reads" : "read"} below the top level, so ${unchecked.length === 1 ? "it was" : "they were"} not checked against the record keys` : refs.top.length > 0 ? "every field it names exists" : "";
|
|
4551
|
+
const withSoundness = (base) => soundness ? `${base}, and ${soundness}` : base;
|
|
4552
|
+
let detail;
|
|
4553
|
+
let lede;
|
|
4554
|
+
if (outcome.kind === "null-elements") {
|
|
4555
|
+
lede = "returned only null values";
|
|
4556
|
+
const projected = `all ${outcome.count} of the elements it projected are null`;
|
|
4557
|
+
if (unknown.length > 0) {
|
|
4558
|
+
detail = `${projected}, because ${isNotAField(unknown)}`;
|
|
4559
|
+
} else if (unchecked.length > 0) {
|
|
4560
|
+
detail = withSoundness(projected);
|
|
4561
|
+
} else {
|
|
4562
|
+
detail = `${projected}, and every field it names exists — a multi-select list ` + `(\`[A, B]\`) reads each entry against \`Data\` itself, so on a list ` + `result use \`[].[A, B]\` or \`[].{a: A, b: B}\` to read the records`;
|
|
4563
|
+
}
|
|
4564
|
+
} else if (outcome.kind === "null-rows") {
|
|
4565
|
+
lede = "returned only null values";
|
|
4566
|
+
const projected = `every value it projected is null on all ${outcome.count} row(s)`;
|
|
4567
|
+
detail = unknown.length > 0 ? `${projected}, because ${isNotAField(unknown)}` : withSoundness(projected);
|
|
4568
|
+
} else if (outcome.kind === "null-values") {
|
|
4569
|
+
lede = "returned only null values";
|
|
4570
|
+
const projected = `every key it projected (${nameList(outcome.keys)}) is null`;
|
|
4571
|
+
const sameSet = unknown.length === outcome.keys.length && outcome.keys.every((k) => unknown.includes(k));
|
|
4572
|
+
if (sameSet) {
|
|
4573
|
+
detail = `${isNotAField(outcome.keys)}, so every key it projected is null`;
|
|
4574
|
+
} else if (unknown.length > 0) {
|
|
4575
|
+
detail = `${projected}, because ${isNotAField(unknown)}`;
|
|
4576
|
+
} else {
|
|
4577
|
+
detail = withSoundness(`${projected} on all ${scope}`);
|
|
4578
|
+
}
|
|
4579
|
+
} else {
|
|
4580
|
+
lede = "returned nothing";
|
|
4581
|
+
if (unknown.length > 0) {
|
|
4582
|
+
detail = isNotAField(unknown);
|
|
4583
|
+
} else {
|
|
4584
|
+
const selection = refs.hasPredicate ? "no record matched" : "the expression resolved to no value";
|
|
4585
|
+
detail = withSoundness(`${selection} — it read ${scope}`);
|
|
4586
|
+
}
|
|
4587
|
+
}
|
|
4588
|
+
const fields = present.length > 0 ? ` Available fields: ${nameList(present)}.` : "";
|
|
4589
|
+
return `--output-filter ${JSON.stringify(filter)} ${lede}: ${detail}.${fields}`;
|
|
4590
|
+
}
|
|
4591
|
+
function appendWarning(existing, note) {
|
|
4592
|
+
return existing ? `${existing} ${note}` : note;
|
|
4593
|
+
}
|
|
4594
|
+
function applyFilter(data, filter, onWarning) {
|
|
4437
4595
|
const codec = requireJmespath();
|
|
4438
4596
|
let result;
|
|
4439
4597
|
try {
|
|
@@ -4441,9 +4599,34 @@ function applyFilter(data, filter) {
|
|
|
4441
4599
|
} catch (err) {
|
|
4442
4600
|
throw new FilterEvaluationError(filter, err);
|
|
4443
4601
|
}
|
|
4444
|
-
|
|
4602
|
+
const inputCount = countRecords(data);
|
|
4603
|
+
const warn = (outcome) => {
|
|
4604
|
+
if (inputCount === 0)
|
|
4605
|
+
return;
|
|
4606
|
+
const note = buildFilterWarning(filter, data, outcome);
|
|
4607
|
+
getOutputSink().writeErr(`[WARN] ${note}
|
|
4608
|
+
`);
|
|
4609
|
+
onWarning?.(note);
|
|
4610
|
+
};
|
|
4611
|
+
const warnIfAllNull = (records) => {
|
|
4612
|
+
const keys = alwaysNullKeys(records);
|
|
4613
|
+
if (keys.length > 0)
|
|
4614
|
+
warn({ kind: "null-values", keys });
|
|
4615
|
+
};
|
|
4616
|
+
if (result == null) {
|
|
4617
|
+
warn({ kind: "empty" });
|
|
4445
4618
|
return [];
|
|
4619
|
+
}
|
|
4446
4620
|
if (Array.isArray(result)) {
|
|
4621
|
+
if (result.length === 0) {
|
|
4622
|
+
warn({ kind: "empty" });
|
|
4623
|
+
} else if (result.every((entry) => entry === null)) {
|
|
4624
|
+
warn({ kind: "null-elements", count: result.length });
|
|
4625
|
+
} else if (result.every((entry) => Array.isArray(entry)) && carriesOnlyNulls(result)) {
|
|
4626
|
+
warn({ kind: "null-rows", count: result.length });
|
|
4627
|
+
} else {
|
|
4628
|
+
warnIfAllNull(result);
|
|
4629
|
+
}
|
|
4447
4630
|
if (result.length > 0 && typeof result[0] !== "object") {
|
|
4448
4631
|
const fieldMatch = filter.match(/\.(\w+)$/);
|
|
4449
4632
|
const key = fieldMatch ? fieldMatch[1] : "Value";
|
|
@@ -4451,10 +4634,30 @@ function applyFilter(data, filter) {
|
|
|
4451
4634
|
}
|
|
4452
4635
|
return result;
|
|
4453
4636
|
}
|
|
4454
|
-
if (typeof result === "object")
|
|
4637
|
+
if (typeof result === "object") {
|
|
4638
|
+
warnIfAllNull([result]);
|
|
4455
4639
|
return result;
|
|
4640
|
+
}
|
|
4456
4641
|
return { Value: result };
|
|
4457
4642
|
}
|
|
4643
|
+
function filterFailureData(envelope) {
|
|
4644
|
+
const filter = getOutputFilter();
|
|
4645
|
+
const data = envelope.Data;
|
|
4646
|
+
if (!filter || data == null)
|
|
4647
|
+
return;
|
|
4648
|
+
let note;
|
|
4649
|
+
const [filterError, filtered] = catchError(() => applyFilter(data, filter, (n) => {
|
|
4650
|
+
note = n;
|
|
4651
|
+
}));
|
|
4652
|
+
if (filterError) {
|
|
4653
|
+
envelope.Warning = appendWarning(envelope.Warning, `--output-filter was not applied, so Data is shown in full: ${filterError.message}`);
|
|
4654
|
+
return;
|
|
4655
|
+
}
|
|
4656
|
+
envelope.Data = filtered;
|
|
4657
|
+
if (note) {
|
|
4658
|
+
envelope.Warning = appendWarning(envelope.Warning, note);
|
|
4659
|
+
}
|
|
4660
|
+
}
|
|
4458
4661
|
function defaultErrorCodeForResult(result) {
|
|
4459
4662
|
switch (result) {
|
|
4460
4663
|
case RESULTS.AuthenticationError:
|
|
@@ -4537,8 +4740,14 @@ var OutputFormatter;
|
|
|
4537
4740
|
}
|
|
4538
4741
|
const filter = getOutputFilter();
|
|
4539
4742
|
if (filter) {
|
|
4540
|
-
|
|
4743
|
+
let note;
|
|
4744
|
+
const filtered = applyFilter(data.Data, filter, (n) => {
|
|
4745
|
+
note = n;
|
|
4746
|
+
});
|
|
4541
4747
|
data.Data = normalize ? normalizeDataKeys(filtered, verbatim, subtrees && { refs: subtrees.refs, mode: "skip" }) : filtered;
|
|
4748
|
+
if (note) {
|
|
4749
|
+
data.Warning = appendWarning(data.Warning, note);
|
|
4750
|
+
}
|
|
4542
4751
|
}
|
|
4543
4752
|
logOutput(normalizeOutputKeys(data), getOutputFormat(), options?.tableRowStyle);
|
|
4544
4753
|
}
|
|
@@ -4566,6 +4775,7 @@ var OutputFormatter;
|
|
|
4566
4775
|
delete envelope.TelemetryErrorClass;
|
|
4567
4776
|
delete envelope.TelemetryTerminalOutcome;
|
|
4568
4777
|
delete envelope.TelemetryTerminalSignal;
|
|
4778
|
+
filterFailureData(envelope);
|
|
4569
4779
|
if (!suppressTelemetry) {
|
|
4570
4780
|
telemetry.trackEvent(CommonTelemetryEvents.Error, {
|
|
4571
4781
|
result: data.Result,
|
|
@@ -4614,13 +4824,20 @@ var OutputFormatter;
|
|
|
4614
4824
|
OutputFormatter.log = log;
|
|
4615
4825
|
function formatToString(data) {
|
|
4616
4826
|
const filter = getOutputFilter();
|
|
4827
|
+
const envelope = data;
|
|
4617
4828
|
if ("Data" in data && data.Data != null) {
|
|
4618
4829
|
data.Data = normalizeDataKeys(data.Data);
|
|
4619
4830
|
if (filter) {
|
|
4620
|
-
|
|
4831
|
+
let note;
|
|
4832
|
+
data.Data = normalizeDataKeys(applyFilter(data.Data, filter, (n) => {
|
|
4833
|
+
note = n;
|
|
4834
|
+
}));
|
|
4835
|
+
if (note) {
|
|
4836
|
+
envelope.Warning = appendWarning(envelope.Warning, note);
|
|
4837
|
+
}
|
|
4621
4838
|
}
|
|
4622
4839
|
}
|
|
4623
|
-
const output = normalizeOutputKeys(
|
|
4840
|
+
const output = normalizeOutputKeys(envelope);
|
|
4624
4841
|
const lines = [];
|
|
4625
4842
|
const sink = getOutputSink();
|
|
4626
4843
|
printOutput(output, getOutputFormat(), (msg) => {
|
|
@@ -7218,4 +7435,4 @@ export {
|
|
|
7218
7435
|
registerCommands
|
|
7219
7436
|
};
|
|
7220
7437
|
|
|
7221
|
-
//# debugId=
|
|
7438
|
+
//# debugId=3806B014A4E8360364756E2164756E21
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uipath/guardrails-tool",
|
|
3
3
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
4
|
-
"version": "1.202.1-preview.
|
|
4
|
+
"version": "1.202.1-preview.239",
|
|
5
5
|
"description": "CLI plugin for UiPath AI Trust Layer guardrail configurations.",
|
|
6
6
|
"private": false,
|
|
7
7
|
"repository": {
|
|
@@ -23,5 +23,5 @@
|
|
|
23
23
|
"files": [
|
|
24
24
|
"dist"
|
|
25
25
|
],
|
|
26
|
-
"gitHead": "
|
|
26
|
+
"gitHead": "97545a7857bdff7e6db62bbe13c6097607cf38f1"
|
|
27
27
|
}
|