librariesio / libraries.io

:books: The Open Source Discovery Service
https://libraries.io
GNU Affero General Public License v3.0
1.1k stars 206 forks source link

Fix a "stack level too deep" bug with repository owner updates. #3271

Closed tiegz closed 7 months ago

tiegz commented 7 months ago

fixes bugsnag 65527440cf4e030007888c55

there are no specs for the RepositoryOwners code, but it seems that there's an infinite recursion bug that pops up when a RepositoryUser's "user_type" is not the same value as found in the GH API (e.g. we have "User" in the database but now they're an "Organization" on GH).

RepositoryUpdateUserWorker
  RepositoryUser.host(host_type).login(login).first.try(:sync)
    download_user_from_host
      download_user_from_host_by(owner.uuid)    
        RepositoryOwner::Base.download_user_from_host(owner.host_type, id_or_login)
          RepositoryUser.create_from_host(host_type, fetch_user(id_or_login))
            RepositoryOwner::Github.create_user(user_hash)
              if user_by_id 
                  unless user_by_id.login.try(:downcase) == user_hash[:login].downcase && user_by_id.user_type == user_hash[:type]
                    user_by_login.destroy if user_by_login && !user_by_login.download_user_from_host
                      -> infinitely recurses via download_user_from_host

I'm not sure why download_user_from_host is being called again inside here, but in the case I looked at user_by_id and user_by_login were the same user, so I've added a check not to destroy user_by_login if they're the same.

this infinite loop was causing these events to occur over and over:

AuthToken Load (10.4ms)  SELECT "auth_tokens".* FROM "auth_tokens" WHERE ("auth_tokens"."authorized" = TRUE OR "auth_tokens"."authorized" IS NULL) ORDER BY RANDOM() LIMIT 1
ETHON: performed EASY effective_url=https://api.github.com/rate_limit response_code=200 return_code=ok total_time=0.066961
ETHON: performed EASY effective_url=https://api.github.com/user/<REPOSITORY-USER-UUID> response_code=200 return_code=ok total_time=0.066953
RepositoryUser Load (3.3ms)  SELECT "repository_users".* FROM "repository_users" WHERE "repository_users"."host_type" = 'GitHub' AND "repository_users"."uuid" = '<REPOSITORY-USER-UUID>' LIMIT 1
RepositoryUser Load (1.7ms)  SELECT "repository_users".* FROM "repository_users" WHERE (lower(repository_users.host_type) = 'github') AND (lower(repository_users.login) = '<REPSOSITORY-USER-LOGIN>') ORDER BY "repository_users"."id" ASC LIMIT 1