bevor-cli 0.1.0__tar.gz → 0.1.1__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.
- bevor_cli-0.1.1/PKG-INFO +130 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/main.py +31 -1
- bevor_cli-0.1.1/bevor_cli/callbacks/notify.py +26 -0
- bevor_cli-0.1.1/bevor_cli/callbacks/upgrade.py +23 -0
- bevor_cli-0.1.1/bevor_cli/callbacks/version.py +25 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/retry.py +2 -2
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/run.py +2 -2
- bevor_cli-0.1.1/bevor_cli/commands/workspaces/__init__.py +0 -0
- bevor_cli-0.1.1/bevor_cli/configuration/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/configuration/creds.py +4 -2
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/configuration/state.py +2 -1
- bevor_cli-0.1.1/bevor_cli/configuration/update.py +50 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/main.py +19 -3
- bevor_cli-0.1.1/bevor_cli/settings.py +4 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/pyproject.toml +4 -2
- bevor_cli-0.1.0/PKG-INFO +0 -14
- bevor_cli-0.1.0/bevor_cli/settings.py +0 -4
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/.gitignore +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/README.md +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/annotations/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/annotations/confirmations.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/annotations/query.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/agent.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/analyses.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/chat.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/codes.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/findings.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/nodes.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/projects.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/sessions.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/workspaces.py +0 -0
- {bevor_cli-0.1.0/bevor_cli/commands → bevor_cli-0.1.1/bevor_cli/callbacks}/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/client.py +0 -0
- {bevor_cli-0.1.0/bevor_cli/commands/agent → bevor_cli-0.1.1/bevor_cli/commands}/__init__.py +0 -0
- {bevor_cli-0.1.0/bevor_cli/commands/analyses → bevor_cli-0.1.1/bevor_cli/commands/agent}/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/agent/materialze_cmd.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/agent/setup_cmd.py +0 -0
- {bevor_cli-0.1.0/bevor_cli/commands/analyses/chats → bevor_cli-0.1.1/bevor_cli/commands/analyses}/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/active.py +0 -0
- {bevor_cli-0.1.0/bevor_cli/commands/codes → bevor_cli-0.1.1/bevor_cli/commands/analyses/chats}/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/chats/get.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/chats/list.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/chats/messages.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/chats/new.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/chats/resume.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/chats/session.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/child.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/commit.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/create.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/delete.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/diff.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/entrypoints.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/findings.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/fork.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/list.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/merge.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/select.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/set_head.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/transitions.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/view.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/auth/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/auth/login.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/auth/logout.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/auth/whoami.py +0 -0
- {bevor_cli-0.1.0/bevor_cli/commands/findings → bevor_cli-0.1.1/bevor_cli/commands/codes}/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/codes/list.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/codes/push.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/codes/select.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/codes/view.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/context/__init__.py +0 -0
- {bevor_cli-0.1.0/bevor_cli/commands/graph → bevor_cli-0.1.1/bevor_cli/commands/findings}/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/acknowledge.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/add.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/bulk.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/delete.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/edit.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/get.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/interactive.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/list.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/revert.py +0 -0
- {bevor_cli-0.1.0/bevor_cli/commands/nodes → bevor_cli-0.1.1/bevor_cli/commands/graph}/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/graph/call_chain.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/graph/edges.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/graph/interactive.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/graph/renderer.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/link/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/link/helpers.py +0 -0
- {bevor_cli-0.1.0/bevor_cli/commands/projects → bevor_cli-0.1.1/bevor_cli/commands/nodes}/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/nodes/get.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/nodes/list.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/nodes/source.py +0 -0
- {bevor_cli-0.1.0/bevor_cli/commands/sessions → bevor_cli-0.1.1/bevor_cli/commands/projects}/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/projects/create.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/projects/list.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/projects/select.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/projects/view.py +0 -0
- {bevor_cli-0.1.0/bevor_cli/commands/workspaces → bevor_cli-0.1.1/bevor_cli/commands/sessions}/__init__.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/sessions/list.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/sessions/revoke.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/workspaces/list.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/workspaces/pick.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/workspaces/select.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/workspaces/view.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/configuration/settings.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/findings_yaml.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/output.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/select.py +0 -0
- {bevor_cli-0.1.0 → bevor_cli-0.1.1}/cli-hierarchy.py +0 -0
bevor_cli-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: bevor-cli
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Bevor CLI tool for security analysis and graph inspection
|
|
5
|
+
Classifier: Development Status :: 3 - Alpha
|
|
6
|
+
Requires-Python: >=3.13
|
|
7
|
+
Requires-Dist: bevor-sdk==0.1.1
|
|
8
|
+
Requires-Dist: click~=8.1
|
|
9
|
+
Requires-Dist: httpx~=0.28
|
|
10
|
+
Requires-Dist: packaging~=26.2
|
|
11
|
+
Requires-Dist: pydantic~=2.12
|
|
12
|
+
Requires-Dist: pyyaml~=6.0
|
|
13
|
+
Requires-Dist: questionary~=2.0
|
|
14
|
+
Requires-Dist: rich~=15.0
|
|
15
|
+
Requires-Dist: typer~=0.26
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# Bevor CLI
|
|
19
|
+
|
|
20
|
+
The official command-line interface for [Bevor](https://bevor.io) — smart contract security analysis and code graph exploration.
|
|
21
|
+
|
|
22
|
+
Use `bevor` to upload Solidity codebases, run security analyses, explore the code graph interactively, and manage findings — all from your terminal.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
curl -LsSf https://bevor.io/install.sh | bash
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Setup
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
bevor login
|
|
38
|
+
bevor link
|
|
39
|
+
#
|
|
40
|
+
bevor codes push
|
|
41
|
+
bevor analyses create
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Contents
|
|
47
|
+
|
|
48
|
+
`[]` -> optional args.
|
|
49
|
+
`<>` -> required args.
|
|
50
|
+
|
|
51
|
+
Simplification: EVERYTHING operates on the currently configured analysis. Findings as well.
|
|
52
|
+
Simplifies the DX, and we can take the stance that it's a rare state to want to operate on OTHER things via the CLI.
|
|
53
|
+
"version" is a flag that can be passed, but it's intentionally hard to act on arbitrary versions, unless the head is moved or the flag is passed.
|
|
54
|
+
|
|
55
|
+
### Local Configuration
|
|
56
|
+
- workspace [id]
|
|
57
|
+
- project [id]
|
|
58
|
+
- code [id, fingerprint]
|
|
59
|
+
- analysis [id]
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
help
|
|
63
|
+
login
|
|
64
|
+
logout
|
|
65
|
+
whoami [--json]
|
|
66
|
+
link
|
|
67
|
+
context [--json]
|
|
68
|
+
sessions
|
|
69
|
+
sessions list
|
|
70
|
+
sessions revoke <token_id>
|
|
71
|
+
workspaces
|
|
72
|
+
workspaces list [--json]
|
|
73
|
+
workspaces view [workspace_id] [--json]
|
|
74
|
+
workspaces select [workspace_id]
|
|
75
|
+
projects
|
|
76
|
+
projects list [--json]
|
|
77
|
+
projects view [project_id] [--json]
|
|
78
|
+
projects select [project_id]
|
|
79
|
+
projects create [--name] [--description] [--kind] [--yes]
|
|
80
|
+
codes
|
|
81
|
+
codes list [--page] [--page-size] [--order] [--order-by] [--project] [--network] [--identifier] [--status] [--json]
|
|
82
|
+
codes view [code_id] [--json]
|
|
83
|
+
codes select [code_id]
|
|
84
|
+
codes push [--path] [--no-wait] [--yes]
|
|
85
|
+
codes nodes
|
|
86
|
+
codes nodes list [--code] [--entrypoints] [--file] [--no-deps] [--name] [--node-type] [--json]
|
|
87
|
+
codes nodes view <node_id> [--code] [--json]
|
|
88
|
+
codes nodes content <node_id> [--code]
|
|
89
|
+
codes nodes edges <node_id> [--code] [--direction] [--type] [--json]
|
|
90
|
+
codes nodes call-chain <node_id> [--code] [--json]
|
|
91
|
+
codes nodes interactive <node_id> [--code]
|
|
92
|
+
analyses
|
|
93
|
+
analyses list [--page] [--page-size] [--order] [--order-by] [--project] [--user] [--is-owner] [--json]
|
|
94
|
+
analyses view [analysis_id] [--version] [--json]
|
|
95
|
+
analyses select [analysis_id] [--page] [--page-size]
|
|
96
|
+
analyses recent [--json]
|
|
97
|
+
analyses create [--name] [--collision] [--yes] [--json] [--force]
|
|
98
|
+
analyses set-head <version_id>
|
|
99
|
+
analyses run [--version] [--no-wait] [--silent]
|
|
100
|
+
analyses retry [--version] [--no-wait] [--silent]
|
|
101
|
+
analyses diff [--version] [--staged] [--json]
|
|
102
|
+
analyses commit [--version]
|
|
103
|
+
analyses child [--version] [--collision]
|
|
104
|
+
analyses fork [--version]
|
|
105
|
+
analyses merge <from_analysis> [--to]
|
|
106
|
+
analyses findings [--version] [--interactive] [--json] [--sarif]
|
|
107
|
+
analyses entrypoints [--version] [--json]
|
|
108
|
+
analyses transitions [--page] [--page-size] [--order] [--order-by] [--reason] [--version] [--project-wide] [--json]
|
|
109
|
+
analyses delete
|
|
110
|
+
analyses delete full
|
|
111
|
+
analyses delete version [version]
|
|
112
|
+
findings
|
|
113
|
+
findings list [--page] [--page-size] [--order] [--order-by] [--project] [--self] [--user] [--code] [--analyses] [--type] [--level] [--acknowledged] [--operation] [--created-by-self] [--created-by] [--json]
|
|
114
|
+
findings view <finding_id> [--json]
|
|
115
|
+
findings add [--version] [--file] [--interactive] [--type] [--level] [--name] [--explanation] [--recommendation] [--poc] [--tool] [--node] [--location] [--uri] [--start-line] [--start-column] [--end-line] [--end-column] [--char-offset] [--char-length] [--byte-offset] [--byte-length] [--fqn]
|
|
116
|
+
findings bulk <source> [--version]
|
|
117
|
+
findings edit <finding_id> [--file]
|
|
118
|
+
findings delete <finding_id>
|
|
119
|
+
findings revert <finding_id>
|
|
120
|
+
findings acknowledge <finding_id>
|
|
121
|
+
agent
|
|
122
|
+
agent setup
|
|
123
|
+
agent materialize
|
|
124
|
+
chats
|
|
125
|
+
chats list --page --page-size --order --order-by --project [--json]
|
|
126
|
+
chats view <chat_id> [--json]
|
|
127
|
+
chats messages <chat_id> [--json]
|
|
128
|
+
chats new <mode>
|
|
129
|
+
chats resume <chat_id>
|
|
130
|
+
```
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
|
|
1
3
|
import typer
|
|
2
4
|
from bevor_cli import output
|
|
3
5
|
from bevor_cli.apps import (
|
|
@@ -10,6 +12,9 @@ from bevor_cli.apps import (
|
|
|
10
12
|
sessions,
|
|
11
13
|
workspaces,
|
|
12
14
|
)
|
|
15
|
+
from bevor_cli.callbacks.notify import _notify_if_outdated, _update_check_enabled
|
|
16
|
+
from bevor_cli.callbacks.upgrade import _upgrade_command
|
|
17
|
+
from bevor_cli.callbacks.version import _current_version, _latest_version, _version_callback
|
|
13
18
|
from bevor_cli.commands.auth import login, logout, whoami
|
|
14
19
|
from bevor_cli.commands.context import run_context
|
|
15
20
|
from bevor_cli.commands.link import run_link
|
|
@@ -26,13 +31,24 @@ app = typer.Typer(
|
|
|
26
31
|
|
|
27
32
|
@app.callback(invoke_without_command=True)
|
|
28
33
|
def _root(
|
|
34
|
+
ctx: typer.Context,
|
|
29
35
|
quiet: bool = typer.Option(
|
|
30
36
|
False,
|
|
31
37
|
"--quiet",
|
|
32
38
|
help="Suppress informational output; useful for scripting.",
|
|
33
|
-
|
|
39
|
+
),
|
|
40
|
+
version: bool = typer.Option(
|
|
41
|
+
False,
|
|
42
|
+
"--version",
|
|
43
|
+
"-v",
|
|
44
|
+
help="Show the CLI version and exit.",
|
|
45
|
+
callback=_version_callback,
|
|
46
|
+
is_eager=True,
|
|
34
47
|
),
|
|
35
48
|
) -> None:
|
|
49
|
+
if ctx.invoked_subcommand != "upgrade" and _update_check_enabled(quiet):
|
|
50
|
+
ctx.call_on_close(_notify_if_outdated)
|
|
51
|
+
|
|
36
52
|
output.set_quiet(quiet)
|
|
37
53
|
|
|
38
54
|
|
|
@@ -43,6 +59,20 @@ def help_command(ctx: typer.Context) -> None:
|
|
|
43
59
|
console.print(root_ctx.get_help())
|
|
44
60
|
|
|
45
61
|
|
|
62
|
+
@app.command("upgrade")
|
|
63
|
+
def upgrade() -> None:
|
|
64
|
+
"""Upgrade bevor-cli to the latest release."""
|
|
65
|
+
current = _current_version()
|
|
66
|
+
latest = _latest_version()
|
|
67
|
+
if current >= latest:
|
|
68
|
+
typer.echo(f"Already on the latest version ({current}).")
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
typer.echo(f"Upgrading {current} → {latest}")
|
|
72
|
+
result = subprocess.run(_upgrade_command())
|
|
73
|
+
raise typer.Exit(result.returncode)
|
|
74
|
+
|
|
75
|
+
|
|
46
76
|
app.command("login")(login)
|
|
47
77
|
app.command("logout")(logout)
|
|
48
78
|
app.command("whoami")(whoami)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
from bevor_cli.callbacks.version import _current_version
|
|
7
|
+
from bevor_cli.configuration.update import UpdateCheck
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _notify_if_outdated() -> None:
|
|
11
|
+
check = UpdateCheck.refresh()
|
|
12
|
+
if check and check.is_outdated:
|
|
13
|
+
typer.echo(
|
|
14
|
+
f"\nA new version of bevor-cli is available: {_current_version()} → {check.latest}\n"
|
|
15
|
+
"Run `bevor upgrade` to update.",
|
|
16
|
+
err=True,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _update_check_enabled(quiet: bool) -> bool:
|
|
21
|
+
return (
|
|
22
|
+
not quiet
|
|
23
|
+
and sys.stderr.isatty()
|
|
24
|
+
and not os.environ.get("CI")
|
|
25
|
+
and not os.environ.get("BEVOR_NO_UPDATE_CHECK")
|
|
26
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
PACKAGE = "bevor-cli"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _uv_tool_dir(uv: str) -> Path | None:
|
|
10
|
+
result = subprocess.run([uv, "tool", "dir"], capture_output=True, text=True)
|
|
11
|
+
if result.returncode != 0:
|
|
12
|
+
return None
|
|
13
|
+
return Path(result.stdout.strip()).resolve()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _upgrade_command() -> list[str]:
|
|
17
|
+
prefix = Path(sys.prefix).resolve()
|
|
18
|
+
uv = shutil.which("uv")
|
|
19
|
+
if uv:
|
|
20
|
+
tool_dir = _uv_tool_dir(uv)
|
|
21
|
+
if tool_dir and prefix.is_relative_to(tool_dir):
|
|
22
|
+
return [uv, "tool", "upgrade", PACKAGE]
|
|
23
|
+
return [sys.executable, "-m", "pip", "install", "--upgrade", PACKAGE]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import importlib.metadata
|
|
2
|
+
import json
|
|
3
|
+
import urllib.request
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from packaging.version import Version
|
|
7
|
+
|
|
8
|
+
PACKAGE = "bevor-cli"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _current_version() -> Version:
|
|
12
|
+
return Version(importlib.metadata.version(PACKAGE))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _latest_version(timeout: float = 5) -> Version:
|
|
16
|
+
url = f"https://pypi.org/pypi/{PACKAGE}/json"
|
|
17
|
+
with urllib.request.urlopen(url, timeout=timeout) as res:
|
|
18
|
+
return Version(json.load(res)["info"]["version"])
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _version_callback(value: bool) -> None:
|
|
22
|
+
if not value:
|
|
23
|
+
return
|
|
24
|
+
typer.echo(f"bevor-cli {_current_version()}")
|
|
25
|
+
raise typer.Exit()
|
|
@@ -59,13 +59,13 @@ def retry_analysis(
|
|
|
59
59
|
for event in run_result.stream_completion():
|
|
60
60
|
if event.id in ep_map:
|
|
61
61
|
short_id, name, _ = ep_map[event.id]
|
|
62
|
-
ep_map[event.id] = (short_id, name, event.status)
|
|
62
|
+
ep_map[event.id] = (short_id, name, event.payload.status)
|
|
63
63
|
render_status(ep_map)
|
|
64
64
|
else:
|
|
65
65
|
for event in run_result.stream_completion():
|
|
66
66
|
if event.id in ep_map:
|
|
67
67
|
short_id, name, _ = ep_map[event.id]
|
|
68
|
-
ep_map[event.id] = (short_id, name, event.status)
|
|
68
|
+
ep_map[event.id] = (short_id, name, event.payload.status)
|
|
69
69
|
|
|
70
70
|
n_failures = sum(1 if status == "failed" else 0 for _, _, status in ep_map.values())
|
|
71
71
|
if n_failures > 0:
|
|
@@ -69,13 +69,13 @@ def run_analysis(
|
|
|
69
69
|
for event in run_result.stream_completion():
|
|
70
70
|
if event.id in ep_map:
|
|
71
71
|
short_id, name, _ = ep_map[event.id]
|
|
72
|
-
ep_map[event.id] = (short_id, name, event.status)
|
|
72
|
+
ep_map[event.id] = (short_id, name, event.payload.status)
|
|
73
73
|
live.update(render_status(ep_map))
|
|
74
74
|
else:
|
|
75
75
|
for event in run_result.stream_completion():
|
|
76
76
|
if event.id in ep_map:
|
|
77
77
|
short_id, name, _ = ep_map[event.id]
|
|
78
|
-
ep_map[event.id] = (short_id, name, event.status)
|
|
78
|
+
ep_map[event.id] = (short_id, name, event.payload.status)
|
|
79
79
|
|
|
80
80
|
n_failures = sum(1 if status == "failed" else 0 for _, _, status in ep_map.values())
|
|
81
81
|
if n_failures > 0:
|
|
File without changes
|
|
File without changes
|
|
@@ -5,10 +5,12 @@ import json
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
7
|
import typer
|
|
8
|
-
from bevor_cli import output
|
|
9
8
|
from pydantic import BaseModel
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
from bevor_cli import output
|
|
11
|
+
|
|
12
|
+
BEVOR_DIR = Path.home() / ".bevor"
|
|
13
|
+
_CREDENTIALS_PATH = BEVOR_DIR / "credentials"
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
class Credentials(BaseModel):
|
|
@@ -5,12 +5,13 @@ from pathlib import Path
|
|
|
5
5
|
from typing import Optional
|
|
6
6
|
|
|
7
7
|
import typer
|
|
8
|
-
from bevor_cli import output
|
|
9
8
|
from bevor_sdk.types import ID
|
|
10
9
|
from bevor_sdk.types.responses.graph import CodeMappingSchema
|
|
11
10
|
from bevor_sdk.types.responses.security import AnalysisSchema
|
|
12
11
|
from pydantic import BaseModel
|
|
13
12
|
|
|
13
|
+
from bevor_cli import output
|
|
14
|
+
|
|
14
15
|
_CONFIG_DIR = ".bevor"
|
|
15
16
|
_CONFIG_FILE = "config.json"
|
|
16
17
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
|
|
3
|
+
from packaging.version import Version
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
from bevor_cli.callbacks.version import _current_version, _latest_version
|
|
7
|
+
|
|
8
|
+
from .creds import BEVOR_DIR
|
|
9
|
+
|
|
10
|
+
_UPDATE_CHECK_PATH = BEVOR_DIR / "update-check.json"
|
|
11
|
+
_UPDATE_CHECK_INTERVAL = datetime.timedelta(days=1)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class UpdateCheck(BaseModel):
|
|
15
|
+
latest: str
|
|
16
|
+
checked_at: datetime.datetime
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def is_stale(self) -> bool:
|
|
20
|
+
return datetime.datetime.now(datetime.UTC) - self.checked_at >= _UPDATE_CHECK_INTERVAL
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def is_outdated(self) -> bool:
|
|
24
|
+
return Version(self.latest) > _current_version()
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def load(cls) -> "UpdateCheck | None":
|
|
28
|
+
if not _UPDATE_CHECK_PATH.exists():
|
|
29
|
+
return None
|
|
30
|
+
try:
|
|
31
|
+
return cls.model_validate_json(_UPDATE_CHECK_PATH.read_text())
|
|
32
|
+
except Exception:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def save(cls, latest: Version) -> "UpdateCheck":
|
|
37
|
+
check = cls(latest=str(latest), checked_at=datetime.datetime.now(datetime.UTC))
|
|
38
|
+
_UPDATE_CHECK_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
39
|
+
_UPDATE_CHECK_PATH.write_text(check.model_dump_json(indent=2))
|
|
40
|
+
return check
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def refresh(cls) -> "UpdateCheck | None":
|
|
44
|
+
check = cls.load()
|
|
45
|
+
if check and not check.is_stale:
|
|
46
|
+
return check
|
|
47
|
+
try:
|
|
48
|
+
return cls.save(_latest_version(timeout=1))
|
|
49
|
+
except (OSError, ValueError):
|
|
50
|
+
return check
|
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
|
|
3
3
|
import typer
|
|
4
|
-
from bevor_sdk.exceptions import
|
|
4
|
+
from bevor_sdk.exceptions import (
|
|
5
|
+
BaseError,
|
|
6
|
+
InvalidScopeError,
|
|
7
|
+
SessionExpiredError,
|
|
8
|
+
UnauthenticatedError,
|
|
9
|
+
UnauthorizedError,
|
|
10
|
+
)
|
|
5
11
|
|
|
6
12
|
from bevor_cli import output
|
|
7
13
|
from bevor_cli.apps.main import app
|
|
14
|
+
from bevor_cli.configuration.creds import Credentials
|
|
8
15
|
|
|
9
16
|
|
|
10
17
|
def main() -> None:
|
|
11
18
|
try:
|
|
12
|
-
app(
|
|
19
|
+
app()
|
|
20
|
+
except UnauthenticatedError:
|
|
21
|
+
Credentials.delete()
|
|
22
|
+
output.error("Unauthenticated.", hint="Run `bevor login`.")
|
|
23
|
+
sys.exit(1)
|
|
13
24
|
except UnauthorizedError:
|
|
14
|
-
output.error("Unauthorized.", hint="Run `bevor
|
|
25
|
+
output.error("Unauthorized.", hint="Run `bevor link`.")
|
|
26
|
+
sys.exit(1)
|
|
27
|
+
except SessionExpiredError:
|
|
28
|
+
Credentials.delete()
|
|
29
|
+
output.error("Session Expired. Please re-authenticate", hint="Run `bevor login`.")
|
|
15
30
|
sys.exit(1)
|
|
16
31
|
except InvalidScopeError:
|
|
17
32
|
output.error("Unauthorized: configure a workspace and project.", hint="Run `bevor link`.")
|
|
@@ -25,6 +40,7 @@ def main() -> None:
|
|
|
25
40
|
except typer.Exit as e:
|
|
26
41
|
sys.exit(e.exit_code)
|
|
27
42
|
except Exception as e:
|
|
43
|
+
print(e, type(e))
|
|
28
44
|
output.error(f"Unexpected error: {e}")
|
|
29
45
|
sys.exit(1)
|
|
30
46
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "bevor-cli"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.1"
|
|
4
4
|
description = "Bevor CLI tool for security analysis and graph inspection"
|
|
5
5
|
requires-python = ">=3.13"
|
|
6
6
|
dependencies = [
|
|
7
|
-
"bevor-sdk==0.1.
|
|
7
|
+
"bevor-sdk==0.1.1",
|
|
8
8
|
"typer~=0.26",
|
|
9
9
|
"httpx~=0.28",
|
|
10
10
|
"pydantic~=2.12",
|
|
@@ -12,8 +12,10 @@ dependencies = [
|
|
|
12
12
|
"rich~=15.0",
|
|
13
13
|
"pyyaml~=6.0",
|
|
14
14
|
"click~=8.1",
|
|
15
|
+
"packaging~=26.2",
|
|
15
16
|
]
|
|
16
17
|
classifiers = ["Development Status :: 3 - Alpha"]
|
|
18
|
+
readme = "README.md"
|
|
17
19
|
|
|
18
20
|
[project.scripts]
|
|
19
21
|
bevor = "bevor_cli.main:main"
|
bevor_cli-0.1.0/PKG-INFO
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.5
|
|
2
|
-
Name: bevor-cli
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Bevor CLI tool for security analysis and graph inspection
|
|
5
|
-
Classifier: Development Status :: 3 - Alpha
|
|
6
|
-
Requires-Python: >=3.13
|
|
7
|
-
Requires-Dist: bevor-sdk==0.1.0
|
|
8
|
-
Requires-Dist: click~=8.1
|
|
9
|
-
Requires-Dist: httpx~=0.28
|
|
10
|
-
Requires-Dist: pydantic~=2.12
|
|
11
|
-
Requires-Dist: pyyaml~=6.0
|
|
12
|
-
Requires-Dist: questionary~=2.0
|
|
13
|
-
Requires-Dist: rich~=15.0
|
|
14
|
-
Requires-Dist: typer~=0.26
|
|
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
|
{bevor_cli-0.1.0/bevor_cli/commands/analyses → bevor_cli-0.1.1/bevor_cli/commands/agent}/__init__.py
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
|
{bevor_cli-0.1.0/bevor_cli/commands/findings → bevor_cli-0.1.1/bevor_cli/commands/codes}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bevor_cli-0.1.0/bevor_cli/commands/graph → bevor_cli-0.1.1/bevor_cli/commands/findings}/__init__.py
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
|
{bevor_cli-0.1.0/bevor_cli/commands/nodes → bevor_cli-0.1.1/bevor_cli/commands/graph}/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bevor_cli-0.1.0/bevor_cli/commands/projects → bevor_cli-0.1.1/bevor_cli/commands/nodes}/__init__.py
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
|