@ai-ecoverse/slicc-spectrum 1.109.0 → 1.109.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 +3 -1
- package/dist/slicc-ui.js +72 -24
- package/dist/slicc-ui.js.map +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -682,6 +682,7 @@ It takes a sudo request's command (without `sudo` and its options) and working f
|
|
|
682
682
|
|
|
683
683
|
- `certain` is an absolute path when the command names a file or folder holding SLICC's secret rules (`/etc/fnox`, `/etc/fnox/config.toml`, `/etc/slicc/secrets-policy.toml`), a folder above them it changes as a whole (`/`, `/etc`, `/etc/slicc`), a glob or brace that matches one, or a file named like them (`fnox`, `secrets-policy`) anywhere, as `/tmp/fnox/config.toml`.
|
|
684
684
|
It sees through quotes, backslashes, `$'…'` and `$"…"`, `cd` and `pushd` (also inside `bash -c`), relative paths and `..`, extglobs, `/proc/self/root` and `/proc/self/cwd`, option clusters like `-t/etc/fnox`, and comma lists.
|
|
685
|
+
When every command in it is read-only and nothing in it expands, quoted text is data: a jq or yq program such as `'.a // .b | {x: .y}'` isn't split into paths, and `*`, `?`, `[` and `{` in quotes (and `$` in single quotes) are literal, as the shell treats them. Other commands, such as `sh -c '…'`, are still looked into.
|
|
685
686
|
- `maybe` is the token when the command may reach one of them and the check can't tell where it leads: an expansion (`$X`, `$(…)`, backticks), a `~user/..`, `~+` or `~-` path, a `/proc/<pid>/cwd` or `/dev/fd` path, or a command over 4096 characters (its first 40 followed by `…`).
|
|
686
687
|
|
|
687
688
|
Both are `null` for a clean command, and at most one is set.
|
|
@@ -945,8 +946,9 @@ Later backed by: BIOS.
|
|
|
945
946
|
`list()` returns waiting `Approval`s; emit `approvals` when the list changes.
|
|
946
947
|
A `sudo` approval has `id`, `requester` (`kind` `agent` or `user`, `name`, optional `agentId` and `where`, such as a terminal's title), `command` (without `sudo`; bios joins the kernel's argv shell-quoted), optional `target` (the user to run as; shown as `sudo -u {target}` unless `root`), optional `cwd` and `verdict` (`{ decision: 'allow' | 'deny' | 'unsure', reason }`, the automatic check’s view), `createdAt`, `expiresAt` (epoch ms) and `always` (offer Always allow, which covers the requester's user and this exact command).
|
|
947
948
|
With `decide(id, 'once' | 'always' | 'deny')`, which resolves once the decision is recorded and then drops the request from `list()`, the tab shows a warning alert dialog (`dialog[data-approval][data-kind][data-requester]`): "Allow sudo?", "{name} wants to run this with sudo[ in {where}]:" for an agent or "You ran this with sudo[ in {where}] (as {name}):" for a user, the command, "In {cwd}", a notice when the command changes secret rules, what Always allow does, "Denied automatically in m:ss." and how many more wait, with **Deny** (`data-action="deny"`, focused; Escape also denies), **Always allow** (`always`) and **Allow once** (`once`).
|
|
948
|
-
A command that names `/etc/fnox` (or anything in it) or `/etc/slicc/secrets-policy.toml`, resolved against `cwd`, globs included (with quotes and backslashes removed, operands after `--` included; a path with `[`, `{` or `$` counts when the part before it could lead to them), or that names `/`, `/etc` or `/etc/slicc` in a command other than a read-only one (such as `ls`, `cat`, `stat` or `
|
|
949
|
+
A command that names `/etc/fnox` (or anything in it) or `/etc/slicc/secrets-policy.toml`, resolved against `cwd`, globs included (with quotes and backslashes removed, operands after `--` included; a path with `[`, `{` or `$` counts when the part before it could lead to them), or that names `/`, `/etc` or `/etc/slicc` in a command other than a read-only one (such as `ls`, `cat`, `stat`, `grep`, `jq`, `cut`, `od`, `sha256sum` or `md5sum`; `find` without `-exec`, `-execdir`, `-ok`, `-okdir`, `-delete` or `-fprint`/`-fls`; `sort` without `-o`, `-T` or `--compress-program`; `yq` without `-i`, `-s` or `--split-exp-file`; `base64` without `-o`; `tree` without `-o` or `-R`; `file` without `-C`; `uniq` and `xxd` with one operand at most, counting everything after `--`; a flag counts inside a short cluster, with a value attached (`-o/x`, `-i.bak`), as `--name=value` and abbreviated; `less` and other pagers aren't, since they run commands), or runs with `cwd` in `/etc/fnox`, or names a relative path with `fnox` or `secrets-policy` in it wherever `cd` may have led, gets "This changes secret rules." with the path (`[data-secret-rules]`, the path in the attribute).
|
|
949
950
|
Read-only commands count only by bare name or from `/bin` and `/usr/bin`.
|
|
951
|
+
In a command made only of read-only commands and with no live expansion, the quoted words count whole: `jq '.a // .b' f` doesn't name `/`, and `jq '{a: .b}' f` in `/etc` isn't a brace that could lead to the rules.
|
|
950
952
|
`/proc/<pid>/root` counts as `/` and `/proc/self/cwd` as `cwd`.
|
|
951
953
|
Otherwise a command with a parameter expansion or command substitution (`$…`, backticks), a `~+` or `~-` path or a `~` path that climbs with `..`, a path through another process's `/proc/<pid>/cwd`, `fd` or `map_files` or through `/dev/fd`, or more than 4096 characters, gets "This may change secret rules." with the first such part in the attribute.
|
|
952
954
|
Other symlinks aren't followed.
|
package/dist/slicc-ui.js
CHANGED
|
@@ -10331,8 +10331,8 @@ var ranges = [
|
|
|
10331
10331
|
[100, "bg", 8]
|
|
10332
10332
|
];
|
|
10333
10333
|
function simple(code3) {
|
|
10334
|
-
const
|
|
10335
|
-
if (
|
|
10334
|
+
const flag2 = flags[code3];
|
|
10335
|
+
if (flag2) return flag2;
|
|
10336
10336
|
const range2 = ranges.find(([start2]) => code3 >= start2 && code3 < start2 + 8);
|
|
10337
10337
|
return range2 ? { [range2[1]]: code3 - range2[0] + range2[2] } : null;
|
|
10338
10338
|
}
|
|
@@ -40184,12 +40184,12 @@ var SliccMonitor = class extends ModelElement {
|
|
|
40184
40184
|
</li>`;
|
|
40185
40185
|
}
|
|
40186
40186
|
#section(section) {
|
|
40187
|
-
const
|
|
40187
|
+
const flag2 = attention2(section);
|
|
40188
40188
|
const surface2 = surfaces[section.id];
|
|
40189
40189
|
const rows2 = section.rows.length > 0;
|
|
40190
|
-
const open = rows2 && (this.expanded[section.id] ??
|
|
40190
|
+
const open = rows2 && (this.expanded[section.id] ?? flag2 !== null);
|
|
40191
40191
|
const list6 = `rows-${section.id}`;
|
|
40192
|
-
const badge =
|
|
40192
|
+
const badge = flag2 ? b`<swc-badge size="s" variant=${flag2.variant} subtle>${flag2.text}</swc-badge>` : A;
|
|
40193
40193
|
return b`<li class="section" data-id=${section.id} data-open=${open ? "" : A}>
|
|
40194
40194
|
<div class="line">
|
|
40195
40195
|
<span class="caption">${rows2 ? b`<button class="toggle" aria-expanded=${open ? "true" : "false"} aria-controls=${open ? list6 : A} @click=${() => {
|
|
@@ -44002,14 +44002,14 @@ var directions2 = /* @__PURE__ */ new Set(["left", "right", "above", "below", "w
|
|
|
44002
44002
|
function scan(parsed, rest, positional) {
|
|
44003
44003
|
for (let index2 = 0; index2 < rest.length; index2++) {
|
|
44004
44004
|
const arg = rest[index2];
|
|
44005
|
-
const
|
|
44006
|
-
if (
|
|
44007
|
-
else if (
|
|
44005
|
+
const flag2 = arg.startsWith("--") ? arg.slice(2) : null;
|
|
44006
|
+
if (flag2 === "json") parsed.json = true;
|
|
44007
|
+
else if (flag2 === "section" || flag2 !== null && directions2.has(flag2)) {
|
|
44008
44008
|
const value = rest[++index2];
|
|
44009
|
-
if (value === void 0) return `--${
|
|
44010
|
-
if (
|
|
44009
|
+
if (value === void 0) return `--${flag2} needs a value`;
|
|
44010
|
+
if (flag2 === "section") parsed.section = value;
|
|
44011
44011
|
else if (parsed.place) return "give one place";
|
|
44012
|
-
else parsed.place = { direction:
|
|
44012
|
+
else parsed.place = { direction: flag2, ref: value };
|
|
44013
44013
|
} else if (arg.startsWith("-")) return `unknown option ${arg}`;
|
|
44014
44014
|
else positional.push(arg);
|
|
44015
44015
|
}
|
|
@@ -49679,27 +49679,67 @@ function pattern(path2) {
|
|
|
49679
49679
|
var opaque = /^\/(?:proc\/[^/]+\/(?:task\/[^/]+\/)?(?:cwd|fd|map_files)|dev\/fd)(?:\/|$)/;
|
|
49680
49680
|
var certain = (rules) => rules.startsWith("/") && !opaque.test(rules) && !rules.endsWith("\u2026");
|
|
49681
49681
|
var readOnly = [
|
|
49682
|
+
"b2sum",
|
|
49683
|
+
"base64",
|
|
49682
49684
|
"cat",
|
|
49683
49685
|
"cd",
|
|
49686
|
+
"cksum",
|
|
49687
|
+
"cut",
|
|
49684
49688
|
"df",
|
|
49685
49689
|
"diff",
|
|
49686
49690
|
"du",
|
|
49687
49691
|
"echo",
|
|
49688
49692
|
"file",
|
|
49693
|
+
"find",
|
|
49689
49694
|
"grep",
|
|
49690
49695
|
"head",
|
|
49696
|
+
"jq",
|
|
49691
49697
|
"ls",
|
|
49698
|
+
"md5sum",
|
|
49699
|
+
"nl",
|
|
49700
|
+
"od",
|
|
49692
49701
|
"pwd",
|
|
49693
49702
|
"readlink",
|
|
49694
49703
|
"realpath",
|
|
49704
|
+
"sha1sum",
|
|
49705
|
+
"sha224sum",
|
|
49706
|
+
"sha256sum",
|
|
49707
|
+
"sha384sum",
|
|
49708
|
+
"sha512sum",
|
|
49709
|
+
"sort",
|
|
49695
49710
|
"stat",
|
|
49711
|
+
"tac",
|
|
49696
49712
|
"tail",
|
|
49697
49713
|
"tree",
|
|
49698
|
-
"
|
|
49714
|
+
"uniq",
|
|
49715
|
+
"wc",
|
|
49716
|
+
"xxd",
|
|
49717
|
+
"yq"
|
|
49699
49718
|
];
|
|
49719
|
+
var flag = (short2, long) => (args2) => args2.some((arg) => {
|
|
49720
|
+
if (!arg.startsWith("--")) return /^-[^-]/.test(arg) && [...short2].some((c29) => arg.includes(c29));
|
|
49721
|
+
const [name] = arg.slice(2).split("=");
|
|
49722
|
+
return !!name && long.some((option) => option.startsWith(name));
|
|
49723
|
+
});
|
|
49724
|
+
var operands = (args2) => {
|
|
49725
|
+
const end = args2.includes("--") ? args2.indexOf("--") : args2.length;
|
|
49726
|
+
const named2 = args2.slice(0, end).filter((arg) => arg === "-" || !arg.startsWith("-"));
|
|
49727
|
+
return named2.length + args2.slice(end + 1).length > 1;
|
|
49728
|
+
};
|
|
49729
|
+
var writes = {
|
|
49730
|
+
base64: flag("o", ["output"]),
|
|
49731
|
+
file: flag("C", ["compile"]),
|
|
49732
|
+
find: (args2) => args2.some((arg) => /^-(?:delete|exec|execdir|ok|okdir|fls|fprint0?|fprintf)$/.test(arg)),
|
|
49733
|
+
sort: flag("oT", ["output", "temporary-directory", "compress-program"]),
|
|
49734
|
+
tree: flag("oR", []),
|
|
49735
|
+
uniq: operands,
|
|
49736
|
+
xxd: operands,
|
|
49737
|
+
yq: flag("is", ["inplace", "in-place", "split-exp", "split-exp-file"])
|
|
49738
|
+
};
|
|
49700
49739
|
function candidates(word2) {
|
|
49701
49740
|
if (word2 === "--") return [];
|
|
49702
|
-
if (word2.startsWith("--"))
|
|
49741
|
+
if (word2.startsWith("--"))
|
|
49742
|
+
return word2.includes("=") ? [word2, word2.split("=").slice(1).join("=")] : [word2];
|
|
49703
49743
|
if (!word2.startsWith("-")) return [word2];
|
|
49704
49744
|
const slash = word2.indexOf("/");
|
|
49705
49745
|
const cluster = Array.from(word2.slice(2), (_7, index2) => word2.slice(index2 + 2));
|
|
@@ -49719,7 +49759,10 @@ function protects(path2, whole) {
|
|
|
49719
49759
|
return rulePaths.some((rule) => glob.test(rule)) || top !== path2 && pattern(top).test("/etc/fnox") || whole && ruleParents.some((parent) => glob.test(parent));
|
|
49720
49760
|
}
|
|
49721
49761
|
var command2 = (word2) => word2.split("/").pop() ?? "";
|
|
49722
|
-
var trusted2 = (word2) =>
|
|
49762
|
+
var trusted2 = ([word2, ...args2]) => {
|
|
49763
|
+
const name = word2.replace(/^\/(?:usr\/)?bin\/(?=[^/]+$)/, "");
|
|
49764
|
+
return readOnly.includes(name) && !writes[name]?.(args2);
|
|
49765
|
+
};
|
|
49723
49766
|
var expansion = /\$\([^)]*\)?|\$\{[^}]*\}?|\$[\w@*#?$!-]*|`[^`]*`?/;
|
|
49724
49767
|
function moved(cwds, word2) {
|
|
49725
49768
|
for (const cwd of [...cwds]) {
|
|
@@ -49795,6 +49838,8 @@ function shield(text4) {
|
|
|
49795
49838
|
}
|
|
49796
49839
|
return out;
|
|
49797
49840
|
}
|
|
49841
|
+
var literal = (char, quote) => /[*?[{]/.test(char) || quote === "'" && char === "$" ? String.fromCharCode(57600 + char.charCodeAt(0)) : char;
|
|
49842
|
+
var unmark = (path2) => path2.replace(/[\ue100-\ue17f]/g, (char) => String.fromCharCode(char.charCodeAt(0) - 57600));
|
|
49798
49843
|
function quoted(segment2) {
|
|
49799
49844
|
const words2 = [];
|
|
49800
49845
|
let word2 = "";
|
|
@@ -49805,7 +49850,7 @@ function quoted(segment2) {
|
|
|
49805
49850
|
word2 += segment2[++index2];
|
|
49806
49851
|
else if (quote) {
|
|
49807
49852
|
if (char === quote) quote = "";
|
|
49808
|
-
else word2 += char;
|
|
49853
|
+
else word2 += literal(char, quote);
|
|
49809
49854
|
} else if (char === "'" || char === '"') quote = char;
|
|
49810
49855
|
else if (char === "\\") word2 += segment2[++index2] ?? "";
|
|
49811
49856
|
else if (/[\s<>=]/.test(char)) {
|
|
@@ -49842,8 +49887,10 @@ function reach2(command3, cwd) {
|
|
|
49842
49887
|
const text4 = unglob(ansi2(command3.replace(/\\\n/g, "")));
|
|
49843
49888
|
const plain4 = text4.split(separators).map((segment2) => commas(segment2.split(/[\s<>=]+/).map((word2) => word2.replace(/['"\\]/g, ""))));
|
|
49844
49889
|
const aware = shield(text4).split(separators).map((segment2) => commas(quoted(unshield(segment2))));
|
|
49845
|
-
const
|
|
49846
|
-
const
|
|
49890
|
+
const live = text4.includes("`") || aware.flat().some((word2) => word2.includes("$"));
|
|
49891
|
+
const inert2 = !live && aware.every((words2) => !words2.length || trusted2(words2));
|
|
49892
|
+
const segments = inert2 || JSON.stringify(aware) === JSON.stringify(plain4) ? aware : [...plain4, ...aware];
|
|
49893
|
+
const whole = !inert2 && segments.some((words2) => words2.length > 0 && !trusted2(words2));
|
|
49847
49894
|
for (const words2 of segments) {
|
|
49848
49895
|
const hit = scan2(words2, cwds, whole);
|
|
49849
49896
|
if (hit) return hit;
|
|
@@ -49855,7 +49902,8 @@ function reach2(command3, cwd) {
|
|
|
49855
49902
|
return segments.flat().some((word2) => word2.includes("$")) || text4.includes("`") ? text4.match(expansion)[0] : null;
|
|
49856
49903
|
}
|
|
49857
49904
|
function secretRules(command3, cwd) {
|
|
49858
|
-
const
|
|
49905
|
+
const found = reach2(command3, cwd);
|
|
49906
|
+
const hit = found && unmark(found);
|
|
49859
49907
|
return hit && certain(hit) ? { certain: hit, maybe: null } : { certain: null, maybe: hit };
|
|
49860
49908
|
}
|
|
49861
49909
|
function origin() {
|
|
@@ -56112,7 +56160,7 @@ var bridge = `(() => {
|
|
|
56112
56160
|
});
|
|
56113
56161
|
post({ type: 'slicc-ready' });
|
|
56114
56162
|
})();`;
|
|
56115
|
-
function
|
|
56163
|
+
function literal2(value) {
|
|
56116
56164
|
try {
|
|
56117
56165
|
return JSON.stringify(value ?? null).replace(/</g, "\\u003c");
|
|
56118
56166
|
} catch {
|
|
@@ -56121,7 +56169,7 @@ function literal(value) {
|
|
|
56121
56169
|
}
|
|
56122
56170
|
function store(state2) {
|
|
56123
56171
|
return `(() => {
|
|
56124
|
-
let state = ${
|
|
56172
|
+
let state = ${literal2(state2)};
|
|
56125
56173
|
const tag = Math.random().toString(36).slice(2);
|
|
56126
56174
|
const pending = new Map();
|
|
56127
56175
|
let next = 0;
|
|
@@ -75264,11 +75312,11 @@ function isDirectoryNode(node2) {
|
|
|
75264
75312
|
function getNodeFlags(node2) {
|
|
75265
75313
|
return node2.depthAndFlags & PATH_STORE_NODE_FLAGS_MASK;
|
|
75266
75314
|
}
|
|
75267
|
-
function hasNodeFlag(node2,
|
|
75268
|
-
return (getNodeFlags(node2) &
|
|
75315
|
+
function hasNodeFlag(node2, flag2) {
|
|
75316
|
+
return (getNodeFlags(node2) & flag2) !== 0;
|
|
75269
75317
|
}
|
|
75270
|
-
function addNodeFlag(node2,
|
|
75271
|
-
node2.depthAndFlags |=
|
|
75318
|
+
function addNodeFlag(node2, flag2) {
|
|
75319
|
+
node2.depthAndFlags |= flag2;
|
|
75272
75320
|
}
|
|
75273
75321
|
function setNodeDepth(node2, depth) {
|
|
75274
75322
|
node2.depthAndFlags = createNodeDepthAndFlags(depth, getNodeFlags(node2), getNodeKind(node2));
|