Política de Software Livre e limpeza do repositório

O que entra, o que sai e por quê — as regras FSDG aplicadas ao espelho GNUcego.

Sumário

1. Filosofia e o que a FSF recomenda 2. O que é (e o que não é) software livre 3. Os critérios FSDG aplicados 4. Por que Firefox, Thunderbird e Chromium saem 5. A parte jurídica das licenças 6. O script de limpeza (passo a passo) 7. Os substitutos livres 8. Licença desta documentação

1. Filosofia e o que a FSF recomenda

O GNUcego existe para ser uma distribuição 100% livre, seguindo as Free System Distribution Guidelines (FSDG) da Free Software Foundation. Isso significa algo mais estrito do que o que o Debian faz.

O Debian separa o software em main, contrib, non-free e non-free-firmware. A FSF considera que, para um sistema ser realmente livre, é preciso:

Este é o critério que guia o que entra e o que sai do repositório repo.gnucego.com.br.

Resumo: o Debian main é quase tudo livre, mas ainda contém pacotes que a FSF rejeita — por recomendarem não-livres ou por conterem firmware com licença restritiva. O GNUcego remove esses restantes.

2. O que é (e o que não é) software livre

As quatro liberdades essenciais definem software livre:

  1. Liberdade de executar o programa como quiser, para qualquer propósito (liberdade 0).
  2. Liberdade de estudar como o programa funciona e adaptá-lo (liberdade 1 — exige código-fonte).
  3. Liberdade de redistribuir cópias (liberdade 2).
  4. Liberdade de distribuir versões modificadas (liberdade 3).

Um pacote é não-livre quando uma dessas liberdades é negada — seja por licença, por firmware binário sem fonte, ou por induzir o usuário a software proprietário.

3. Os critérios FSDG aplicados

Tipo de problemaExemplosAção no GNUcego
Firmware/blob binário (licença que proíbe modificação)linux-firmware, intel-microcode, amd64-microcode, firmware Realtek/Intel Wi-FiRemovido (já fica fora por ser non-free-firmware no Debian)
Recomenda/baixa não-livrefirefox-esr (addons + codec H.264 da Cisco), thunderbird, chromium, command-not-found, hplip, snapd, boincRemovido
Licença de conteúdo restritiva (ex.: CMap da Adobe, MIB, Artistic 1.0)poppler-data, libsnmp-base, libsmi2-common, aee, afioRemovido
Jogos com arte/música mal licenciadafreedoom, simutrans, blobwars, mameRemovido
Instaladores de não-livresteam-installer, unetbootin, torbrowser-launcher, winetricksRemovido

4. Por que Firefox, Thunderbird e Chromium saem

Esta é a pergunta mais comum — afinal, o código deles é, em grande parte, livre. O motivo é o critério FSDG de "não recomendar/baixar não-livre":

A FSF recomenda o GNU IceCat (um Firefox com os pedaços não-livres removidos) no lugar do Firefox, e o Evolution (ou claws-mail/mutt) no lugar do Thunderbird. São exatamente os substitutos que o GNUcego adota.

5. A parte jurídica das licenças

As licenças definem legalmente o que você pode e não pode fazer com o código. O GNUcego só aceita software que respeite as quatro liberdades. As licenças recomendadas (do guia de licenças do GNU) são:

LicençaTipoCopyright-left?Observação
GPL v3 (GNU General Public License)copyleft forteSimUsada no kernel Linux-libre, no GNOME, no GIMP, no coreutils.
LGPL v3 (Lesser GPL)copyleft fracoParcialBibliotecas (permite linkar a código não-GPL).
AGPL v3 (Affero GPL)copyleft de redeSimPara software servidor (ex.: GNUnet, alguns serviços web).
FDL (GNU Free Documentation License)documentaçãoSimManuais GNU.
MIT / ExpatpermissivaNãoSimples, permite relicenciar em proprietário.
BSD (2/3 cláusulas)permissivaNãoIdem.
Apache 2.0permissiva + patenteNãoTem cláusula de patentes.
MPL 2.0 (Mozilla)copyleft por arquivoParcialLicença do Firefox/Thunderbird/IceCat.

