forked from baron/baron-sso
345 lines
13 KiB
Bash
Executable File
345 lines
13 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
script="$repo_root/scripts/docker-image/upload_works_drive.sh"
|
|
doc="$repo_root/docs/works-drive-docker-image-archive.md"
|
|
makefile="$repo_root/Makefile"
|
|
|
|
fail() {
|
|
echo "ERROR: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
[[ -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_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.${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 '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."
|
|
grep -Fq 'staging과 production은 같은 image_tag' "$doc" \
|
|
|| fail "document must state that staging and production consume the same image tag."
|
|
grep -Fq 'docker-image-upload-works:' "$makefile" \
|
|
|| fail "Makefile must expose a docker-image-upload-works target."
|
|
grep -Fq 'scripts/docker-image/upload_works_drive.sh' "$makefile" \
|
|
|| fail "Makefile target must call the WORKS Drive image upload script."
|
|
if grep -Eq 'docker (push|pull)' "$script"; then
|
|
fail "WORKS Drive image archive script must not pretend to be a Docker Registry push/pull backend."
|
|
fi
|
|
|
|
tmp_dir="$(mktemp -d /tmp/baron-sso-works-image-test.XXXXXX)"
|
|
trap 'rm -rf "$tmp_dir"' EXIT INT TERM
|
|
|
|
fake_bin="$tmp_dir/bin"
|
|
mkdir -p "$fake_bin"
|
|
|
|
cat >"$fake_bin/docker" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
printf 'docker %s\n' "$*" >>"${FAKE_DOCKER_LOG}"
|
|
|
|
if [[ "$1" == "commit" ]]; then
|
|
printf 'sha256:committed-image\n'
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "$1" == "image" && "$2" == "inspect" ]]; then
|
|
printf 'sha256:inspect-image-id\n'
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "$1" == "save" ]]; then
|
|
output=""
|
|
image_ref=""
|
|
shift
|
|
while [[ "$#" -gt 0 ]]; do
|
|
case "$1" in
|
|
-o)
|
|
output="$2"
|
|
shift 2
|
|
;;
|
|
*)
|
|
image_ref="$1"
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
[[ -n "$output" ]] || exit 2
|
|
printf 'docker image archive for %s\n' "$image_ref" >"$output"
|
|
exit 0
|
|
fi
|
|
|
|
echo "unexpected docker command: $*" >&2
|
|
exit 2
|
|
EOF
|
|
chmod +x "$fake_bin/docker"
|
|
|
|
cat >"$fake_bin/zstd" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
output=""
|
|
input=""
|
|
while [[ "$#" -gt 0 ]]; do
|
|
case "$1" in
|
|
-o)
|
|
output="$2"
|
|
shift 2
|
|
;;
|
|
-*)
|
|
shift
|
|
;;
|
|
*)
|
|
input="$1"
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
[[ -n "$output" && -n "$input" ]] || exit 2
|
|
cp "$input" "$output"
|
|
EOF
|
|
chmod +x "$fake_bin/zstd"
|
|
|
|
fake_curl="$tmp_dir/fake-curl.sh"
|
|
cat >"$fake_curl" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
printf '%s\n' "$*" >>"${FAKE_CURL_LOG}"
|
|
last_arg="${!#}"
|
|
|
|
case "$last_arg" in
|
|
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/root-folder/children)
|
|
printf '{"files":[]}'
|
|
;;
|
|
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/root-folder/createfolder)
|
|
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":"tag-id","fileName":"v1.2606.ab12","fileType":"FOLDER"}'
|
|
;;
|
|
https://www.worksapis.com/v1.0/sharedrives/shared-drive-1/files/tag-id)
|
|
printf '{"uploadUrl":"https://upload.example.test/docker-image"}'
|
|
;;
|
|
https://upload.example.test/docker-image)
|
|
printf '{"fileId":"uploaded-file-id"}'
|
|
;;
|
|
*)
|
|
echo "unexpected curl URL: $last_arg" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
EOF
|
|
chmod +x "$fake_curl"
|
|
|
|
docker_log="$tmp_dir/docker.log"
|
|
curl_log="$tmp_dir/curl.log"
|
|
archive_dir="$tmp_dir/archive"
|
|
|
|
FAKE_DOCKER_LOG="$docker_log" \
|
|
FAKE_CURL_LOG="$curl_log" \
|
|
PATH="$fake_bin:$PATH" \
|
|
WORKS_DRIVE_ACCESS_TOKEN="test-access-token" \
|
|
WORKS_DRIVE_TARGET="sharedrive" \
|
|
WORKS_DRIVE_SHARED_DRIVE_ID="shared-drive-1" \
|
|
WORKS_DRIVE_PARENT_FILE_ID="root-folder" \
|
|
WORKS_DRIVE_CURL_BIN="$fake_curl" \
|
|
WORKS_DOCKER_IMAGE_ARCHIVE_DIR="$archive_dir" \
|
|
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/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 .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 archive folder when needed."
|
|
grep -Fq "baron-sso" "$curl_log" \
|
|
|| fail "script must create repository namespace folder."
|
|
grep -Fq "v1.2606.ab12" "$curl_log" \
|
|
|| fail "script must create tag folder."
|
|
grep -Fq "backend.v1.2606.ab12.tar.zst" "$curl_log" \
|
|
|| fail "script must upload the compressed image archive."
|
|
grep -Fq "backend.v1.2606.ab12.sha256" "$curl_log" \
|
|
|| fail "script must upload the checksum file."
|
|
grep -Fq "manifest.v1.2606.ab12.json" "$curl_log" \
|
|
|| fail "script must upload the manifest file."
|
|
|
|
report_file="$artifact_dir/works-upload.json"
|
|
[[ -f "$report_file" ]] || fail "script must write works-upload.json."
|
|
jq -e '.status == "uploaded" and (.files | length) == 3' "$report_file" >/dev/null \
|
|
|| fail "upload report must include three uploaded artifact files."
|
|
|
|
root_curl_log="$tmp_dir/root-curl.log"
|
|
root_fake_curl="$tmp_dir/root-fake-curl.sh"
|
|
cat >"$root_fake_curl" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
printf '%s\n' "$*" >>"${FAKE_CURL_LOG}"
|
|
last_arg="${!#}"
|
|
|
|
case "$last_arg" in
|
|
https://www.worksapis.com/v1.0/sharedrives/root-drive/files)
|
|
printf '{"files":[]}\n200'
|
|
;;
|
|
https://www.worksapis.com/v1.0/sharedrives/root-drive/files/createfolder)
|
|
create_count_file="${FAKE_CURL_LOG}.root-create-count"
|
|
create_count=0
|
|
[[ -f "$create_count_file" ]] && create_count="$(cat "$create_count_file")"
|
|
create_count=$((create_count + 1))
|
|
printf '%s' "$create_count" >"$create_count_file"
|
|
if [[ "$create_count" -eq 1 ]]; then
|
|
printf '{"fileId":"root-baron-sso-id","fileName":"baron-sso","fileType":"FOLDER"}\n200'
|
|
else
|
|
printf '{"code":"RESOURCE_ALREADY_EXIST","description":"Resource already exists."}\n409'
|
|
fi
|
|
;;
|
|
https://www.worksapis.com/v1.0/sharedrives/root-drive/files/root-baron-sso-id/children)
|
|
printf '{"files":[]}\n200'
|
|
;;
|
|
https://www.worksapis.com/v1.0/sharedrives/root-drive/files/root-baron-sso-id/createfolder)
|
|
printf '{"fileId":"root-tag-id","fileName":"v1.2606.ab12","fileType":"FOLDER"}\n200'
|
|
;;
|
|
https://www.worksapis.com/v1.0/sharedrives/root-drive/files/root-tag-id)
|
|
printf '{"uploadUrl":"https://upload.example.test/root-docker-image"}\n200'
|
|
;;
|
|
https://upload.example.test/root-docker-image)
|
|
printf '{"fileId":"uploaded-root-file-id"}\n200'
|
|
;;
|
|
*)
|
|
echo "unexpected root curl URL: $last_arg" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
EOF
|
|
chmod +x "$root_fake_curl"
|
|
|
|
root_archive_dir="$tmp_dir/root-archive"
|
|
for image in backend userfront; do
|
|
FAKE_DOCKER_LOG="$docker_log" \
|
|
FAKE_CURL_LOG="$root_curl_log" \
|
|
PATH="$fake_bin:$PATH" \
|
|
WORKS_DRIVE_ACCESS_TOKEN="test-access-token" \
|
|
WORKS_DRIVE_TARGET="sharedrive" \
|
|
WORKS_DRIVE_SHARED_DRIVE_ID="root-drive" \
|
|
WORKS_DRIVE_PARENT_FILE_ID="" \
|
|
WORKS_DRIVE_CURL_BIN="$root_fake_curl" \
|
|
WORKS_DOCKER_IMAGE_ARCHIVE_DIR="$root_archive_dir" \
|
|
DOCKER_IMAGE_REF="baron_sso/${image}:v1.2606.ab12" \
|
|
"$script" >"$tmp_dir/root-${image}.out"
|
|
done
|
|
|
|
root_artifact_dir="$root_archive_dir/baron-sso/v1.2606.ab12"
|
|
[[ -f "$root_artifact_dir/backend.v1.2606.ab12.tar.zst" ]] \
|
|
|| fail "script must keep the backend image archive after follow-up image uploads."
|
|
[[ -f "$root_artifact_dir/userfront.v1.2606.ab12.tar.zst" ]] \
|
|
|| fail "script must keep the userfront image archive after follow-up image uploads."
|
|
jq -e \
|
|
'.images.backend.archive.file_name == "backend.v1.2606.ab12.tar.zst"
|
|
and .images.userfront.archive.file_name == "userfront.v1.2606.ab12.tar.zst"' \
|
|
"$root_artifact_dir/manifest.v1.2606.ab12.json" >/dev/null \
|
|
|| fail "manifest must accumulate all uploaded images for the same tag."
|
|
|
|
root_create_count="$(cat "${root_curl_log}.root-create-count")"
|
|
[[ "$root_create_count" == "1" ]] || fail "script must reuse the cached root archive folder id across image uploads in the same run."
|
|
grep -Fq "sharedrives/root-drive/files/root-tag-id" "$root_curl_log" \
|
|
|| fail "script must upload follow-up images into the cached tag folder."
|
|
|
|
conflict_curl_log="$tmp_dir/conflict-curl.log"
|
|
conflict_fake_curl="$tmp_dir/conflict-fake-curl.sh"
|
|
cat >"$conflict_fake_curl" <<'EOF'
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
printf '%s\n' "$*" >>"${FAKE_CURL_LOG}"
|
|
last_arg="${!#}"
|
|
|
|
case "$last_arg" in
|
|
https://www.worksapis.com/v1.0/sharedrives/conflict-drive/files)
|
|
list_count_file="${FAKE_CURL_LOG}.root-list-count"
|
|
list_count=0
|
|
[[ -f "$list_count_file" ]] && list_count="$(cat "$list_count_file")"
|
|
list_count=$((list_count + 1))
|
|
printf '%s' "$list_count" >"$list_count_file"
|
|
if [[ "$list_count" -eq 1 ]]; then
|
|
printf '{"files":[]}\n200'
|
|
else
|
|
printf '{"files":[{"fileId":"conflict-baron-sso-id","fileName":"baron-sso","fileType":"FILE"}]}\n200'
|
|
fi
|
|
;;
|
|
https://www.worksapis.com/v1.0/sharedrives/conflict-drive/files/createfolder)
|
|
printf '{"code":"RESOURCE_ALREADY_EXIST","description":"Resource already exists."}\n409'
|
|
;;
|
|
https://www.worksapis.com/v1.0/sharedrives/conflict-drive/files/conflict-baron-sso-id/children)
|
|
printf '{"files":[]}\n200'
|
|
;;
|
|
https://www.worksapis.com/v1.0/sharedrives/conflict-drive/files/conflict-baron-sso-id/createfolder)
|
|
printf '{"fileId":"conflict-tag-id","fileName":"v1.2606.ab12","fileType":"FOLDER"}\n200'
|
|
;;
|
|
https://www.worksapis.com/v1.0/sharedrives/conflict-drive/files/conflict-tag-id)
|
|
printf '{"uploadUrl":"https://upload.example.test/conflict-docker-image"}\n200'
|
|
;;
|
|
https://upload.example.test/conflict-docker-image)
|
|
printf '{"fileId":"uploaded-conflict-file-id"}\n200'
|
|
;;
|
|
*)
|
|
echo "unexpected conflict curl URL: $last_arg" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
EOF
|
|
chmod +x "$conflict_fake_curl"
|
|
|
|
FAKE_DOCKER_LOG="$docker_log" \
|
|
FAKE_CURL_LOG="$conflict_curl_log" \
|
|
PATH="$fake_bin:$PATH" \
|
|
WORKS_DRIVE_ACCESS_TOKEN="test-access-token" \
|
|
WORKS_DRIVE_TARGET="sharedrive" \
|
|
WORKS_DRIVE_SHARED_DRIVE_ID="conflict-drive" \
|
|
WORKS_DRIVE_PARENT_FILE_ID="" \
|
|
WORKS_DRIVE_CURL_BIN="$conflict_fake_curl" \
|
|
WORKS_DOCKER_IMAGE_ARCHIVE_DIR="$tmp_dir/conflict-archive" \
|
|
DOCKER_IMAGE_REF="baron_sso/backend:v1.2606.ab12" \
|
|
"$script" >"$tmp_dir/conflict.out" 2>&1
|
|
|
|
grep -Fq "WORKS folder already exists, resolving existing folder id: baron-sso" "$tmp_dir/conflict.out" \
|
|
|| fail "script must recover an existing folder id after WORKS createfolder returns 409."
|
|
grep -Fq "sharedrives/conflict-drive/files/conflict-tag-id" "$conflict_curl_log" \
|
|
|| fail "script must upload into the resolved folder after a create conflict."
|
|
|
|
echo "OK: WORKS Drive Docker image archive upload flow commits, packages, and uploads image artifacts"
|