# Linux

El camino completo en Linux: el archivo correcto, la firma, el PATH, un servicio y compilarlo tú mismo.

Source: https://docs.jmrp.io/ghchronicle/es/install/linux/

Un único binario estático, `CGO_ENABLED=0`, así que no hay librería de C que
instalar ni distribución con la que cuadrar. Un archivo de release y una
entrada en el `PATH` es toda la instalación; lo que hay debajo va de hacerlo a
conciencia.

## La instalación en una línea

```sh
curl -fsSL https://raw.githubusercontent.com/jmrplens/ghchronicle/main/install.sh | bash
```

Deduce la arquitectura, coge la release más nueva, comprueba el archivo contra
la suma de verificación que esa release publicó, y deja el binario en
`/usr/local/bin` si tiene permiso de escritura. Si no lo tiene, coge el primero
de `~/.local/bin` y `~/bin` que exista y ya esté en tu `PATH`, y recurre a
`~/.local/bin` cuando no lo está ninguno. Una suma que no cuadra lo detiene sin
instalar nada, y no hay opción para saltarse ese paso. Si `cosign` 2.4.2 o
posterior ya está en la máquina, verifica además que el propio fichero de sumas
viene del workflow de release, y una firma que cosign no confirma lo detiene,
con lo que dijo cosign. Un cosign más antiguo no sabe leer el bundle de la
firma, así que entonces, como sin cosign, dice que solo se verificó la suma.
Termina ejecutando lo que ha instalado, así que la versión que ves
es la del fichero recién escrito, y avisa cuando otro `ghchronicle` anterior en
tu `PATH` sigue ganando el nombre.

Fijar una versión, o elegir dónde va:

```sh
curl -fsSL https://raw.githubusercontent.com/jmrplens/ghchronicle/main/install.sh | VERSION=2.6.5 BIN_DIR=~/bin bash
```

> **Leerlo antes es justo para lo que sirve que sea corto**
>
> Meter cualquier cosa por una tubería a un shell es ejecutar lo que esa URL
> responda hoy. `curl -fsSL <url> -o install.sh`, léelo, y luego
> `bash install.sh`: es el mismo script, y es lo bastante corto para leerlo.

El resto de esta página es esa misma instalación hecha a mano, que es lo que
seguir cuando quieres saber exactamente qué ha aterrizado dónde, o cuando
prefieres no ejecutar un script que no has escrito.

## Elegir el archivo

Los archivos de release se llaman
`ghchronicle_<versión>_linux_<arq>.tar.gz`, donde `<arq>` es `amd64` o
`arm64`. `uname -m` dice cuál.

| Lo que dice `uname -m` | El archivo que toca |
| ---------------------- | ------------------- |
| `x86_64`               | `linux_amd64`       |
| `aarch64`              | `linux_arm64`       |

```sh
VERSION=2.6.5
arch=$(uname -m); case "$arch" in x86_64) arch=amd64 ;; aarch64) arch=arm64 ;; esac
base=https://github.com/jmrplens/ghchronicle/releases/download/v$VERSION
curl -fsSLO "$base/ghchronicle_${VERSION}_linux_${arch}.tar.gz"
```

