Автоматизация тестирования в CI/CD

Криптографические библиотеки предъявляют повышенные требования к тестированию: ошибка в реализации алгоритма приводит не к деградации функциональности, а к компрометации безопасности. Для Stanford JavaScript Crypto Library (SJCL) автоматизация тестирования в CI/CD должна учитывать детерминированность вычислений, кросс-платформенность JavaScript-окружений и необходимость проверки стандартных криптографических векторов.

Ключевая цель CI/CD в контексте SJCL — гарантировать идентичность результатов между Node.js, браузерными окружениями и различными сборками библиотеки при любых изменениях кода.


Структура тестовой системы SJCL

Тестирование SJCL обычно разделяется на несколько уровней:

Юнит-тесты криптографических примитивов

Проверяются базовые операции:

  • AES (режимы CBC, CCM)
  • SHA-256 / SHA-512
  • HMAC
  • PBKDF2
  • ECC операции (в зависимости от сборки)
  • генерация случайных чисел

Каждый тест опирается на фиксированные входные данные и заранее известные выходные значения.

Особое значение имеют тестовые векторы:

  • NIST vectors для AES и SHA
  • RFC vectors для HMAC и PBKDF2
  • собственные регрессионные наборы SJCL

Детерминированность тестов и управление RNG

SJCL использует собственный генератор случайных чисел (sjcl.random). В CI/CD среде его поведение должно быть строго контролируемым.

Для тестов применяются подходы:

  • фиксация seed перед запуском тестов
  • подмена entropy sources
  • отключение реальных событий браузера (mousemove, keyboard entropy)
  • использование заранее подготовленных entropy pools

Ключевое требование: любая криптографическая операция в тестах должна быть воспроизводимой.


Запуск тестов в Node.js окружении

Node.js используется как основная среда быстрых проверок.

Типичный сценарий:

  • загрузка SJCL как CommonJS/UMD модуля
  • выполнение тестов через Mocha или встроенный test runner
  • проверка совпадения результатов с эталонными векторами

Особое внимание уделяется:

  • корректности BigInt/bitwise операций
  • различиям в endianness
  • совместимости Buffer vs ArrayBuffer

Браузерное тестирование

SJCL исторически ориентирован на браузер, поэтому CI/CD обязательно включает headless-окружение.

Используются подходы:

  • запуск тестов в headless Chrome
  • выполнение через Karma или Puppeteer
  • прогон тестов в нескольких движках (Chrome, Firefox)

Проверяются:

  • работа Web Crypto fallback-логики
  • корректность DOM-based entropy collection
  • отсутствие зависимостей от Node API

Интеграция с GitHub Actions

CI/CD пайплайн обычно строится вокруг нескольких этапов:

1. Установка зависимостей

  • npm install
  • фиксация версии Node.js (LTS)
  • кэширование node_modules

2. Линтинг и статический анализ

  • ESLint для проверки JS-кода
  • выявление потенциально опасных паттернов
  • запрет небезопасных преобразований типов

3. Юнит-тесты

  • запуск полного набора криптографических тестов
  • проверка векторов AES/SHA/HMAC
  • контроль регрессий

4. Browser tests

  • headless Chrome execution
  • Karma/Puppeteer integration
  • параллельный запуск тестов

5. Coverage

  • Istanbul / nyc для покрытия кода
  • минимальные пороги покрытия для криптографических модулей
  • контроль ветвлений в алгоритмах (branch coverage критичен)

Пример CI-конфигурации (GitHub Actions)

name: sjcl-tests

on:
  push:
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [18, 20]

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Unit tests
        run: npm test

      - name: Coverage
        run: npm run coverage

      - name: Browser tests
        run: npm run test:browser

Тестирование криптографических векторов

Основой корректности SJCL являются фиксированные входы и выходы.

Пример структуры теста:

  • входной текст
  • ключ
  • ожидаемый ciphertext
  • ожидаемый tag (для AEAD)

Любое отклонение считается критической ошибкой.

Особое внимание уделяется:

  • padding PKCS#7
  • корректности IV
  • режимам шифрования (CBC vs CCM)
  • согласованности encoding (hex, base64, bitArray)

Фаззинг криптографических функций

Фаззинг применяется для проверки устойчивости к неожиданным входным данным:

  • случайные битовые массивы
  • некорректные длины ключей
  • повреждённые ciphertext
  • null/undefined входы

Цель фаззинга не только обнаружение падений, но и предотвращение:

  • утечек памяти
  • зависаний алгоритмов
  • неконсистентного поведения между платформами

Кросс-платформенная проверка

SJCL должен работать одинаково в:

  • Node.js
  • браузерах
  • гибридных окружениях (Electron)

CI/CD проверяет:

  • идентичность выходов SHA/AES между платформами
  • отсутствие platform-specific branching
  • корректность polyfill-логики

Проверка безопасности сборки

Дополнительно в pipeline включаются проверки:

  • audit зависимостей (npm audit)
  • поиск известных уязвимостей
  • контроль отсутствия утечек entropy
  • запрет логирования секретных данных

Особое правило: любые изменения в криптографических модулях требуют полного прогрева всех тестов, а не частичного запуска.


Регрессионные сценарии

Каждое изменение SJCL должно проходить регрессионный набор:

  • старые ciphertext должны оставаться валидными
  • поведение RNG не должно меняться без явного version bump
  • изменения оптимизаций не должны влиять на битовую идентичность результатов

Регрессия в криптографии рассматривается как критическая ошибка уровня безопасности.