seizu-cli 2.0.0__py3-none-any.whl
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.
- seizu_cli/__init__.py +0 -0
- seizu_cli/__main__.py +4 -0
- seizu_cli/auth.py +365 -0
- seizu_cli/client.py +62 -0
- seizu_cli/commands/__init__.py +0 -0
- seizu_cli/commands/auth.py +84 -0
- seizu_cli/commands/reports.py +223 -0
- seizu_cli/commands/scheduled_queries.py +157 -0
- seizu_cli/commands/seed.py +852 -0
- seizu_cli/commands/skillsets.py +371 -0
- seizu_cli/commands/toolsets.py +506 -0
- seizu_cli/config.py +38 -0
- seizu_cli/main.py +181 -0
- seizu_cli/schema.py +31 -0
- seizu_cli/state.py +29 -0
- seizu_cli-2.0.0.dist-info/METADATA +13 -0
- seizu_cli-2.0.0.dist-info/RECORD +22 -0
- seizu_cli-2.0.0.dist-info/WHEEL +5 -0
- seizu_cli-2.0.0.dist-info/entry_points.txt +2 -0
- seizu_cli-2.0.0.dist-info/top_level.txt +2 -0
- seizu_schema/__init__.py +1 -0
- seizu_schema/reporting_config.py +939 -0
seizu_cli/main.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""Seizu CLI entry point."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from seizu_cli import auth, state
|
|
8
|
+
from seizu_cli import config as cli_config
|
|
9
|
+
from seizu_cli.commands import auth as auth_commands
|
|
10
|
+
from seizu_cli.commands import reports, scheduled_queries, seed, skillsets, toolsets
|
|
11
|
+
|
|
12
|
+
app = typer.Typer(
|
|
13
|
+
help="Seizu CLI — manage reports, scheduled queries, and toolsets via the Seizu API.",
|
|
14
|
+
no_args_is_help=True,
|
|
15
|
+
)
|
|
16
|
+
app.add_typer(reports.app, name="reports")
|
|
17
|
+
app.add_typer(scheduled_queries.app, name="scheduled-queries")
|
|
18
|
+
app.add_typer(toolsets.app, name="toolsets")
|
|
19
|
+
app.add_typer(skillsets.app, name="skillsets")
|
|
20
|
+
app.add_typer(auth_commands.app, name="auth")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@app.callback()
|
|
24
|
+
def main(
|
|
25
|
+
api_url: str | None = typer.Option(
|
|
26
|
+
None,
|
|
27
|
+
envvar="SEIZU_API_URL",
|
|
28
|
+
help=("Seizu API base URL. Overrides the 'api_url' setting in ~/.config/seizu/seizu.conf."),
|
|
29
|
+
),
|
|
30
|
+
token: str | None = typer.Option(
|
|
31
|
+
None,
|
|
32
|
+
envvar="SEIZU_TOKEN",
|
|
33
|
+
help=("Bearer token for API authentication. If omitted, a stored token from 'seizu login' is used."),
|
|
34
|
+
),
|
|
35
|
+
credentials_file: Path | None = typer.Option(
|
|
36
|
+
None,
|
|
37
|
+
envvar="SEIZU_CREDENTIALS_FILE",
|
|
38
|
+
help=("Path to a JSON credentials file. Forces file-based token storage even if an OS keyring is available."),
|
|
39
|
+
),
|
|
40
|
+
config_file: Path | None = typer.Option(
|
|
41
|
+
None,
|
|
42
|
+
"--config-file",
|
|
43
|
+
envvar="SEIZU_CONFIG_FILE",
|
|
44
|
+
help=("Path to the CLI config file. Defaults to ~/.config/seizu/seizu.conf."),
|
|
45
|
+
),
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Seizu CLI — manage reports, scheduled queries, and toolsets via the Seizu API.
|
|
48
|
+
|
|
49
|
+
Configuration is read from ~/.config/seizu/seizu.conf (YAML).
|
|
50
|
+
CLI flags and environment variables take precedence over config-file values.
|
|
51
|
+
|
|
52
|
+
\b
|
|
53
|
+
Example ~/.config/seizu/seizu.conf:
|
|
54
|
+
api_url: https://seizu.example.com
|
|
55
|
+
seed_file: ~/dashboards/reporting.yaml
|
|
56
|
+
|
|
57
|
+
Authentication is handled via the Device Authorization Grant flow.
|
|
58
|
+
Run 'seizu login' once; credentials are stored in the OS-native keyring
|
|
59
|
+
and loaded automatically on every subsequent command.
|
|
60
|
+
|
|
61
|
+
\b
|
|
62
|
+
Quick start:
|
|
63
|
+
seizu login # authenticate (opens browser URL)
|
|
64
|
+
seizu reports list # list reports
|
|
65
|
+
seizu reports clone <id> <name> # clone a report
|
|
66
|
+
seizu scheduled-queries list # list scheduled queries
|
|
67
|
+
seizu toolsets list # list toolsets
|
|
68
|
+
seizu toolsets tools list <toolset_id>
|
|
69
|
+
seizu toolsets tools call <toolset_id> <tool_id> --arg limit=10
|
|
70
|
+
|
|
71
|
+
\b
|
|
72
|
+
To use a different deployment:
|
|
73
|
+
seizu --api-url https://seizu.example.com login
|
|
74
|
+
seizu --api-url https://seizu.example.com reports list
|
|
75
|
+
|
|
76
|
+
\b
|
|
77
|
+
To generate client libraries in other languages from the OpenAPI spec:
|
|
78
|
+
make generate_openapi # exports schema/openapi.json
|
|
79
|
+
make generate_client LANG=go # generates a Go client
|
|
80
|
+
make generate_client LANG=typescript-fetch
|
|
81
|
+
make generate_client LANG=java
|
|
82
|
+
|
|
83
|
+
See https://openapi-generator.tech/docs/generators for all supported languages.
|
|
84
|
+
"""
|
|
85
|
+
cfg = cli_config.load_config(config_file)
|
|
86
|
+
|
|
87
|
+
# Resolution order: CLI flag → env var → config file → built-in default
|
|
88
|
+
resolved_api_url = api_url or cfg.api_url or "http://localhost:8080"
|
|
89
|
+
|
|
90
|
+
state.api_url = resolved_api_url
|
|
91
|
+
state.credentials_file = credentials_file
|
|
92
|
+
state.seed_file = cfg.seed_file
|
|
93
|
+
|
|
94
|
+
if token:
|
|
95
|
+
# Explicit --token / SEIZU_TOKEN takes precedence over stored credentials.
|
|
96
|
+
state.token = token
|
|
97
|
+
else:
|
|
98
|
+
# Fall back to stored credentials for this API URL.
|
|
99
|
+
state.token = auth.load_token(resolved_api_url, credentials_file)
|
|
100
|
+
|
|
101
|
+
state.reset_client()
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@app.command("login")
|
|
105
|
+
def login_cmd() -> None:
|
|
106
|
+
"""Authenticate via the Device Authorization Grant (RFC 8628).
|
|
107
|
+
|
|
108
|
+
Fetches the OIDC configuration from the API, then starts a Device
|
|
109
|
+
Authorization flow. A URL and short code are displayed; open the URL
|
|
110
|
+
in your browser, enter the code, and the CLI will receive an access
|
|
111
|
+
token automatically.
|
|
112
|
+
|
|
113
|
+
The token is stored in the OS-native keyring and loaded automatically on
|
|
114
|
+
subsequent commands. Pass --credentials-file PATH to store in a plain JSON
|
|
115
|
+
file instead.
|
|
116
|
+
|
|
117
|
+
\b
|
|
118
|
+
Example:
|
|
119
|
+
seizu login
|
|
120
|
+
seizu --api-url https://seizu.example.com login
|
|
121
|
+
seizu --credentials-file ~/seizu-creds.json login
|
|
122
|
+
"""
|
|
123
|
+
auth_commands.login()
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@app.command("logout")
|
|
127
|
+
def logout_cmd() -> None:
|
|
128
|
+
"""Remove stored credentials for the current API URL."""
|
|
129
|
+
auth_commands.logout()
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@app.command("whoami")
|
|
133
|
+
def whoami_cmd() -> None:
|
|
134
|
+
"""Show the currently authenticated user."""
|
|
135
|
+
auth_commands.whoami()
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@app.command("seed")
|
|
139
|
+
def seed_cmd(
|
|
140
|
+
config: str | None = typer.Option(
|
|
141
|
+
None,
|
|
142
|
+
envvar="REPORTING_CONFIG_FILE",
|
|
143
|
+
help=(
|
|
144
|
+
"Path to the YAML dashboard config file. "
|
|
145
|
+
"Defaults to 'seed_file' in ~/.config/seizu/seizu.conf, "
|
|
146
|
+
"then ~/.config/seizu/reporting-dashboard.yaml."
|
|
147
|
+
),
|
|
148
|
+
),
|
|
149
|
+
force: bool = typer.Option(
|
|
150
|
+
False,
|
|
151
|
+
help="Update existing records even if their content is unchanged.",
|
|
152
|
+
),
|
|
153
|
+
dry_run: bool = typer.Option(
|
|
154
|
+
False,
|
|
155
|
+
help="Preview what would be created or updated without writing anything.",
|
|
156
|
+
),
|
|
157
|
+
) -> None:
|
|
158
|
+
"""Seed reports and scheduled queries from a YAML config file via the API."""
|
|
159
|
+
resolved_config = config or state.seed_file or cli_config.default_seed_file()
|
|
160
|
+
seed.seed_cmd(config=resolved_config, force=force, dry_run=dry_run)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
@app.command("export")
|
|
164
|
+
def export_cmd(
|
|
165
|
+
config: str | None = typer.Option(
|
|
166
|
+
None,
|
|
167
|
+
envvar="REPORTING_CONFIG_FILE",
|
|
168
|
+
help=(
|
|
169
|
+
"Path to the YAML dashboard config file. "
|
|
170
|
+
"Defaults to 'seed_file' in ~/.config/seizu/seizu.conf, "
|
|
171
|
+
"then ~/.config/seizu/reporting-dashboard.yaml."
|
|
172
|
+
),
|
|
173
|
+
),
|
|
174
|
+
dry_run: bool = typer.Option(
|
|
175
|
+
False,
|
|
176
|
+
help="Print the resulting YAML without overwriting the config file.",
|
|
177
|
+
),
|
|
178
|
+
) -> None:
|
|
179
|
+
"""Export the latest version of every report from the API back into a YAML config file."""
|
|
180
|
+
resolved_config = config or state.seed_file or cli_config.default_seed_file()
|
|
181
|
+
seed.export_cmd(config=resolved_config, dry_run=dry_run)
|
seizu_cli/schema.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Re-exports from ``seizu_schema.reporting_config``.
|
|
2
|
+
|
|
3
|
+
The authoritative model definitions live in the shared ``seizu_schema``
|
|
4
|
+
package. This module re-exports everything so that existing imports within
|
|
5
|
+
``seizu_cli`` continue to work unchanged.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from seizu_schema.reporting_config import (
|
|
9
|
+
BarPanelSettings, # noqa: F401
|
|
10
|
+
GraphPanelSettings, # noqa: F401
|
|
11
|
+
Input, # noqa: F401
|
|
12
|
+
InputDefault, # noqa: F401
|
|
13
|
+
Panel, # noqa: F401
|
|
14
|
+
PanelParam, # noqa: F401
|
|
15
|
+
PiePanelSettings, # noqa: F401
|
|
16
|
+
Report, # noqa: F401
|
|
17
|
+
ReportingConfig, # noqa: F401
|
|
18
|
+
Row, # noqa: F401
|
|
19
|
+
ScheduledQuery, # noqa: F401
|
|
20
|
+
ScheduledQueryAction, # noqa: F401
|
|
21
|
+
ScheduledQueryParam, # noqa: F401
|
|
22
|
+
ScheduledQueryWatchScan, # noqa: F401
|
|
23
|
+
SkillDef, # noqa: F401
|
|
24
|
+
SkillsetDef, # noqa: F401
|
|
25
|
+
ToolDef, # noqa: F401
|
|
26
|
+
ToolParamDef, # noqa: F401
|
|
27
|
+
ToolsetDef, # noqa: F401
|
|
28
|
+
dump_yaml, # noqa: F401
|
|
29
|
+
load_file, # noqa: F401
|
|
30
|
+
output_json_schema, # noqa: F401
|
|
31
|
+
)
|
seizu_cli/state.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Global CLI state shared between the callback and command handlers."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import TYPE_CHECKING, Optional
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from seizu_cli.client import SeizuClient
|
|
8
|
+
|
|
9
|
+
api_url: str = "http://localhost:8080"
|
|
10
|
+
token: str | None = None
|
|
11
|
+
credentials_file: Path | None = None
|
|
12
|
+
seed_file: str | None = None
|
|
13
|
+
_client: Optional["SeizuClient"] = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_client() -> "SeizuClient":
|
|
17
|
+
"""Return the shared API client, creating it lazily on first call."""
|
|
18
|
+
from seizu_cli.client import SeizuClient
|
|
19
|
+
|
|
20
|
+
global _client
|
|
21
|
+
if _client is None:
|
|
22
|
+
_client = SeizuClient(api_url, token)
|
|
23
|
+
return _client
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def reset_client() -> None:
|
|
27
|
+
"""Drop the cached client so the next call to get_client() creates a fresh one."""
|
|
28
|
+
global _client
|
|
29
|
+
_client = None
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: seizu-cli
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Command-line interface for the Seizu reporting platform
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Requires-Python: >=3.12
|
|
7
|
+
Requires-Dist: keyring>=25.0.0
|
|
8
|
+
Requires-Dist: pydantic>=2.13.0
|
|
9
|
+
Requires-Dist: pyyaml>=6.0.0
|
|
10
|
+
Requires-Dist: requests>=2.33.0
|
|
11
|
+
Requires-Dist: rich>=15.0.0
|
|
12
|
+
Requires-Dist: shellingham>=1.5.0
|
|
13
|
+
Requires-Dist: typer>=0.25.0
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
seizu_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
seizu_cli/__main__.py,sha256=T9XdZWrZhGHwRh9xNJoSXve3_AniZiLC2NjHPLf6too,69
|
|
3
|
+
seizu_cli/auth.py,sha256=6cHrMQWQCOJQpF5Onnrilde4surP2wCthzaChiJrV4A,12829
|
|
4
|
+
seizu_cli/client.py,sha256=93hElrHvhECsPbvptlwwLLwdoyqMxuD85bPws7-f77Y,2169
|
|
5
|
+
seizu_cli/config.py,sha256=YpAhQkfV2OvrFIV43PUtgsfooC_CTnVR6p8snltvjhY,1143
|
|
6
|
+
seizu_cli/main.py,sha256=EgEuQbb1K0bPET_8iWX_krRfFVk54bBTJnmaqP4ysXc,6344
|
|
7
|
+
seizu_cli/schema.py,sha256=T2gdaBQSo_Cyb6rzEWhVE-UfbgDfaNIZcHBAs4DE8Bw,1002
|
|
8
|
+
seizu_cli/state.py,sha256=E3RFfiYVxpOLCfmS6DMZWVHhhoz_JyeRKg2nws16PXo,797
|
|
9
|
+
seizu_cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
seizu_cli/commands/auth.py,sha256=7mm2QjRU94UTcMXC-Ek_p_39DZ2tKCSWTeAyvOAOGmk,2506
|
|
11
|
+
seizu_cli/commands/reports.py,sha256=3e_vq3ue9Va28peiyhTjn9PPMAsty8-GaxaA_q5Tr-g,6864
|
|
12
|
+
seizu_cli/commands/scheduled_queries.py,sha256=Mf4w8WGX2njHoFAnl4OzlOA6MzpYYp42YRJtQqonBjQ,4974
|
|
13
|
+
seizu_cli/commands/seed.py,sha256=UdIQqnJS-Leg8l1yHFzWLw3c76TxisWhSSyIXpB2lN8,31875
|
|
14
|
+
seizu_cli/commands/skillsets.py,sha256=Wm3rb8xG46pSmj98TfqrkJd2uw6tcSli_-h4yACrSxc,13878
|
|
15
|
+
seizu_cli/commands/toolsets.py,sha256=J229Ql5zfoYQC3ZSAlOrFnONJa4Ks-VjM3tFTtL9-UE,17052
|
|
16
|
+
seizu_schema/__init__.py,sha256=fcClhxPFoodNdqaJA7tR9YwPuxYz-EKEWntmFnmizek,90
|
|
17
|
+
seizu_schema/reporting_config.py,sha256=ZEggz6LZUtbW3EwUOylBj9JAvUF_enfvLD03YyEp9OY,26828
|
|
18
|
+
seizu_cli-2.0.0.dist-info/METADATA,sha256=bQSaeCF83LGgTNiFyrOujTlnTP9gHsrLKVdlw-0Y7GU,388
|
|
19
|
+
seizu_cli-2.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
20
|
+
seizu_cli-2.0.0.dist-info/entry_points.txt,sha256=gcy52hJBVowGqvk2E5LPlba2DWhNQRpBb94jZdcHs6s,45
|
|
21
|
+
seizu_cli-2.0.0.dist-info/top_level.txt,sha256=gopt93v86vi8YhhlRs3kAYGksSBpIOX7eYplQWvTMbk,23
|
|
22
|
+
seizu_cli-2.0.0.dist-info/RECORD,,
|
seizu_schema/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""seizu_schema — shared Pydantic models for the Seizu reporting YAML config format."""
|