|
| 1 | +# Etapa 9 — C5: Pipeline Otimizado |
| 2 | + |
| 3 | +<!-- Observação interna: revisar prints e atualizar caminhos das evidências antes de abrir o PR. --> |
| 4 | + |
| 5 | +> **TCC:** Avaliação Experimental do Impacto de Práticas DevSecOps no Lead Time de Pipelines CI/CD |
| 6 | +> **Repositório:** [r2WillDev/tcc-devsecops-pipeline](https://github.com/r2WillDev/tcc-devsecops-pipeline) |
| 7 | +> **Branch:** `feature/c5-optimized-pipeline` |
| 8 | +> **Status:** :white_check_mark: Concluída — aguardando PR |
| 9 | +
|
| 10 | +--- |
| 11 | + |
| 12 | +## Sumário |
| 13 | + |
| 14 | +- [Objetivo da Etapa](#objetivo-da-etapa) |
| 15 | +- [Contexto Experimental](#contexto-experimental) |
| 16 | +- [Arquivos Criados e Modificados](#arquivos-criados-e-modificados) |
| 17 | +- [Otimizações Aplicadas](#otimizações-aplicadas) |
| 18 | +- [Problemas Encontrados e Solução](#problemas-encontrados-e-solução) |
| 19 | +- [Resultados das 5 Execuções Oficiais](#resultados-das-5-execuções-oficiais) |
| 20 | +- [Estatísticas Consolidadas](#estatísticas-consolidadas) |
| 21 | +- [Comparação C4 vs C5](#comparação-c4-vs-c5) |
| 22 | +- [Resultados de Segurança](#resultados-de-segurança) |
| 23 | +- [Observações Metodológicas](#observações-metodológicas) |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## Objetivo da Etapa |
| 28 | + |
| 29 | +A Etapa 9 tem como objetivo criar, executar e documentar o cenário **C5 — Pipeline Otimizado**, uma versão aperfeiçoada do cenário C4 que **preserva integralmente as práticas DevSecOps** (SAST, SCA e DAST), mas aplica otimizações controladas para **reduzir o overhead operacional** e melhorar o lead time do pipeline CI/CD. |
| 30 | + |
| 31 | +> [!IMPORTANT] |
| 32 | +> O C5 **não remove** nenhuma ferramenta de segurança. O SonarQube SAST, o Trivy SCA e o OWASP ZAP DAST **continuaram ativos** em todas as execuções oficiais. As otimizações foram aplicadas na camada de infraestrutura e orquestração do pipeline, não na cobertura de segurança. |
| 33 | +
|
| 34 | +A métrica principal de lead time neste experimento é o `workflow_total`, que representa o tempo total de execução do pipeline do início ao fim. As demais etapas são métricas operacionais individuais e **não** devem ser somadas ao `workflow_total` para evitar dupla contagem. |
| 35 | + |
| 36 | +--- |
| 37 | + |
| 38 | +## Contexto Experimental |
| 39 | + |
| 40 | +O experimento é estruturado em cinco cenários progressivos de pipeline CI/CD: |
| 41 | + |
| 42 | +| Cenário | Descrição | Ferramentas de Segurança | |
| 43 | +| ------- | --------- | ------------------------ | |
| 44 | +| **C1** | Pipeline Baseline | Nenhuma | |
| 45 | +| **C2** | Pipeline com SAST | SonarQube | |
| 46 | +| **C3** | Pipeline com SAST + SCA | SonarQube + Trivy | |
| 47 | +| **C4** | Pipeline com SAST + SCA + DAST | SonarQube + Trivy + OWASP ZAP | |
| 48 | +| **C5** | Pipeline Otimizado | SonarQube + Trivy + OWASP ZAP *(com otimizações)* | |
| 49 | + |
| 50 | +O **C5** é comparado **principalmente com o C4**, pois ambos possuem a mesma cobertura de segurança. O objetivo da comparação é quantificar o impacto das otimizações no lead time sem comprometer a postura de segurança do pipeline. |
| 51 | + |
| 52 | +O ambiente de execução utilizou: |
| 53 | + |
| 54 | +- Runner **self-hosted** (`tcc-wsl-runner`) |
| 55 | +- **WSL 2** com Ubuntu 24.04 |
| 56 | +- **Docker Desktop** com integração WSL ativa |
| 57 | +- **kind** para cluster Kubernetes local |
| 58 | +- **SonarQube** Community Edition em container Docker |
| 59 | +- **OWASP ZAP** em execução automatizada |
| 60 | + |
| 61 | +--- |
| 62 | + |
| 63 | +## Arquivos Criados e Modificados |
| 64 | + |
| 65 | +| Arquivo | Ação | Finalidade | |
| 66 | +| ------- | ---- | ---------- | |
| 67 | +| [`.github/workflows/c5-optimized.yml`](../.github/workflows/c5-optimized.yml) | Criado | Workflow do cenário C5 com otimizações | |
| 68 | +| [`analysis/raw/c5_optimized.csv`](../analysis/raw/c5_optimized.csv) | Criado | Armazenamento das métricas brutas das execuções C5 | |
| 69 | +| [`docs/09-c5-optimized-pipeline.md`](../docs/09-c5-optimized-pipeline.md) | Criado | Documentação desta etapa | |
| 70 | + |
| 71 | +> [!NOTE] |
| 72 | +> O script `ci/scripts/measure_step.sh` **não foi modificado**. O comportamento de medição, registro de status e fail-fast herdado das etapas anteriores foi reaproveitado sem alteração. |
| 73 | +
|
| 74 | +### Commits realizados |
| 75 | + |
| 76 | +| Hash | Mensagem | |
| 77 | +| ---- | -------- | |
| 78 | +| `18e1e93` | `analysis: add C5 results CSV header` | |
| 79 | +| `ce7f225` | `ci: add initial C5 optimized workflow` | |
| 80 | +| `4e1ab5d` | `ci: add Python dependency cache to C5 workflow` | |
| 81 | +| `e935bab` | `ci: add Trivy cache to optimized pipeline` | |
| 82 | +| `5fb08dc` | `ci: add conditional DAST execution to C5 workflow` | |
| 83 | + |
| 84 | +Adicionalmente, foi realizado um ajuste posterior: |
| 85 | + |
| 86 | +```text |
| 87 | +ci: force JavaScript actions to Node 24 in C5 workflow |
| 88 | +``` |
| 89 | + |
| 90 | +Esse commit adicionou a variável de ambiente `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true` ao workflow. Com isso, o aviso sobre Node.js 20 passou a ser apenas informativo — as actions JavaScript foram forçadas a executar com Node.js 24, garantindo compatibilidade futura com a plataforma GitHub Actions. |
| 91 | + |
| 92 | +--- |
| 93 | + |
| 94 | +## Otimizações Aplicadas |
| 95 | + |
| 96 | +| Otimização | Implementação | Impacto esperado | Evidência | |
| 97 | +| ---------- | ------------- | ---------------- | --------- | |
| 98 | +| Cache de dependências Python | `actions/setup-python@v6` com `cache: "pip"` | Elimina o download repetido de pacotes PyPI entre execuções | `Cache restored successfully` nos logs | |
| 99 | +| Cache do banco de dados Trivy | `actions/cache@v4` em `~/.cache/trivy` | Evita download repetido do banco de vulnerabilidades | `Cache hit occurred on the primary key Linux-trivy-v0.71.0-...` | |
| 100 | +| Execução condicional do OWASP ZAP | Input `run_zap` com padrão `"true"` | Permite execuções manuais econômicas sem comprometer dados oficiais | Parâmetro `run_zap` visível no `workflow_dispatch` | |
| 101 | +| Fail-fast herdado | Comportamento do `measure_step.sh` | Encerra o pipeline imediatamente quando uma etapa crítica falha, evitando execução de etapas pesadas desnecessárias | Comportamento observado em tentativas com falha | |
| 102 | +| Compatibilidade futura Node.js 24 | `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true` | Prepara o workflow para a descontinuação do Node.js 20 nas actions | Warning informativo nos logs de execução | |
| 103 | + |
| 104 | +### Detalhamento das otimizações |
| 105 | + |
| 106 | +#### 1. Cache de dependências Python |
| 107 | + |
| 108 | +O cache foi configurado usando `actions/setup-python@v6` com os parâmetros: |
| 109 | + |
| 110 | +```yaml |
| 111 | +- name: Setup Python with pip cache |
| 112 | + uses: actions/setup-python@v6 |
| 113 | + with: |
| 114 | + python-version: "3.12" |
| 115 | + cache: "pip" |
| 116 | + cache-dependency-path: "app/requirements.txt" |
| 117 | +``` |
| 118 | +
|
| 119 | +Evidência de cache hit nos logs: |
| 120 | +
|
| 121 | +```text |
| 122 | +Cache hit for: setup-python-Linux-x64-24.04-Ubuntu-python-3.12.13-pip-... |
| 123 | +Cache restored successfully |
| 124 | +``` |
| 125 | + |
| 126 | +#### 2. Cache do Trivy |
| 127 | + |
| 128 | +O banco de dados de vulnerabilidades do Trivy foi cacheado usando `actions/cache@v4`: |
| 129 | + |
| 130 | +```yaml |
| 131 | +- name: Cache Trivy vulnerability database |
| 132 | + uses: actions/cache@v4 |
| 133 | + with: |
| 134 | + path: ~/.cache/trivy |
| 135 | + key: ${{ runner.os }}-trivy-${{ env.TRIVY_VERSION }}-${{ hashFiles('ci/config/trivy.yaml') }} |
| 136 | + restore-keys: | |
| 137 | + ${{ runner.os }}-trivy-${{ env.TRIVY_VERSION }}- |
| 138 | +``` |
| 139 | +
|
| 140 | +Evidência de cache hit nos logs: |
| 141 | +
|
| 142 | +```text |
| 143 | +Cache hit occurred on the primary key Linux-trivy-v0.71.0-... |
| 144 | +``` |
| 145 | + |
| 146 | +#### 3. Execução condicional do OWASP ZAP |
| 147 | + |
| 148 | +O input `run_zap` foi adicionado ao `workflow_dispatch`, com valor padrão `"true"`: |
| 149 | + |
| 150 | +```yaml |
| 151 | +on: |
| 152 | + workflow_dispatch: |
| 153 | + inputs: |
| 154 | + run_zap: |
| 155 | + description: "Run OWASP ZAP DAST scan" |
| 156 | + required: true |
| 157 | + default: "true" |
| 158 | + type: choice |
| 159 | + options: |
| 160 | + - "true" |
| 161 | + - "false" |
| 162 | +``` |
| 163 | +
|
| 164 | +> [!WARNING] |
| 165 | +> A execução condicional do ZAP **não foi usada para reduzir artificialmente o tempo** das execuções oficiais. Nas 5 execuções coletadas para o experimento, o `run_zap` manteve o valor padrão `"true"` e o DAST foi executado normalmente. A condicional existe apenas para facilitar execuções de teste manual sem custo de tempo, sem impactar os dados experimentais. |
| 166 | + |
| 167 | +Quando `run_zap=false`, as etapas de DAST registram métricas com status `skipped`, preservando a comparabilidade estrutural do CSV. |
| 168 | + |
| 169 | +#### 4. Fail-fast herdado |
| 170 | + |
| 171 | +O script `ci/scripts/measure_step.sh` registra o status de cada etapa e, em caso de falha, encerra com `exit 1`. Esse comportamento evita que etapas pesadas como o ZAP sejam executadas após uma falha crítica anterior, reduzindo o desperdício de tempo em runs com erro. |
| 172 | + |
| 173 | +#### 5. Compatibilidade futura com Node.js 24 |
| 174 | + |
| 175 | +```yaml |
| 176 | +env: |
| 177 | + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true |
| 178 | +``` |
| 179 | + |
| 180 | +O warning sobre Node.js 20 permaneceu nos logs apenas como aviso informativo. Com essa variável ativa, as actions que ainda usavam o runtime Node.js 20 passaram a ser executadas com Node.js 24, preparando o workflow para a descontinuação futura do Node.js 20 na plataforma GitHub Actions. |
| 181 | + |
| 182 | + |
| 183 | + |
| 184 | +## Problemas Encontrados e Solução |
| 185 | + |
| 186 | +### Falha na etapa `Run SonarQube SAST analysis` |
| 187 | + |
| 188 | +<details> |
| 189 | +<summary>:warning: Expandir detalhes do problema e solução</summary> |
| 190 | + |
| 191 | +#### Erro observado |
| 192 | + |
| 193 | +```text |
| 194 | +failed to connect to the docker API at unix:///var/run/docker.sock |
| 195 | +``` |
| 196 | + |
| 197 | +#### Causa raiz |
| 198 | + |
| 199 | +O runner `tcc-wsl-runner` estava em execução dentro do WSL, mas o **Docker Desktop** não estava ativo ou a integração com a distro `Ubuntu-24.04` havia sido desativada. Como consequência: |
| 200 | + |
| 201 | +- O socket `/var/run/docker.sock` não estava disponível no WSL |
| 202 | +- O SonarQube Scanner não conseguia se comunicar com o daemon Docker |
| 203 | +- A etapa de SAST falhou antes de completar a análise |
| 204 | + |
| 205 | +#### Solução aplicada |
| 206 | + |
| 207 | +1. Reiniciar o Docker Desktop no Windows |
| 208 | +2. Aguardar inicialização completa do daemon Docker |
| 209 | +3. Verificar e ativar a integração Docker Desktop → WSL2 → `Ubuntu-24.04` |
| 210 | +4. Confirmar a presença do socket no WSL: |
| 211 | + |
| 212 | + ```bash |
| 213 | + ls -l /var/run/docker.sock |
| 214 | + ``` |
| 215 | + |
| 216 | +5. Subir novamente o container do SonarQube: |
| 217 | + |
| 218 | + ```powershell |
| 219 | + docker compose -f .\infra\sonarqube\docker-compose.yml up -d |
| 220 | + ``` |
| 221 | + |
| 222 | +6. Aguardar o SonarQube ficar `UP`: |
| 223 | + |
| 224 | + ```powershell |
| 225 | + Invoke-RestMethod http://localhost:9000/api/system/status |
| 226 | + ``` |
| 227 | + |
| 228 | +7. Reiniciar o runner no WSL: |
| 229 | + |
| 230 | + ```bash |
| 231 | + cd ~/actions-runner-tcc |
| 232 | + ./run.sh |
| 233 | + ``` |
| 234 | + |
| 235 | +#### Resultado |
| 236 | + |
| 237 | +- Runner voltou a ouvir e processar jobs |
| 238 | +- Docker ficou acessível no WSL via socket |
| 239 | +- SonarQube retornou ao status `UP` |
| 240 | +- O workflow C5 executou com sucesso nas execuções subsequentes |
| 241 | + |
| 242 | +</details> |
| 243 | + |
| 244 | +--- |
| 245 | + |
| 246 | +## Resultados das 5 Execuções Oficiais |
| 247 | + |
| 248 | + |
| 249 | +Os dados abaixo foram extraídos dos artifacts gerados pelo GitHub Actions, especialmente do arquivo `analysis/raw/c5_optimized_run.csv`, produzido em cada execução oficial do workflow C5. O arquivo versionado `analysis/raw/c5_optimized.csv` contém apenas o cabeçalho base para padronização dos dados. |
| 250 | + |
| 251 | +| Run | `workflow_total` | `dast_zap_baseline` | `kubernetes_deploy` | `sonarqube_sast` | Status | |
| 252 | +| --: | ---------------: | ------------------: | ------------------: | ---------------: | ------ | |
| 253 | +| 1 | 172 | 44 | 39 | 16 | :white_check_mark: success | |
| 254 | +| 2 | 240 | 79 | 37 | 12 | :white_check_mark: success | |
| 255 | +| 3 | 180 | 44 | 29 | 20 | :white_check_mark: success | |
| 256 | +| 4 | 178 | 37 | 34 | 13 | :white_check_mark: success | |
| 257 | +| 5 | 189 | 36 | 38 | 18 | :white_check_mark: success | |
| 258 | + |
| 259 | +### Dados brutos completos (CSV) |
| 260 | + |
| 261 | +<details> |
| 262 | +<summary>Expandir CSV completo</summary> |
| 263 | + |
| 264 | +```csv |
| 265 | +run,install_dependencies,unit_tests,sonarqube_sast,docker_build,sca_fs,sca_image,sca_total,kubernetes_deploy,kubernetes_smoke_test,dast_health_check,dast_zap_baseline,workflow_total |
| 266 | +1,0,2,16,5,0,1,1,39,5,0,44,172 |
| 267 | +2,1,1,12,2,1,0,1,37,6,0,79,240 |
| 268 | +3,1,1,20,2,0,3,3,29,5,0,44,180 |
| 269 | +4,0,1,13,2,0,2,2,34,5,0,37,178 |
| 270 | +5,0,2,18,2,0,2,2,38,5,0,36,189 |
| 271 | +``` |
| 272 | + |
| 273 | +</details> |
| 274 | + |
| 275 | +--- |
| 276 | + |
| 277 | +## Estatísticas Consolidadas |
| 278 | + |
| 279 | +> [!NOTE] |
| 280 | +> O `workflow_total` é a **métrica principal de lead time** do experimento e **não** é incluído no ranking de etapas operacionais. As médias abaixo são calculadas sobre as 5 execuções oficiais. |
| 281 | + |
| 282 | +| Métrica | Resultado | |
| 283 | +| ------- | --------: | |
| 284 | +| `workflow_total` médio | **191,80 s** | |
| 285 | +| `workflow_total` mínimo | 172,00 s | |
| 286 | +| `workflow_total` máximo | 240,00 s | |
| 287 | +| Variação (`max - min`) | 68,00 s | |
| 288 | +| Desvio padrão amostral | 27,63 s | |
| 289 | +| Etapa operacional mais lenta | `dast_zap_baseline` — 48,00 s | |
| 290 | +| Segunda etapa mais lenta | `kubernetes_deploy` — 35,40 s | |
| 291 | + |
| 292 | +### Ranking das etapas operacionais por média (s) |
| 293 | + |
| 294 | +> `workflow_total` **excluído** do ranking por ser a métrica agregada de lead time. |
| 295 | + |
| 296 | +| Posição | Etapa | Média (s) | |
| 297 | +| ------: | ----- | --------: | |
| 298 | +| 1 | `dast_zap_baseline` | **48,00** | |
| 299 | +| 2 | `kubernetes_deploy` | **35,40** | |
| 300 | +| 3 | `sonarqube_sast` | 15,80 | |
| 301 | +| 4 | `kubernetes_smoke_test` | 5,20 | |
| 302 | +| 5 | `docker_build` | 2,60 | |
| 303 | +| 6 | `sca_total` | 1,80 | |
| 304 | +| 7 | `sca_image` | 1,60 | |
| 305 | +| 8 | `unit_tests` | 1,40 | |
| 306 | +| 9 | `install_dependencies` | 0,40 | |
| 307 | +| 10 | `sca_fs` | 0,20 | |
| 308 | +| 11 | `dast_health_check` | 0,00 | |
| 309 | + |
| 310 | +--- |
| 311 | + |
| 312 | +## Comparação C4 vs C5 |
| 313 | + |
| 314 | +<a id="comparacao-c4-c5"></a> |
| 315 | + |
| 316 | +> [!IMPORTANT] |
| 317 | +> A comparação entre C4 e C5 é o principal indicador do impacto das otimizações aplicadas, **mantendo a mesma cobertura de segurança** (SAST + SCA + DAST). |
| 318 | + |
| 319 | +| Métrica | C4 (referência) | C5 (médio) | Redução absoluta | Redução percentual | |
| 320 | +| ------- | --------------: | ---------: | ---------------: | -----------------: | |
| 321 | +| `workflow_total` | 309 s | 191,80 s | **117,20 s** | **37,93%** | |
| 322 | +| `dast_zap_baseline` | 197 s | 48,00 s | **149,00 s** | **75,63%** | |
| 323 | + |
| 324 | +### Análise da redução |
| 325 | + |
| 326 | +A redução de **~37,93%** no `workflow_total` do C5 em relação ao C4 de referência não deve ser atribuída exclusivamente ao cache. Os fatores que contribuíram para a melhora incluem: |
| 327 | + |
| 328 | +- :rocket: **Cache de dependências Python** — eliminou o download repetido de pacotes PyPI |
| 329 | +- :rocket: **Cache do banco de dados Trivy** — eliminou o download repetido do banco de CVEs |
| 330 | +- :rocket: **Ambiente aquecido** — o runner self-hosted manteve dados de camadas Docker e artefatos locais entre execuções |
| 331 | +- :rocket: **Variações naturais do runner local** — o ambiente WSL + Docker Desktop apresenta variabilidade inerente |
| 332 | +- :rocket: **Menor overhead operacional** — a soma das otimizações reduziu o tempo de preparação de cada etapa |
| 333 | + |
| 334 | +A redução expressiva do `dast_zap_baseline` pode estar relacionada ao aquecimento do ambiente local, reaproveitamento de camadas/imagens Docker, menor overhead do runner self-hosted e variações naturais da execução do ZAP em ambiente WSL + Docker Desktop. |
| 335 | + |
| 336 | + |
| 337 | +--- |
| 338 | + |
| 339 | +## Resultados de Segurança |
| 340 | + |
| 341 | +O C5 manteve plena cobertura de segurança. Os resultados abaixo confirmam que as ferramentas continuaram operacionais e reportando achados. |
| 342 | + |
| 343 | +### Trivy SCA |
| 344 | + |
| 345 | +| Alvo | Low | Medium | High | Critical | Total | |
| 346 | +| ---- | --: | -----: | ---: | -------: | ----: | |
| 347 | +| Filesystem | — | 1 | — | — | 1 | |
| 348 | +| Image | 63 | 33 | 8 | 2 | **106** | |
| 349 | +| **Total** | **63** | **34** | **8** | **2** | **107** | |
| 350 | + |
| 351 | +> [!NOTE] |
| 352 | +> O total agregado soma os achados por alvo de análise (`filesystem` e `image`) e não representa necessariamente vulnerabilidades únicas deduplicadas entre os dois scans. |
| 353 | + |
| 354 | + |
| 355 | +> [!NOTE] |
| 356 | +> As vulnerabilidades reportadas pelo Trivy são consistentes com os resultados dos cenários anteriores (C3 e C4), confirmando que o C5 não alterou o escopo de análise de dependências. |
| 357 | + |
| 358 | +### OWASP ZAP DAST |
| 359 | + |
| 360 | +| Info | Low | Medium | High | Total | |
| 361 | +| ---: | --: | -----: | ---: | ----: | |
| 362 | +| 1 | 2 | 0 | 0 | **3** | |
| 363 | + |
| 364 | + |
| 365 | +> [!NOTE] |
| 366 | +> Nenhuma vulnerabilidade de severidade **Medium** ou **High** foi identificada pelo ZAP. O resultado está alinhado com os cenários anteriores, confirmando que a aplicação FastAPI de teste mantém o mesmo perfil de exposição. |
| 367 | + |
| 368 | + |
| 369 | + |
| 370 | +## Observações Metodológicas |
| 371 | + |
| 372 | +1. **`workflow_total` como métrica de lead time:** o `workflow_total` representa o tempo total decorrido desde o início do workflow até sua conclusão. É a métrica que mais se aproxima do conceito de *lead time* em CI/CD. As demais métricas são etapas operacionais individuais e servem para diagnóstico, não para ranking de lead time. |
| 373 | + |
| 374 | +2. **Não atribuir todo o ganho ao cache:** as otimizações de cache são uma parte do ganho, mas o ambiente aquecido (runner self-hosted que mantém estado entre runs), as variações naturais do WSL e do Docker Desktop, e a menor sobrecarga operacional agregada também contribuíram para a redução observada. |
| 375 | + |
| 376 | +3. **Comparabilidade dos dados:** as 5 execuções oficiais do C5 foram realizadas com `run_zap=true` (valor padrão), garantindo que o DAST esteve ativo em todas as medições. Execuções de teste manual com `run_zap=false` não foram incluídas nos dados experimentais. |
| 377 | + |
| 378 | +4. **Variabilidade esperada:** o desvio padrão amostral de 27,63 s (sobre uma média de 191,80 s) é esperado em ambientes self-hosted locais. A run 2 apresentou o maior `workflow_total` (240 s), puxado pelo `dast_zap_baseline` de 79 s, o que é consistente com a variabilidade do ZAP em ambientes locais. |
| 379 | + |
| 380 | +5. **Preservação das práticas DevSecOps:** o C5 demonstra que é possível **reduzir o lead time de um pipeline DevSecOps sem abrir mão das verificações de segurança**. Esse é o ponto central da contribuição do cenário C5 para o experimento. |
| 381 | + |
| 382 | +> O C5 preservou SAST, SCA e DAST, aplicando otimizações controladas para reduzir overhead operacional e melhorar o lead time sem eliminar práticas de segurança. |
| 383 | + |
| 384 | + |
| 385 | + |
| 386 | +### Notas de rodapé |
| 387 | + |
| 388 | +O `workflow_total` é calculado pelo script `measure_step.sh` como a diferença entre o timestamp de início do job e o timestamp de conclusão da última etapa medida.[^1] |
| 389 | + |
| 390 | +O desvio padrão amostral foi calculado com `n-1` no denominador (fórmula de Bessel), adequado para amostras pequenas.[^2] |
| 391 | +[^1]: O script `ci/scripts/measure_step.sh` registra timestamps em epoch Unix e calcula a duração em segundos inteiros por diferença simples. |
| 392 | + |
| 393 | +[^2]: Fórmula: s = √(Σ(xᵢ − x̄)² / (n − 1)), onde n = 5 execuções e x̄ = 191,80 s. |
| 394 | + O uso de n-1 é recomendado quando a amostra é pequena e o objetivo é estimar o desvio padrão populacional a partir de uma amostra. |
| 395 | + |
| 396 | +--- |
| 397 | + |
| 398 | +*Documento gerado para o TCC — Avaliação Experimental do Impacto de Práticas DevSecOps no Lead Time de Pipelines CI/CD.*<br> |
0 commit comments