@uipath/guardrails-tool 1.203.0-preview.233 → 1.203.0-preview.237
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
|
@@ -2101,7 +2101,7 @@ var package_default = {
|
|
|
2101
2101
|
name: "@uipath/guardrails-tool",
|
|
2102
2102
|
author: "UiPath",
|
|
2103
2103
|
license: "SEE LICENSE IN LICENSE.txt",
|
|
2104
|
-
version: "1.203.0-preview.
|
|
2104
|
+
version: "1.203.0-preview.237",
|
|
2105
2105
|
description: "CLI plugin for UiPath AI Trust Layer guardrail configurations.",
|
|
2106
2106
|
private: false,
|
|
2107
2107
|
repository: {
|
|
@@ -4663,7 +4663,165 @@ class FilterImplicitLimitError extends Error {
|
|
|
4663
4663
|
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).";
|
|
4664
4664
|
}
|
|
4665
4665
|
}
|
|
4666
|
-
function
|
|
4666
|
+
function countRecords(data) {
|
|
4667
|
+
if (Array.isArray(data))
|
|
4668
|
+
return data.length;
|
|
4669
|
+
return data == null ? 0 : 1;
|
|
4670
|
+
}
|
|
4671
|
+
function availableFields(data) {
|
|
4672
|
+
const records = Array.isArray(data) ? data : [data];
|
|
4673
|
+
const keys = new Set;
|
|
4674
|
+
for (const record of records) {
|
|
4675
|
+
if (record && typeof record === "object" && !Array.isArray(record)) {
|
|
4676
|
+
for (const key of Object.keys(record))
|
|
4677
|
+
keys.add(key);
|
|
4678
|
+
}
|
|
4679
|
+
}
|
|
4680
|
+
return [...keys];
|
|
4681
|
+
}
|
|
4682
|
+
function decodeQuotedIdentifier(whole, inner) {
|
|
4683
|
+
const [error, decoded] = catchError(() => JSON.parse(whole));
|
|
4684
|
+
if (!error && typeof decoded === "string")
|
|
4685
|
+
return decoded;
|
|
4686
|
+
return inner.replace(/\\(.)/g, "$1");
|
|
4687
|
+
}
|
|
4688
|
+
function referencedFields(filter) {
|
|
4689
|
+
const top = new Set;
|
|
4690
|
+
const nested = new Set;
|
|
4691
|
+
const withoutValueLiterals = filter.replace(/'(?:\\.|[^'\\])*'/g, " ").replace(/`(?:\\.|[^`\\])*`/g, " ");
|
|
4692
|
+
const isPathTail = (text, index) => text[index - 1] === "." && /[A-Za-z0-9_"]/.test(text[index - 2] ?? "");
|
|
4693
|
+
const quoted = [];
|
|
4694
|
+
const withoutLiterals = withoutValueLiterals.replace(/"((?:\\.|[^"\\])*)"/g, (whole, name, index) => {
|
|
4695
|
+
const isAlias = /^\s*:/.test(withoutValueLiterals.slice(index + whole.length));
|
|
4696
|
+
if (!isAlias) {
|
|
4697
|
+
quoted.push({
|
|
4698
|
+
name: decodeQuotedIdentifier(whole, name),
|
|
4699
|
+
index,
|
|
4700
|
+
tail: isPathTail(withoutValueLiterals, index)
|
|
4701
|
+
});
|
|
4702
|
+
}
|
|
4703
|
+
return `"${" ".repeat(whole.length - 2)}"`;
|
|
4704
|
+
});
|
|
4705
|
+
const descent = /[A-Za-z0-9_"]\s*[.[]/.exec(withoutLiterals);
|
|
4706
|
+
const rootEnd = descent ? descent.index + 1 : Number.POSITIVE_INFINITY;
|
|
4707
|
+
const place = (name, index, tail) => {
|
|
4708
|
+
if (tail || index >= rootEnd)
|
|
4709
|
+
nested.add(name);
|
|
4710
|
+
else
|
|
4711
|
+
top.add(name);
|
|
4712
|
+
};
|
|
4713
|
+
for (const entry of quoted)
|
|
4714
|
+
place(entry.name, entry.index, entry.tail);
|
|
4715
|
+
const identifiers = withoutLiterals.matchAll(/([A-Za-z_][A-Za-z0-9_]*)(\s*[:(])?/g);
|
|
4716
|
+
const reserved = new Set(["true", "false", "null", "and", "or", "not"]);
|
|
4717
|
+
for (const match of identifiers) {
|
|
4718
|
+
const [, name, trailing] = match;
|
|
4719
|
+
if (trailing || reserved.has(name))
|
|
4720
|
+
continue;
|
|
4721
|
+
place(name, match.index, isPathTail(withoutLiterals, match.index));
|
|
4722
|
+
}
|
|
4723
|
+
return {
|
|
4724
|
+
top: [...top],
|
|
4725
|
+
nested: [...nested].filter((name) => !top.has(name)),
|
|
4726
|
+
hasPredicate: /\[\s*\?/.test(withoutValueLiterals)
|
|
4727
|
+
};
|
|
4728
|
+
}
|
|
4729
|
+
function appearsBelowTopLevel(data, name) {
|
|
4730
|
+
let budget = 2000;
|
|
4731
|
+
const visit = (value, depth) => {
|
|
4732
|
+
if (budget-- <= 0 || depth > 4)
|
|
4733
|
+
return false;
|
|
4734
|
+
if (value === null || typeof value !== "object")
|
|
4735
|
+
return false;
|
|
4736
|
+
if (Array.isArray(value))
|
|
4737
|
+
return value.some((entry) => visit(entry, depth));
|
|
4738
|
+
const record = value;
|
|
4739
|
+
if (depth > 0 && Object.hasOwn(record, name))
|
|
4740
|
+
return true;
|
|
4741
|
+
return Object.values(record).some((entry) => visit(entry, depth + 1));
|
|
4742
|
+
};
|
|
4743
|
+
return visit(data, 0);
|
|
4744
|
+
}
|
|
4745
|
+
function alwaysNullKeys(records) {
|
|
4746
|
+
const objects = records.filter((r) => r != null && typeof r === "object" && !Array.isArray(r));
|
|
4747
|
+
if (objects.length === 0 || objects.length !== records.length)
|
|
4748
|
+
return [];
|
|
4749
|
+
const keys = [...new Set(objects.flatMap((o) => Object.keys(o)))];
|
|
4750
|
+
if (keys.length === 0)
|
|
4751
|
+
return [];
|
|
4752
|
+
const nullKeys = keys.filter((key) => objects.every((record) => record[key] === null));
|
|
4753
|
+
return nullKeys.length === keys.length ? nullKeys : [];
|
|
4754
|
+
}
|
|
4755
|
+
function carriesOnlyNulls(value) {
|
|
4756
|
+
if (value === null)
|
|
4757
|
+
return true;
|
|
4758
|
+
if (Array.isArray(value)) {
|
|
4759
|
+
return value.length > 0 && value.every(carriesOnlyNulls);
|
|
4760
|
+
}
|
|
4761
|
+
if (typeof value === "object" && value !== undefined) {
|
|
4762
|
+
const values = Object.values(value);
|
|
4763
|
+
return values.length > 0 && values.every(carriesOnlyNulls);
|
|
4764
|
+
}
|
|
4765
|
+
return false;
|
|
4766
|
+
}
|
|
4767
|
+
function nameList(names, cap2 = 12) {
|
|
4768
|
+
const shown = names.slice(0, cap2).map((n) => `\`${n}\``);
|
|
4769
|
+
const rest = names.length - shown.length;
|
|
4770
|
+
return shown.join(", ") + (rest > 0 ? `, and ${rest} more` : "");
|
|
4771
|
+
}
|
|
4772
|
+
function buildFilterWarning(filter, data, outcome) {
|
|
4773
|
+
const present = availableFields(data);
|
|
4774
|
+
const refs = referencedFields(filter);
|
|
4775
|
+
const unknown = refs.top.filter((name) => !present.includes(name) && !appearsBelowTopLevel(data, name));
|
|
4776
|
+
const unchecked = refs.nested.filter((name) => !present.includes(name));
|
|
4777
|
+
const count = countRecords(data);
|
|
4778
|
+
const scope = `${count} record(s)`;
|
|
4779
|
+
const isNotAField = (names) => `${nameList(names)} ${names.length === 1 ? "is not a field" : "are not fields"} on the ${scope} it read`;
|
|
4780
|
+
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" : "";
|
|
4781
|
+
const withSoundness = (base) => soundness ? `${base}, and ${soundness}` : base;
|
|
4782
|
+
let detail;
|
|
4783
|
+
let lede;
|
|
4784
|
+
if (outcome.kind === "null-elements") {
|
|
4785
|
+
lede = "returned only null values";
|
|
4786
|
+
const projected = `all ${outcome.count} of the elements it projected are null`;
|
|
4787
|
+
if (unknown.length > 0) {
|
|
4788
|
+
detail = `${projected}, because ${isNotAField(unknown)}`;
|
|
4789
|
+
} else if (unchecked.length > 0) {
|
|
4790
|
+
detail = withSoundness(projected);
|
|
4791
|
+
} else {
|
|
4792
|
+
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`;
|
|
4793
|
+
}
|
|
4794
|
+
} else if (outcome.kind === "null-rows") {
|
|
4795
|
+
lede = "returned only null values";
|
|
4796
|
+
const projected = `every value it projected is null on all ${outcome.count} row(s)`;
|
|
4797
|
+
detail = unknown.length > 0 ? `${projected}, because ${isNotAField(unknown)}` : withSoundness(projected);
|
|
4798
|
+
} else if (outcome.kind === "null-values") {
|
|
4799
|
+
lede = "returned only null values";
|
|
4800
|
+
const projected = `every key it projected (${nameList(outcome.keys)}) is null`;
|
|
4801
|
+
const sameSet = unknown.length === outcome.keys.length && outcome.keys.every((k) => unknown.includes(k));
|
|
4802
|
+
if (sameSet) {
|
|
4803
|
+
detail = `${isNotAField(outcome.keys)}, so every key it projected is null`;
|
|
4804
|
+
} else if (unknown.length > 0) {
|
|
4805
|
+
detail = `${projected}, because ${isNotAField(unknown)}`;
|
|
4806
|
+
} else {
|
|
4807
|
+
detail = withSoundness(`${projected} on all ${scope}`);
|
|
4808
|
+
}
|
|
4809
|
+
} else {
|
|
4810
|
+
lede = "returned nothing";
|
|
4811
|
+
if (unknown.length > 0) {
|
|
4812
|
+
detail = isNotAField(unknown);
|
|
4813
|
+
} else {
|
|
4814
|
+
const selection = refs.hasPredicate ? "no record matched" : "the expression resolved to no value";
|
|
4815
|
+
detail = withSoundness(`${selection} — it read ${scope}`);
|
|
4816
|
+
}
|
|
4817
|
+
}
|
|
4818
|
+
const fields = present.length > 0 ? ` Available fields: ${nameList(present)}.` : "";
|
|
4819
|
+
return `--output-filter ${JSON.stringify(filter)} ${lede}: ${detail}.${fields}`;
|
|
4820
|
+
}
|
|
4821
|
+
function appendWarning(existing, note) {
|
|
4822
|
+
return existing ? `${existing} ${note}` : note;
|
|
4823
|
+
}
|
|
4824
|
+
function applyFilter(data, filter, onWarning) {
|
|
4667
4825
|
const codec = requireJmespath();
|
|
4668
4826
|
let result;
|
|
4669
4827
|
try {
|
|
@@ -4671,9 +4829,34 @@ function applyFilter(data, filter) {
|
|
|
4671
4829
|
} catch (err) {
|
|
4672
4830
|
throw new FilterEvaluationError(filter, err);
|
|
4673
4831
|
}
|
|
4674
|
-
|
|
4832
|
+
const inputCount = countRecords(data);
|
|
4833
|
+
const warn = (outcome) => {
|
|
4834
|
+
if (inputCount === 0)
|
|
4835
|
+
return;
|
|
4836
|
+
const note = buildFilterWarning(filter, data, outcome);
|
|
4837
|
+
getOutputSink().writeErr(`[WARN] ${note}
|
|
4838
|
+
`);
|
|
4839
|
+
onWarning?.(note);
|
|
4840
|
+
};
|
|
4841
|
+
const warnIfAllNull = (records) => {
|
|
4842
|
+
const keys = alwaysNullKeys(records);
|
|
4843
|
+
if (keys.length > 0)
|
|
4844
|
+
warn({ kind: "null-values", keys });
|
|
4845
|
+
};
|
|
4846
|
+
if (result == null) {
|
|
4847
|
+
warn({ kind: "empty" });
|
|
4675
4848
|
return [];
|
|
4849
|
+
}
|
|
4676
4850
|
if (Array.isArray(result)) {
|
|
4851
|
+
if (result.length === 0) {
|
|
4852
|
+
warn({ kind: "empty" });
|
|
4853
|
+
} else if (result.every((entry) => entry === null)) {
|
|
4854
|
+
warn({ kind: "null-elements", count: result.length });
|
|
4855
|
+
} else if (result.every((entry) => Array.isArray(entry)) && carriesOnlyNulls(result)) {
|
|
4856
|
+
warn({ kind: "null-rows", count: result.length });
|
|
4857
|
+
} else {
|
|
4858
|
+
warnIfAllNull(result);
|
|
4859
|
+
}
|
|
4677
4860
|
if (result.length > 0 && typeof result[0] !== "object") {
|
|
4678
4861
|
const fieldMatch = filter.match(/\.(\w+)$/);
|
|
4679
4862
|
const key = fieldMatch ? fieldMatch[1] : "Value";
|
|
@@ -4681,10 +4864,30 @@ function applyFilter(data, filter) {
|
|
|
4681
4864
|
}
|
|
4682
4865
|
return result;
|
|
4683
4866
|
}
|
|
4684
|
-
if (typeof result === "object")
|
|
4867
|
+
if (typeof result === "object") {
|
|
4868
|
+
warnIfAllNull([result]);
|
|
4685
4869
|
return result;
|
|
4870
|
+
}
|
|
4686
4871
|
return { Value: result };
|
|
4687
4872
|
}
|
|
4873
|
+
function filterFailureData(envelope) {
|
|
4874
|
+
const filter = getOutputFilter();
|
|
4875
|
+
const data = envelope.Data;
|
|
4876
|
+
if (!filter || data == null)
|
|
4877
|
+
return;
|
|
4878
|
+
let note;
|
|
4879
|
+
const [filterError, filtered] = catchError(() => applyFilter(data, filter, (n) => {
|
|
4880
|
+
note = n;
|
|
4881
|
+
}));
|
|
4882
|
+
if (filterError) {
|
|
4883
|
+
envelope.Warning = appendWarning(envelope.Warning, `--output-filter was not applied, so Data is shown in full: ${filterError.message}`);
|
|
4884
|
+
return;
|
|
4885
|
+
}
|
|
4886
|
+
envelope.Data = filtered;
|
|
4887
|
+
if (note) {
|
|
4888
|
+
envelope.Warning = appendWarning(envelope.Warning, note);
|
|
4889
|
+
}
|
|
4890
|
+
}
|
|
4688
4891
|
function defaultErrorCodeForResult(result) {
|
|
4689
4892
|
switch (result) {
|
|
4690
4893
|
case RESULTS.AuthenticationError:
|
|
@@ -4767,8 +4970,14 @@ var OutputFormatter;
|
|
|
4767
4970
|
}
|
|
4768
4971
|
const filter = getOutputFilter();
|
|
4769
4972
|
if (filter) {
|
|
4770
|
-
|
|
4973
|
+
let note;
|
|
4974
|
+
const filtered = applyFilter(data.Data, filter, (n) => {
|
|
4975
|
+
note = n;
|
|
4976
|
+
});
|
|
4771
4977
|
data.Data = normalize ? normalizeDataKeys(filtered, verbatim, subtrees && { refs: subtrees.refs, mode: "skip" }) : filtered;
|
|
4978
|
+
if (note) {
|
|
4979
|
+
data.Warning = appendWarning(data.Warning, note);
|
|
4980
|
+
}
|
|
4772
4981
|
}
|
|
4773
4982
|
logOutput(normalizeOutputKeys(data), getOutputFormat(), options?.tableRowStyle);
|
|
4774
4983
|
}
|
|
@@ -4796,6 +5005,7 @@ var OutputFormatter;
|
|
|
4796
5005
|
delete envelope.TelemetryErrorClass;
|
|
4797
5006
|
delete envelope.TelemetryTerminalOutcome;
|
|
4798
5007
|
delete envelope.TelemetryTerminalSignal;
|
|
5008
|
+
filterFailureData(envelope);
|
|
4799
5009
|
if (!suppressTelemetry) {
|
|
4800
5010
|
telemetry.trackEvent(CommonTelemetryEvents.Error, {
|
|
4801
5011
|
result: data.Result,
|
|
@@ -4844,13 +5054,20 @@ var OutputFormatter;
|
|
|
4844
5054
|
OutputFormatter.log = log;
|
|
4845
5055
|
function formatToString(data) {
|
|
4846
5056
|
const filter = getOutputFilter();
|
|
5057
|
+
const envelope = data;
|
|
4847
5058
|
if ("Data" in data && data.Data != null) {
|
|
4848
5059
|
data.Data = normalizeDataKeys(data.Data);
|
|
4849
5060
|
if (filter) {
|
|
4850
|
-
|
|
5061
|
+
let note;
|
|
5062
|
+
data.Data = normalizeDataKeys(applyFilter(data.Data, filter, (n) => {
|
|
5063
|
+
note = n;
|
|
5064
|
+
}));
|
|
5065
|
+
if (note) {
|
|
5066
|
+
envelope.Warning = appendWarning(envelope.Warning, note);
|
|
5067
|
+
}
|
|
4851
5068
|
}
|
|
4852
5069
|
}
|
|
4853
|
-
const output = normalizeOutputKeys(
|
|
5070
|
+
const output = normalizeOutputKeys(envelope);
|
|
4854
5071
|
const lines = [];
|
|
4855
5072
|
const sink = getOutputSink();
|
|
4856
5073
|
printOutput(output, getOutputFormat(), (msg) => {
|
|
@@ -7451,4 +7668,4 @@ export {
|
|
|
7451
7668
|
registerCommands
|
|
7452
7669
|
};
|
|
7453
7670
|
|
|
7454
|
-
//# debugId=
|
|
7671
|
+
//# debugId=2453649C1BE3874564756E2164756E21
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@uipath/guardrails-tool",
|
|
3
3
|
"author": "UiPath",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
5
|
-
"version": "1.203.0-preview.
|
|
5
|
+
"version": "1.203.0-preview.237",
|
|
6
6
|
"description": "CLI plugin for UiPath AI Trust Layer guardrail configurations.",
|
|
7
7
|
"private": false,
|
|
8
8
|
"repository": {
|
|
@@ -24,5 +24,5 @@
|
|
|
24
24
|
"files": [
|
|
25
25
|
"dist"
|
|
26
26
|
],
|
|
27
|
-
"gitHead": "
|
|
27
|
+
"gitHead": "4ad3e17a66f2c7fb7fe1f0e3e04a5b6175a0a9a3"
|
|
28
28
|
}
|