OpenCyber Academy
Grado · Capítulo 3 · Español
Código del curso: OCA-115Capítulo 03: OCA-115-C003

Capítulo 3 — Programación I

Aprendizaje gratuito y abierto para quienes desean proteger a las personas y la tecnología. No se necesita una cuenta para estudiar ni consultar las respuestas.

Mapa de la lección

Lección 03 publicada. Mapa, ejemplo, EX005.

flowchart TD
  N0["Resultados de aprendizaje y conexión"]
  N1["3.1 Por qué programa un estudiante de seguridad"]
  N2["3.2 Las construcciones básicas"]
  N3["3.4 Actividad práctica"]
  N4["Síntesis del capítulo"]
  N0 --> N1 --> N2 --> N3 --> N4
  N4 --> EX["Ejemplo resuelto"]
  EX --> Q["Ejercicio EX005"]

Dibujo lógico

flowchart LR
  N0["Resultados de aprendizaje y conexión"]
  N1["3.1 Por qué programa un estudiante de seguridad"]
  N2["3.2 Las construcciones básicas"]
  N3["3.4 Actividad práctica"]
  N4["Síntesis del capítulo"]
  N0 --> N1 --> N2 --> N3 --> N4 --> Q["EX005"]
[Resultados de aprendizaje y conexión]
    |
    v
[3.1 Por qué programa un estudiante de seguridad]
    |
    v
[3.2 Las construcciones básicas]
    |
    v
[3.4 Actividad práctica]
    |
    v
[Síntesis del capítulo]
    |
    v
[Ejemplo resuelto] --> [Ejercicio EX005]

Resultados de aprendizaje y conexión

Después de este capítulo usted podrá (1) escribir programas breves en Python con variables, condiciones, bucles, funciones, listas y diccionarios; (2) leer texto estructurado (CSV) con la biblioteca estándar; (3) convertir una pregunta sobre un sistema («¿qué dispositivos han superado el fin de su soporte?») en un filtro, un recuento y un informe; y (4) probar un programa con un caso pequeño cuya respuesta ya conoce. Se apoya en el ciclo de vida de los dispositivos del capítulo 2 y prepara el capítulo 8, en el que los programas se vuelven robustos frente a entradas defectuosas.

3.1 Por qué programa un estudiante de seguridad

El trabajo de seguridad en los servicios críticos consiste sobre todo en saber qué se tiene y en advertir qué ha cambiado. Ambas cosas exigen procesar datos: inventarios con miles de filas, registros con millones de líneas, avisos publicados a diario. Una hoja de cálculo sirve para cincuenta filas; un programa breve sirve para cincuenta mil y puede volver a ejecutarse mañana. Aquí se usa Python porque su biblioteca estándar lee CSV, JSON, fechas y bases de datos sin instalar nada, y porque el código legible es más fácil de revisar, una propiedad que importa cuando su resultado informa una decisión sobre la seguridad de los pacientes.

3.2 Las construcciones básicas

Una variable da nombre a un valor (year = 2026). Una condición elige entre caminos (if eos < year:). Un bucle repite el trabajo para cada elemento (for row in rows:). Una función empaqueta un paso con un nombre y unas entradas para poder probarlo por separado. Una lista contiene elementos en orden; un diccionario asocia claves con valores (row["os"]). El módulo csv convierte cada línea de un archivo CSV en un diccionario cuyas claves son las del encabezado. La clase collections.Counter cuenta cuántas veces aparece cada valor. Con esto se puede responder a la mayoría de las preguntas sobre un inventario.

Dos disciplinas importan desde el principio. Primero, pruebe con una respuesta conocida: antes de ejecutar sobre el archivo real, ejecute sobre cinco filas que comprobó a mano. Segundo, imprima lo que excluyó, no solo lo que encontró: un filtro que descarta en silencio las filas con la fecha en blanco informará de «ningún dispositivo sin soporte» precisamente para los dispositivos que nadie documentó.

3.3 Ejemplo resuelto y Lab 2: clasificación del inventario del CVH (sintético)

Este caso es sintético. El equipo de ingeniería clínica del CVH exporta una muestra de ocho filas de su inventario de dispositivos. La pregunta: ¿qué dispositivos ejecutan software que ha superado el fin de su soporte, dónde están y hay algún dispositivo no clínico en la red clínica?

# Lab 2 - triage a synthetic hospital device inventory with the standard library (offline)
import csv, io
from collections import Counter
DATA = """asset,type,os,os_end_of_support,network,clinical
INF-01,infusion pump,RTOS-x 2.1,2030,clinical-vlan,yes
INF-02,infusion pump,RTOS-x 1.4,2021,clinical-vlan,yes
IMG-01,imaging workstation,Windows 7,2020,clinical-vlan,yes
IMG-02,imaging workstation,Windows 10,2025,clinical-vlan,yes
LAB-01,lab analyser,Linux 3.10,2019,lab-vlan,yes
ADM-01,office pc,Windows 11,2031,corporate,no
ADM-02,office pc,Windows 10,2025,clinical-vlan,no
BMS-01,building controller,vendor fw 4,2027,bms-vlan,no
"""
YEAR = 2026
rows = list(csv.DictReader(io.StringIO(DATA)))
unsupported = [r for r in rows if int(r["os_end_of_support"]) < YEAR]
print("assets:", len(rows), "| unsupported:", len(unsupported))
for r in unsupported:
    print(f"  {r['asset']:7} {r['type']:20} {r['os']:12} EoS {r['os_end_of_support']} clinical={r['clinical']}")
