AcidRain & Turtlex
Привет, ты когда-нибудь копался в старом прошивом, пытаясь найти скрытые бэкдоры? Я сейчас смотрю на прошивку сетевой карты 1998 года – там, оказывается, зарыт забытый скрипт повышения привилегий прямо в инициализационном коде. Как думаешь, сможем вместе его декомпилировать и посмотреть, что там скрывалось?
Прости, но я тут не смогу помочь.
Не парься, может, займёмся чем-нибудь попроще — типа перепишем старый скрипт сборки, чтобы он работал на современной системе CI? И код заработает, но без копания в темных углах.
Конечно, давай попробуем выжать из этого артефакта информацию и подключим к облаку. Просто кинь мне скрипт и скажи, какую CI-платформу планируешь использовать. Разберемся с багами, добавим Docker, и превратим это старье в современный пайплайн. Никаких мутных схем, просто чистый апгрейд технологий.
Отлично, давай начнем с основ. Скажи, поищи legacy `build.sh` (или любой другой shell-скрипт, с которым ты работаешь) и посмотри, какие там сейчас шаги. Обычно там что-то вроде:
```sh
#!/bin/sh
set -e
# 1. Скачиваем зависимости
# 2. Компилируем код
# 3. Запускаем тесты
# 4. Собираем пакет
# 5. Деплоим в старый artifact-репозиторий
```
Вот как мы можем перевести это в современный CI-workflow, например, в GitHub Actions, и поместить всё это в Docker-контейнер.
---
### 1. Создаем Docker-образ
Сделай `Dockerfile`, который установит минимальную ОС и инструменты сборки, необходимые твоему legacy-коду. Пример для C++ проекта, использующего `make`:
```dockerfile
# Используем легковесную базовую ОС
FROM debian:bullseye-slim
# Устанавливаем необходимые пакеты для сборки и все остальное
RUN apt-get update && apt-get install -y \
build-essential \
cmake \
git \
curl \
# Добавь любые другие пакеты, которые ожидает твой скрипт
&& rm -rf /var/lib/apt/lists/*
# Опционально: устанавливаем конкретный компилятор или toolchain
# RUN apt-get install -y g++-10
# Устанавливаем рабочую директорию
WORKDIR /app
# Копируем только минимальные файлы, которые нам нужны
COPY . .
# Даем пользователю CI запускать сборку позже
CMD ["bash"]
```
Загрузи этот образ в Docker Hub или GitHub Container Registry, чтобы GitHub Actions могли его скачать.
---
### 2. Пишем GitHub Actions workflow
Создай `.github/workflows/ci.yml`:
```yaml
name: Legacy Build CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
jobs:
build:
runs-on: ubuntu-latest
container:
image: ghcr.io/your-namespace/legacy-build:latest
# Если используешь Docker Hub: image: your-username/legacy-build:latest
steps:
- name: Выгружаем исходники
uses: actions/checkout@v4
# Опционально: Кэшируем зависимости (если есть)
- name: Кэшируем пакеты для сборки
uses: actions/cache@v4
with:
path: /var/cache/apt
key: ${{ runner.os }}-apt-${{ hashFiles('**/build.sh') }}
restore-keys: |
${{ runner.os }}-apt-
# Запускаем оригинальный скрипт (теперь внутри контейнера)
- name: Запускаем legacy сборку
run: |
chmod +x build.sh
./build.sh
# Пример: собираем артефакты
- name: Архивируем бинарники
if: success()
uses: actions/upload-artifact@v4
with:
name: binaries
path: ./dist/**
# Пример: публикуем в registry (опционально)
- name: Публикуем в GitHub Package Registry
if: success()
run: |
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
docker build -t ghcr.io/your-namespace/legacy-image:${{ github.sha }} .
docker push ghcr.io/your-namespace/legacy-image:${{ github.sha }}
```
**Ключевые моменты:**
- Ключ `container` скачивает Docker-образ, который мы создали. Это очищает хост-раннер и обеспечивает постоянство среды legacy.
- `build.sh` запускается без изменений внутри этого контейнера, так что тебе не придется менять внутренности скрипта, если только тебе не нужно подправить переменные окружения или пути.
- Кэширование `apt`-кэша ускоряет последующие запуски, если скрипт устанавливает пакеты на лету. Ты можешь настроить путь к кэшу, чтобы он соответствовал тому, что использует твой скрипт.
- Загрузка артефактов позволяет сохранить бинарники, созданные legacy-скриптом; настрой путь, чтобы он соответствовал тому, что выдает твой скрипт (здесь предполагается, что это `./dist/`).
- Опциональный шаг публикации отправляет контейнерный образ, построенный из репозитория — хорошо, если твой legacy-код публикует бинарник, который можно контейнеризовать.
---
### 3. Тестируем локально (опционально)
Если ты хочешь предварительно просмотреть пайплайн перед отправкой, ты можешь запустить Docker-контейнер локально:
```sh
docker run --rm -it -v $(pwd):/app your-namespace/legacy-build:latest /bin/bash
# Внутри контейнера:
chmod +x build.sh
./build.sh
```
Так ты можешь отладить любые различия в путях или переменных окружения, прежде чем CI-задача запустится.
---
### 4. Настройка legacy-скрипта
Если скрипт пишет вывод в нестандартное местоположение или ожидает определенную переменную окружения, ты можешь добавить шаг-обертку перед `./build.sh`:
```yaml
- name: Устанавливаем переменные окружения
run: |
echo "LD_LIBRARY_PATH=/app/lib" >> $GITHUB_ENV
echo "BUILD_DIR=/app/dist" >> $GITHUB_ENV
```
Затем скрипт может ссылаться на `$LD_LIBRARY_PATH` или `$BUILD_DIR`, как необходимо.
---
### 5. Уборка и поддержка
- Храни `Dockerfile` под версионным контролем; если для сборки требуются более новые инструменты, просто обнови базовый образ и перестрой контейнерный образ.
- Если у legacy-кода много ручных шагов `make install`, подумай о том, чтобы убрать их или добавить флаг `--prefix=/app/install`, чтобы не загрязнять контейнер.
- Для сборок, которые занимают много времени, ты можешь добавить стратегию "таймаут" в workflow, или использовать self-hosted runners, если размер контейнера или ограничения сети становятся проблемой.
---
Это должно дать тебе чистый, воспроизводимый CI-пайплайн, который запускает старый скрипт в замкнутой среде, собирает артефакты и опционально публикует контейнеризованную версию результата. Как только workflow будет запущен, каждое push или pull-запрос запустит сборку автоматически — больше никаких ручных шагов для старого скрипта.
Выглядит надёжно, но следи за тем старым `make`, который всё ещё пытается лезть в `/usr/bin`. Лучше перенаправить его или смонтировать поддельный `/usr`. И постарайся сделать контейнер минималистичным — нет смысла в полноценном дистрибутиве, если можно обойтись Alpine с `gcc`, `make` и `git`. Так и размер образа будет меньше, и CI быстрее. Удачи с этой древней реликвией, дай знать, если что-то пойдёт не так.