knowledge-base/records/plugin-dev/KB-PLUGIN-013-mindplace-plugin-publication-runbook.md

451 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
id: KB-PLUGIN-013
title: Runbook — Publicação de plugin no Mindplace (procedimento padrão)
domain: plugin-dev
tags:
- mindplace
- runbook
- publish
- license
- forgejo
- release
- kill-switch
- workflow
- automation
- script
status: active
severity: high
created_at: 2026-05-09
updated_at: 2026-05-21
applies_to:
- GLPI 11.0.x
- Mindplace 1.0+
- Forgejo (servicedesk.mindtek.com.br/git)
---
# Runbook — Publicação de plugin no Mindplace
Procedimento padrão completo para publicar um novo plugin proprietário no Mindplace (marketplace privado da Mindtek). Cobre desde a integração do kill switch de licença no código até a entrega do serial ao cliente.
> **⚡ TL;DR — Publicação automatizada:** As Fases 2, 3 e 4 (Forgejo + ZIP + Release + plugins.json) estão **100% automatizadas** pelo script `bin/mindplace-release.sh`. Leia a seção **Publicação Automatizada** antes de executar os passos manuais.
## Pré-requisitos
- [ ] Plugin está em estado funcional e testado localmente
- [ ] Acesso de admin ao Forgejo (`servicedesk.mindtek.com.br/git`)
- [ ] Acesso ao GLPI de produção da Mindtek (`servicedesk.mindtek.com.br`) com perfil que crie licenças de software
- [ ] Plugin já tem `setup.php` válido com `plugin_version_<name>()` retornando metadata
- [ ] `version` no `setup.php` segue SemVer (ex: `1.0.0`)
- [ ] **Para publicação automatizada:** `FORGEJO_TOKEN` disponível (PAT com escopo `write:repository`)
---
## ⚡ Publicação Automatizada (Fases 25)
As fases de publicação no Forgejo e catálogo são cobertas pelo script `bin/mindplace-release.sh` localizado na raiz do projeto GLPI11.
### Pré-requisito único: Personal Access Token (PAT)
Gere em: `https://servicedesk.mindtek.com.br/git/user/settings/applications`
- Nome sugerido: `antigravity-publisher`
- Escopo necessário: `write:repository`
Exporte como variável de ambiente (ou edite a variável `FORGEJO_TOKEN` diretamente no script):
```bash
export FORGEJO_TOKEN="seu_token_aqui"
```
### Uso
```bash
# Na raiz do projeto GLPI11:
./bin/mindplace-release.sh ./docker/glpi/plugins/<nome-do-plugin>
```
### O que o script faz automaticamente
| Fase | Ação |
|---|---|
| **1** | Cria repositório no Forgejo (se não existir) |
| **2** | `git init` + commit + push para o Forgejo |
| **3** | Gera ZIP limpo do plugin (exclui `.git`, `vendor`, `node_modules`, `*.DS_Store`) |
| **4** | Cria tag `v{versão}` + Release no Forgejo + faz upload do ZIP como asset |
| **5** | Atualiza `plugins.json` no repo `mindplace` com a entrada do novo plugin |
### Comportamento idempotente
O script é seguro para rodar múltiplas vezes:
- ✅ Repositório já existe → pula criação
- ✅ Release já existe → pula criação
- ✅ Plugin já no `plugins.json` → pula atualização
- ✅ Sempre faz push do código mais recente
### Fluxo de nova versão
```bash
# 1. Bump da versão no setup.php
# 'version' => '1.0.0' → '1.1.0'
# 2. Rodar o script — ele detecta a nova versão e cria nova Release
./bin/mindplace-release.sh ./docker/glpi/plugins/meu-plugin
```
### Notas importantes
- O script lê a versão diretamente da constante `PLUGIN_XXXVERSION` no `setup.php`
- Arquivos de teste (`ajax/test*.php`, `front/test*.php`) devem estar no `.gitignore` do plugin para não serem publicados
- O `.gitignore` padrão para plugins está documentado abaixo
- O ZIP do asset pode acumular múltiplas versões na mesma Release se o script for rodado mais de uma vez sem bump de versão (não causa erro, apenas duplicata)
### .gitignore padrão para plugins
```gitignore
# Dependências
vendor/
node_modules/
# macOS
.DS_Store
**/.DS_Store
# IDE
.idea/
.vscode/
# Logs
*.log
# Build artifacts
*.zip
# Arquivos de teste (não publicar)
ajax/test*.php
ajax/mcp_test.php
front/test*.php
```
---
---
## Fase 1 — Kill switch de licença no código
Cada plugin do Mindplace **precisa** validar a licença antes de fazer qualquer coisa. O padrão do "Kill Switch" funciona em duas camadas:
1. `plugin_<name>_check_config()` impede ativação se licença inválida
2. `plugin_init_<name>()` aborta silenciosamente se licença inválida (proteção em profundidade)
### Template do `setup.php`
```php
<?php
use Glpi\Plugin\Hooks;
function plugin_version_<name>(): array
{
return [
'name' => 'Plugin Name',
'version' => '1.0.0',
'author' => 'Mindtek Tecnologia',
'license' => 'GPLv2+',
'requirements' => ['glpi' => ['min' => '11.0', 'max' => '12.0']],
];
}
function plugin_<name>_check_prerequisites(): bool
{
if (version_compare(GLPI_VERSION, '11.0', '<')) {
echo 'This plugin requires GLPI >= 11.0';
return false;
}
return true;
}
/**
* Carrega a classe License do Mindplace caso o autoload ainda não tenha rodado.
* Necessário porque o plugin pode inicializar antes do mindplace.
*/
function plugin_<name>_load_license(): void
{
if (class_exists('\GlpiPlugin\Mindplace\License')) {
return;
}
foreach ([
GLPI_ROOT . '/plugins/mindplace/src/License.php',
GLPI_ROOT . '/marketplace/mindplace/src/License.php',
] as $path) {
if (file_exists($path)) {
include_once $path;
return;
}
}
}
function plugin_<name>_check_config($verbose = false): bool
{
plugin_<name>_load_license();
if (!class_exists('\GlpiPlugin\Mindplace\License') || !\GlpiPlugin\Mindplace\License::isValid()) {
if ($verbose && !isCommandLine()) {
echo "<div class='alert alert-danger'>Licença Mindtek inativa ou Mind Place ausente. O plugin foi desativado por segurança.</div>";
}
return false;
}
return true;
}
function plugin_init_<name>(): void
{
global $PLUGIN_HOOKS;
$PLUGIN_HOOKS['csrf_compliant']['<name>'] = true;
// ──────────────────────────────────────────────────────────────────
// KILL SWITCH — abort silently if license invalid
// ──────────────────────────────────────────────────────────────────
plugin_<name>_load_license();
if (!class_exists('\GlpiPlugin\Mindplace\License') || !\GlpiPlugin\Mindplace\License::isValid()) {
return;
}
// ─── A partir daqui, registrar todos os hooks/classes do plugin ───
// $PLUGIN_HOOKS[Hooks::ADD_CSS]['<name>'] = [...];
// Plugin::registerClass(...);
}
```
### Comportamento do Kill Switch
| Cenário | Resultado |
|---|---|
| Mindplace não instalado | `check_config` retorna `false` → plugin não pode ativar |
| Mindplace instalado mas licença inválida/expirada | mesmo do anterior |
| Plugin já estava ativo e licença expirou | `init` aborta sem registrar hooks → GLPI ignora o plugin como se não existisse |
| Tudo OK | Plugin funciona normalmente |
### Checklist da Fase 1
- [ ] `plugin_<name>_load_license()` adicionada
- [ ] `plugin_<name>_check_config()` valida licença
- [ ] `plugin_init_<name>()` aborta se inválida
- [ ] Testado: desativar mindplace → tentar ativar plugin → deve falhar com aviso
- [ ] Testado: licença válida → plugin ativa e funciona
---
## Fase 2 — Publicação no Forgejo
Forgejo é onde o código-fonte e os releases ficam. URL base: `https://servicedesk.mindtek.com.br/git/`.
### 2.1 — Criar repositório
1. Acesse o Forgejo logado como admin (`rodolpho.lopes`)
2. **+** → **New Repository**
- Owner: `rodolpho.lopes`
- Repository name: nome do plugin (ex: `tilesections`)
- Visibility: **Public**
- Initialize repository: ✅ (com README mínimo — releases exigem ao menos um commit)
3. **Create Repository**
### 2.2 — Push do código-fonte
```bash
cd /caminho/local/do/plugin
# Se ainda não é um repo git
git init
git branch -M main
# Adicionar Forgejo como remote
git remote add forgejo https://servicedesk.mindtek.com.br/git/rodolpho.lopes/<plugin>.git
# Commit + push
git add .
git commit -m "Initial commit"
git push forgejo main
```
Vai pedir credenciais do Forgejo na primeira vez.
### 2.3 — Criar release com ZIP
1. No Forgejo, no repo do plugin: **Releases****New Release**
2. **Tag name**: `v1.0.0` (deve bater com `version` em `setup.php`)
3. **Title**: `v1.0.0`
4. **Description**: changelog resumido
5. Em **Attachments**, fazer upload do ZIP gerado:
```bash
cd /caminho/local/do/plugin
zip -r <plugin>-1.0.0.zip . \
--exclude "*.git*" \
--exclude "node_modules/*" \
--exclude "vendor/*" \
--exclude "*.DS_Store"
```
6. **Publish Release**
### Checklist da Fase 2
- [ ] Repositório criado público no Forgejo
- [ ] Código-fonte push para `main`
- [ ] Logo `logo.png` na raiz do plugin (será exibido no Mindplace)
- [ ] Tag `v<versão>` criada
- [ ] ZIP do plugin anexado como asset da release
- [ ] Versão do ZIP bate com `setup.php`
---
## Fase 3 — Cadastro no catálogo Mindplace
O Mindplace lê `plugins.json` do repositório `rodolpho.lopes/mindplace` no Forgejo. Cada plugin é uma entrada nesse array.
### 3.1 — Editar `plugins.json`
Acesse: `https://servicedesk.mindtek.com.br/git/rodolpho.lopes/mindplace`
Edite o arquivo `plugins.json` (ícone do lápis na visualização do arquivo) e adicione a nova entrada:
```json
{
"key": "<plugin>",
"repo": "rodolpho.lopes/<plugin>",
"name": "Nome Bonito do Plugin",
"description": "Descrição curta de uma frase.",
"authors": [{"name": "Rodolpho O Lopes"}],
"license": "GPL-2.0-or-later",
"logo_url": null,
"homepage_url": "https://servicedesk.mindtek.com.br/git/rodolpho.lopes/<plugin>",
"issues_url": "https://servicedesk.mindtek.com.br/git/rodolpho.lopes/<plugin>/issues",
"note": 5
}
```
**Campos importantes:**
- `key`: igual ao nome do diretório do plugin (sem espaços, lowercase)
- `repo`: caminho `<owner>/<repo>` no Forgejo
- `logo_url: null`: faz o Mindplace buscar `logo.png` da raiz do repo automaticamente
Commit direto pelo Forgejo (Commit Changes na interface).
### 3.2 — Validação
No GLPI do cliente (com mindplace instalado e licença ativa), abra a aba **Mind Place**. O novo plugin deve aparecer no grid em até 1 hora (cache TTL). Para forçar refresh imediato, clica no botão de refresh do Mindplace.
### Checklist da Fase 3
- [ ] Entrada adicionada em `plugins.json`
- [ ] Commit feito
- [ ] Plugin aparece no grid do Mindplace
- [ ] Logo carrega corretamente (se `logo.png` existe na raiz do repo)
- [ ] Botão **Download/Install** funciona
---
## Fase 4 — Cadastro de licença no GLPI de produção
Cada cliente recebe um serial único. O serial fica em `glpi_softwarelicenses` do GLPI da Mindtek e é validado pelo `mindtek_validador.php`.
### 4.1 — Criar entrada de licença
No GLPI de produção (`servicedesk.mindtek.com.br`):
1. **Ativos → Licenças de Software → +**
2. Preencher:
- **Nome**: `Licença <Plugin> — <Cliente>` (ex: `Licença Tilesections — Empresa Acme`)
- **Software**: associar ao software do plugin (criar se não existir)
- **Número de série**: gerar hash hex aleatório de 32 caracteres
```bash
openssl rand -hex 16 | tr 'a-z' 'A-Z'
# exemplo: 7C9F1E3A4B5D6F8E2C0A1B3D4E5F6071
```
- **Tipo**: livre (sugestão: `Mindplace Plugin`)
- **Validade**: opcional, conforme contrato
3. Salvar
### 4.2 — Entregar o serial ao cliente
Mensagem padrão para o cliente:
> Olá,
>
> Sua licença do plugin **\<Plugin\>** está ativa. Use o serial abaixo para ativar no Mindplace do seu GLPI:
>
> `7C9F1E3A4B5D6F8E2C0A1B3D4E5F6071`
>
> **Como ativar:**
> 1. No GLPI, acesse **Configurar → Plugins → Mind Place** (ícone de chave)
> 2. Cole o serial no campo **API Token** e salve
> 3. Aguarde o status mudar para "Ativo" (alguns segundos)
> 4. Pronto, o plugin pode ser ativado normalmente
### Checklist da Fase 4
- [ ] Software cadastrado em `Ativos → Software` (se primeira vez)
- [ ] Licença criada com serial único de 32 chars hex
- [ ] Serial enviado ao cliente
- [ ] Cliente confirmou ativação no Mindplace dele
---
## Fase 5 — Manutenção contínua
### Lançar nova versão do plugin
1. Atualizar `version` no `setup.php` (ex: `1.0.0``1.1.0`)
2. Commit + push para `main` no Forgejo
3. Criar nova release no Forgejo com tag `v1.1.0` + novo ZIP
4. **Não** atualiza `plugins.json` — o Mindplace pega automaticamente a release mais recente
5. Clientes verão o botão **Atualizar** no Mindplace dentro de 1 hora (cache TTL)
### Revogar licença de um cliente
1. No GLPI de produção: **Ativos → Licenças de Software** → encontrar o serial
2. Marcar `is_deleted = 1` (mover para a lixeira) **OU** deletar permanentemente
3. No próximo cron (1x por dia) ou na próxima vez que o cliente salvar a config do mindplace, `License::cronCheck()` vai retornar `expired`
4. Plugin do cliente desativa automaticamente
### Verificar status de licença de um cliente
```sql
-- No GLPI de produção
SELECT id, name, serial, is_deleted, completename
FROM glpi_softwarelicenses
WHERE serial = 'SERIAL_DO_CLIENTE';
```
Ou consultar o validador diretamente:
```bash
curl "https://servicedesk.mindtek.com.br/mindtek_validador.php?token=SERIAL_DO_CLIENTE"
# {"status":"active"} ou {"status":"expired"}
```
---
## Referências cruzadas
- [KB-PLUGIN-011](KB-PLUGIN-011-mindplace-release-zip-procedure.md) — procedimento de ZIP via GitHub (legado, antes da migração para Forgejo)
- [KB-PLUGIN-012](KB-PLUGIN-012-helpdesk-tiles-extension-patterns.md) — padrões para estender o sistema de tiles do Helpdesk
## Script de automação
| Arquivo | Localização | Função |
|---|---|---|
| `mindplace-release.sh` | `bin/mindplace-release.sh` na raiz do projeto GLPI11 | Script Bash que automatiza as Fases 25 completas via API do Forgejo |
## Arquivos críticos
| Arquivo | Localização | Função |
|---|---|---|
| `mindtek_validador.php` | `/var/www/html/glpi/public/` no servidor de produção | Endpoint que valida serials contra `glpi_softwarelicenses` |
| `License.php` | `plugins/mindplace/src/` no GLPI do cliente | Cron + `isValid()` que outros plugins consultam |
| `plugins.json` | repo `rodolpho.lopes/mindplace` no Forgejo | Catálogo do Mindplace |
| `secrets.php` | NÃO USAR no setup atual com Forgejo (era para PAT do GitHub) | — |
## Notas importantes
- **Forgejo não tem rate limit** — não precisa de token de autenticação. Repositórios são públicos
- **`License::isValid()` é zero-latency** — lê cache no banco, não bate em API. Pode ser chamado em cada page load sem custo
- **Cron de validação roda 1x/dia** — se o cliente quer validar agora, salvar a config do mindplace força o check imediato
- **Sem licença, sem prejuízo** — o kill switch é silencioso; o GLPI continua funcional sem o plugin, sem mensagens de erro