forked from baron/baron-sso
웍스 드라이브 구조 변경
This commit is contained in:
@@ -9,6 +9,7 @@ deploy_workflow="$repo_root/.gitea/workflows/production_image_deploy.yml"
|
||||
image_compose="$repo_root/deploy/templates/docker-compose.images.yaml"
|
||||
bundle_script="$repo_root/scripts/deploy/build_image_deploy_bundle.sh"
|
||||
remote_deploy_script="$repo_root/scripts/deploy/upload_and_run_image_deploy.sh"
|
||||
works_image_download_script="$repo_root/scripts/docker-image/download_works_drive.sh"
|
||||
|
||||
fail() {
|
||||
echo "$1" >&2
|
||||
@@ -22,6 +23,7 @@ fail() {
|
||||
[[ -f "$image_compose" ]] || fail "image-based production compose template must exist."
|
||||
[[ -f "$bundle_script" ]] || fail "shared image deployment bundle script must exist."
|
||||
[[ -f "$remote_deploy_script" ]] || fail "shared image remote deploy script must exist."
|
||||
[[ -f "$works_image_download_script" ]] || fail "shared WORKS Drive image download script must exist."
|
||||
|
||||
grep -Fq "name: Publish Baron SSO Images" "$publish_workflow" \
|
||||
|| fail "publish workflow must have the shared stage/production name."
|
||||
@@ -58,8 +60,10 @@ grep -Fq "WORKS_DRIVE_OAUTH_CLIENT_SECRET: \${{ secrets.WORKS_OAUTH_CLIENT_SECRE
|
||||
|| fail "publish workflow must use the Gitea-compatible WORKS OAuth client secret name."
|
||||
grep -Fq "WORKS_DRIVE_OAUTH_REFRESH_TOKEN: \${{ secrets.WORKS_DRIVE_REFRESH_TOKEN }}" "$publish_workflow" \
|
||||
|| fail "publish workflow must support WORKS Drive refresh-token auth."
|
||||
grep -Fq "WORKS_DRIVE_PARENT_FILE_ID" "$publish_workflow" \
|
||||
|| fail "publish workflow must target a WORKS Drive folder."
|
||||
grep -Fq "WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID: \${{ vars.WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID }}" "$publish_workflow" \
|
||||
|| fail "publish workflow must use the Docker-image-specific WORKS Drive ID variable."
|
||||
grep -Fq 'WORKS_DRIVE_SHARED_DRIVE_ID="${WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID}"' "$publish_workflow" \
|
||||
|| fail "publish workflow must map WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID into the shared upload script."
|
||||
grep -Fq "Resolve WORKS Drive access token" "$publish_workflow" \
|
||||
|| fail "publish workflow must resolve a short-lived WORKS Drive access token before uploads."
|
||||
grep -Fq "WORKS_DRIVE_ACCESS_TOKEN_INPUT" "$publish_workflow" \
|
||||
@@ -90,6 +94,8 @@ grep -Fq "scripts/deploy/build_image_deploy_bundle.sh" "$staging_deploy_workflow
|
||||
|| fail "staging deploy workflow must use the shared bundle script."
|
||||
grep -Fq "scripts/deploy/upload_and_run_image_deploy.sh" "$staging_deploy_workflow" \
|
||||
|| fail "staging deploy workflow must use the shared remote deploy script."
|
||||
grep -Fq "WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID: \${{ vars.WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID }}" "$staging_deploy_workflow" \
|
||||
|| fail "staging deploy workflow must pass the Docker-image-specific WORKS Drive ID variable."
|
||||
|
||||
grep -Fq "name: Deploy Baron SSO Production Images" "$deploy_workflow" \
|
||||
|| fail "deploy workflow must have the expected name."
|
||||
@@ -109,14 +115,23 @@ grep -Fq "scripts/deploy/build_image_deploy_bundle.sh" "$deploy_workflow" \
|
||||
|| fail "production deploy workflow must use the shared bundle script."
|
||||
grep -Fq "scripts/deploy/upload_and_run_image_deploy.sh" "$deploy_workflow" \
|
||||
|| fail "production deploy workflow must use the shared remote deploy script."
|
||||
grep -Fq "WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID: \${{ vars.WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID }}" "$deploy_workflow" \
|
||||
|| fail "production deploy workflow must pass the Docker-image-specific WORKS Drive ID variable."
|
||||
grep -Fq "Same image tag contract as staging" "$deploy_workflow" \
|
||||
|| fail "production deploy workflow must document that it uses the same image tag as staging."
|
||||
grep -Fq "TRAEFIK_PUBLIC_NETWORK=traefik-public" "$bundle_script" \
|
||||
|| fail "shared bundle script must write Traefik public network env."
|
||||
grep -Fq "docker compose --env-file .env -f docker-compose.yml pull" "$remote_deploy_script" \
|
||||
|| fail "shared remote deploy script must pull the requested image version before running."
|
||||
grep -Fq "scripts/docker-image/download_works_drive.sh" "$remote_deploy_script" \
|
||||
|| fail "shared remote deploy script must load requested image archives from WORKS Drive before running."
|
||||
grep -Fq "docker load" "$works_image_download_script" \
|
||||
|| fail "WORKS Drive image download script must load downloaded archives into Docker."
|
||||
grep -Fq 'baron-sso/${IMAGE_TAG}/${image}.${IMAGE_TAG}.tar.zst' "$works_image_download_script" \
|
||||
|| fail "WORKS Drive image download script must document the normalized archive path."
|
||||
grep -Fq "docker compose --env-file .env -f docker-compose.yml up -d" "$remote_deploy_script" \
|
||||
|| fail "shared remote deploy script must start the stack after pulling images."
|
||||
if grep -Eiq 'harbor|docker login|docker compose --env-file .env -f docker-compose.yml pull|HARBOR_' "$staging_deploy_workflow" "$deploy_workflow" "$remote_deploy_script"; then
|
||||
fail "image deploy workflows/scripts must not depend on Harbor registry login or compose pull."
|
||||
fi
|
||||
|
||||
if grep -Eq 'docker (build|commit)' "$staging_deploy_workflow" "$deploy_workflow"; then
|
||||
fail "staging/production deploy workflows must never build or commit images remotely."
|
||||
|
||||
146
test/works_drive_docker_image_download_policy_test.sh
Normal file
146
test/works_drive_docker_image_download_policy_test.sh
Normal file
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
script="$repo_root/scripts/docker-image/download_works_drive.sh"
|
||||
tmp_root="$(mktemp -d)"
|
||||
|
||||
cleanup() {
|
||||
rm -rf "$tmp_root"
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
fail() {
|
||||
echo "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
[[ -x "$script" ]] || fail "download script must exist and be executable."
|
||||
grep -Fq 'baron-sso/${IMAGE_TAG}/${image}.${IMAGE_TAG}.tar.zst' "$script" \
|
||||
|| fail "download script must document the normalized archive path."
|
||||
grep -Fq -- '--location-trusted' "$script" \
|
||||
|| fail "download script must preserve Authorization across WORKS download redirects."
|
||||
|
||||
source_dir="$tmp_root/source"
|
||||
mkdir -p "$source_dir"
|
||||
printf 'backend image archive payload\n' >"$source_dir/backend.txt"
|
||||
tar -C "$source_dir" -cf "$tmp_root/backend.v1.2606.ab12.tar" backend.txt
|
||||
zstd -q -f -o "$tmp_root/backend.v1.2606.ab12.tar.zst" "$tmp_root/backend.v1.2606.ab12.tar"
|
||||
archive_sha256="$(sha256sum "$tmp_root/backend.v1.2606.ab12.tar.zst" | awk '{print $1}')"
|
||||
archive_size="$(wc -c <"$tmp_root/backend.v1.2606.ab12.tar.zst" | tr -d ' ')"
|
||||
printf '%s backend.v1.2606.ab12.tar.zst\n' "$archive_sha256" >"$tmp_root/backend.v1.2606.ab12.sha256"
|
||||
jq -n \
|
||||
--arg sha "$archive_sha256" \
|
||||
--argjson size "$archive_size" \
|
||||
'{
|
||||
schema_version: 1,
|
||||
format: "docker-save-zstd",
|
||||
image_ref: "baron_sso/backend:v1.2606.ab12",
|
||||
repository: "baron_sso/backend",
|
||||
release_repository: "baron-sso",
|
||||
image_name: "backend",
|
||||
tag: "v1.2606.ab12",
|
||||
remote_path: "baron-sso/v1.2606.ab12",
|
||||
archive: {
|
||||
file_name: "backend.v1.2606.ab12.tar.zst",
|
||||
sha256: $sha,
|
||||
size_bytes: $size
|
||||
},
|
||||
images: {
|
||||
backend: {
|
||||
archive: {
|
||||
file_name: "backend.v1.2606.ab12.tar.zst",
|
||||
sha256: $sha,
|
||||
size_bytes: $size
|
||||
}
|
||||
}
|
||||
}
|
||||
}' >"$tmp_root/manifest.v1.2606.ab12.json"
|
||||
|
||||
curl_log="$tmp_root/curl.log"
|
||||
docker_log="$tmp_root/docker.log"
|
||||
fake_curl="$tmp_root/curl"
|
||||
cat >"$fake_curl" <<'SH'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
printf '%s\n' "$*" >>"$FAKE_CURL_LOG"
|
||||
|
||||
output_file=""
|
||||
args=("$@")
|
||||
for ((i = 0; i < ${#args[@]}; i += 1)); do
|
||||
if [[ "${args[$i]}" == "-o" ]]; then
|
||||
output_file="${args[$((i + 1))]}"
|
||||
fi
|
||||
done
|
||||
url="${args[-1]}"
|
||||
|
||||
if [[ -n "$output_file" ]]; then
|
||||
case "$url" in
|
||||
*/files/backend-archive/download) cp "$FAKE_WORKS_SOURCE/backend.v1.2606.ab12.tar.zst" "$output_file" ;;
|
||||
*/files/backend-checksum/download) cp "$FAKE_WORKS_SOURCE/backend.v1.2606.ab12.sha256" "$output_file" ;;
|
||||
*/files/backend-manifest/download) cp "$FAKE_WORKS_SOURCE/manifest.v1.2606.ab12.json" "$output_file" ;;
|
||||
*) echo "unexpected download URL: $url" >&2; exit 2 ;;
|
||||
esac
|
||||
exit 0
|
||||
fi
|
||||
|
||||
case "$url" in
|
||||
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/children)
|
||||
printf '{"files":[{"fileId":"baron-sso-id","fileName":"baron-sso","fileType":"FOLDER"}]}\n200\n'
|
||||
;;
|
||||
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/baron-sso-id/children)
|
||||
printf '{"files":[{"fileId":"tag-id","fileName":"v1.2606.ab12","fileType":"FOLDER"}]}\n200\n'
|
||||
;;
|
||||
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/tag-id/children)
|
||||
printf '{"files":[{"fileId":"backend-archive","fileName":"backend.v1.2606.ab12.tar.zst","fileType":"FILE"},{"fileId":"backend-checksum","fileName":"backend.v1.2606.ab12.sha256","fileType":"FILE"},{"fileId":"backend-manifest","fileName":"manifest.v1.2606.ab12.json","fileType":"FILE"}]}\n200\n'
|
||||
;;
|
||||
*)
|
||||
echo "unexpected list URL: $url" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
SH
|
||||
chmod +x "$fake_curl"
|
||||
|
||||
fake_bin="$tmp_root/bin"
|
||||
mkdir -p "$fake_bin"
|
||||
cat >"$fake_bin/docker" <<'SH'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "$1" == "load" ]]; then
|
||||
bytes="$(wc -c | tr -d ' ')"
|
||||
printf 'docker load bytes=%s\n' "$bytes" >>"$FAKE_DOCKER_LOG"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "unexpected docker command: $*" >&2
|
||||
exit 2
|
||||
SH
|
||||
chmod +x "$fake_bin/docker"
|
||||
|
||||
PATH="$fake_bin:$PATH" \
|
||||
FAKE_CURL_LOG="$curl_log" \
|
||||
FAKE_DOCKER_LOG="$docker_log" \
|
||||
FAKE_WORKS_SOURCE="$tmp_root" \
|
||||
WORKS_DRIVE_CURL_BIN="$fake_curl" \
|
||||
WORKS_DRIVE_ACCESS_TOKEN="test-access-token" \
|
||||
WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID="shared-drive-1" \
|
||||
WORKS_DOCKER_IMAGE_NAMES="backend" \
|
||||
WORKS_DOCKER_IMAGE_DOWNLOAD_DIR="$tmp_root/downloaded" \
|
||||
IMAGE_TAG="v1.2606.ab12" \
|
||||
"$script" >/dev/null
|
||||
|
||||
grep -Fq "sharedrives/shared-drive-1/files/children" "$curl_log" \
|
||||
|| fail "download script must list the shared drive root."
|
||||
grep -Fq "sharedrives/shared-drive-1/files/baron-sso-id/children" "$curl_log" \
|
||||
|| fail "download script must resolve the baron-sso folder."
|
||||
grep -Fq "sharedrives/shared-drive-1/files/tag-id/children" "$curl_log" \
|
||||
|| fail "download script must resolve the image tag folder."
|
||||
grep -Fq "files/backend-archive/download" "$curl_log" \
|
||||
|| fail "download script must download the normalized backend archive."
|
||||
grep -Fq "docker load bytes=" "$docker_log" \
|
||||
|| fail "download script must load the downloaded archive into Docker."
|
||||
|
||||
echo "OK: WORKS Drive Docker image archive download flow resolves, verifies, and loads image artifacts"
|
||||
@@ -14,19 +14,19 @@ fail() {
|
||||
[[ -f "$script" ]] || fail "WORKS Drive Docker image upload script must exist."
|
||||
[[ -f "$doc" ]] || fail "WORKS Drive Docker image archive design document must exist."
|
||||
|
||||
grep -Fq 'WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR:-docker-build-image' "$script" \
|
||||
|| fail "script must default WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR to docker-build-image."
|
||||
grep -Fq 'WORKS_DRIVE_DOCKER_IMAGE_DIR:-${WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR:-baron-sso}' "$script" \
|
||||
|| fail "script must default WORKS_DRIVE_DOCKER_IMAGE_DIR to baron-sso with legacy fallback."
|
||||
grep -Fq 'docker commit' "$script" \
|
||||
|| fail "script must support committing a local container before image export."
|
||||
grep -Fq 'docker save' "$script" \
|
||||
|| fail "script must use docker save for CLI-compatible image artifacts."
|
||||
grep -Fq 'zstd' "$script" \
|
||||
|| fail "script must compress Docker image archives with zstd."
|
||||
grep -Fq 'manifest.json' "$script" \
|
||||
|| fail "script must write a manifest.json next to the image archive."
|
||||
grep -Fq 'image.tar.zst.sha256' "$script" \
|
||||
grep -Fq 'manifest.${image_tag}.json' "$script" \
|
||||
|| fail "script must write a versioned manifest next to the image archive."
|
||||
grep -Fq '${image_name}.${image_tag}.sha256' "$script" \
|
||||
|| fail "script must write a checksum file for the compressed image archive."
|
||||
grep -Fq 'docker-build-image/baron_sso/backend/v1.2606.ab12' "$doc" \
|
||||
grep -Fq 'baron-sso/v1.2606.ab12/backend.v1.2606.ab12.tar.zst' "$doc" \
|
||||
|| fail "document must describe the expected WORKS Drive folder layout."
|
||||
grep -Fq 'debian:trixie-slim' "$doc" \
|
||||
|| fail "document must use debian:trixie-slim for smoke image examples."
|
||||
@@ -124,24 +124,12 @@ case "$last_arg" in
|
||||
printf '{"files":[]}'
|
||||
;;
|
||||
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/root-folder/createfolder)
|
||||
printf '{"fileId":"docker-build-image-id","fileName":"docker-build-image","fileType":"FOLDER"}'
|
||||
;;
|
||||
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/docker-build-image-id/children)
|
||||
printf '{"files":[]}'
|
||||
;;
|
||||
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/docker-build-image-id/createfolder)
|
||||
printf '{"fileId":"baron-sso-id","fileName":"baron_sso","fileType":"FOLDER"}'
|
||||
printf '{"fileId":"baron-sso-id","fileName":"baron-sso","fileType":"FOLDER"}'
|
||||
;;
|
||||
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/baron-sso-id/children)
|
||||
printf '{"files":[]}'
|
||||
;;
|
||||
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/baron-sso-id/createfolder)
|
||||
printf '{"fileId":"backend-id","fileName":"backend","fileType":"FOLDER"}'
|
||||
;;
|
||||
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/backend-id/children)
|
||||
printf '{"files":[]}'
|
||||
;;
|
||||
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/backend-id/createfolder)
|
||||
printf '{"fileId":"tag-id","fileName":"v1.2606.ab12","fileType":"FOLDER"}'
|
||||
;;
|
||||
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/tag-id)
|
||||
@@ -175,41 +163,41 @@ WORKS_DOCKER_COMMIT_CONTAINER="baron_backend" \
|
||||
DOCKER_IMAGE_REF="registry.example/baron_sso/backend:v1.2606.ab12" \
|
||||
"$script" >"$tmp_dir/upload.out"
|
||||
|
||||
artifact_dir="$archive_dir/baron_sso/backend/v1.2606.ab12"
|
||||
[[ -f "$artifact_dir/image.tar.zst" ]] || fail "script must create image.tar.zst."
|
||||
[[ -f "$artifact_dir/image.tar.zst.sha256" ]] || fail "script must create image.tar.zst.sha256."
|
||||
[[ -f "$artifact_dir/manifest.json" ]] || fail "script must create manifest.json."
|
||||
artifact_dir="$archive_dir/baron-sso/v1.2606.ab12"
|
||||
[[ -f "$artifact_dir/backend.v1.2606.ab12.tar.zst" ]] || fail "script must create backend.v1.2606.ab12.tar.zst."
|
||||
[[ -f "$artifact_dir/backend.v1.2606.ab12.sha256" ]] || fail "script must create backend.v1.2606.ab12.sha256."
|
||||
[[ -f "$artifact_dir/manifest.v1.2606.ab12.json" ]] || fail "script must create manifest.v1.2606.ab12.json."
|
||||
|
||||
jq -e \
|
||||
'.schema_version == 1
|
||||
and .format == "docker-save-zstd"
|
||||
and .image_ref == "registry.example/baron_sso/backend:v1.2606.ab12"
|
||||
and .repository == "baron_sso/backend"
|
||||
and .tag == "v1.2606.ab12"
|
||||
and .remote_path == "docker-build-image/baron_sso/backend/v1.2606.ab12"
|
||||
and .archive.file_name == "image.tar.zst"
|
||||
and (.archive.sha256 | type == "string")' \
|
||||
"$artifact_dir/manifest.json" >/dev/null || fail "manifest must describe the image archive and remote path."
|
||||
and .release_repository == "baron-sso"
|
||||
and .image_name == "backend"
|
||||
and .tag == "v1.2606.ab12"
|
||||
and .remote_path == "baron-sso/v1.2606.ab12"
|
||||
and .archive.file_name == "backend.v1.2606.ab12.tar.zst"
|
||||
and (.archive.sha256 | type == "string")
|
||||
and .images.backend.archive.file_name == "backend.v1.2606.ab12.tar.zst"
|
||||
and .images.backend.archive.sha256 == .archive.sha256' \
|
||||
"$artifact_dir/manifest.v1.2606.ab12.json" >/dev/null || fail "manifest must describe the image archive and remote path."
|
||||
|
||||
grep -Fq "docker commit baron_backend registry.example/baron_sso/backend:v1.2606.ab12" "$docker_log" \
|
||||
|| fail "script must commit the requested container into the requested image ref."
|
||||
grep -Fq "docker save -o" "$docker_log" \
|
||||
|| fail "script must save the requested image."
|
||||
grep -Fq "sharedrives/shared-drive-1/files/root-folder/createfolder" "$curl_log" \
|
||||
|| fail "script must create the top-level docker-build-image folder when needed."
|
||||
grep -Fq "docker-build-image" "$curl_log" \
|
||||
|| fail "script must use WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR in folder creation."
|
||||
grep -Fq "baron_sso" "$curl_log" \
|
||||
|| fail "script must create the top-level archive folder when needed."
|
||||
grep -Fq "baron-sso" "$curl_log" \
|
||||
|| fail "script must create repository namespace folder."
|
||||
grep -Fq "backend" "$curl_log" \
|
||||
|| fail "script must create image repository folder."
|
||||
grep -Fq "v1.2606.ab12" "$curl_log" \
|
||||
|| fail "script must create tag folder."
|
||||
grep -Fq "image.tar.zst" "$curl_log" \
|
||||
grep -Fq "backend.v1.2606.ab12.tar.zst" "$curl_log" \
|
||||
|| fail "script must upload the compressed image archive."
|
||||
grep -Fq "image.tar.zst.sha256" "$curl_log" \
|
||||
grep -Fq "backend.v1.2606.ab12.sha256" "$curl_log" \
|
||||
|| fail "script must upload the checksum file."
|
||||
grep -Fq "manifest.json" "$curl_log" \
|
||||
grep -Fq "manifest.v1.2606.ab12.json" "$curl_log" \
|
||||
|| fail "script must upload the manifest file."
|
||||
|
||||
report_file="$artifact_dir/works-upload.json"
|
||||
|
||||
Reference in New Issue
Block a user