raijin-server 0.2.3__py3-none-any.whl → 0.2.5__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.
@@ -25,6 +25,49 @@ from raijin_server.modules import (
25
25
  )
26
26
 
27
27
 
28
+ def _cert_manager_install_only(ctx: ExecutionContext) -> None:
29
+ """Wrapper para instalar cert-manager sem interação."""
30
+ if not cert_manager.install_only(ctx):
31
+ raise RuntimeError("Falha na instalação do cert-manager")
32
+
33
+ # Cria issuer HTTP01 padrão para staging (teste) e produção
34
+ # O usuário pode criar issuers adicionais depois com 'raijin-server cert install'
35
+ email = os.environ.get("RAIJIN_ACME_EMAIL", "")
36
+ if email and "@" in email:
37
+ typer.secho("\n📜 Criando ClusterIssuers padrão...", fg=typer.colors.CYAN)
38
+
39
+ # Cria issuer de staging (para testes)
40
+ cert_manager.create_issuer(
41
+ ctx,
42
+ name="letsencrypt-staging",
43
+ email=email,
44
+ challenge_type="http01",
45
+ staging=True,
46
+ ingress_class="traefik",
47
+ )
48
+
49
+ # Cria issuer de produção
50
+ cert_manager.create_issuer(
51
+ ctx,
52
+ name="letsencrypt-prod",
53
+ email=email,
54
+ challenge_type="http01",
55
+ staging=False,
56
+ ingress_class="traefik",
57
+ )
58
+
59
+ typer.secho("✓ ClusterIssuers 'letsencrypt-staging' e 'letsencrypt-prod' criados", fg=typer.colors.GREEN)
60
+ else:
61
+ typer.secho(
62
+ "ℹ Para criar ClusterIssuers automaticamente, defina RAIJIN_ACME_EMAIL",
63
+ fg=typer.colors.YELLOW,
64
+ )
65
+ typer.secho(
66
+ " Exemplo: export RAIJIN_ACME_EMAIL=admin@seudominio.com",
67
+ fg=typer.colors.YELLOW,
68
+ )
69
+
70
+
28
71
  # Ordem de execucao dos modulos para instalacao completa
29
72
  # Modulos marcados com skip_env podem ser pulados via variavel de ambiente