Licenças não-livres que levam à remoção

Por que o copyleft importa: a GPL garante que as quatro liberdades se propaguem para quem receber o código (você não pode tirar a liberdade de ninguém). Já licenças permissivas (MIT/BSD) permitem que alguém transforme o código em software proprietário — por isso o GNU prefere o copyleft para seus projetos, mas aceita as permissivas no repositório.

6. O script de limpeza (passo a passo)

O script gnucego-repositorio-limpando.py (junto de gnucego-forbidden-packages.txt) é o mecanismo que remove os pacotes não-livres do espelho. Ele fica em /media/wellton/backup/debian/gnucego/.

Veja o código-fonte completo dos dois arquivos abaixo. Eles residem em /media/wellton/backup/debian/gnucego/.

6.0. O script gnucego-repositorio-limpando.py

#!/usr/bin/env python3
"""
gnucego-repositorio-limpando.py — Remove pacotes não-livres (FSDG) do espelho GNUcego.

Lê a lista de pacotes proibidos (gnucego-forbidden-packages.txt), remove os
arquivos .deb/.udeb correspondentes do pool e REGENERA os índices (Packages*)
filtrando as entradas proibidas, depois re-assina os Releases via fix-releases.py.

Uso:
  gnucego-repositorio-limpando.py [--dry-run] [--dist trixie,testing] [--no-sign]

  --dry-run   só lista o que seria removido, não altera nada.
  --no-sign   não roda o fix-releases.py no final (útil p/ testar).

Segurança:
  - Usa 'debmirror' é quem baixa o pool; aqui só REMOVEMOS.
  - Regenera o Packages mantendo os hashes dos pacotes que ficam.
  - Não toca no componente 'extra' (kernel linux-libre, icecat etc. são livres).
"""
import os
import sys
import gzip
import shutil
import subprocess
import glob
import re

MIRROR = "/media/wellton/backup/debian"
FORBIDDEN_LIST = os.path.join(MIRROR, "gnucego", "gnucego-forbidden-packages.txt")
DISTS = ("trixie", "testing")      # exu / ogum
ARCHES = ("binary-amd64", "binary-all")

DRY_RUN = "--dry-run" in sys.argv
NO_SIGN = "--no-sign" in sys.argv

# extrai --dist=... se presente (senão usa todos)


def parse_dists():
    for a in sys.argv:
        if a.startswith("--dist="):
            return tuple(a.split("=", 1)[1].split(","))
    return DISTS


def load_forbidden(path):
    """Retorna (exact_names, prefix_patterns)."""
    exact, prefix = set(), []
    if not os.path.isfile(path):
        print(f"ERRO: lista não encontrada: {path}")
        sys.exit(1)
    with open(path) as f:
        for line in f:
            line = line.strip()
            if not line or line.startswith("#"):
                continue
            if line.endswith("*"):
                prefix.append(line[:-1])
            else:
                exact.add(line)
    return exact, prefix


def is_forbidden(pkgname, exact, prefix):
    if pkgname in exact:
        return True
    for p in prefix:
        if pkgname.startswith(p):
            return True
    return False


def filter_packages_text(text, exact, prefix):
    """Remove os blocos de pacotes proibidos do texto de um Packages."""
    blocks = text.split("\n\n")
    kept = []
    removed = []
    for b in blocks:
        if not b.strip():
            continue
        m = re.search(r'^Package:\s*(\S+)', b)
        pkg = m.group(1) if m else None
        if pkg and is_forbidden(pkg, exact, prefix):
            removed.append(pkg)
        else:
            kept.append(b)
    return "\n\n".join(kept) + ("\n\n" if kept else ""), removed


