fullcourtdefense-cli 1.34.10 → 1.34.11
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/actionPolicyEngine.js +46 -3
- package/dist/blockExplanation.js +1 -1
- package/dist/commands/hook.js +1 -1
- package/dist/version.json +1 -1
- package/package.json +1 -1
|
@@ -6645,13 +6645,55 @@ function extractUrl(args, _argsText) {
|
|
|
6645
6645
|
const direct = args.url || args.uri || args.endpoint || args.webhookUrl || args.callbackUrl || args.href || args.link;
|
|
6646
6646
|
if (typeof direct === "string" && direct.trim()) return direct.trim();
|
|
6647
6647
|
for (const field of URL_ACTION_FIELDS) {
|
|
6648
|
-
const
|
|
6649
|
-
if (typeof
|
|
6648
|
+
const raw = args[field];
|
|
6649
|
+
if (typeof raw !== "string") continue;
|
|
6650
|
+
const value = ["command", "cmd", "script", "input"].includes(field) ? shellUrlActionText(raw) : raw;
|
|
6650
6651
|
const found = value.match(/https?:\/\/[^\s"'<>]+/i)?.[0] || value.match(/\b(?:s3|gs|ftp|sftp|smb):\/\/[^\s"'<>]+/i)?.[0];
|
|
6651
6652
|
if (found) return found;
|
|
6652
6653
|
}
|
|
6653
6654
|
return "";
|
|
6654
6655
|
}
|
|
6656
|
+
function shellUrlActionText(command) {
|
|
6657
|
+
const segments = splitShellSegments(command);
|
|
6658
|
+
const filtered = segments.map((segment) => {
|
|
6659
|
+
const literal2 = /^(?:@'\r?\n[\s\S]*?\r?\n'@|@"\r?\n[^$`]*?\r?\n"@|'(?:[^']|'')*'|"[^"$`]*")/;
|
|
6660
|
+
const piped = segment.match(literal2);
|
|
6661
|
+
let tail = piped ? segment.slice(piped[0].length).replace(/^\s*\|\s*/, "") : "";
|
|
6662
|
+
if (!piped || !/^\s*\|/.test(segment.slice(piped[0].length))) {
|
|
6663
|
+
const argument = segment.match(/^(Set-Content|Add-Content|Out-File)\s+([\s\S]*?)\s+-(Value|InputObject)\s+([\s\S]+)$/i);
|
|
6664
|
+
const value = argument?.[4].match(literal2);
|
|
6665
|
+
if (!argument || !value) return segment;
|
|
6666
|
+
tail = `${argument[1]} ${argument[2]} ${argument[4].slice(value[0].length)}`;
|
|
6667
|
+
}
|
|
6668
|
+
const writer = tail.match(/^(?:Set-Content|Add-Content|Out-File)\s+([\s\S]+)$/i);
|
|
6669
|
+
if (!writer) return segment;
|
|
6670
|
+
const tokens = writer[1].match(/'[^']*'|"[^"$`]*"|[^\s'"$`|;&(){}]+/g) || [];
|
|
6671
|
+
if (tokens.join(" ").replace(/\s/g, "") !== writer[1].replace(/\s/g, "")) return segment;
|
|
6672
|
+
let target = "";
|
|
6673
|
+
for (let i2 = 0; i2 < tokens.length; i2++) {
|
|
6674
|
+
const token = tokens[i2];
|
|
6675
|
+
if (/^-(?:LiteralPath|Path|FilePath)$/i.test(token)) {
|
|
6676
|
+
if (target || !tokens[i2 + 1]) return segment;
|
|
6677
|
+
target = tokens[++i2];
|
|
6678
|
+
} else if (/^-Encoding$/i.test(token)) {
|
|
6679
|
+
if (!/^(?:utf8|utf8BOM|utf8NoBOM|unicode|ascii|default|oem|bigendianunicode|utf32)$/i.test(tokens[++i2] || "")) return segment;
|
|
6680
|
+
} else if (/^-(?:Force|NoNewline|Append)$/i.test(token)) {
|
|
6681
|
+
continue;
|
|
6682
|
+
} else if (!target && !token.startsWith("-")) target = token;
|
|
6683
|
+
else return segment;
|
|
6684
|
+
}
|
|
6685
|
+
target = target.replace(/^['"]|['"]$/g, "");
|
|
6686
|
+
if (!target || /^[\\/]{2}|[\r\n*?\[\]<>]/.test(target) || /:/.test(target.replace(/^[A-Za-z]:[\\/]/, ""))) return segment;
|
|
6687
|
+
return tail;
|
|
6688
|
+
});
|
|
6689
|
+
const onlyStoredData = segments.every((segment, index) => {
|
|
6690
|
+
if (filtered[index] !== segment) return true;
|
|
6691
|
+
const words = maskQuotedSpans(segment);
|
|
6692
|
+
if (!/[$`|;&(){}<>]/.test(segment) && /^(?:(?:cd|pushd|set-location)\s+[^\r\n]+|(?:pwd|popd|get-location)|git\s+status(?:\s+[^\r\n]+)?)$/i.test(segment)) return true;
|
|
6693
|
+
return !/[$`]/.test(segment) && /^\(Get-Content\s+(?:[A-Za-z]:[\\/])?[\w./\\-]+\s+-Raw\)\.Replace\("",\s*""\)\s*\|\s*Set-Content\s+(?:[A-Za-z]:[\\/])?[\w./\\-]+\s+-Encoding\s+utf8\s*$/i.test(words);
|
|
6694
|
+
});
|
|
6695
|
+
return onlyStoredData && filtered.some((value, index) => value !== segments[index]) ? filtered.join("\n") : command;
|
|
6696
|
+
}
|
|
6655
6697
|
function splitShellSegments(command, alsoOnPipe = false) {
|
|
6656
6698
|
const out = [];
|
|
6657
6699
|
let cur = "";
|
|
@@ -6941,7 +6983,7 @@ function classifyShellWords(masked, raw, lead) {
|
|
|
6941
6983
|
if (lead === "gh" && /\bgh\s+(?:pr|issue|repo|run|release|workflow)\s+(?:view|list|status|checks|diff|download)\b/.test(value)) return "read";
|
|
6942
6984
|
if (lead === "gh" && /\bgh\s+auth\s+status\b/.test(value) && !/--show-token|\s-t\b/.test(value)) return "read";
|
|
6943
6985
|
if (/^(?:gcloud\s+run\s+services\s+(?:describe|logs\s+read)|kubectl\s+(?:get|describe|logs|top|config\s+(?:current-context|get-contexts|view(?!\s+--raw)))|docker\s+(?:ps|images|logs|inspect|version|info)|terraform\s+(?:plan|validate|fmt|show|state\s+list|output)|aws\s+(?:s3\s+ls|sts\s+get-caller-identity)|az\s+account\s+show|npm\s+(?:ls|list|view|outdated|--version)|node\s+--version|python3?\s+--version)\b/.test(value)) return "read";
|
|
6944
|
-
if (/\b(rm\s+-[a-z]*r[a-z]*f|rm\s+-[a-z]*f[a-z]*r|del\s+\/[fqs]|remove-item\b.*\
|
|
6986
|
+
if (/\b(rm\s+-[a-z]*r[a-z]*f|rm\s+-[a-z]*f[a-z]*r|del\s+\/[fqs]|remove-item\b.*\s-recurse\b|rmdir\s+\/s)\b/.test(value)) {
|
|
6945
6987
|
return isWorkspaceScopedRemoval(segment) ? "write" : "DELETE";
|
|
6946
6988
|
}
|
|
6947
6989
|
if (/\b(drop\s+(database|table|schema)|truncate\s+table|kubectl\s+delete|terraform\s+destroy|gcloud\s+(?:sql\s+instances|compute\s+instances|projects|run\s+services)\s+delete|az\s+(?:group|vm|sql\s+server)\s+delete|aws\s+(?:s3\s+rb|rds\s+delete-db-instance|ec2\s+terminate-instances)|docker\s+(?:system\s+prune|volume\s+rm|rm\s+-f)|mkfs|dd\s+if=)\b/.test(value)) {
|
|
@@ -6971,6 +7013,7 @@ function classifyShellWords(masked, raw, lead) {
|
|
|
6971
7013
|
return "SHELL";
|
|
6972
7014
|
}
|
|
6973
7015
|
function classifyShellCommandOperation(command, depth = 0) {
|
|
7016
|
+
if (shellUrlActionText(command) !== command) return "write";
|
|
6974
7017
|
const segments = splitShellSegments(command);
|
|
6975
7018
|
if (segments.length === 0) return "SHELL";
|
|
6976
7019
|
return worstShellOp(segments.map((segment) => classifyShellSegment(segment, depth)), "read");
|
package/dist/blockExplanation.js
CHANGED
|
@@ -84,7 +84,7 @@ const FACT_WORDS = [
|
|
|
84
84
|
? `a secret-shaped value was found in the arguments${f['toolArgs.secretKind'] && f['toolArgs.secretKind'] !== 'none' ? ` (${f['toolArgs.secretKind'].replace(/_/g, ' ')})` : ''}`
|
|
85
85
|
: undefined],
|
|
86
86
|
['toolArgs.containsPii', v => v === 'true' ? 'personal data (PII) was found in the arguments' : undefined],
|
|
87
|
-
['destination.type', (v, f) => v === 'external' ? `the destination ${f['destination.domain'] ? `"${f['destination.domain']}" ` : ''}is
|
|
87
|
+
['destination.type', (v, f) => v === 'external' ? `the destination ${f['destination.domain'] ? `"${f['destination.domain']}" ` : ''}is classified as external; this does not establish whether your organisation trusts it` : undefined],
|
|
88
88
|
['destination.domain', (v, f) => f['destination.type'] === 'external' ? undefined : `destination host: ${v}`],
|
|
89
89
|
['url.risk', v => v && v !== 'none' && v !== 'low' ? `the URL was rated ${v} risk` : undefined],
|
|
90
90
|
['path.sensitive', v => v === 'true' ? 'the path is a sensitive location' : undefined],
|
package/dist/commands/hook.js
CHANGED
|
@@ -830,7 +830,7 @@ function prepareDeveloperConfirmation(event, call, payload, source) {
|
|
|
830
830
|
// Name the rule in the prompt itself: a developer deciding y/n must see WHICH
|
|
831
831
|
// rule is asking and where to change it — same builder as every block.
|
|
832
832
|
const ceilingNote = source.askedInsteadOfBlocked
|
|
833
|
-
? 'This policy is set to Block.
|
|
833
|
+
? 'This policy is set to Block. Because it is not marked "Hard block", your workstation requires your approval before continuing. An admin can review the matching rule and its scope in the console.'
|
|
834
834
|
: undefined;
|
|
835
835
|
const explained = source.where === 'local-safety' && source.localFinding
|
|
836
836
|
? explainLocalSafetyStop('ask', event, call, source.localFinding)
|
package/dist/version.json
CHANGED