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/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,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ seizu = seizu_cli.main:app
@@ -0,0 +1,2 @@
1
+ seizu_cli
2
+ seizu_schema
@@ -0,0 +1 @@
1
+ """seizu_schema — shared Pydantic models for the Seizu reporting YAML config format."""