diff --git a/.github/actions/security/org-membership-check/README.md b/.github/actions/security/org-membership-check/README.md index a3b48ef3f4f9..49dc37cc21de 100644 --- a/.github/actions/security/org-membership-check/README.md +++ b/.github/actions/security/org-membership-check/README.md @@ -39,12 +39,7 @@ This composite action checks if a GitHub user is a member of the dotCMS organiza ## Implementation Details -The action uses the GitHub CLI (`gh`) with a fine-grained GitHub token to check organization membership via the GitHub API endpoint `GET /orgs/dotCMS/members/{username}`. - -**Token Requirements:** -- Fine-grained token with organization membership read permissions -- Should be from a machine/service account for security -- Stored as repository secret: `MACHINE_USER_CORE_ORG_MEMBERSHIP_CHECK` +The action uses the GitHub CLI (`gh`) with the repository's `GITHUB_TOKEN` to check organization membership via the GitHub API endpoint `GET /orgs/dotCMS/members/{username}`. **Key Design Decision: Status Code vs Response Body** diff --git a/.github/actions/security/org-membership-check/action.yml b/.github/actions/security/org-membership-check/action.yml index 1b67872dfd5d..bc66ffe0a683 100644 --- a/.github/actions/security/org-membership-check/action.yml +++ b/.github/actions/security/org-membership-check/action.yml @@ -31,26 +31,27 @@ runs: set +e # Don't exit on error, we want to handle it gracefully - # Check organization membership using GitHub API with fine-grained token + # Check organization membership using GitHub API # - # Uses a fine-grained token with organization membership read permissions - # to check both public and private organization membership reliably. + # IMPORTANT: We check the HTTP status code (via exit code) rather than parsing + # the response body because GitHub's membership API has specific behavior: # - # API Behavior: - # - HTTP 200 + user object = Public member - # - HTTP 200 + empty response = Private member - # - HTTP 404 = Not a member - # - Other errors = API/token issues - - echo "Checking organization membership for ${{ inputs.username }} in dotCMS..." + # HTTP 200 (exit code 0) = User IS a member (regardless of response content) + # - Public member: Returns user object with populated fields + # - Private member: Returns empty response body (but still 200 OK) + # + # HTTP 404 (exit code 1) = User is NOT a member + # - Returns {"message":"Not Found",...} error response + # + # This approach correctly handles both public and private organization members + # without needing to distinguish between their visibility settings. - # Use the provided fine-grained token instead of default GITHUB_TOKEN - response=$(gh api orgs/dotCMS/members/${{ inputs.username }} \ - --header "Authorization: token ${{ inputs.github_token }}" 2>/dev/null) + response=$(gh api orgs/dotCMS/members/${{ inputs.username }} 2>/dev/null) api_exit_code=$? if [ $api_exit_code -eq 0 ]; then # HTTP 200: User is a member (public or private) + # We check response content only for logging clarity, not authorization logic if [ -n "$response" ]; then echo "✅ User ${{ inputs.username }} is a member of dotCMS (public membership)" else @@ -59,7 +60,8 @@ runs: echo "is_member=true" >> $GITHUB_OUTPUT echo "membership_status=member" >> $GITHUB_OUTPUT else - # HTTP 404 or other error: User is not a member or API issue + # HTTP 404 or other error: User is not a member + echo "❌ User ${{ inputs.username }} is not a member of dotCMS (API exit code: $api_exit_code)" echo "is_member=false" >> $GITHUB_OUTPUT echo "membership_status=non-member" >> $GITHUB_OUTPUT