airvzxf / airvzxf/ftp-deployment-action
test(integration): INPUT_MAX_RETRIES=3 enmascara flake de lftp AUTH TLS sin diagnosticar la causa raíz
- Dominant language
- Shell
- Stars
- 37
- Forks
- 9
- Avg merge
- 44m
- Merged PRs (30d)
- 47
Description
## Summary
Durante la investigación de #135 se encontró un segundo modo de falla (Mode B) distinto al `apk add` race: el handshake TLS AUTH entre vsftpd Alpine 3.24 y lftp 4.9.3 OpenSSL 3.x falla transientemente, y `lftp` sale con código 1 en el primer intento. Como defensa contra este flake, el PR de #135 bumpea `INPUT_MAX_RETRIES=1` a `INPUT_MAX_RETRIES=3` en los escenarios 03 y 04. El bump hace el test menos estricto y puede enmascarar bugs reales sin diagnosticar la causa raíz.
## Archivos afectados
- `tests/integration/scenarios/03-ftps-explicit-upload.sh:89`
- `tests/integration/scenarios/04-ftps-implicit-upload.sh:83`
Ambos ahora pasan `INPUT_MAX_RETRIES=3` en vez de `INPUT_MAX_RETRIES=1`.
## Observación Mode B
Run CI [`33705252859`](https://github.com/airvzxf/ftp-deployment-action/actions/runs/33705252859) (mismo run que destapó el Mode A de #135) tuvo también un fallo de lftp en el primer intento del escenario 04:
```
[DEBUG lftp] ---> AUTH TLS
<--- 234 AUTH TLS OK.
[SSL negotiation...]
lftp: error: Fatal error: TLS handshake failure
```
El error es de handshake TLS — lftp 4.9.3 OpenSSL 3.x contra vsftpd Alpine 3.24. En retry (con el `INPUT_MAX_RETRIES=3` que pusimos como defensa), el mismo escenario pasó. No hay aserción sobre `Try #1` que pueda distinguir "el primer intento falló pero los retries lo recuperaron" de "el primer intento funcionó".
## Por qué es un problema
`INPUT_MAX_RETRIES=3` es un setting de producción del action (los usuarios lo ven y lo setean). Bumpearlo en los tests para defense-in-depth significa:
1. **El test ya no detecta regresiones reales de lftp-vs-vsftpd.** Si una nueva versión de lftp introduce un TLS bug que solo se manifiesta en el primer intento, el test pasa gracias al retry y nunca lo vemos.
2. **El test no diagnostica la causa raíz.** No hay log que diga "Try #1 falló por X, Try #2 pasó". El operador que vea el fallo tiene que adivinar.
3. **Mode B sugiere un problema del servidor, no del cliente.** El flake se manifiesta en `vsftpd` con `ssl_ciphers=HIGH:MEDIUM:!DHE:!DH` y `seccomp_sandbox=NO`. Vale la pena investigar si la combinación de cipher list + sandbox disabled es lo que hace que el primer handshake falle mientras que los retries pasen (probable: race entre init del sandbox y accept del primer cliente).
## Suggested fix
Tres pasos en orden de preferencia:
### A. Restaurar `INPUT_MAX_RETRIES=1` y abrir issue específico de Mode B
Si Mode B no reaparece en 5 corridas consecutivas post-merge de #135, restaurar `INPUT_MAX_RETRIES=1` en los escenarios 03 y 04. Esto devuelve el rigor al test.
### B. Investigar el path TLS entre vsftpd Alpine 3.24 y lftp 4.9.3 OpenSSL 3.x
Hipótesis a validar:
- ¿El cipher list `HIGH:MEDIUM:!DHE:!DH` fuerza un cipher que OpenSSL 3.x tarda en negociar la primera vez pero negocia rápido en los retries?
- ¿`seccomp_sandbox=NO` es la causa del primer-fail? ¿Activar `seccomp_sandbox=YES` cambia el comportamiento?
- ¿Es un bug específico de la versión de vsftpd Alpine 3.24? ¿Bajar a 3.23 (alineado con la del action image) lo elimina?
- ¿Es un bug específico de lftp 4.9.3 OpenSSL 3.x? ¿Forzar lftp 4.9.2 (GnuTLS) lo elimina?
### C. Añadir aserción sobre `Try #1` y `Try #N`
Independientemente del path A o B, los tests deberían poder distinguir "pasó al primer intento" de "pasó tras N retries". El output de la action incluye líneas como `::group::Mirror attempt 1/3` que se pueden grepear:
```sh
# Cerca del final del escenario
assert_log_contains "Mirror attempt 1/N" "${WORK_DIR}/action.log" \
|| log_fail "Expected 'Mirror attempt 1/N' in log, got retries only"
```
Si la aserción falla, el test falla con un mensaje claro en vez de pasar silenciosamente gracias al retry.
## Acceptance criteria
1. Si Mode B no reaparece post-#135, `INPUT_MAX_RETRIES=1` restaurado en escenarios 03 y 04.
2. Si Mode B reaparece, hay un issue específico de Mode B abierto con hipótesis (A/B/C de arriba) validadas o refutadas.
3. Los escenarios 03 y 04 tienen una aserción que falla si el primer intento del action falla (independientemente del retry que lo recupere).
4. CI 7/7 verde.
## Out of scope
Este cambio es independiente del fix de #135 — son archivos distintos y la investigación de Mode B es open-ended. El PR que cierra #135 deja `INPUT_MAX_RETRIES=3` como defense temporal y este issue es para tracking del seguimiento.
Si el contributor decide abordar Mode B en un PR futuro, no es bloqueante para merge de #135 (los tests pasan con `INPUT_MAX_RETRIES=3`). Pero sí es bloqueante para v2.11.x: queremos rigor en los tests antes de cortar el próximo release candidate.
## Related
- PR: https://github.com/airvzxf/ftp-deployment-action/pull/139
- Original investigation: #135 (Mode A: `apk add` race)
- Sister issues: #136 (`lftp_run_script` latente), #137 (`smoke.sh` latente)
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.