def scan_pool_not_used():
    pass  # mantido por compatibilidade


def main():
    exact, prefix = load_forbidden(FORBIDDEN_LIST)
    print(f"Lista de proibidos: {len(exact)} exatos + {len(prefix)} prefixos")
    dists = parse_dists()

    total_removed_files = 0
    total_removed_entries = 0

    for dist in dists:
        for arch in ARCHES:
            pkgdir = os.path.join(MIRROR, "dists", dist, "main", arch)
            if not os.path.isdir(pkgdir):
                continue

            # --- 1) remover .deb/.udeb do pool referenciados por pacotes proibidos ---
            # Lê o Packages atual para saber o Filename de cada pacote proibido.
            for ext in ("Packages.gz", "Packages.xz", "Packages"):
                p = os.path.join(pkgdir, ext)
                if not os.path.isfile(p):
                    continue
                # ler texto
                if ext.endswith(".gz"):
                    with gzip.open(p, "rt", encoding="utf-8", errors="replace") as fh:
                        text = fh.read()
                elif ext.endswith(".xz"):
                    text = subprocess.run(["xz", "-dc", p], capture_output=True).stdout.decode("utf-8", "replace")
                else:
                    with open(p, encoding="utf-8", errors="replace") as fh:
                        text = fh.read()

                # coletar Filename dos proibidos (para remover do pool)
                for b in text.split("\n\n"):
                    if not b.strip():
                        continue
                    m = re.search(r'^Package:\s*(\S+)', b)
                    pkg = m.group(1) if m else None
                    if pkg and is_forbidden(pkg, exact, prefix):
                        fm = re.search(r'^Filename:\s*(\S+)', b, re.M)
                        if fm:
                            fp = os.path.join(MIRROR, fm.group(1))
                            if os.path.isfile(fp):
                                if DRY_RUN:
                                    print(f"[dry-run] removeria .deb: {fm.group(1)}")
                                else:
                                    try:
                                        os.remove(fp)
                                        total_removed_files += 1
                                        print(f"removido .deb: {fm.group(1)}")
                                    except OSError as e:
                                        print(f"  ERRO removendo {fp}: {e}")

        # --- 2) regenerar os Packages (filtrando) em cada arch ---
        for arch in ARCHES:
            pkgdir = os.path.join(MIRROR, "dists", dist, "main", arch)
            if not os.path.isdir(pkgdir):
                continue
            src = os.path.join(pkgdir, "Packages.gz")
            if not os.path.isfile(src):
                continue
            with gzip.open(src, "rt", encoding="utf-8", errors="replace") as fh:
                text = fh.read()
            new_text, removed = filter_packages_text(text, exact, prefix)
            if removed:
                total_removed_entries += len(removed)
                print(f"{dist}/{arch}: {len(removed)} entradas de pacote removidas do índice")
                if DRY_RUN:
                    continue
                # escrever Packages (uncompressed), .gz, .xz
                with open(os.path.join(pkgdir, "Packages"), "w", encoding="utf-8") as fh:
                    fh.write(new_text)
                with gzip.open(os.path.join(pkgdir, "Packages.gz"), "wt", encoding="utf-8") as fh:
                    fh.write(new_text)
                with open(os.path.join(pkgdir, "Packages.xz"), "wb") as fh:
                    fh.write(subprocess.run(["xz", "-c"], input=new_text.encode("utf-8"), capture_output=True).stdout)

    print(f"\nResumo: {total_removed_files} arquivo(s) .deb removidos, {total_removed_entries} entradas de índice regeneradas")

    if DRY_RUN:
        print("[dry-run] Nada foi alterado. Rode sem --dry-run para aplicar.")
        return

    # --- 3) re-assinar os Releases ---
    if not NO_SIGN:
        print("\nRe-assinando Releases (fix-releases.py)...")
        subprocess.run(["python3", "/usr/local/bin/fix-releases.py"])


if __name__ == "__main__":
    main()