30
73
  INSTALL_SEQUENCE = [
@@ -36,7 +79,7 @@ INSTALL_SEQUENCE = [
36
79
  ("firewall", firewall.run, "Firewall UFW", None),
37
80
  ("kubernetes", kubernetes.run, "Cluster Kubernetes (kubeadm)", None),
38
81
  ("calico", calico.run, "CNI Calico + NetworkPolicy", None),
39
- ("cert_manager", cert_manager.run, "cert-manager + ClusterIssuer ACME", None),
82
+ ("cert_manager", _cert_manager_install_only, "cert-manager (instalacao base)", None),
40
83
  ("secrets", secrets.run, "Sealed-Secrets + External-Secrets", None),
41
84
  ("prometheus", prometheus.run, "Monitoramento Prometheus", None),
42
85
  ("grafana", grafana.run, "Dashboards Grafana", None),
raijin_server/utils.py CHANGED
@@ -299,6 +299,62 @@ def helm_repo_update(ctx: ExecutionContext) -> None:
299
299
  run_cmd(["helm", "repo", "update"], ctx)
300
300
 
301
301
 
302
+ def _get_helm_release_status(release: str, namespace: str) -> str:
303
+ """Retorna status do release Helm (lowercased) ou string vazia se nao existir."""
304
+ try:
305
+ import json
306
+ result = subprocess.run(
307
+ ["helm", "status", release, "-n", namespace, "-o", "json"],
308
+ capture_output=True,
309
+ text=True,
310
+ timeout=30,
311
+ )
312
+ if result.returncode != 0 or not result.stdout:
313
+ return ""
314
+ data = json.loads(result.stdout)
315
+ return str(data.get("info", {}).get("status", "")).lower()
316
+ except Exception:
317
+ return ""
318
+
319
+
320
+ def _cleanup_pending_helm_release(release: str, namespace: str, ctx: ExecutionContext) -> None:
321
+ """Remove release Helm em estado pendente que bloqueia novas operacoes."""
322
+ if ctx.dry_run:
323
+ return
324
+
325
+ status = _get_helm_release_status(release, namespace)
326
+ if not status:
327
+ return
328
+
329
+ # Estados que bloqueiam: pending-install, pending-upgrade, pending-rollback
330
+ if status.startswith("pending"):
331
+ typer.secho(
332
+ f"⚠ Release '{release}' em estado '{status}'. Limpando antes de prosseguir...",
333
+ fg=typer.colors.YELLOW,
334
+ )
335
+ # Tenta rollback primeiro (funciona para pending-upgrade)
336
+ subprocess.run(
337
+ ["helm", "rollback", release, "-n", namespace, "--wait", "--timeout", "2m"],
338
+ capture_output=True,
339
+ timeout=150,
340
+ )
341
+ # Verifica se resolveu
342
+ new_status = _get_helm_release_status(release, namespace)
343
+ if new_status.startswith("pending"):
344
+ # Se ainda pendente, desinstala
345
+ typer.secho(
346
+ f" Rollback nao resolveu. Desinstalando release '{release}'...",
347
+ fg=typer.colors.YELLOW,
348
+ )
349
+ subprocess.run(
350
+ ["helm", "uninstall", release, "-n", namespace, "--wait", "--timeout", "3m"],
351
+ capture_output=True,
352
+ timeout=200,
353
+ )
354
+ time.sleep(5)
355
+ typer.secho(f"✓ Release '{release}' limpo.", fg=typer.colors.GREEN)
356
+
357
+
302
358
  def helm_upgrade_install(
303
359
  release: str,
304
360
  chart: str,
@@ -311,9 +367,16 @@ def helm_upgrade_install(
311
367
  create_namespace: bool = True,
312
368
  extra_args: list[str] | None = None,
313
369
  ) -> None:
314
- """Executa helm upgrade --install com opcoes comuns."""
370
+ """Executa helm upgrade --install com opcoes comuns.
371
+
372
+ Automaticamente detecta e limpa releases em estado pendente antes de instalar.
373
+ """
315
374
 
316
375
  ensure_tool("helm", ctx, install_hint="Instale helm ou habilite dry-run para so visualizar.")
376
+
377
+ # Limpa releases pendentes antes de tentar instalar
378
+ _cleanup_pending_helm_release(release, namespace, ctx)
379
+
317
380
  if repo and repo_url:
318
381
  helm_repo_add(repo, repo_url, ctx)
319
382
  helm_repo_update(ctx)
@@ -328,7 +391,21 @@ def helm_upgrade_install(
328
391
  cmd.extend(["--set", value])
329
392
  if extra_args:
330
393
  cmd.extend(extra_args)
331
- run_cmd(cmd, ctx)
394
+
395
+ try:
396
+ run_cmd(cmd, ctx)
397
+ except Exception as e:
398
+ err_text = str(e).lower()
399
+ # Se falhou por operacao em progresso, tenta limpar e reinstalar uma vez
400
+ if "another operation" in err_text and "in progress" in err_text:
401
+ typer.secho(
402
+ f"⚠ Helm detectou operacao pendente em '{release}'. Limpando e tentando novamente...",
403
+ fg=typer.colors.YELLOW,
404
+ )
405
+ _cleanup_pending_helm_release(release, namespace, ctx)
406
+ run_cmd(cmd, ctx)
407
+ else:
408
+ raise
332
409
 
333
410
 
334
411
  def kubectl_apply(target: str, ctx: ExecutionContext) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: raijin-server
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: CLI para automacao de setup e hardening de servidores Ubuntu Server.
5
5
  Home-page: https://example.com/raijin-server
6
6
  Author: Equipe Raijin
@@ -37,6 +37,14 @@ CLI em Python (Typer) para automatizar setup e hardening de servidores Ubuntu Se
37
37
 
38
38
  **✨ Versão Auditada e Resiliente para Produção**
39
39
 
40
+ ## Links úteis
41
+
42
+ - Repositório: https://github.com/rafaelluisdacostacoelho/raijin-server
43
+ - Documentação completa: [docs/INFRASTRUCTURE_GUIDE.md](docs/INFRASTRUCTURE_GUIDE.md)
44
+ - Arquitetura: [ARCHITECTURE.md](ARCHITECTURE.md)
45
+ - Auditoria: [AUDIT.md](AUDIT.md)
46
+ - Segurança: [SECURITY.md](SECURITY.md)
47
+
40
48
  ## Destaques
41
49
 
42
50
  - ✅ **Validações de Pré-requisitos**: OS, espaço em disco, memória, conectividade, ambiente Python (venv)
@@ -81,6 +89,36 @@ source .venv/bin/activate
81
89
  python -m pip install -e .
82
90
  ```
83
91
 
92
+ ### Instalação em Produção (Recomendado)
93
+
94
+ Para servidores em produção, use um venv isolado e execute com sudo preservando o ambiente:
95
+
96
+ ```bash
97
+ # 1. Sair do venv atual (se estiver ativo)
98
+ deactivate
99
+
100
+ # 2. (Opcional) Remover venv antigo
101
+ rm -rf ~/.venvs/raijin
102
+
103
+ # 3. Criar venv novo
104
+ python3 -m venv ~/.venvs/raijin
105
+ source ~/.venvs/raijin/bin/activate
106
+ pip install -U pip setuptools
107
+
108
+ # 4. Instalar a versão mais recente
109
+ pip install -U raijin-server
110
+
111
+ # 5. Rodar usando root preservando o venv
112
+ sudo -E ~/.venvs/raijin/bin/raijin-server --version
113
+ sudo -E ~/.venvs/raijin/bin/raijin-server validate
114
+ sudo -E ~/.venvs/raijin/bin/raijin-server full-install
115
+
116
+ # 6. Para sair do venv quando terminar
117
+ deactivate
118
+ ```
119
+
120
+ > **Nota**: O `-E` no sudo preserva as variáveis de ambiente, garantindo que o Python use o venv correto mesmo como root.
121
+
84
122
  ## Uso rapido
85
123
 
86
124
  ### Validar Sistema
@@ -375,6 +413,32 @@ pytest
375
413
  ruff check src tests
376
414
  ```
377
415
 
416
+ ## Publicar no PyPI (Twine)
417
+
418
+ O Twine é a ferramenta oficial para enviar pacotes Python ao PyPI com upload seguro (HTTPS e checagem de hash). Use sempre um token de API.
419
+
420
+ Passo a passo:
421
+ ```bash
422
+ # 1) Gere artefatos
423
+ python -m build --sdist --wheel --outdir dist/
424
+
425
+ # 2) Configure o token (crie em https://pypi.org/manage/account/token/)
426
+ export TWINE_USERNAME=__token__
427
+ export TWINE_PASSWORD="<seu-token>"
428
+
429
+ # 3) Envie para o PyPI
430
+ python -m twine upload dist/*
431
+
432
+ # 4) Verifique instalação
433
+ python -m pip install -U raijin-server
434
+ raijin-server --version
435
+ ```
436
+
437
+ Boas práticas:
438
+ - Use venv dedicado para publicar (`python -m venv ~/.venvs/publish && source ~/.venvs/publish/bin/activate`).
439
+ - Nunca commite ou exponha o token; mantenha em variável de ambiente/secret manager.
440
+ - Sempre suba primeiro para TestPyPI se quiser validar (`--repository testpypi`).
441
+
378
442
  ## Acesso remoto seguro (VPN + SSH)
379
443
 
380
444
  Execute `raijin-server ssh-hardening` para aplicar as politicas abaixo automaticamente e `raijin-server vpn` para subir o servidor WireGuard com um cliente inicial. Use `--dry-run` se quiser apenas revisar os comandos.
@@ -1,17 +1,17 @@
1
- raijin_server/__init__.py,sha256=AKDS9uS_9UXF-3BZWSJvcQdgvkhbsxMs1o-P7R5xBE4,94
2
- raijin_server/cli.py,sha256=ZgaSkXwXaND7HHeySjIn4GEmTVTqUDttUfqXJ9yZV1E,16772
1
+ raijin_server/__init__.py,sha256=7-69Vj-HYrv98hWrKmwDqDQ-ehtTqJebx1JeP4St6Q4,94
2
+ raijin_server/cli.py,sha256=PfuIXc-pw1yZtJzCrxDVSWSsPAVBt9wqZBF-dWh6mwo,19274
3
3
  raijin_server/config.py,sha256=Dta2CS1d6RgNiQ84P6dTXk98boFrjzuvhs_fCdlm0I4,4810
4
- raijin_server/healthchecks.py,sha256=-mQq-dGZ2id16wvPmiTPjDHw14PBwz_i8AXi307V38k,12411
5
- raijin_server/utils.py,sha256=oQM-NGL_kmlNZejFvxXk85MI_WkcxNfwaw5LeAsKUFU,11476
4
+ raijin_server/healthchecks.py,sha256=BJyWyUDtEswEblvGwWMejtMnsUb8kJcULVdS9iycrcc,14565
5
+ raijin_server/utils.py,sha256=MNIevCttKq5fVS-I4ZwlY7f7JZtEiwwY_kj69WV4AsQ,14330
6
6
  raijin_server/validators.py,sha256=qOZMHgwjHogVf17UPlxfUCpQd9qAGQW7tycd8mUvnEs,9404
7
7
  raijin_server/modules/__init__.py,sha256=e_IbkhLGPcF8to9QUmIESP6fpcTOYcIhaXLKIvqRJMY,920
8
- raijin_server/modules/apokolips_demo.py,sha256=gMUpYNaO0V20KoNa4ljyA1W9HJbY__O9AEO64NuWGhE,12365
8
+ raijin_server/modules/apokolips_demo.py,sha256=8ltsXRbVDwlDwLMIvh02NG-FeAfBWw_v6lh7IGOyNqs,13725
9
9
  raijin_server/modules/bootstrap.py,sha256=oVIGNRW_JbgY8zXNHGAIP0vGbbHNHyQexthxo5zhbcw,9762
10
10
  raijin_server/modules/calico.py,sha256=a8N7YYv7NoaspPKdhRtwHy3V2mM4cP5xA1H8BwslB18,4139
11
- raijin_server/modules/cert_manager.py,sha256=bSv5CRbPlH3DHWHBqUNTKVh0C973E4XC8WzGieOHh3A,4882
11
+ raijin_server/modules/cert_manager.py,sha256=dse7AIUVOM2h7d2i3DWsvHLsA9NtcazebTPgOEUWB-8,34473
12
12
  raijin_server/modules/essentials.py,sha256=2xUXCyCQtFGd2DnCKV81N1R6bEJqH8zaet8mLovtQ1I,689
13
13
  raijin_server/modules/firewall.py,sha256=h6AISqiZeTinVT7BjmQIS872qRAFZJLg7meqlth3cfw,757
14
- raijin_server/modules/full_install.py,sha256=Mk_SHBrtL4zgjgd2shUuhp4fyDIPdlBVZtC5t8x-1vU,5908
14
+ raijin_server/modules/full_install.py,sha256=aR3yOuD7y0KLI20eMrxuFBNrWWn7JMpI4HFKNizEF3o,7464
15
15
  raijin_server/modules/grafana.py,sha256=zxYpWBM-fD8vTgoJ2Hmb9P66wz_JuiidO6_cGK3jG30,1809
16
16
  raijin_server/modules/hardening.py,sha256=4hz3ifkMhPlXa2n7gPxN0gitQgzALZ-073vuU3LM4RI,1616
17
17
  raijin_server/modules/harness.py,sha256=dhZ89YIhlkuxiRU1deN6wXVWnXm0xeI03PwYf_qgfak,1527
@@ -36,9 +36,9 @@ raijin_server/scripts/checklist.sh,sha256=j6E0Kmk1EfjLvKK1VpCqzXJAXI_7Bm67LK4ndy
36
36
  raijin_server/scripts/install.sh,sha256=IZOTujOSGmKpznwgL59picsQNVzYkai6FtfFS3Klf34,3908
37
37
  raijin_server/scripts/log_size_metric.sh,sha256=rC2Ck4xnYVJV4Qymu24-indC8bkzfZs4FBqqxGPRl1I,1143
38
38
  raijin_server/scripts/pre-deploy-check.sh,sha256=naPUgKjnKgsh-eGDH2623C7zcr9VjDEw1H0lfYaXW8c,4853
39
- raijin_server-0.2.3.dist-info/licenses/LICENSE,sha256=kJsMCjOiRZE0AQNtxWqBa32z9kMAaF4EUxyHj3hKaJo,1105
40
- raijin_server-0.2.3.dist-info/METADATA,sha256=Bh7AicqZXP3kLYhHxgf1uB3R4PGI4hcC8AYaDAaUg6A,16941
41
- raijin_server-0.2.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
42
- raijin_server-0.2.3.dist-info/entry_points.txt,sha256=3ZvxDX4pvcjkIRsXAJ69wIfVmKa78LKo-C3QhqN2KVM,56
43
- raijin_server-0.2.3.dist-info/top_level.txt,sha256=Yz1xneCRtsZOzbPIcTAcrSxd-1p80pohMXYAZ74dpok,14
44
- raijin_server-0.2.3.dist-info/RECORD,,
39
+ raijin_server-0.2.5.dist-info/licenses/LICENSE,sha256=kJsMCjOiRZE0AQNtxWqBa32z9kMAaF4EUxyHj3hKaJo,1105
40
+ raijin_server-0.2.5.dist-info/METADATA,sha256=TVzTE_0qlyVoyy3lsoWfFn97hJylE_oKyXDFv32BMkg,18925
41
+ raijin_server-0.2.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
42
+ raijin_server-0.2.5.dist-info/entry_points.txt,sha256=3ZvxDX4pvcjkIRsXAJ69wIfVmKa78LKo-C3QhqN2KVM,56
43
+ raijin_server-0.2.5.dist-info/top_level.txt,sha256=Yz1xneCRtsZOzbPIcTAcrSxd-1p80pohMXYAZ74dpok,14
44
+ raijin_server-0.2.5.dist-info/RECORD,,