Исправить передачу исходников в CI-контейнеры
Some checks failed
Проверка, сборка и развёртывание Magistr / Обязательные проверки (push) Successful in 1m23s
Проверка, сборка и развёртывание Magistr / Собрать backend image (push) Successful in 7m36s
Проверка, сборка и развёртывание Magistr / Собрать frontend image (push) Successful in 31s
Проверка, сборка и развёртывание Magistr / Проверить опубликованные образы (push) Failing after 4m56s
Проверка, сборка и развёртывание Magistr / Развернуть проверенные digests (push) Has been skipped
Some checks failed
Проверка, сборка и развёртывание Magistr / Обязательные проверки (push) Successful in 1m23s
Проверка, сборка и развёртывание Magistr / Собрать backend image (push) Successful in 7m36s
Проверка, сборка и развёртывание Magistr / Собрать frontend image (push) Successful in 31s
Проверка, сборка и развёртывание Magistr / Проверить опубликованные образы (push) Failing after 4m56s
Проверка, сборка и развёртывание Magistr / Развернуть проверенные digests (push) Has been skipped
This commit is contained in:
@@ -4,6 +4,8 @@ set -euo pipefail
|
||||
|
||||
PROJECT_ROOT=${PROJECT_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}
|
||||
WORKFLOW="$PROJECT_ROOT/.gitea/workflows/docker-build.yaml"
|
||||
CI_CONTAINER_SCRIPT="$PROJECT_ROOT/scripts/run-ci-container.sh"
|
||||
CI_CONTAINER_TEST="$PROJECT_ROOT/scripts/test-run-ci-container.sh"
|
||||
|
||||
failures=0
|
||||
|
||||
@@ -60,7 +62,7 @@ require_count() {
|
||||
local description=$3
|
||||
local actual
|
||||
|
||||
actual=$(grep -Ec "$pattern" "$WORKFLOW" || true)
|
||||
actual=$(grep -Ec -- "$pattern" "$WORKFLOW" || true)
|
||||
if (( actual < expected )); then
|
||||
fail "$description: ожидается не менее $expected, найдено $actual"
|
||||
fi
|
||||
@@ -68,6 +70,8 @@ require_count() {
|
||||
|
||||
check_workflow_gates() {
|
||||
require_file "$WORKFLOW" || return
|
||||
require_file "$CI_CONTAINER_SCRIPT" || return
|
||||
require_file "$CI_CONTAINER_TEST" || return
|
||||
|
||||
require_count '^[[:space:]]+sbom:[[:space:]]+true$' 2 \
|
||||
"для обоих образов должна публиковаться SBOM attestation"
|
||||
@@ -81,6 +85,17 @@ check_workflow_gates() {
|
||||
"образ Maven для CI должен быть закреплён digest"
|
||||
require_count 'NODE_IMAGE: [^[:space:]]+@sha256:[0-9a-f]{64}$' 1 \
|
||||
"образ Node.js для CI должен быть закреплён digest"
|
||||
require_count 'bash scripts/run-ci-container\.sh' 4 \
|
||||
"тесты и Trivy должны передавать файлы через Docker API"
|
||||
require_count 'bash scripts/test-run-ci-container\.sh' 1 \
|
||||
"workflow должен проверять helper запуска CI-контейнеров"
|
||||
require_count '--env DOCKER_CONFIG=/workspace' 2 \
|
||||
"оба Trivy scan должны получать registry credentials через Docker API"
|
||||
|
||||
if grep -Fq '${{ github.workspace }}' "$WORKFLOW" \
|
||||
|| grep -Fq -- '-v "$HOME' "$WORKFLOW"; then
|
||||
fail "нельзя использовать пути job-контейнера в bind mount внешнего Docker daemon"
|
||||
fi
|
||||
|
||||
if ! grep -Eq '^ needs: \[build-and-push-backend, build-and-push-frontend, security-scan\]$' "$WORKFLOW"; then
|
||||
fail "deploy обязан зависеть от успешного security-scan"
|
||||
|
||||
87
scripts/run-ci-container.sh
Executable file
87
scripts/run-ci-container.sh
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if (( $# < 4 )); then
|
||||
printf 'Использование: %s <каталог-исходников> <образ> [--copy <каталог> <путь>] [--env <ИМЯ=значение>] -- <команда> [аргументы...]\n' \
|
||||
"${0##*/}" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
SOURCE_DIR=$1
|
||||
IMAGE=$2
|
||||
shift 2
|
||||
EXTRA_SOURCE_DIRS=()
|
||||
EXTRA_DESTINATIONS=()
|
||||
CREATE_ARGS=()
|
||||
|
||||
while (( $# > 0 )); do
|
||||
case "$1" in
|
||||
--copy)
|
||||
if (( $# < 3 )); then
|
||||
printf '[CI-КОНТЕЙНЕР] Ошибка: для --copy нужны каталог и путь в контейнере\n' >&2
|
||||
exit 2
|
||||
fi
|
||||
EXTRA_SOURCE_DIRS+=("$2")
|
||||
EXTRA_DESTINATIONS+=("$3")
|
||||
shift 3
|
||||
;;
|
||||
--env)
|
||||
if (( $# < 2 )) || [[ ! "$2" =~ ^[A-Za-z_][A-Za-z0-9_]*=.*$ ]]; then
|
||||
printf '[CI-КОНТЕЙНЕР] Ошибка: для --env ожидается ИМЯ=значение\n' >&2
|
||||
exit 2
|
||||
fi
|
||||
CREATE_ARGS+=(--env "$2")
|
||||
shift 2
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
*)
|
||||
printf '[CI-КОНТЕЙНЕР] Ошибка: неизвестный аргумент до команды: %s\n' "$1" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if (( $# == 0 )); then
|
||||
printf '[CI-КОНТЕЙНЕР] Ошибка: не указана команда контейнера\n' >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ ! -d "$SOURCE_DIR" ]]; then
|
||||
printf '[CI-КОНТЕЙНЕР] Ошибка: каталог исходников не найден: %s\n' "$SOURCE_DIR" >&2
|
||||
exit 2
|
||||
fi
|
||||
for index in "${!EXTRA_SOURCE_DIRS[@]}"; do
|
||||
extra_source=${EXTRA_SOURCE_DIRS[$index]}
|
||||
extra_destination=${EXTRA_DESTINATIONS[$index]}
|
||||
if [[ ! -d "$extra_source" ]]; then
|
||||
printf '[CI-КОНТЕЙНЕР] Ошибка: дополнительный каталог не найден: %s\n' \
|
||||
"$extra_source" >&2
|
||||
exit 2
|
||||
fi
|
||||
if [[ "$extra_destination" != /* || "$extra_destination" == *..* ]]; then
|
||||
printf '[CI-КОНТЕЙНЕР] Ошибка: путь назначения должен быть абсолютным без ..: %s\n' \
|
||||
"$extra_destination" >&2
|
||||
exit 2
|
||||
fi
|
||||
done
|
||||
|
||||
CONTAINER_ID=
|
||||
|
||||
cleanup() {
|
||||
if [[ -n "$CONTAINER_ID" ]]; then
|
||||
docker rm --force "$CONTAINER_ID" >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
CONTAINER_ID=$(docker create --workdir /workspace "${CREATE_ARGS[@]}" "$IMAGE" "$@")
|
||||
docker cp "$SOURCE_DIR/." "$CONTAINER_ID:/workspace"
|
||||
for index in "${!EXTRA_SOURCE_DIRS[@]}"; do
|
||||
docker cp "${EXTRA_SOURCE_DIRS[$index]}/." \
|
||||
"$CONTAINER_ID:${EXTRA_DESTINATIONS[$index]}"
|
||||
done
|
||||
docker start --attach "$CONTAINER_ID"
|
||||
@@ -7,12 +7,20 @@ CHECK_SCRIPT="$ROOT_DIR/scripts/check-artifact-pinning.sh"
|
||||
FIXTURE_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$FIXTURE_DIR"' EXIT
|
||||
|
||||
mkdir -p "$FIXTURE_DIR/backend" "$FIXTURE_DIR/frontend" "$FIXTURE_DIR/.gitea/workflows"
|
||||
mkdir -p \
|
||||
"$FIXTURE_DIR/backend" \
|
||||
"$FIXTURE_DIR/frontend" \
|
||||
"$FIXTURE_DIR/.gitea/workflows" \
|
||||
"$FIXTURE_DIR/scripts"
|
||||
cp "$ROOT_DIR/backend/Dockerfile" "$FIXTURE_DIR/backend/Dockerfile"
|
||||
cp "$ROOT_DIR/frontend/Dockerfile" "$FIXTURE_DIR/frontend/Dockerfile"
|
||||
cp "$ROOT_DIR/compose.yaml" "$FIXTURE_DIR/compose.yaml"
|
||||
cp "$ROOT_DIR/.gitea/workflows/docker-build.yaml" \
|
||||
"$FIXTURE_DIR/.gitea/workflows/docker-build.yaml"
|
||||
cp "$ROOT_DIR/scripts/run-ci-container.sh" \
|
||||
"$FIXTURE_DIR/scripts/run-ci-container.sh"
|
||||
cp "$ROOT_DIR/scripts/test-run-ci-container.sh" \
|
||||
"$FIXTURE_DIR/scripts/test-run-ci-container.sh"
|
||||
|
||||
PROJECT_ROOT="$FIXTURE_DIR" bash "$CHECK_SCRIPT" >/dev/null
|
||||
|
||||
@@ -38,4 +46,13 @@ if PROJECT_ROOT="$FIXTURE_DIR" bash "$CHECK_SCRIPT" >/dev/null 2>&1; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp "$ROOT_DIR/.gitea/workflows/docker-build.yaml" \
|
||||
"$FIXTURE_DIR/.gitea/workflows/docker-build.yaml"
|
||||
sed -i '$a\# docker run --rm -v "${{ github.workspace }}/backend:/workspace"' \
|
||||
"$FIXTURE_DIR/.gitea/workflows/docker-build.yaml"
|
||||
if PROJECT_ROOT="$FIXTURE_DIR" bash "$CHECK_SCRIPT" >/dev/null 2>&1; then
|
||||
printf 'Ошибка теста: bind mount github.workspace не был отклонён\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf 'Проверка закрепления артефактов завершена успешно\n'
|
||||
|
||||
75
scripts/test-run-ci-container.sh
Executable file
75
scripts/test-run-ci-container.sh
Executable file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
RUN_SCRIPT="$ROOT_DIR/scripts/run-ci-container.sh"
|
||||
FIXTURE_DIR=$(mktemp -d)
|
||||
CALL_LOG="$FIXTURE_DIR/docker-calls.log"
|
||||
FAKE_BIN="$FIXTURE_DIR/bin"
|
||||
SOURCE_DIR="$FIXTURE_DIR/source"
|
||||
EXTRA_SOURCE_DIR="$FIXTURE_DIR/extra-source"
|
||||
trap 'rm -rf "$FIXTURE_DIR"' EXIT
|
||||
|
||||
mkdir -p "$FAKE_BIN" "$SOURCE_DIR" "$EXTRA_SOURCE_DIR"
|
||||
printf 'fixture\n' > "$SOURCE_DIR/pom.xml"
|
||||
printf 'extra fixture\n' > "$EXTRA_SOURCE_DIR/backend.java"
|
||||
|
||||
cat > "$FAKE_BIN/docker" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
printf '%s\n' "$*" >> "$DOCKER_CALL_LOG"
|
||||
case "$1" in
|
||||
create)
|
||||
printf 'ci-container-id\n'
|
||||
;;
|
||||
start)
|
||||
exit "${DOCKER_START_EXIT_CODE:-0}"
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
chmod +x "$FAKE_BIN/docker"
|
||||
|
||||
DOCKER_CALL_LOG="$CALL_LOG" PATH="$FAKE_BIN:$PATH" \
|
||||
bash "$RUN_SCRIPT" "$SOURCE_DIR" 'registry.local/test@sha256:abc' \
|
||||
--copy "$EXTRA_SOURCE_DIR" /backend \
|
||||
--env DOCKER_CONFIG=/workspace \
|
||||
-- sh -c 'exit 0'
|
||||
|
||||
grep --fixed-strings \
|
||||
'create --workdir /workspace --env DOCKER_CONFIG=/workspace registry.local/test@sha256:abc sh -c exit 0' \
|
||||
"$CALL_LOG" >/dev/null
|
||||
grep --fixed-strings \
|
||||
"cp $SOURCE_DIR/. ci-container-id:/workspace" \
|
||||
"$CALL_LOG" >/dev/null
|
||||
grep --fixed-strings \
|
||||
"cp $EXTRA_SOURCE_DIR/. ci-container-id:/backend" \
|
||||
"$CALL_LOG" >/dev/null
|
||||
grep --fixed-strings 'start --attach ci-container-id' "$CALL_LOG" >/dev/null
|
||||
grep --fixed-strings 'rm --force ci-container-id' "$CALL_LOG" >/dev/null
|
||||
if grep -Eq '(^|[[:space:]])(-v|--volume)([[:space:]]|=)' "$CALL_LOG"; then
|
||||
printf 'Ошибка теста: helper использовал bind mount\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
: > "$CALL_LOG"
|
||||
set +e
|
||||
DOCKER_CALL_LOG="$CALL_LOG" DOCKER_START_EXIT_CODE=17 PATH="$FAKE_BIN:$PATH" \
|
||||
bash "$RUN_SCRIPT" "$SOURCE_DIR" 'registry.local/test@sha256:abc' \
|
||||
-- sh -c 'exit 17' >/dev/null 2>&1
|
||||
status=$?
|
||||
set -e
|
||||
|
||||
if (( status != 17 )); then
|
||||
printf 'Ошибка теста: код контейнера 17 превратился в %d\n' "$status" >&2
|
||||
exit 1
|
||||
fi
|
||||
grep --fixed-strings 'rm --force ci-container-id' "$CALL_LOG" >/dev/null
|
||||
|
||||
if PATH="$FAKE_BIN:$PATH" bash "$RUN_SCRIPT" "$FIXTURE_DIR/missing" \
|
||||
'registry.local/test@sha256:abc' -- true >/dev/null 2>&1; then
|
||||
printf 'Ошибка теста: отсутствующий каталог исходников не был отклонён\n' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf 'Проверка запуска CI-контейнеров без bind mount завершена успешно\n'
|
||||
Reference in New Issue
Block a user