print("by network:", dict(Counter(r["network"] for r in unsupported)))
misplaced = [r["asset"] for r in rows if r["clinical"] == "no" and r["network"] == "clinical-vlan"]
print("non-clinical devices on clinical VLAN:", misplaced)

Salida esperada:

assets: 8 | unsupported: 5
  INF-02  infusion pump        RTOS-x 1.4   EoS 2021 clinical=yes
  IMG-01  imaging workstation  Windows 7    EoS 2020 clinical=yes
  IMG-02  imaging workstation  Windows 10   EoS 2025 clinical=yes
  LAB-01  lab analyser         Linux 3.10   EoS 2019 clinical=yes
  ADM-02  office pc            Windows 10   EoS 2025 clinical=no
by network: {'clinical-vlan': 4, 'lab-vlan': 1}
non-clinical devices on clinical VLAN: ['ADM-02']

Interpretación: cuatro dispositivos clínicos no tienen soporte, lo que es un problema de planificación de sustituciones con controles compensatorios (capítulo 2). ADM-02 es distinto: un PC de oficina sin soporte en la red clínica es el hallazgo más barato de corregir; actualícelo y muévalo. Las filas son datos didácticos: las etiquetas de los dispositivos son inventadas y, aunque algunos nombres de sistemas operativos resulten familiares, trate cada año de fin de soporte como una entrada de muestra y compruebe cualquier producto real con la página de ciclo de vida que publica su fabricante.

3.4 Actividad práctica

Amplíe el Lab 2: (1) añada una fila con os_end_of_support vacío y observe el error; (2) cambie el programa para que esas filas se notifiquen como «desconocido: necesita responsable» en lugar de provocar un fallo o ser omitidas; (3) escriba un assert que compruebe que el recuento de dispositivos sin soporte para las ocho filas originales es 5. El paso (2) es el importante. Una fila notificada como «desconocido: necesita responsable» pone nombre a una carencia; una fila omitida la oculta, y un fallo detiene el informe para todos. El assert del paso (3) es una prueba con respuesta conocida: si un cambio posterior en el filtro hace que imprima 4 o 6, la prueba falla antes de que nadie lea un informe erróneo.

3.5 Errores comunes y límites

En el Lab 2, el segundo error habría ocultado VEN-01 en EX005; el tercero habría hecho que los dispositivos de 2025 volvieran a parecer con soporte si el año se hubiera quedado en 2025; y el cuarto se aplica a toda la exportación: ADM-02 aparece en la VLAN clínica solo porque alguien registró correctamente su red.

Ejercicios — capítulo 3

EX005 — Lo desconocido es un hallazgo. Objetivo: hacer visibles los datos que faltan. Entradas: el Lab 2 más una novena fila VEN-01,ventilator,,,clinical-vlan,yes. Pasos: modifique el programa para que imprima una sección de desconocidos; explique por qué una fecha de soporte desconocida en un ventilador debe escalarse. Evidencia esperada: el cambio en el código, la salida y dos frases. Rúbrica: 3 = sin fallo, VEN-01 notificado como desconocido, razón de escalamiento vinculada a la consecuencia clínica; 2 = funciona, sin razonamiento; 1 = evita el fallo omitiendo la fila; 0 = nada.

EX006 — Una función que se puede probar. Objetivo: separar la lógica de los datos. Entradas: el Lab 2. Pasos: escriba def is_unsupported(row, year) -> bool, pruébela con tres filas hechas a mano (con soporte, sin soporte y el año límite igual a year) y enuncie su regla para el límite. Evidencia esperada: la función, las pruebas y la regla. Rúbrica: 3 = función correcta, las tres pruebas, regla del límite enunciada y justificada; 2 = no se discute el límite; 1 = solo la función; 0 = nada.

Síntesis del capítulo

Los programas breves y legibles convierten los inventarios en decisiones. Filtre, cuente e informe, y notifique siempre lo que no pudo clasificar. Pruebe con casos que conoce, mantenga la lógica en funciones y recuerde que el programa solo es tan veraz como sus datos.

Respuestas desarrolladas

EX005. Cambie el filtro para tratar por separado row["os_end_of_support"] == "": unknown = [r for r in rows if not r["os_end_of_support"].strip()], notifíquelos bajo «DESCONOCIDO: necesita responsable» y calcule unsupported solo a partir de las filas con fecha. La salida añade VEN-01 ventilator. Un ventilador con estado de soporte desconocido es un equipo de soporte vital en la red clínica cuya exposición a parches nadie puede precisar; escálelo a ingeniería clínica para obtener la declaración de soporte del fabricante y revisar su ubicación.

EX006. def is_unsupported(row, year): return int(row["os_end_of_support"]) < year. Pruebas: fin de soporte 2030 → False; 2020 → True; fin de soporte igual a year (2026) → False con esta regla. Regla enunciada: un dispositivo cuyo soporte termina durante el año en curso todavía tiene soporte ahora, pero debe señalarse en una lista aparte de «termina este año»; una regla alternativa defendible trata <= como sin soporte, para ser conservadora. Cualquiera de las dos es aceptable si se enuncia y se prueba.