6.0-bis. A lista gnucego-forbidden-packages.txt

# gnucego-forbidden-packages.txt
# Lista de pacotes e padrões que NÃO podem estar no repositório GNUcego,
# segundo as Free System Distribution Guidelines (FSDG) da FSF.
#
# Formato: um nome/padrão por linha. Linhas em branco e começando com # são ignoradas.
# Padrões com '*' no final são tratados como PREFIXO (ex.: "linux-firmware*" casa linux-firmware-*).
#
# Baseado em:
#   - LibrePlanet "List of software that does not respect the FSDG"
#   - purge-noble do Trisquel (ubuntu-purge)
#   - Análise do repositório GNUcego (nov/2026)
#
# IMPORTANTE: não mexa sem discutir — alguns removem pacotes inteiros,
# outros precisariam de "reempacotar" (ex.: remover só a menção a não-livre).

# ====================== NAVEGADORES / E-MAIL ======================
# FSDG: "Recomenda addons não-livres / baixa codec binário H.264 da Cisco"
# Substituo GNUcego: icecat (navegador) e evolution (e-mail).
firefox-esr
firefox-esr-l10n-*
firefox-esr-mobile-config
firefox-esr-l10n-all
thunderbird
thunderbird-l10n-*
thunderbird-bidiui
thunderbird-l10n-all
chromium
chromium-common
chromium-driver
chromium-l10n
chromium-headless-shell
chromium-sandbox
chromium-shell
chromium-lwn4chrome
chromium
firefox
iceweasel
iceape
seamonkey

# ====================== FIRMWARE NÃO-LIVRE / MICROCÓDIGO ======================
# IMPORTANTE: estes pacotes NÃO estão no 'main' do Debian — ficam em
# non-free/non-free-firmware, que o debmirror --section=main JÁ exclui.
# Listados aqui apenas como "fail-safe" (caso um dia o sync inclua non-free):
linux-firmware
firmware-linux-nonfree
intel-microcode
amd64-microcode
firmware-realtek
firmware-iwlwifi
firmware-amd-graphics
firmware-misc-nonfree
b43-fwcutter
bcm43xx-fwcutter
firmware-b43-installer
rtl8812au
rtl8821ce

# NOTA: NÃO remover os firmwares LIVRES que estão no main:
#   firmware-linux-free, firmware-ath9k-htc, firmware-carl9170, crust-firmware,
#   arm-trusted-firmware-tools, hackrf-firmware, nxt-firmware, ubertooth-firmware, etc.

# ====================== DRIVERS PROPRIETÁRIOS ======================
# NOTA: os drivers nvidia/ati PROPRIETÁRIOS NÃO estão no 'main' (ficam em
# non-free, já excluído). O único 'nvidia-*' no main é o nvidia-vaapi-driver,
# que é LIVRE (VA-API). Listados apenas como fail-safe:
nvidia-common
nvidia-driver
nvidia-graphics-drivers
nvidia-nsight
nvidia-prime
nvidia-profiler
nvidia-xconfig
fglrx

# ====================== FIRMWARE UPDATE (removido no Trisquel) ======================
fwupd
fwupd-signed
fwupdate
fwupdate-signed
gnome-firmware

# ====================== PACOTES QUE RECOMENDAM NÃO-LIVRE ======================
command-not-found
ubuntu-drivers-common
drivers-collector
software-center
software-properties-common
software-properties-gtk
snapd
snapd-xdg-open
gnome-software
gnome-software-common
gnome-software-plugin-deb
gnome-software-plugin-flatpak
gnome-software-plugin-snap

# ====================== INSTALADORES DE NÃO-LIVRE ======================
steam-installer
torbrowser-launcher
unetbootin
winetricks
testdrive
jockey

# NOTA: 'wine' em si é software livre (o Trisquel mantém no main). Decisão
# de removê-lo é opcional/polêmica — deixado de fora por padrão para não
# divergir do critério do Trisquel.

