mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-14 10:17:55 +00:00
The backend import package is now docsgpt, the name it will carry on PyPI; application was far too generic to install into anyone's site-packages. git mv plus a mechanical rewrite of every import, dotted string and path reference: 734 Python files, the compose files, Dockerfile, workflows, docs, setup scripts, devcontainer, k8s manifests, vscode config, pytest and coverage config, .gitignore. Behaviour is unchanged. Kept for one release: - A top-level application package whose meta-path finder resolves application.x.y to the already-imported docsgpt.x.y object, so old imports and entry points (celery -A application.app.celery, uvicorn application.asgi:asgi_app) keep working with a FutureWarning. - Celery registers every application.* task name as an alias of its docsgpt.* task on start-up, so messages queued by the previous release still run. The redbeat key prefix moves to redbeat:docsgpt:v2: so schedule entries the previous release wrote are left unread instead of firing twice. The backend image builds from the repository root (docker build -f docsgpt/Dockerfile .) so it can ship the alias package; a root .dockerignore allow-lists docsgpt/ and application/ and keeps caches, local data, .env files, the sample index files and the Dockerfile out. Compose and the image workflows point at the new context.
213 lines
5.3 KiB
Python
213 lines
5.3 KiB
Python
"""Tests for docsgpt.devices.denylist."""
|
|
|
|
from docsgpt.devices.denylist import check_denylist
|
|
|
|
|
|
def test_rm_rf_slash():
|
|
assert check_denylist("rm -rf /") == "rm -rf /"
|
|
|
|
|
|
def test_rm_rf_short_flag_order():
|
|
assert check_denylist("rm -fr /") == "rm -rf /"
|
|
|
|
|
|
def test_rm_rf_slash_star():
|
|
assert check_denylist("rm -rf /*") == "rm -rf /"
|
|
|
|
|
|
def test_rm_rf_long_flags():
|
|
assert check_denylist("rm --recursive --force /") == "rm -rf /"
|
|
|
|
|
|
def test_rm_rf_no_preserve_root():
|
|
assert check_denylist("rm -rf --no-preserve-root /") == "rm -rf /"
|
|
|
|
|
|
def test_rm_rf_no_preserve_root_before_flags():
|
|
assert check_denylist("rm --no-preserve-root -rf /") == "rm -rf /"
|
|
|
|
|
|
def test_rm_rf_no_preserve_root_slash_star():
|
|
assert check_denylist("rm -rf --no-preserve-root /*") == "rm -rf /"
|
|
|
|
|
|
def test_rm_rf_long_flags_with_no_preserve_root():
|
|
assert (
|
|
check_denylist("rm --recursive --no-preserve-root --force /")
|
|
== "rm -rf /"
|
|
)
|
|
|
|
|
|
def test_rm_separated_flags_r_then_f():
|
|
# ``rm -r -f /`` (flags as separate tokens) must still trip.
|
|
assert check_denylist("rm -r -f /") == "rm -rf /"
|
|
|
|
|
|
def test_rm_separated_flags_f_then_r():
|
|
assert check_denylist("rm -f -r /") == "rm -rf /"
|
|
|
|
|
|
def test_rm_rfv_bundle_root():
|
|
assert check_denylist("rm -rfv /") == "rm -rf /"
|
|
|
|
|
|
def test_rm_short_recursive_long_force():
|
|
assert check_denylist("rm -r --force /") == "rm -rf /"
|
|
|
|
|
|
def test_rm_long_recursive_short_force_slash_star():
|
|
assert check_denylist("rm --recursive -f /*") == "rm -rf /"
|
|
|
|
|
|
def test_rm_rf_tmp_subpath_safe():
|
|
assert check_denylist("rm -rf /tmp/foo") is None
|
|
|
|
|
|
def test_rm_rf_relative_build_safe():
|
|
assert check_denylist("rm -rf ./build") is None
|
|
|
|
|
|
def test_rm_rf_home_subpath_safe():
|
|
assert check_denylist("rm -rf /home/x") is None
|
|
|
|
|
|
def test_rm_recursive_only_safe():
|
|
# Recursive without force isn't the catastrophic root-wipe form.
|
|
assert check_denylist("rm -r /tmp") is None
|
|
|
|
|
|
def test_rm_force_only_slash_safe():
|
|
# Force without recursive (``rm -f /``) fails on a non-empty dir; not denied.
|
|
assert check_denylist("rm -f /") is None
|
|
|
|
|
|
def test_rm_force_only_etc_safe():
|
|
# Force without recursive on a real path is not the root-wipe form.
|
|
assert check_denylist("rm -f /etc/hosts") is None
|
|
|
|
|
|
def test_rm_separated_flags_subpath_safe():
|
|
# Separated recursive+force on a subpath stays safe.
|
|
assert check_denylist("rm -r -f /tmp/x") is None
|
|
|
|
|
|
def test_rm_wrapped_timeout_separated_flags():
|
|
# ``timeout 5 rm -r -f /`` — wrapper + separated flags must still trip.
|
|
assert check_denylist("timeout 5 rm -r -f /") == "rm -rf /"
|
|
|
|
|
|
def test_rm_wrapped_nice_separated_flags():
|
|
assert check_denylist("nice rm -f -r /") == "rm -rf /"
|
|
|
|
|
|
def test_rm_wrapped_nohup_bundle():
|
|
assert check_denylist("nohup rm -rf /") == "rm -rf /"
|
|
|
|
|
|
def test_rm_wrapped_timeout_duration_slash_star():
|
|
# ``timeout 30s rm -rf /*`` — duration token skipped, root-star target.
|
|
assert check_denylist("timeout 30s rm -rf /*") == "rm -rf /"
|
|
|
|
|
|
def test_wrapped_safe_ls_not_denied():
|
|
# ``timeout 5 ls`` is harmless even though it's wrapped.
|
|
assert check_denylist("timeout 5 ls") is None
|
|
|
|
|
|
def test_wrapped_rm_subpath_safe():
|
|
# ``nice rm -rf /tmp/foo`` is a subpath wipe; stays safe.
|
|
assert check_denylist("nice rm -rf /tmp/foo") is None
|
|
|
|
|
|
def test_rm_rf_home_tilde():
|
|
assert check_denylist("rm -rf ~") == "rm -rf ~"
|
|
|
|
|
|
def test_rm_rf_home_var():
|
|
assert check_denylist("rm -rf $HOME") == "rm -rf $HOME"
|
|
|
|
|
|
def test_fork_bomb():
|
|
assert check_denylist(":(){:|:&};:") == "fork bomb"
|
|
|
|
|
|
def test_fork_bomb_with_spaces():
|
|
assert check_denylist(":(){ :|:& };:") == "fork bomb"
|
|
|
|
|
|
def test_dd_to_block_device():
|
|
assert (
|
|
check_denylist("dd if=/dev/zero of=/dev/sda")
|
|
== "dd to block device"
|
|
)
|
|
|
|
|
|
def test_dd_with_random_to_nvme():
|
|
assert (
|
|
check_denylist("dd if=/dev/random of=/dev/nvme0n1")
|
|
== "dd to block device"
|
|
)
|
|
|
|
|
|
def test_mkfs():
|
|
assert check_denylist("mkfs.ext4 /dev/sda1") == "mkfs"
|
|
|
|
|
|
def test_mkfs_bare():
|
|
assert check_denylist("mkfs /dev/sda1") == "mkfs"
|
|
|
|
|
|
def test_shutdown():
|
|
assert check_denylist("shutdown -h now") == "shutdown"
|
|
|
|
|
|
def test_halt():
|
|
assert check_denylist("halt") == "halt"
|
|
|
|
|
|
def test_poweroff():
|
|
assert check_denylist("poweroff") == "poweroff"
|
|
|
|
|
|
def test_init_0():
|
|
assert check_denylist("init 0") == "init 0/6"
|
|
|
|
|
|
def test_init_6():
|
|
assert check_denylist("init 6") == "init 0/6"
|
|
|
|
|
|
def test_init_other_levels_safe():
|
|
# ``init 3`` shouldn't trigger.
|
|
assert check_denylist("init 3") is None
|
|
|
|
|
|
def test_git_push_force_long():
|
|
assert check_denylist("git push --force origin main") == "git push --force"
|
|
|
|
|
|
def test_git_push_force_with_lease_safe():
|
|
# --force-with-lease is allowed.
|
|
assert check_denylist("git push --force-with-lease origin main") is None
|
|
|
|
|
|
def test_git_push_short_flag():
|
|
assert check_denylist("git push -f origin main") == "git push --force"
|
|
|
|
|
|
def test_git_push_mirror():
|
|
assert check_denylist("git push --mirror origin") == "git push --force"
|
|
|
|
|
|
def test_safe_command_no_match():
|
|
assert check_denylist("ls -la /tmp") is None
|
|
|
|
|
|
def test_compound_with_dangerous_segment():
|
|
# ``echo safe && rm -rf /`` must still trip.
|
|
assert check_denylist("echo safe && rm -rf /") == "rm -rf /"
|
|
|
|
|
|
def test_empty_command():
|
|
assert check_denylist("") is None
|