diff --git a/.gitea/ai-review/exclusions.json b/.gitea/ai-review/exclusions.json index f81c74a..42335d1 100644 --- a/.gitea/ai-review/exclusions.json +++ b/.gitea/ai-review/exclusions.json @@ -89,6 +89,21 @@ "location": "entrypoint.sh(整體)", "title": "end-to-end tests", "reason": "This repository intentionally excludes test fixtures and CI workflows." + }, + { + "location": "entrypoint.sh:290-332", + "title": "main integration tests", + "reason": "This repository intentionally excludes test fixtures and CI workflows." + }, + { + "location": "entrypoint.sh:78-120", + "title": "api_request mock tests", + "reason": "This repository intentionally excludes test fixtures and CI workflows." + }, + { + "location": "entrypoint.sh:7-12", + "title": "token export preference", + "reason": "Token is now passed explicitly between functions instead of exported." } ] } diff --git a/README.md b/README.md index 0b77d0f..ddd28e5 100644 --- a/README.md +++ b/README.md @@ -80,8 +80,10 @@ jobs: - `entrypoint.sh:122-181` `fetch_package_versions` - `entrypoint.sh:183-241` `collect_package_candidates` - `entrypoint.sh:243-286` `process_candidates` +- `entrypoint.sh:290-332` `main` 整合 / E2E 測試 - `entrypoint.sh(整體)` 新增測試程式碼與測試框架 - `entrypoint.sh(整體)` 端對端測試 +- `entrypoint.sh:78-120` `api_request` mock 測試 - `entrypoint.sh:7` 結構化 logging - `entrypoint.sh:105` 驗證 `GITEA_SERVER_URL` - `entrypoint.sh:125-126,241` 暫存檔重用與 I/O 微調 @@ -89,3 +91,4 @@ jobs: - `entrypoint.sh:204,215` 排序與日誌分離建議 - `entrypoint.sh:243-286` 重複 `url_encode` 進一步最佳化 - `entrypoint.sh:183-241` 改回掃描 owner 全量套件的 N+1 API 建議 +- `entrypoint.sh:7-12` token 不使用 `export` 的安全偏好 diff --git a/entrypoint.sh b/entrypoint.sh index e418acd..4d28cf5 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -106,10 +106,11 @@ parse_repo_context() { api_request() { # Perform one HTTP request and return status metadata as TSV. # stdout format: http_codestatus_textrequest_id - local method="$1" - local path="$2" - local body_file="$3" - local headers_file="$4" + local token="$1" + local method="$2" + local path="$3" + local body_file="$4" + local headers_file="$5" local url http_code status_text request_id status_line url="${GITEA_SERVER_URL%/}${path}" @@ -117,7 +118,7 @@ api_request() { if ! http_code="$( curl -sS \ -H "Accept: application/json" \ - -H "Authorization: token ${RESOLVED_GITEA_TOKEN}" \ + -H "Authorization: token ${token}" \ -X "${method}" \ -D "${headers_file}" \ -o "${body_file}" \ @@ -147,10 +148,12 @@ fetch_package_versions() { # Params: # $1 owner # $2 package_name + # $3 token # stdout: # JSON array of version objects. local owner="$1" local package_name="$2" + local token="$3" local page=1 local limit="${PAGE_LIMIT:-100}" local aggregate_file page_file headers_file meta http_code status_text request_id page_length path tmp_file @@ -172,7 +175,7 @@ fetch_package_versions() { path="/api/v1/packages/${encoded_owner}/nuget/${encoded_package_name}?page=${page}&limit=${limit}" : > "${page_file}" : > "${headers_file}" - meta="$(api_request GET "${path}" "${page_file}" "${headers_file}")" + meta="$(api_request "${token}" GET "${path}" "${page_file}" "${headers_file}")" IFS=$'\t' read -r http_code status_text request_id <<< "${meta}" if [[ "${http_code}" == "404" ]]; then @@ -209,13 +212,15 @@ collect_package_candidates() { # $1 owner # $2 keep_count # $3 candidate_file - # $4... package names + # $4 token + # $5... package names # stdout: # package_counttotal_version_countkept_countcandidate_count local owner="$1" local keep_count="$2" local candidate_file="$3" - shift 3 + local token="$4" + shift 4 local -a package_names=("$@") local package_name versions_json total_versions candidates_json local package_count=0 @@ -226,7 +231,7 @@ collect_package_candidates() { : > "${candidate_file}" for package_name in "${package_names[@]}"; do - versions_json="$(fetch_package_versions "${owner}" "${package_name}")" + versions_json="$(fetch_package_versions "${owner}" "${package_name}" "${token}")" if [[ "$(jq 'length' <<<"${versions_json}")" -eq 0 ]]; then log "No versions found for package ${package_name}" @@ -276,12 +281,14 @@ process_candidates() { # $4 total_version_count # $5 kept_count # $6 candidate_count + # $7 token local owner="$1" local candidate_file="$2" local package_count="$3" local total_version_count="$4" local kept_count="$5" local candidate_count="$6" + local token="$7" local deleted_count=0 local error_count=0 local package_name version _created_at @@ -304,7 +311,7 @@ process_candidates() { encoded_version="$(url_encode "${version}")" : > "${body_file}" : > "${headers_file}" - meta="$(api_request DELETE "/api/v1/packages/${encoded_owner}/nuget/${encoded_package_name}/${encoded_version}" "${body_file}" "${headers_file}")" + meta="$(api_request "${token}" DELETE "/api/v1/packages/${encoded_owner}/nuget/${encoded_package_name}/${encoded_version}" "${body_file}" "${headers_file}")" IFS=$'\t' read -r http_code status_text request_id <<< "${meta}" if [[ "${http_code}" =~ ^2 ]]; then @@ -338,8 +345,6 @@ main() { fail "No Gitea token available, exiting" fi - export RESOLVED_GITEA_TOKEN="$token" - repository="${GITEA_REPOSITORY:-}" IFS=$'\t' read -r owner _repo <<< "$(parse_repo_context "${repository}")" keep_count="$(resolve_keep_count)" @@ -354,14 +359,14 @@ main() { candidate_file="$(mktemp)" trap "rm -f -- '${candidate_file}'" EXIT - summary="$(collect_package_candidates "${owner}" "${keep_count}" "${candidate_file}" "${package_names[@]}")" + summary="$(collect_package_candidates "${owner}" "${keep_count}" "${candidate_file}" "${token}" "${package_names[@]}")" IFS=$'\t' read -r package_count total_version_count kept_count candidate_count <<< "${summary}" if (( package_count == 0 )); then log "No matching packages found for requested package_names" fi - process_candidates "${owner}" "${candidate_file}" "${package_count}" "${total_version_count}" "${kept_count}" "${candidate_count}" + process_candidates "${owner}" "${candidate_file}" "${package_count}" "${total_version_count}" "${kept_count}" "${candidate_count}" "${token}" log "Stage 4 complete" }