# ====================== EMULADORES/VM COM NÃO-LIVRE ======================
virtualbox
virtualbox-guest-additions-iso
virtualbox-guest-utils
virtualbox-dkms
virtualbox-ext-pack

# ====================== JOGOS COM CONTEÚDO NÃO-LIVRE ======================
freedoom
simutrans
teeworlds
blobwars
blobandconquer
starfighter
viruskiller
mame
mame-data
dosbox

# ====================== ÁUDIO/CODEC ======================
mp32ogg
# (lame/musepack/mpc ficaram livres após patentes expirarem — NÃO remover)

# ====================== LICENÇAS RESTRITIVAS (Artistic 1.0, MIB, CMap) ======================
aee
ee
afio
d4x
libsmi2-common
libsnmp-base
poppler-data
gs-cjk-resource
hplip
hplip-gui
nikto
rman
cracklib2

# ====================== FERRAMENTAS "NÃO-LIVRE-ONLY" ======================
ndiswrapper
ndisgtk
bnetd
pvpgn
cia-clients
vrms
xv
xchat
pdftk
acetoneiso
boinc
boinc-client
boinc-app-seti
konqueror
kopete
liferea
galeon
cacti
gkrellm-snmp
helix-player
jcadencii
scribus-doc
scribus-ng-doc

6.1. Como usar

# 1) Simular (não altera nada) — recomendado antes de qualquer mudança:
python3 gnucego-repositorio-limpando.py --dry-run

# 2) Aplicar de verdade:
python3 gnucego-repositorio-limpando.py

# 3) Aplicar sem re-assinar (útil p/ teste):
python3 gnucego-repositorio-limpando.py --no-sign

6.2. O que ele faz, em ordem

  1. Lê a lista de proibidos (gnucego-forbidden-packages.txt): nomes exatos e prefixos (prefixo-*).
  2. Localiza os arquivos .deb correspondentes no pool/main, para trixie (exu) e testing (ogum).
  3. Remove os .deb do pool.
  4. Regenera os índices Packages / Packages.gz / Packages.xz (filtrando as entradas proibidas, mantendo os hashes dos pacotes que ficam).
  5. Re-assina os Release/InRelease via fix-releases.py.

6.3. Segurança e cuidados

Dependências: remover firefox-esr/thunderbird/chromium não quebra o sistema, porque os metapacotes (gnome-core, cinnamon-desktop-environment) referenciam o navegador como Recommends ... | www-browser (com alternativa), e o IceCat já fornece (Provides:) www-browser, gnome-www-browser e firefox-esr. O Thunderbird também tem substituto (evolution fornece mail-reader).

7. Os substitutos livres

RemovidoMotivoSubstituto GNUcego
Firefox / Firefox ESRrecomenda não-livres + H.264 binárioGNU IceCat (via Trisquel)
Thunderbirdrecomenda não-livresEvolution (ou claws-mail / mutt)
Chromiumlicença incerta + pluginsIceCat
linux (kernel com blobs)firmware proprietárioGNU Linux-libre (via Freesh/FSFLA)
linux-firmwareblobs sem fontefirmwares livres do main (ath9k_htc, carl9170…)

Onde o GNUcego busca esses substitutos:

Outras fontes de software GNU (fora do Debian e do Trisquel) incluem o GNU Guix (o gerenciador de pacotes do projeto GNU, com 20.000+ pacotes), a Parabola, a Hyperbola e a PureOS — mas a maioria usa formatos de pacote diferentes (.pkg.tar, .scm), exceto a PureOS (.deb). Veja a seção de espelho para detalhes.

8. Licença desta documentação

Esta página, os scripts e a lista de proibidos são software livre/documentação livre: você pode usá-los e adaptá-los sob a GNU GPL v3 (código) e a GNU FDL 1.3 (documentação). A intenção é que qualquer distribuição livre possa reutilizar o método de limpeza FSDG do GNUcego.