bash-classify 0.7.0__tar.gz → 0.8.0__tar.gz
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.
- {bash_classify-0.7.0 → bash_classify-0.8.0}/.claude-plugin/marketplace.json +1 -1
- {bash_classify-0.7.0 → bash_classify-0.8.0}/PKG-INFO +1 -1
- {bash_classify-0.7.0 → bash_classify-0.8.0}/SPEC.md +4 -2
- {bash_classify-0.7.0 → bash_classify-0.8.0}/coding-agent-plugins/claude-code/.claude-plugin/plugin.json +1 -1
- {bash_classify-0.7.0 → bash_classify-0.8.0}/schemas/command.schema.json +8 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/bash.yaml +2 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/sh.yaml +2 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/database.py +4 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/matcher.py +28 -8
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/models.py +2 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/tests/test_classifier.py +4 -2
- {bash_classify-0.7.0 → bash_classify-0.8.0}/tests/test_matcher.py +71 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/.claude/rules/command-database.md +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/.editorconfig +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/.github/workflows/ci.yml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/.github/workflows/publish.yml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/.gitignore +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/.python-version +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/CLAUDE.md +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/LICENSE +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/README.md +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/coding-agent-plugins/claude-code/hooks/hook-permission-request.sh +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/coding-agent-plugins/claude-code/hooks/hook-pre-tool-use.sh +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/coding-agent-plugins/claude-code/hooks/hooks.json +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/docs/classification-guidance.md +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/pyproject.toml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/ruff.toml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/__init__.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/__main__.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/classifier.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/cli.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/agent-browser.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/apt.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/awk.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/basename.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/bash-classify.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/black.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/brew.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/builtin.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/cargo.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/cat.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/chgrp.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/chmod.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/chown.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/column.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/comm.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/command.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/cp.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/curl.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/cut.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/date.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/df.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/diff.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/dig.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/dirname.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/docker.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/du.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/echo.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/env.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/eslint.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/expand.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/false.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/file.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/find.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/fmt.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/fold.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/free.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/gawk.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/gcloud.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/gh.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/git.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/glab-discussion.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/glab.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/go.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/gog.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/gradle.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/gradlew.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/grep.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/groups.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/gunzip.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/gws.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/gzip.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/hadolint.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/head.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/helm.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/hostname.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/id.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/install.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/isort.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/java.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/javac.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/join.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/journalctl.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/jq.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/kill.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/killall.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/kubectl.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/less.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/ln.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/ls.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/make.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/md5sum.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/mise.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/mkdir.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/more.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/mv.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/mvn.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/mvnw.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/mypy.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/netstat.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/nice.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/nl.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/node.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/nohup.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/npm.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/npx.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/nslookup.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/paste.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/ping.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/pip.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/pip3.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/pipx.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/pkill.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/pnpm.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/poetry.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/prettier.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/printenv.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/printf.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/ps.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/pup.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/pwd.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/pytest.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/python.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/python3.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/read.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/readlink.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/realpath.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/rev.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/rg.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/rm.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/rsync.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/ruff.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/scp.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/sed.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/seq.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/sha1sum.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/sha256sum.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/shellcheck.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/sort.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/ss.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/ssh.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/stat.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/strace.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/sudo.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/systemctl.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/tac.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/tail.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/tar.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/tee.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/terraform.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/test.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/time.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/timeout.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/top.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/touch.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/tr.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/traceroute.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/true.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/tsc.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/type.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/uname.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/unexpand.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/uniq.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/unzip.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/uptime.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/uv.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/wc.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/wget.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/whereis.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/which.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/whoami.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/xargs.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/xmllint.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/yarn.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/yes.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/yq.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/zip.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/commands/zsh.yaml +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/parser.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/src/bash_classify/py.typed +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/tests/__init__.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/tests/conftest.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/tests/test_cli.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/tests/test_cli_serialization.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/tests/test_database.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/tests/test_models.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/tests/test_parser.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/tests/test_real_world.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/tests/test_schema.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/tests/test_smoke.py +0 -0
- {bash_classify-0.7.0 → bash_classify-0.8.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bash-classify
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Classify bash commands as READONLY, WRITE, DANGEROUS, or UNKNOWN
|
|
5
5
|
Project-URL: Homepage, https://github.com/fprochazka/bash-classify
|
|
6
6
|
Project-URL: Repository, https://github.com/fprochazka/bash-classify
|
|
@@ -151,13 +151,13 @@ $ echo 'sh -c "ls /tmp | grep log"' | bash-classify
|
|
|
151
151
|
```json
|
|
152
152
|
{
|
|
153
153
|
"expression": "sh -c \"ls /tmp | grep log\"",
|
|
154
|
-
"classification": "
|
|
154
|
+
"classification": "READONLY",
|
|
155
155
|
"directories": ["/tmp"],
|
|
156
156
|
"commands": [
|
|
157
157
|
{
|
|
158
158
|
"command": ["sh"],
|
|
159
159
|
"argv": ["sh", "-c", "ls /tmp | grep log"],
|
|
160
|
-
"classification": "
|
|
160
|
+
"classification": "READONLY",
|
|
161
161
|
"matched_rule": "sh",
|
|
162
162
|
"inner_commands": [
|
|
163
163
|
{
|
|
@@ -850,6 +850,8 @@ The `delegates_to` field defines how a command (or option like `find -exec`) han
|
|
|
850
850
|
| `flag` | `string` | For `flag_value_is_expression`: which flag's value to parse |
|
|
851
851
|
| `strip_assignments` | `bool` | For `rest_are_argv`: strip leading `KEY=VALUE` tokens before the inner command |
|
|
852
852
|
| `min_classification` | `enum` | Floor classification for the inner command (e.g. `sudo` forces at least `EXTERNAL_EFFECTS`) |
|
|
853
|
+
| `delegated_classification` | `enum` | When delegation resolves at least one inner command, the wrapper's own classification drops to this value before inner-elevation is applied. Intended for pure delegation wrappers like `sh -c` / `bash -c` where the wrapper itself has no effect beyond the command it runs. Only applies when the current classification came from the command's own base (not from an option override or strict-mode escalation). |
|
|
854
|
+
| `delegated_risk` | `enum` | Optional companion to `delegated_classification` — the risk floor applied when delegation resolves. Defaults to the default risk for `delegated_classification`. |
|
|
853
855
|
|
|
854
856
|
### Database field reference
|
|
855
857
|
|
|
@@ -116,6 +116,14 @@
|
|
|
116
116
|
"min_classification": {
|
|
117
117
|
"$ref": "#/$defs/Classification",
|
|
118
118
|
"description": "Floor classification for the inner command"
|
|
119
|
+
},
|
|
120
|
+
"delegated_classification": {
|
|
121
|
+
"$ref": "#/$defs/Classification",
|
|
122
|
+
"description": "When delegation successfully resolves at least one inner command, the wrapper's own classification drops to this value before inner-elevation is applied. Use for pure delegation wrappers like sh/bash where the wrapper itself has no effect beyond the command it runs."
|
|
123
|
+
},
|
|
124
|
+
"delegated_risk": {
|
|
125
|
+
"$ref": "#/$defs/Risk",
|
|
126
|
+
"description": "Optional companion to delegated_classification — the risk floor applied when delegation resolves. Defaults to the default risk for delegated_classification."
|
|
119
127
|
}
|
|
120
128
|
}
|
|
121
129
|
},
|
|
@@ -289,6 +289,8 @@ def _parse_delegation_config(raw: dict | None) -> DelegationConfig | None:
|
|
|
289
289
|
|
|
290
290
|
mode = DelegationMode(raw["mode"])
|
|
291
291
|
min_class = _parse_classification(raw.get("min_classification"))
|
|
292
|
+
delegated_class = _parse_classification(raw.get("delegated_classification"))
|
|
293
|
+
delegated_risk = _parse_risk(raw.get("delegated_risk"))
|
|
292
294
|
|
|
293
295
|
return DelegationConfig(
|
|
294
296
|
mode=mode,
|
|
@@ -297,4 +299,6 @@ def _parse_delegation_config(raw: dict | None) -> DelegationConfig | None:
|
|
|
297
299
|
flag=raw.get("flag"),
|
|
298
300
|
strip_assignments=raw.get("strip_assignments", False),
|
|
299
301
|
min_classification=min_class,
|
|
302
|
+
delegated_classification=delegated_class,
|
|
303
|
+
delegated_risk=delegated_risk,
|
|
300
304
|
)
|
|
@@ -248,24 +248,44 @@ def match_command(
|
|
|
248
248
|
|
|
249
249
|
# Step 6: Handle delegation
|
|
250
250
|
inner_commands: list[InnerCommandResult] = []
|
|
251
|
+
command_level_inner_count = 0
|
|
251
252
|
|
|
252
253
|
# Command-level delegation
|
|
253
254
|
if matched_def.delegates_to is not None:
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
matched_def,
|
|
261
|
-
)
|
|
255
|
+
command_level_inner = _handle_delegation(
|
|
256
|
+
remaining_positional,
|
|
257
|
+
matched_def.delegates_to,
|
|
258
|
+
database,
|
|
259
|
+
argv,
|
|
260
|
+
matched_def,
|
|
262
261
|
)
|
|
262
|
+
command_level_inner_count = len(command_level_inner)
|
|
263
|
+
inner_commands.extend(command_level_inner)
|
|
263
264
|
|
|
264
265
|
# Option-level delegation (e.g., find -exec)
|
|
265
266
|
for opt_name, delegation_config, delegation_tokens in option_delegations:
|
|
266
267
|
inner_results = _handle_option_delegation(opt_name, delegation_config, delegation_tokens, database)
|
|
267
268
|
inner_commands.extend(inner_results)
|
|
268
269
|
|
|
270
|
+
# When command-level delegation actually produced inner commands, optionally
|
|
271
|
+
# drop the wrapper's own base classification to `delegated_classification`.
|
|
272
|
+
# This only applies when the current classification came from the command's
|
|
273
|
+
# own base (no option override and no strict-mode escalation) — otherwise
|
|
274
|
+
# we'd be erasing an intentional escalation.
|
|
275
|
+
if (
|
|
276
|
+
matched_def.delegates_to is not None
|
|
277
|
+
and matched_def.delegates_to.delegated_classification is not None
|
|
278
|
+
and command_level_inner_count > 0
|
|
279
|
+
and not all_overrides
|
|
280
|
+
and not (matched_def.strict and unknown_options)
|
|
281
|
+
):
|
|
282
|
+
final_classification = matched_def.delegates_to.delegated_classification
|
|
283
|
+
if matched_def.delegates_to.delegated_risk is not None:
|
|
284
|
+
final_risk = matched_def.delegates_to.delegated_risk
|
|
285
|
+
else:
|
|
286
|
+
final_risk = _default_risk(final_classification)
|
|
287
|
+
classification_reason = f"delegated to inner via {matched_rule}"
|
|
288
|
+
|
|
269
289
|
# Inner command classifications and risks affect the parent
|
|
270
290
|
for inner in inner_commands:
|
|
271
291
|
if inner.classification.severity() > final_classification.severity():
|
|
@@ -116,6 +116,8 @@ class DelegationConfig:
|
|
|
116
116
|
flag: str | None = None
|
|
117
117
|
strip_assignments: bool = False
|
|
118
118
|
min_classification: Classification | None = None
|
|
119
|
+
delegated_classification: Classification | None = None
|
|
120
|
+
delegated_risk: Risk | None = None
|
|
119
121
|
|
|
120
122
|
|
|
121
123
|
@dataclass
|
|
@@ -105,11 +105,13 @@ class TestSpecExamples:
|
|
|
105
105
|
'sh -c "ls /tmp | grep log"',
|
|
106
106
|
database=database,
|
|
107
107
|
)
|
|
108
|
-
|
|
108
|
+
# sh -c with only READONLY inner commands drops the DANGEROUS floor
|
|
109
|
+
# via delegated_classification and ends up READONLY.
|
|
110
|
+
assert result.classification == Classification.READONLY
|
|
109
111
|
|
|
110
112
|
sh_cmd = result.commands[0]
|
|
111
113
|
assert sh_cmd.matched_rule == "sh"
|
|
112
|
-
assert sh_cmd.classification == Classification.
|
|
114
|
+
assert sh_cmd.classification == Classification.READONLY
|
|
113
115
|
assert len(sh_cmd.inner_commands) >= 2
|
|
114
116
|
|
|
115
117
|
inner_cmds = {tuple(ic.command) for ic in sh_cmd.inner_commands}
|
|
@@ -553,6 +553,77 @@ class TestShFlagEqualsValue:
|
|
|
553
553
|
pytest.skip("sh -c=value form not supported — known limitation")
|
|
554
554
|
|
|
555
555
|
|
|
556
|
+
class TestDelegatedClassification:
|
|
557
|
+
"""Tests for `delegated_classification` on delegates_to — sh/bash -c drops floor."""
|
|
558
|
+
|
|
559
|
+
def test_sh_c_readonly_inner(self, database: dict[str, CommandDef]) -> None:
|
|
560
|
+
"""sh -c 'cat /tmp/x' -> READONLY/LOW (floor dropped, inner is READONLY)."""
|
|
561
|
+
result = match_command(_make_invocation(["sh", "-c", "cat /tmp/x"]), database)
|
|
562
|
+
assert result.classification == Classification.READONLY
|
|
563
|
+
assert result.risk == Risk.LOW
|
|
564
|
+
|
|
565
|
+
def test_bash_c_readonly_inner(self, database: dict[str, CommandDef]) -> None:
|
|
566
|
+
"""bash -c 'cat /tmp/x' -> READONLY/LOW (same behavior for bash)."""
|
|
567
|
+
result = match_command(_make_invocation(["bash", "-c", "cat /tmp/x"]), database)
|
|
568
|
+
assert result.classification == Classification.READONLY
|
|
569
|
+
assert result.risk == Risk.LOW
|
|
570
|
+
|
|
571
|
+
def test_sh_c_dangerous_inner_elevates(self, database: dict[str, CommandDef]) -> None:
|
|
572
|
+
"""sh -c 'rm -rf /' -> DANGEROUS (inner elevates past dropped floor)."""
|
|
573
|
+
result = match_command(_make_invocation(["sh", "-c", "rm -rf /"]), database)
|
|
574
|
+
assert result.classification == Classification.DANGEROUS
|
|
575
|
+
assert result.risk == Risk.HIGH
|
|
576
|
+
|
|
577
|
+
def test_sh_c_local_effects_inner(self, database: dict[str, CommandDef]) -> None:
|
|
578
|
+
"""sh -c 'git add .' -> LOCAL_EFFECTS (inner elevates from READONLY floor)."""
|
|
579
|
+
result = match_command(_make_invocation(["sh", "-c", "git add ."]), database)
|
|
580
|
+
assert result.classification == Classification.LOCAL_EFFECTS
|
|
581
|
+
# git add is LOCAL_EFFECTS/LOW in the database
|
|
582
|
+
assert result.risk == Risk.LOW
|
|
583
|
+
|
|
584
|
+
def test_sh_without_c_preserves_base(self, database: dict[str, CommandDef]) -> None:
|
|
585
|
+
"""sh alone (no -c) -> DANGEROUS/HIGH (no delegation fired, base preserved)."""
|
|
586
|
+
result = match_command(_make_invocation(["sh"]), database)
|
|
587
|
+
assert result.classification == Classification.DANGEROUS
|
|
588
|
+
assert result.risk == Risk.HIGH
|
|
589
|
+
|
|
590
|
+
def test_sh_c_empty_preserves_base(self, database: dict[str, CommandDef]) -> None:
|
|
591
|
+
"""sh -c '' -> DANGEROUS (empty expression produces no inner, base preserved)."""
|
|
592
|
+
result = match_command(_make_invocation(["sh", "-c", ""]), database)
|
|
593
|
+
assert result.classification == Classification.DANGEROUS
|
|
594
|
+
assert result.risk == Risk.HIGH
|
|
595
|
+
|
|
596
|
+
def test_sudo_cat_unchanged(self, database: dict[str, CommandDef]) -> None:
|
|
597
|
+
"""sudo cat x -> DANGEROUS (sudo.yaml untouched, regression test)."""
|
|
598
|
+
result = match_command(_make_invocation(["sudo", "cat", "/tmp/x"]), database)
|
|
599
|
+
assert result.classification == Classification.DANGEROUS
|
|
600
|
+
|
|
601
|
+
def test_sh_c_unknown_option_stays_dangerous(self, database: dict[str, CommandDef]) -> None:
|
|
602
|
+
"""sh -c 'cat x' --bogus -> strict-mode escalation should not be dropped.
|
|
603
|
+
|
|
604
|
+
sh.yaml has default strict=true; an unknown option should escalate to
|
|
605
|
+
UNKNOWN/HIGH. The delegated_classification drop must not undo that.
|
|
606
|
+
"""
|
|
607
|
+
result = match_command(_make_invocation(["sh", "--bogus", "-c", "cat /tmp/x"]), database)
|
|
608
|
+
# Inner is READONLY, but strict-mode unknown option should keep it non-READONLY.
|
|
609
|
+
assert result.classification != Classification.READONLY
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
class TestShXargsIntegration:
|
|
613
|
+
"""Integration: xargs sh -c 'cat x' should come out as READONLY/LOW.
|
|
614
|
+
|
|
615
|
+
This uses parse_expression to exercise the full pipeline including xargs's
|
|
616
|
+
rest_are_argv delegation wrapping sh's flag_value_is_expression delegation.
|
|
617
|
+
"""
|
|
618
|
+
|
|
619
|
+
def test_xargs_sh_c_readonly(self, database: dict[str, CommandDef]) -> None:
|
|
620
|
+
from bash_classify.classifier import classify_expression
|
|
621
|
+
|
|
622
|
+
result = classify_expression("xargs -I{} sh -c 'cat {}'")
|
|
623
|
+
assert result.classification == Classification.READONLY
|
|
624
|
+
assert result.risk == Risk.LOW
|
|
625
|
+
|
|
626
|
+
|
|
556
627
|
class TestGlobalOptionOverrides:
|
|
557
628
|
"""Global options with overrides should affect classification."""
|
|
558
629
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bash_classify-0.7.0 → bash_classify-0.8.0}/coding-agent-plugins/claude-code/hooks/hooks.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|