mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 14:20:44 +00:00
test: normalize safe-bin docs parity indentation
This commit is contained in:
@@ -316,60 +316,60 @@ so file operands cannot be smuggled as ambiguous positionals.
|
||||
|
||||
[//]: # "SAFE_BIN_DENIED_FLAGS:START"
|
||||
|
||||
- `grep`: `--dereference-recursive`, `--directories`, `--exclude-from`, `--file`, `--recursive`, `-R`, `-d`, `-f`, `-r`
|
||||
- `jq`: `--argfile`, `--from-file`, `--library-path`, `--rawfile`, `--slurpfile`, `-L`, `-f`
|
||||
- `sort`: `--compress-program`, `--files0-from`, `--output`, `--random-source`, `--temporary-directory`, `-T`, `-o`
|
||||
- `wc`: `--files0-from`
|
||||
- `grep`: `--dereference-recursive`, `--directories`, `--exclude-from`, `--file`, `--recursive`, `-R`, `-d`, `-f`, `-r`
|
||||
- `jq`: `--argfile`, `--from-file`, `--library-path`, `--rawfile`, `--slurpfile`, `-L`, `-f`
|
||||
- `sort`: `--compress-program`, `--files0-from`, `--output`, `--random-source`, `--temporary-directory`, `-T`, `-o`
|
||||
- `wc`: `--files0-from`
|
||||
|
||||
[//]: # "SAFE_BIN_DENIED_FLAGS:END"
|
||||
[//]: # "SAFE_BIN_DENIED_FLAGS:END"
|
||||
|
||||
Safe bins also force argv tokens to be treated as **literal text** at
|
||||
execution time (no globbing and no `$VARS` expansion) for stdin-only
|
||||
segments, so patterns like `*` or `$HOME/...` cannot be used to smuggle
|
||||
file reads.
|
||||
Safe bins also force argv tokens to be treated as **literal text** at
|
||||
execution time (no globbing and no `$VARS` expansion) for stdin-only
|
||||
segments, so patterns like `*` or `$HOME/...` cannot be used to smuggle
|
||||
file reads.
|
||||
|
||||
</Accordion>
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Trusted binary directories">
|
||||
Safe bins must resolve from trusted binary directories (system defaults
|
||||
plus optional `tools.exec.safeBinTrustedDirs`). `PATH` entries are never
|
||||
auto-trusted. Default trusted directories are intentionally minimal:
|
||||
`/bin`, `/usr/bin`. If your safe-bin executable lives in
|
||||
package-manager/user paths (for example `/opt/homebrew/bin`,
|
||||
`/usr/local/bin`, `/opt/local/bin`, `/snap/bin`), add them explicitly to
|
||||
`tools.exec.safeBinTrustedDirs`.
|
||||
</Accordion>
|
||||
<Accordion title="Trusted binary directories">
|
||||
Safe bins must resolve from trusted binary directories (system defaults
|
||||
plus optional `tools.exec.safeBinTrustedDirs`). `PATH` entries are never
|
||||
auto-trusted. Default trusted directories are intentionally minimal:
|
||||
`/bin`, `/usr/bin`. If your safe-bin executable lives in
|
||||
package-manager/user paths (for example `/opt/homebrew/bin`,
|
||||
`/usr/local/bin`, `/opt/local/bin`, `/snap/bin`), add them explicitly to
|
||||
`tools.exec.safeBinTrustedDirs`.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Shell chaining, wrappers, and multiplexers">
|
||||
Shell chaining (`&&`, `||`, `;`) is allowed when every top-level segment
|
||||
satisfies the allowlist (including safe bins or skill auto-allow).
|
||||
Redirections remain unsupported in allowlist mode. Command substitution
|
||||
(`$()` / backticks) is rejected during allowlist parsing, including inside
|
||||
double quotes; use single quotes if you need literal `$()` text.
|
||||
<Accordion title="Shell chaining, wrappers, and multiplexers">
|
||||
Shell chaining (`&&`, `||`, `;`) is allowed when every top-level segment
|
||||
satisfies the allowlist (including safe bins or skill auto-allow).
|
||||
Redirections remain unsupported in allowlist mode. Command substitution
|
||||
(`$()` / backticks) is rejected during allowlist parsing, including inside
|
||||
double quotes; use single quotes if you need literal `$()` text.
|
||||
|
||||
On macOS companion-app approvals, raw shell text containing shell control
|
||||
or expansion syntax (`&&`, `||`, `;`, `|`, `` ` ``, `$`, `<`, `>`, `(`,
|
||||
`)`) is treated as an allowlist miss unless the shell binary itself is
|
||||
allowlisted.
|
||||
On macOS companion-app approvals, raw shell text containing shell control
|
||||
or expansion syntax (`&&`, `||`, `;`, `|`, `` ` ``, `$`, `<`, `>`, `(`,
|
||||
`)`) is treated as an allowlist miss unless the shell binary itself is
|
||||
allowlisted.
|
||||
|
||||
For shell wrappers (`bash|sh|zsh ... -c/-lc`), request-scoped env
|
||||
overrides are reduced to a small explicit allowlist (`TERM`, `LANG`,
|
||||
`LC_*`, `COLORTERM`, `NO_COLOR`, `FORCE_COLOR`).
|
||||
For shell wrappers (`bash|sh|zsh ... -c/-lc`), request-scoped env
|
||||
overrides are reduced to a small explicit allowlist (`TERM`, `LANG`,
|
||||
`LC_*`, `COLORTERM`, `NO_COLOR`, `FORCE_COLOR`).
|
||||
|
||||
For `allow-always` decisions in allowlist mode, known dispatch wrappers
|
||||
(`env`, `nice`, `nohup`, `stdbuf`, `timeout`) persist the inner executable
|
||||
path instead of the wrapper path. Shell multiplexers (`busybox`, `toybox`)
|
||||
are unwrapped for shell applets (`sh`, `ash`, etc.) the same way. If a
|
||||
wrapper or multiplexer cannot be safely unwrapped, no allowlist entry is
|
||||
persisted automatically.
|
||||
For `allow-always` decisions in allowlist mode, known dispatch wrappers
|
||||
(`env`, `nice`, `nohup`, `stdbuf`, `timeout`) persist the inner executable
|
||||
path instead of the wrapper path. Shell multiplexers (`busybox`, `toybox`)
|
||||
are unwrapped for shell applets (`sh`, `ash`, etc.) the same way. If a
|
||||
wrapper or multiplexer cannot be safely unwrapped, no allowlist entry is
|
||||
persisted automatically.
|
||||
|
||||
If you allowlist interpreters like `python3` or `node`, prefer
|
||||
`tools.exec.strictInlineEval=true` so inline eval still requires an
|
||||
explicit approval. In strict mode, `allow-always` can still persist benign
|
||||
interpreter/script invocations, but inline-eval carriers are not persisted
|
||||
automatically.
|
||||
If you allowlist interpreters like `python3` or `node`, prefer
|
||||
`tools.exec.strictInlineEval=true` so inline eval still requires an
|
||||
explicit approval. In strict mode, `allow-always` can still persist benign
|
||||
interpreter/script invocations, but inline-eval carriers are not persisted
|
||||
automatically.
|
||||
|
||||
</Accordion>
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
### Safe bins versus allowlist
|
||||
|
||||
@@ -17,6 +17,24 @@ const SAFE_BIN_DOC_DEFAULTS_END = '[//]: # "SAFE_BIN_DEFAULTS:END"';
|
||||
const SAFE_BIN_DOC_DENIED_FLAGS_START = '[//]: # "SAFE_BIN_DENIED_FLAGS:START"';
|
||||
const SAFE_BIN_DOC_DENIED_FLAGS_END = '[//]: # "SAFE_BIN_DENIED_FLAGS:END"';
|
||||
|
||||
function normalizeGeneratedDocBlock(block: string): string {
|
||||
const lines = block.split("\n");
|
||||
while (lines[0]?.trim() === "") {
|
||||
lines.shift();
|
||||
}
|
||||
while (lines.at(-1)?.trim() === "") {
|
||||
lines.pop();
|
||||
}
|
||||
const indents = lines
|
||||
.filter((line) => line.trim().length > 0)
|
||||
.map((line) => line.match(/^ */)?.[0].length ?? 0);
|
||||
const commonIndent = Math.min(...indents);
|
||||
if (commonIndent <= 0) {
|
||||
return lines.join("\n");
|
||||
}
|
||||
return lines.map((line) => line.slice(Math.min(line.length, commonIndent))).join("\n");
|
||||
}
|
||||
|
||||
function buildDeniedFlagArgvVariants(flag: string): string[][] {
|
||||
const value = "blocked";
|
||||
if (flag.startsWith("--")) {
|
||||
@@ -187,7 +205,9 @@ describe("exec safe bin policy docs parity", () => {
|
||||
const end = docs.indexOf(SAFE_BIN_DOC_DENIED_FLAGS_END);
|
||||
expect(start).toBeGreaterThanOrEqual(0);
|
||||
expect(end).toBeGreaterThan(start);
|
||||
const actual = docs.slice(start + SAFE_BIN_DOC_DENIED_FLAGS_START.length, end).trim();
|
||||
const actual = normalizeGeneratedDocBlock(
|
||||
docs.slice(start + SAFE_BIN_DOC_DENIED_FLAGS_START.length, end),
|
||||
);
|
||||
const expected = renderSafeBinDeniedFlagsDocBullets();
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user