> **Nombra la versión en vez de pedir la más nueva**
>
> El repositorio publica una etiqueta mayor móvil junto a las releases
> numeradas, porque la Action está listada en el Marketplace y ese listado
> necesita una. La release de esa etiqueta **no lleva ningún fichero**, así que
> nunca construyas una URL de descarga a partir de la etiqueta mayor: detrás no
> hay nada que descargar. Coge la versión de la
> [página de releases](https://github.com/jmrplens/ghchronicle/releases) y
> escríbela, como arriba.

## Comprobar lo que has descargado

Junto a los archivos se publican dos ficheros: `checksums.txt`, que lleva el
SHA-256 de cada archivo, y `checksums.txt.sigstore.json`, que es una firma
sobre ese fichero. La cadena es entonces una firma y un resumen: verifica el
fichero y luego verifica el archivo contra el fichero.

1. Coge el fichero de sumas y su firma.

    ```sh
    curl -fsSLO "$base/checksums.txt"
    curl -fsSLO "$base/checksums.txt.sigstore.json"
    ```

2. Comprueba el archivo contra él. `--ignore-missing` es lo que permite
   comprobar una línea de un fichero de doce sin tener los otros once
   archivos.

    ```sh
    sha256sum --ignore-missing -c checksums.txt
    ```

    ```text
    ghchronicle_2.6.5_linux_amd64.tar.gz: OK
    ```

3. Comprueba el propio fichero de sumas, si tienes
   [cosign](https://docs.sigstore.dev/cosign/system_config/installation/)
   2.4.2 o posterior. Uno más antiguo no sabe leer el bundle y falla diga lo
   que diga el fichero.

    ```sh
    cosign verify-blob \
      --certificate-identity-regexp 'https://github.com/jmrplens/ghchronicle/.github/workflows/release.yml@refs/tags/.*' \
      --certificate-oidc-issuer https://token.actions.githubusercontent.com \
      --bundle checksums.txt.sigstore.json \
      checksums.txt
    ```

    ```text
    Verified OK
    ```

La firma es sin claves: no hay clave pública que buscar ni clave privada que
nadie pueda perder, porque la identidad que se verifica es el workflow que se
ejecutó, anotado en un registro público de transparencia. Eso es lo que dicen
las dos opciones `--certificate`, y por eso no son opcionales: sin ellas cosign
confirmaría que alguien firmó el fichero, que no es la pregunta.

Después deja que escriba la configuración:

```sh
ghchronicle -setup
```

Pide un token y dónde van los números, comprueba cada respuesta contra aquello
que nombra, y escribe un `config.yaml` y, si lo quieres, una unidad de systemd.
El instalador de arriba lo ofrece como último paso.

## Ponerlo en el PATH

El archivo lleva tres ficheros y ningún directorio, así que descomprímelo donde
quieras de verdad.

- ghchronicle_VERSION_linux_ARCH.tar.gz
  - ghchronicle el binario
  - LICENSE
  - README.md

- **Para todos**

  ```sh
  tar -xzf "ghchronicle_${VERSION}_linux_${arch}.tar.gz" ghchronicle
  sudo install -m 755 ghchronicle /usr/local/bin/
  ghchronicle -version
  ```

- **Para una cuenta**

  ```sh
  mkdir -p ~/.local/bin
  tar -xzf "ghchronicle_${VERSION}_linux_${arch}.tar.gz" -C ~/.local/bin ghchronicle
  chmod 755 ~/.local/bin/ghchronicle
  ghchronicle -version
  ```

  `~/.local/bin` ya está en el `PATH` de la mayoría de distribuciones. Si
  `ghchronicle -version` responde «orden no encontrada», en la tuya no lo
  está.

`-version` responde con una línea: el número de la versión, y después el
commit y la fecha de compilación de esa versión.

```text
ghchronicle 2.6.5 (commit <commit>, built <date>)
```

## Ejecutarlo una vez

El binario necesita un fichero de configuración y un token, y
[el inicio rápido](https://docs.jmrp.io/ghchronicle/es/start/quickstart/) escribe los dos en seis
pasos. Con eso hecho:

```sh
ghchronicle -config config.yaml -list   # qué se recogería
ghchronicle -config config.yaml -once   # una pasada y termina
```

## Dejarlo corriendo

[systemd](https://docs.jmrp.io/ghchronicle/es/install/systemd/) es el montaje que esta
documentación toma por omisión en Linux, y la unidad de ahí está blindada en
vez de ser mínima, porque este es con mucha probabilidad el único proceso de la
máquina que guarda un token de GitHub con acceso de lectura a todos los
repositorios de una cuenta. Un servicio que arranca sobre un fichero de estado
que nadie ha escrito aún trae sus once familias de seis horas o más al almacén
a lo largo de sus dos primeras horas y media, una por pasada, y solo esa vez;
la página de systemd explica por qué.

Un planificador también vale:
[cron con `-once`](https://docs.jmrp.io/ghchronicle/es/install/systemd/#cron-en-vez-de-un-servicio)
es una sola línea, a cambio de dar a todas las familias la misma cadencia.

## Compilarlo desde fuente

Go 1.27.2 o más nuevo es lo que declara el módulo. No hace falta nada más: la
compilación fija `CGO_ENABLED=0`, así que no hay compilador ni paquete de
cabeceras que encontrar.

- **go install**

  ```sh
  go install github.com/jmrplens/ghchronicle/v2/cmd/ghchronicle@latest
  ```

  Cae en `$(go env GOPATH)/bin`, que es `~/go/bin` salvo que lo hayas
  movido, y ese directorio tiene que estar en tu `PATH`.

  Un binario hecho así no tiene commit ni fecha de compilación de los que
  informar: esas dos las sella la compilación de release y nada más, y un
  módulo descargado por el proxy no lleva copia de trabajo de donde leerlas.
  `-version` nombra en su lugar lo que la compilación sí registra, la versión
  del módulo que descargó la orden go y la versión de Go que lo compiló:

  ```text
  ghchronicle 2.6.5 (module v2.6.5, built with <go version>)
  ```

  La primera versión sale del fichero `VERSION` que el módulo incrusta.

- **make**

  ```sh
  git clone https://github.com/jmrplens/ghchronicle
  cd ghchronicle
  make build      # a bin/ghchronicle
  make install    # a GOBIN, sellado como una compilación de release
  ```

  `make build` sella la versión, el commit corto y la fecha del commit, así
  que `-version` dice exactamente de qué árbol viene. `make` sin objetivo
  lista todos los que hay.

## Dónde van los ficheros

El colector no busca el fichero de configuración en ningún sitio concreto:
`-config` vale por omisión `config.yaml` **relativo al directorio de trabajo**,
y detrás no hay ninguna ruta de búsqueda. Así que la ruta es una decisión que
tomas una vez y luego pasas en cada invocación. Lo que asume el resto de esta
documentación:

| Fichero            | Ruta                               | Modo                              |
| ------------------ | ---------------------------------- | --------------------------------- |
| Configuración      | `/etc/ghchronicle/config.yaml`     | legible por todos, sin secretos   |
| Tokens             | `/etc/ghchronicle/ghchronicle.env` | `600`                             |
| Estado, registro, caché | `/var/lib/ghchronicle/`       | lo escribe el usuario del servicio |

`state_file` tiene un valor por omisión propio, `ghchronicle-state.json` en el
directorio de trabajo, con el registro de escrituras al lado como
`ghchronicle-state-written.bin` y la caché como `ghchronicle-state-cache.bin`.
Ese valor está bien para una primera prueba en un directorio que hayas hecho tú,
y mal para un servicio, cuyo directorio de trabajo no es algo en lo que
apoyarse. Ponlo.
