Satélite del pilar Escribir sobre calidad con evidencia. Cubre cómo publicar evidencia sin exponer secretos, PII ni datos sensibles. Etiquetas: HECHO, INFERENCIA, DECISIÓN, OPINIÓN.
Aviso de alcance: las referencias a PCI DSS, GDPR y BCRA delimitan jurisdicción y versión, y no constituyen asesoramiento legal ni de cumplimiento. Ante datos reales, consultá al equipo de seguridad/legal de tu organización.
El problema: la evidencia que te delata
El artículo pilar te pide publicar evidencia reproducible: comandos, reportes, capturas, configuración. INFERENCIA Justo ahí aparece el riesgo: la evidencia que hace creíble tu post es la misma que puede filtrar un token, una URL interna, un número de tarjeta o el correo de un cliente. Un dashboard de JMeter trae URLs completas; un .env “de ejemplo” trae una API key real; una captura de un test trae, en la esquina, el email de una persona.
[HECHO/OPINIÓN] Un secreto commiteado no se borra con un git commit posterior: queda en el historial y, en un repo público, puede haber sido clonado, indexado o cacheado en segundos. La regla operativa: tratá todo secreto que tocó un repo público como comprometido y rotalo.
Este satélite es la lista de control de seguridad y privacidad para que la fintech ficticia Nexo Finanzas —y tu portfolio— publiquen evidencia sin convertirse en un incidente.
Prerrequisitos y glosario
- Secreto: cualquier credencial que da acceso: token, API key, contraseña, cadena de conexión, clave privada, cookie de sesión.
- PII (Información Personal Identificable): datos que identifican a una persona: nombre, email, teléfono, documento, y —en pagos— PAN (número de tarjeta), CVV, etc.
- PAN / CHD: Primary Account Number y Cardholder Data, términos del universo de tarjetas de pago.
- Sanear (redact): eliminar o enmascarar datos sensibles de un artefacto antes de publicarlo.
- Artefacto: salida de una prueba: reporte HTML/XML, log,
.jtl, screenshot, traza.
Concepto: qué nunca se publica
Lista dura (el prompt del pilar la exige explícitamente):
| Nunca publicar | Por qué | Dónde suele filtrarse |
|---|---|---|
| Tokens, API keys, contraseñas | Acceso directo a sistemas | .env, configs, logs, capturas de terminal |
Archivos .env reales | Concentran secretos | Commit accidental; falta de .gitignore |
| URLs/endpoints internos | Mapa de superficie de ataque | Dashboards de carga, logs, HAR |
| PII | Privacidad y normativa | Screenshots, datos de fixtures, reportes |
| Datos bancarios reales (PAN/CVV) | Riesgo legal y de fraude | Fixtures “copiados de prod”, capturas |
| Reportes sin sanear | Mezclan todo lo anterior | Artefactos de CI subidos “tal cual” |
DECISIÓN La contramedida de fondo: usá siempre datos sintéticos para el contenido público (como hace toda esta colección con Nexo Finanzas). Si nunca hubo un dato real en tu fixture, no hay nada que filtrar. Para tarjetas de prueba, usá los números de test que publican los procesadores de pago (por ejemplo, los rangos de prueba documentados por Stripe u otros gateways), nunca un PAN real.
Concepto: el flujo de saneo antes de publicar
Tres compuertas, en orden: secretos → PII/URLs → tamaño/crudo. Nada se publica sin pasar las tres.
Implementación 1: prevenir el commit del secreto
.gitignore primero
DECISIÓN La prevención más barata es no rastrear lo que no debe versionarse:
# Secretos y entorno
.env
.env.*
!.env.example # el ejemplo SIN valores reales SI se versiona
*.pem
*.key
secrets/
# Artefactos crudos y pesados de pruebas
results/*.jtl
report/ # dashboards HTML de JMeter/k6 (pueden traer URLs)
*.har # capturas de red: casi siempre traen tokens/PII
screenshots/raw/ # capturas sin sanear
Explicación por bloque:
.env.*se ignora, pero!.env.examplese incluye: versioná una plantilla con claves sin valores (API_KEY=), para que otro sepa qué variables necesita sin recibir tus secretos.report/,*.jtl,*.har: los artefactos crudos se ignoran por defecto; se publica un resumen saneado (ver más abajo), no el crudo.
Escaneo automático de secretos
HECHO Existen escáneres de secretos open source de uso extendido: gitleaks (github.com/gitleaks/gitleaks) y TruffleHog (github.com/trufflesecurity/trufflehog). GitHub, además, ofrece secret scanning nativo en sus repos (docs de GitHub secret scanning). Verificá el estado y las opciones vigentes al configurarlo.
Hook de pre-commit para frenar el secreto antes de que entre al historial:
# .pre-commit-config.yaml (framework pre-commit)
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: <tag-vigente> # fijá un tag; verificá el vigente al instalar
hooks:
- id: gitleaks
# Instalación local y ejecución sobre TODO el historial (no solo el diff)
pip install pre-commit
pre-commit install # activa el hook en cada commit
gitleaks detect --source . --redact # --redact oculta el valor en el output
Explicación:
pre-commit installhace que el escaneo corra en cada commit: un secreto detectado aborta el commit.gitleaks detect ... --redactescanea el historial completo y oculta el valor del secreto en su propio reporte (para no filtrarlo en los logs de CI).- INFERENCIA Ponelo también como job de CI: la máquina no se olvida de correrlo, la persona sí.
Si ya commiteaste un secreto: HECHO eliminarlo del último commit no basta; sigue en el historial. Hay que rotar la credencial (invalidarla en el proveedor) y reescribir el historial (por ejemplo con
git filter-repo, git-filter-repo). Rotar primero; limpiar el historial después.
Implementación 2: sanear PII y URLs en artefactos
Cuando el artefacto ya existe y necesitás publicar una parte:
Capturas de pantalla
- DECISIÓN Recortá antes de subir: la barra de URL, los emails, los nombres reales, los IDs internos. INFERENCIA El enmascarado con un rectángulo negro encima en algunos editores no borra el pixel subyacente si se guarda mal; preferí recortar (crop) o repintar la zona y reexportar el PNG, no superponer una forma en un PDF/SVG editable.
- Reemplazá datos por sintéticos legibles:
cliente@ejemplo.test,Ana Prueba,**** **** **** 4242.
Logs y reportes de texto
Un sed puede enmascarar patrones antes de versionar un resumen (ejemplo ilustrativo, ajustá los patrones a tus datos):
# Enmascara emails y (fragmentos tipo) PAN en un log antes de publicar un extracto.
# Revisar SIEMPRE la salida a mano: una regex no captura todo.
sed -E \
-e 's/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/<email>/g' \
-e 's/\b[0-9]{13,19}\b/<pan-enmascarado>/g' \
results/run.log > results/run.public.log
Explicación y límite importante:
- La primera regla enmascara emails; la segunda, secuencias largas de dígitos (posibles PAN).
- [OPINIÓN/advertencia] Una regex no es un saneador completo: no entiende contexto, no captura formatos partidos ni datos en campos codificados. Usala como primer filtro y revisá el resultado a ojo antes de publicar. Nunca confíes el saneo de datos regulados únicamente a un
sed.
Implementación 3: resumen versionado vs. artefacto pesado
DECISIÓN Diferenciá qué va al repositorio:
| Artefacto | ¿Versionar en el repo? | Alternativa |
|---|---|---|
| Reporte resumido y saneado (tabla de percentiles, veredicto) | Sí — es liviano, legible en diff y es la evidencia que respalda el post | — |
| Dashboard HTML crudo de JMeter/k6 (MBs, con URLs) | No | Publicar el resumen; guardar el crudo fuera del repo público |
.jtl / .har crudos, videos de e2e | No | Artifact store del CI con retención/acceso controlado |
| Datasets grandes | No (hincha el repo y su historial para siempre) | Almacenamiento de artefactos o Git LFS, según sensibilidad |
HECHO En pipelines, la forma correcta de manejar reportes es declararlos como reports del CI, que la plataforma parsea y expone de forma controlada. En GitLab, por ejemplo, artifacts:reports soporta junit, coverage_report (Cobertura/JaCoCo), codequality, sarif (SARIF 2.1.0) y otros; y esos artefactos se suben siempre, aun si el job falla. Fuente primaria: GitLab — CI/CD artifacts reports types.
# .gitlab-ci.yml — publica el reporte JUnit de forma estructurada,
# en vez de subir el dashboard crudo al repo.
test:
stage: test
script:
- npm test -- --reporter junit --output report/junit.xml
artifacts:
when: always # se sube aun si el job falla (util para evidencia)
reports:
junit: report/junit.xml
expire_in: 30 days # retencion acotada; no eternizar artefactos
Explicación:
reports:junitdeja que GitLab parse y muestre los resultados en la UI del MR, sin que subas HTML pesado al repo.when: alwaysconserva la evidencia incluso cuando el test rojo es justamente lo que querés mostrar (resultado negativo honesto, como en el satélite de experimentos).expire_inevita acumular artefactos indefinidamente.
Verificación: etiquetá la naturaleza de la integración
El pilar exige declarar si un resultado es simulado, con trial, local o productivo. DECISIÓN Poné una etiqueta visible en cada pieza de evidencia:
SIMULADO: mock/stub, ningún sistema real detrás.TRIAL: cuenta de prueba de un tercero (sandbox del gateway, plan free).LOCAL: tu máquina/Docker, sin datos ni infraestructura productiva.PRODUCTIVO: rara vez debería publicarse; solo con datos sintéticos y aprobación.
INFERENCIA Esta etiqueta protege dos cosas: la seguridad (nadie confunde tu laptop con prod) y la honestidad (nadie cree que probaste en prod cuando probaste en local).
Nota de cumplimiento (delimitada y sin asesoramiento legal)
Aviso: lo siguiente ubica jurisdicción y versión de algunos marcos; no es asesoramiento legal ni de cumplimiento. Verificá siempre la versión vigente en la fuente oficial y consultá a tu equipo legal/seguridad.
- PCI DSS (tarjetas de pago) — administrado por el PCI Security Standards Council; la familia vigente es la v4.x. HECHO El PAN, el CVV y demás cardholder data están sujetos a requisitos estrictos de protección; publicarlos es incompatible con el estándar. Fuente oficial: PCI SSC — Document Library. (Alcance: aplica a entidades que almacenan/procesan/transmiten datos de tarjeta; verificá la versión vigente el día que lo cites.)
- GDPR (protección de datos, UE) — Reglamento (UE) 2016/679. HECHO Regula el tratamiento de datos personales de personas en la UE; publicar PII sin base legal es un riesgo. Fuente oficial: EUR-Lex — Reglamento 2016/679. (Alcance: jurisdicción de la UE/EEE.)
- BCRA (Argentina) — el Banco Central de la República Argentina emite normativa para el sistema financiero argentino. INFERENCIA Si tu portfolio simula una fintech argentina, mencioná el marco pero no cites números de comunicación de memoria: remití a la fuente oficial y aclarante que es contexto ficticio. Fuente oficial: bcra.gob.ar. (Alcance: jurisdicción argentina.)
- OWASP API Security Top 10 (2023) — estándar de facto de riesgos de API; útil para razonar qué exponés en endpoints de evidencia. Fuente: OWASP API Security.
Límites y trade-offs
- OPINIÓN El saneo perfecto no existe: siempre podés omitir un dato en una esquina de una captura. Por eso la mejor defensa es no tener datos reales en el material público, no confiar en enmascararlos después.
- Menos crudo publicado = menos reproducibilidad literal. Al publicar resúmenes en vez de artefactos crudos, sacrificás algo de reproducibilidad exacta. DECISIÓN Es un trade-off correcto: describís cómo regenerar el crudo (comando + entorno) en vez de exponerlo.
- Los escáneres tienen falsos negativos. gitleaks/TruffleHog no detectan todo; son una red, no una garantía.
Anti-patrones (causa → consecuencia → alternativa)
-
Subir el reporte “tal cual”. Causa: comodidad. Consecuencia: URLs internas, tokens y PII en un repo público. Alternativa: las tres compuertas (secretos → PII → resumen) antes de publicar.
-
Enmascarar con un rectángulo encima en un formato editable. Causa: creer que taparlo es borrarlo. Consecuencia: el dato sigue debajo y se recupera. Alternativa: recortar/repintar el pixel y reexportar.
-
“Borré el secreto en el commit siguiente”. Causa: desconocer cómo funciona Git. Consecuencia: el secreto sigue en el historial y probablemente ya fue clonado. Alternativa: rotar la credencial + reescribir historial.
-
.envreal “de ejemplo” versionado. Causa: copiar el.envde trabajo. Consecuencia: filtración directa. Alternativa:.env.examplecon claves vacías +.enven.gitignore. -
Fixtures con datos “copiados de producción”. Causa: atajo para tener datos “realistas”. Consecuencia: PII/PAN reales en el repo. Alternativa: datos sintéticos y números de tarjeta de prueba oficiales del gateway.
Conexión accionable con Nexo Finanzas
SECURITY.md # qué reportar, qué nunca publicar, cómo rotar
.gitignore # .env, artefactos crudos, capturas sin sanear
.pre-commit-config.yaml # gitleaks como hook
evidence/
README.md # SOLO resúmenes saneados + etiqueta (LOCAL/TRIAL/...)
docs/runbooks/
sanitize-evidence.md # pasos para sanear capturas y reportes
.env.example # plantilla sin valores
Acciones:
- Creá
SECURITY.mdcon: qué no se publica, cómo reportar una filtración, y el procedimiento de rotación de credenciales. - Activá gitleaks como pre-commit y como job de CI.
- Escribí
docs/runbooks/sanitize-evidence.mdcon la checklist de saneo, y exigí enCONTRIBUTING.mdque toda evidencia pase por él.
Qué aprendimos / próximos pasos
- La evidencia que da credibilidad es también la que puede filtrar datos: publicá con tres compuertas (secretos → PII/URLs → resumen vs. crudo).
- La defensa de fondo es usar datos sintéticos: si nunca hubo un dato real, no hay filtración posible.
- Un secreto que tocó un repo público se considera comprometido: rotá primero, limpiá el historial después.
- Versioná resúmenes saneados, no dashboards crudos; usá el report del CI para los artefactos estructurados.
Continuá con:
- El pilar para integrar el saneo al flujo editorial de la semana.
- El satélite de experimentos: aplicá el saneo a los reportes de JMeter/k6.
- El satélite de ADR: al publicar capturas de tu suite, saneá antes.
Checklist final
-
.gitignorecubre.env*,*.pem/*.key, artefactos crudos y capturas sin sanear. - Hay escaneo de secretos en pre-commit y en CI.
- Si hubo un secreto commiteado, se rotó la credencial y se limpió el historial.
- Toda captura/reporte pasó por saneo (recorte real, no rectángulo encima).
- Los datos son sintéticos; las tarjetas usan números de prueba oficiales.
- Se publica el resumen saneado, no el dashboard/
.jtl/.harcrudo. - Cada evidencia lleva etiqueta: SIMULADO / TRIAL / LOCAL / PRODUCTIVO.
- Las menciones a PCI DSS/GDPR/BCRA delimitan versión y jurisdicción y aclaran que no son asesoramiento legal.
- Existe
SECURITY.mdcon procedimiento de reporte y rotación.
Nota de veracidad: Nexo Finanzas y todos sus datos son ficticios. Las herramientas (gitleaks, TruffleHog, git-filter-repo) y los marcos (PCI DSS v4.x, GDPR 2016/679, BCRA, OWASP API Security 2023) fueron ubicados contra fuentes oficiales el 2026-07-09; verificá versión y vigencia antes de publicar. Este artículo no es asesoramiento legal ni de cumplimiento.