clickhouse-users-cli 0.1.2__tar.gz → 0.1.4__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.
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/PKG-INFO +2 -1
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/README.md +1 -0
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli/__init__.py +1 -1
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli/app.py +73 -11
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli/sql_builder.py +13 -0
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli.egg-info/PKG-INFO +2 -1
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/LICENSE +0 -0
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli/db.py +0 -0
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli/session.py +0 -0
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli/style.py +0 -0
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli/validators.py +0 -0
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli.egg-info/SOURCES.txt +0 -0
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli.egg-info/dependency_links.txt +0 -0
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli.egg-info/entry_points.txt +0 -0
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli.egg-info/requires.txt +0 -0
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli.egg-info/top_level.txt +0 -0
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/pyproject.toml +0 -0
- {clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clickhouse-users-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: CLI interativa para criar usuarios ClickHouse com privilegio minimo (least privilege)
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Keywords: clickhouse,cli,users,access-control,least-privilege
|
|
@@ -76,6 +76,7 @@ GRANT SHOW, SELECT ON `vendas`.`clientes` TO `analyst_julho`;
|
|
|
76
76
|
|
|
77
77
|
- **Listar** — `SHOW USERS` em tabela + opção de ver `SHOW CREATE USER` e `SHOW GRANTS FOR` de um usuário.
|
|
78
78
|
- **Gerenciar** — escolhe 1 usuário, vê status (`HOST NONE` = inativo) + grants, depois:
|
|
79
|
+
- **Editar permissões** → pergunta perfil (tipo de acesso) + bancos/tabelas e aplica `REVOKE ALL ON *.*` + novos `GRANTs` (com preview e confirmação);
|
|
79
80
|
- **Desativar** → `ALTER USER \`nome\` HOST NONE` (reversível, bloqueia login);
|
|
80
81
|
- **Reativar** → `ALTER USER \`nome\` HOST ANY`;
|
|
81
82
|
- **Excluir** → `DROP USER IF EXISTS \`nome\`` (definitivo).
|
|
@@ -52,6 +52,7 @@ GRANT SHOW, SELECT ON `vendas`.`clientes` TO `analyst_julho`;
|
|
|
52
52
|
|
|
53
53
|
- **Listar** — `SHOW USERS` em tabela + opção de ver `SHOW CREATE USER` e `SHOW GRANTS FOR` de um usuário.
|
|
54
54
|
- **Gerenciar** — escolhe 1 usuário, vê status (`HOST NONE` = inativo) + grants, depois:
|
|
55
|
+
- **Editar permissões** → pergunta perfil (tipo de acesso) + bancos/tabelas e aplica `REVOKE ALL ON *.*` + novos `GRANTs` (com preview e confirmação);
|
|
55
56
|
- **Desativar** → `ALTER USER \`nome\` HOST NONE` (reversível, bloqueia login);
|
|
56
57
|
- **Reativar** → `ALTER USER \`nome\` HOST ANY`;
|
|
57
58
|
- **Excluir** → `DROP USER IF EXISTS \`nome\`` (definitivo).
|
|
@@ -17,6 +17,7 @@ from clickhouse_users_cli.sql_builder import (
|
|
|
17
17
|
build_all_statements,
|
|
18
18
|
build_deactivate_user_sql,
|
|
19
19
|
build_drop_user_sql,
|
|
20
|
+
build_edit_grants_statements,
|
|
20
21
|
)
|
|
21
22
|
from clickhouse_users_cli.style import APP_STYLE, banner, console, error, info, make_table, step, success, warn
|
|
22
23
|
from clickhouse_users_cli.session import SESSION_FILE
|
|
@@ -105,11 +106,16 @@ def connect_with_retry(conn: ConnectionInfo) -> ClickHouseAdmin:
|
|
|
105
106
|
|
|
106
107
|
# ── Etapa 2: perfil do novo usuário ───────────────────────────────────────────
|
|
107
108
|
|
|
108
|
-
def ask_profile() -> str:
|
|
109
|
-
|
|
109
|
+
def ask_profile(mode: str = "create") -> str:
|
|
110
|
+
if mode == "edit":
|
|
111
|
+
step("Editar · Tipo de acesso", "O perfil redefine os privilégios (os atuais serão zerados).")
|
|
112
|
+
question = "Qual o novo tipo de acesso?"
|
|
113
|
+
else:
|
|
114
|
+
step("2/6 · Tipo de usuário", "O perfil define os privilégios padrão (least privilege primeiro).")
|
|
115
|
+
question = "Que tipo de usuário criar?"
|
|
110
116
|
return _ask_or_abort(
|
|
111
117
|
Q.select(
|
|
112
|
-
|
|
118
|
+
question,
|
|
113
119
|
choices=[Q.Choice(PROFILE_LABELS[k], value=k) for k in ("readonly", "readwrite", "admin", "custom")],
|
|
114
120
|
default="readonly",
|
|
115
121
|
style=APP_STYLE, qmark="›",
|
|
@@ -139,8 +145,11 @@ def ask_new_credentials() -> tuple[str, str]:
|
|
|
139
145
|
|
|
140
146
|
# ── Etapa 4: escopo (bancos → tabelas) ────────────────────────────────────────
|
|
141
147
|
|
|
142
|
-
def ask_databases(admin: ClickHouseAdmin) -> list[str]:
|
|
143
|
-
|
|
148
|
+
def ask_databases(admin: ClickHouseAdmin, mode: str = "create") -> list[str]:
|
|
149
|
+
if mode == "edit":
|
|
150
|
+
step("Editar · Escopo — bancos", "Espaço marca · A confirma · Ctrl+A inverte a seleção.")
|
|
151
|
+
else:
|
|
152
|
+
step("4/6 · Escopo — bancos", "Espaço marca · A confirma · Ctrl+A inverte a seleção.")
|
|
144
153
|
with console.status("[cyan]Listando bancos…[/]", spinner="dots"):
|
|
145
154
|
try:
|
|
146
155
|
databases = admin.list_databases()
|
|
@@ -175,8 +184,11 @@ def ask_databases(admin: ClickHouseAdmin) -> list[str]:
|
|
|
175
184
|
return selected
|
|
176
185
|
|
|
177
186
|
|
|
178
|
-
def ask_tables(admin: ClickHouseAdmin, databases: list[str]) -> list[GrantScope]:
|
|
179
|
-
|
|
187
|
+
def ask_tables(admin: ClickHouseAdmin, databases: list[str], mode: str = "create") -> list[GrantScope]:
|
|
188
|
+
if mode == "edit":
|
|
189
|
+
step("Editar · Escopo — tabelas", "Escolha '*' para o banco inteiro ou marque tabelas específicas.")
|
|
190
|
+
else:
|
|
191
|
+
step("4/6 · Escopo — tabelas", "Escolha '*' para o banco inteiro ou marque tabelas específicas.")
|
|
180
192
|
scopes: list[GrantScope] = []
|
|
181
193
|
for db in databases:
|
|
182
194
|
try:
|
|
@@ -225,13 +237,16 @@ PRIVILEGE_CHOICES = [
|
|
|
225
237
|
]
|
|
226
238
|
|
|
227
239
|
|
|
228
|
-
def ask_privileges(profile: str) -> tuple[list[str], bool]:
|
|
240
|
+
def ask_privileges(profile: str, mode: str = "create") -> tuple[list[str], bool]:
|
|
229
241
|
"""Retorna (privilégios, grant_option)."""
|
|
230
242
|
if profile != "custom":
|
|
231
243
|
grant_option = profile == "admin"
|
|
232
244
|
return list(PROFILE_PRIVILEGES[profile]), grant_option
|
|
233
245
|
|
|
234
|
-
|
|
246
|
+
if mode == "edit":
|
|
247
|
+
step("Editar · Privilégios personalizados", "Marque só o necessário — DROP/TRUNCATE exigem confirmação extra.")
|
|
248
|
+
else:
|
|
249
|
+
step("5/6 · Privilégios personalizados", "Marque só o necessário — DROP/TRUNCATE exigem confirmação extra.")
|
|
235
250
|
privs: list[str] = _ask_or_abort(
|
|
236
251
|
Q.checkbox(
|
|
237
252
|
"Quais privilégios conceder?",
|
|
@@ -246,7 +261,7 @@ def ask_privileges(profile: str) -> tuple[list[str], bool]:
|
|
|
246
261
|
Q.confirm("Você marcou privilégio destrutivo. Tem certeza?", default=False, style=APP_STYLE, qmark="›")
|
|
247
262
|
)
|
|
248
263
|
if not grant_option_confirm:
|
|
249
|
-
return ask_privileges("custom")
|
|
264
|
+
return ask_privileges("custom", mode=mode)
|
|
250
265
|
else:
|
|
251
266
|
grant_option = _ask_or_abort(
|
|
252
267
|
Q.confirm("Permitir repassar acessos (WITH GRANT OPTION)?", default=False, style=APP_STYLE, qmark="›")
|
|
@@ -418,7 +433,7 @@ def ask_main_action(show_forget: bool = False) -> str:
|
|
|
418
433
|
choices = [
|
|
419
434
|
Q.Choice("Criar usuário — com privilégio mínimo", value="create"),
|
|
420
435
|
Q.Choice("Listar usuários — SHOW USERS + grants", value="list"),
|
|
421
|
-
Q.Choice("Gerenciar usuário — desativar / reativar / excluir", value="manage"),
|
|
436
|
+
Q.Choice("Gerenciar usuário — acessos, desativar / reativar / excluir", value="manage"),
|
|
422
437
|
]
|
|
423
438
|
if show_forget:
|
|
424
439
|
choices.append(Q.Choice("Esquecer sessão — apagar YAML salvo", value="forget"))
|
|
@@ -504,6 +519,49 @@ def flow_list_users(admin: ClickHouseAdmin) -> None:
|
|
|
504
519
|
show_user_details(admin, target)
|
|
505
520
|
|
|
506
521
|
|
|
522
|
+
def flow_edit_grants(admin: ClickHouseAdmin, username: str) -> None:
|
|
523
|
+
"""Redefine os acessos: REVOKE ALL + GRANTs novos (perfil + escopo + hosts intactos)."""
|
|
524
|
+
step("Usuários · Editar permissões", "Os acessos atuais serão zerados e reaplicados. Nada muda sem confirmação.")
|
|
525
|
+
if username == admin.conn.username:
|
|
526
|
+
warn(f"'{username}' é o usuário conectado agora. Zerar os próprios acessos pode te derrubar.")
|
|
527
|
+
|
|
528
|
+
profile = ask_profile(mode="edit")
|
|
529
|
+
privileges, grant_option = ask_privileges(profile, mode="edit")
|
|
530
|
+
if profile == "admin":
|
|
531
|
+
grant_option = True
|
|
532
|
+
databases = ask_databases(admin, mode="edit")
|
|
533
|
+
scopes = ask_tables(admin, databases, mode="edit")
|
|
534
|
+
|
|
535
|
+
statements = build_edit_grants_statements(username, privileges, scopes, grant_option)
|
|
536
|
+
table = make_table(f"Novos acessos de '{username}'")
|
|
537
|
+
table.add_column("Privilégios", style="bold")
|
|
538
|
+
table.add_column("Escopo", style="bold")
|
|
539
|
+
table.add_column("Grant option", style="dim")
|
|
540
|
+
for s in scopes:
|
|
541
|
+
table.add_row(", ".join(privileges), s.on_clause(), "sim" if grant_option else "não")
|
|
542
|
+
console.print(table)
|
|
543
|
+
|
|
544
|
+
console.print("[dim]SQL a executar (ordem importa: primeiro zera, depois concede):[/]")
|
|
545
|
+
from rich.panel import Panel as RichPanel
|
|
546
|
+
|
|
547
|
+
for sql in statements:
|
|
548
|
+
console.print(RichPanel(Syntax(sql + ";", "sql", theme="monokai"), border_style="dim"))
|
|
549
|
+
|
|
550
|
+
go = _ask_or_abort(Q.confirm(f"Aplicar novos acessos a '{username}' agora?", default=False, style=APP_STYLE, qmark="›"))
|
|
551
|
+
if not go:
|
|
552
|
+
console.print("[dim]Nada foi executado.[/]")
|
|
553
|
+
return
|
|
554
|
+
|
|
555
|
+
with console.status("[cyan]Aplicando acessos…[/]", spinner="dots"):
|
|
556
|
+
try:
|
|
557
|
+
admin.execute_statements(statements)
|
|
558
|
+
except Exception as e:
|
|
559
|
+
error(f"Falha ao editar acessos: {e}")
|
|
560
|
+
info("Dica: a conta precisa de GRANT/REVOKE nos escopos envolvidos. Os acessos antigos podem ter sido zerados — confira com Listar.")
|
|
561
|
+
return
|
|
562
|
+
success(f"Acessos de '{username}' atualizados ({len(statements)} comando(s)).")
|
|
563
|
+
|
|
564
|
+
|
|
507
565
|
def flow_manage_users(admin: ClickHouseAdmin) -> None:
|
|
508
566
|
step("Usuários · Gerenciar", "Desativar = HOST NONE (reversível). Excluir = DROP USER (definitivo).")
|
|
509
567
|
with console.status("[cyan]Listando usuários…[/]", spinner="dots"):
|
|
@@ -537,6 +595,7 @@ def flow_manage_users(admin: ClickHouseAdmin) -> None:
|
|
|
537
595
|
else:
|
|
538
596
|
options.append(Q.Choice("Desativar — ALTER USER … HOST NONE (reversível)", value="deactivate"))
|
|
539
597
|
options += [
|
|
598
|
+
Q.Choice("Editar permissões — bancos/tabelas + tipo de acesso", value="edit"),
|
|
540
599
|
Q.Choice("Excluir — DROP USER (definitivo!)", value="drop"),
|
|
541
600
|
Q.Choice("Voltar ao menu", value="back"),
|
|
542
601
|
]
|
|
@@ -545,6 +604,9 @@ def flow_manage_users(admin: ClickHouseAdmin) -> None:
|
|
|
545
604
|
)
|
|
546
605
|
if action == "back":
|
|
547
606
|
return
|
|
607
|
+
if action == "edit":
|
|
608
|
+
flow_edit_grants(admin, target)
|
|
609
|
+
return
|
|
548
610
|
|
|
549
611
|
preview = {
|
|
550
612
|
"deactivate": build_deactivate_user_sql(target),
|
{clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli/sql_builder.py
RENAMED
|
@@ -114,3 +114,16 @@ def build_drop_user_sql(username: str, if_exists: bool = True) -> str:
|
|
|
114
114
|
"""Exclui o usuário em definitivo."""
|
|
115
115
|
ine = "IF EXISTS " if if_exists else ""
|
|
116
116
|
return f"DROP USER {ine}{escape_ident(username)}"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def build_revoke_all_sql(username: str) -> str:
|
|
120
|
+
"""Remove todos os privilégios em todos os escopos (zera antes de reaplicar)."""
|
|
121
|
+
return f"REVOKE ALL ON *.* FROM {escape_ident(username)}"
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def build_edit_grants_statements(
|
|
125
|
+
username: str, privileges: list[str], scopes: list[GrantScope], grant_option: bool = False
|
|
126
|
+
) -> list[str]:
|
|
127
|
+
"""Edição de acessos: REVOKE ALL + GRANTs novos (com preview + confirmação no CLI)."""
|
|
128
|
+
spec = UserSpec(username=username, password="", privileges=privileges, scopes=scopes, grant_option=grant_option)
|
|
129
|
+
return [build_revoke_all_sql(username), *build_grant_sql(spec)]
|
{clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clickhouse-users-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: CLI interativa para criar usuarios ClickHouse com privilegio minimo (least privilege)
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Keywords: clickhouse,cli,users,access-control,least-privilege
|
|
@@ -76,6 +76,7 @@ GRANT SHOW, SELECT ON `vendas`.`clientes` TO `analyst_julho`;
|
|
|
76
76
|
|
|
77
77
|
- **Listar** — `SHOW USERS` em tabela + opção de ver `SHOW CREATE USER` e `SHOW GRANTS FOR` de um usuário.
|
|
78
78
|
- **Gerenciar** — escolhe 1 usuário, vê status (`HOST NONE` = inativo) + grants, depois:
|
|
79
|
+
- **Editar permissões** → pergunta perfil (tipo de acesso) + bancos/tabelas e aplica `REVOKE ALL ON *.*` + novos `GRANTs` (com preview e confirmação);
|
|
79
80
|
- **Desativar** → `ALTER USER \`nome\` HOST NONE` (reversível, bloqueia login);
|
|
80
81
|
- **Reativar** → `ALTER USER \`nome\` HOST ANY`;
|
|
81
82
|
- **Excluir** → `DROP USER IF EXISTS \`nome\`` (definitivo).
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli/validators.py
RENAMED
|
File without changes
|
{clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{clickhouse_users_cli-0.1.2 → clickhouse_users_cli-0.1.4}/clickhouse_users_cli.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|