5 KiB
| id | title | domain | tags | status | severity | created_at | updated_at | applies_to | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| KB-PLUGIN-017 | Bug do detector de wrapper directory no instalador Mindplace mutilava nomes de arquivos | plugin-dev |
|
active | high | 2026-05-21 | 2026-05-21 |
|
KB-PLUGIN-017 — Bug do detector de wrapper directory no instalador Mindplace
Contexto
O extrator de plugins do Mindplace (/home/glpi/glpi_dev/plugins/mindplace/ajax/marketplace.php) baixa o .zip da release do GitHub, detecta um "wrapper directory" no topo e remove esse prefixo dos demais entries antes de extrair para marketplace/<plugin>/.
Quando o ZIP de release de um plugin é gerado sem um wrapper directory consistente, a heurística antiga aceitava qualquer pasta top-level como wrapper e mutilava os paths de todos os outros entries.
Sintoma
A instalação via Mindplace completa "com sucesso" mas o GLPI marca o plugin como não-carregável silenciosamente. Listando o diretório de instalação aparecem arquivos com nomes truncados:
marketplace/mcprotocol/
├── .php ← deveria ser hook.php
├── .png ← deveria ser logo.png
├── p.php ← deveria ser setup.php
├── est.php ← deveria ser apirest.php
├── ic/ ← deveria ser public/
│ ├── index.php
│ └── logo.png
├── t/ ← deveria ser front/
└── Boot.php ← deveria ser src/Boot.php
O conteúdo dos arquivos está íntegro — apenas o nome do arquivo (caminho) foi mutilado.
Causa Raiz
A detecção em ajax/marketplace.php (versão buggy):
$first = $zip->getNameIndex(0);
$prefix = '';
if ($first !== false && str_ends_with($first, '/') && substr_count(rtrim($first, '/'), '/') === 0) {
$prefix = $first; // aceito como wrapper sem validar
}
A heurística aceitava como wrapper qualquer pasta top-level que fosse o primeiro entry do ZIP, mesmo que essa pasta não fosse realmente um wrapper (envelopando todos os demais).
Quando o ZIP do MCProtocol foi gerado pelo script bin/mindplace-release.sh (versão anterior, que fazia cd "$PLUGIN_DIR" && zip -r "$ZIP_PATH" . — sem wrapper directory), o primeiro entry era a pasta inc/ (top-level legítima do plugin). O extrator então removia 4 chars (inc/) do começo de todos os outros entries:
| Entry no ZIP | substr(_, 4) | Resultado em disco |
|---|---|---|
hook.php |
.php |
.php |
logo.png |
.png |
.png |
setup.php |
p.php |
p.php |
apirest.php |
est.php |
est.php |
public/ |
ic/ |
pasta ic/ |
public/index.php |
ic/index.php |
dentro de ic/ |
front/ |
t/ |
pasta t/ |
src/Boot.php |
Boot.php |
top-level |
inc/mcp.class.php |
mcp.class.php |
top-level |
Resolução (fix aplicado em maio/2026)
O detector agora valida que o candidato a wrapper é prefixo de todos os entries antes de aceitá-lo. Se algum entry não começar com o candidato, o prefix fica vazio e a extração preserva a estrutura original do ZIP.
// Detect common top-level wrapper directory.
// The wrapper is only valid if EVERY entry starts with it; otherwise a
// top-level folder like "inc/" would be mistaken for a wrapper and the
// substr() below would mutilate the remaining entries' paths.
$prefix = '';
$count = $zip->count();
$candidate = $count > 0 ? $zip->getNameIndex(0) : false;
if (
$candidate !== false
&& str_ends_with($candidate, '/')
&& substr_count(rtrim($candidate, '/'), '/') === 0
) {
$allMatch = true;
for ($i = 1; $i < $count; $i++) {
$name = $zip->getNameIndex($i);
if ($name === false || !str_starts_with($name, $candidate)) {
$allMatch = false;
break;
}
}
if ($allMatch) {
$prefix = $candidate;
}
}
Arquivo: /home/glpi/glpi_dev/plugins/mindplace/ajax/marketplace.php (linhas ~91-114).
Como diagnosticar uma instalação afetada
- Listar
/home/glpi/glpi_dev/marketplace/<plugin>/— se aparecerem arquivos com nomes começando por.(.php,.png), arquivos com nomes incompletos (p.php,est.php), ou pastas com nomes esquisitos (ic/,t/), o bug está presente. - Confirmar inspecionando o
.ziporiginal:unzip -l <plugin>.zip | head— se o primeiro entry não é um wrapper directory que contém todos os demais, o ZIP é vulnerável a esta versão do bug.
Como evitar (em plugins novos)
Gerar releases com wrapper directory consistente — ver KB-PLUGIN-018 para a workflow recomendada.
Veja também
- KB-PLUGIN-011 — Procedimento de release do Mindplace
- KB-PLUGIN-013 — Runbook de publicação de plugin no Mindplace
- KB-PLUGIN-018 — Convenção de wrapper directory para ZIPs de release