Fix Sawyer::Error crash when GitHub GraphQL search returns nil nodes

What does this MR do and why?

GitHub's GraphQL search can return a nil node in search.nodes for a repo it can't resolve. A nil in that array stops Sawyer's own to_h from deep-converting it, leaving raw Sawyer::Resource objects (plus the nil) to reach the provider_repos serializer, which then trips the Sawyer patch that forbids method-style attribute access.

Sanitize nodes in Proxy#fetch_repos_via_graphql: drop nils and convert any remaining Sawyer::Resource to a plain hash before it leaves the client layer.

References

#601540 (closed)

Screenshots or screen recordings

How to set up and validate locally

You can validate this fix from a Rails console, without a real GitHub account or token, by pointing the importer at a small local fake GitHub GraphQL server that always returns a nil node alongside a valid one (the exact shape that used to crash).

  1. Save this as fake_github.js (requires npm install express):

    const express = require('express');
    const app = express();
    app.use(express.json());
    
    app.all('*', (req, res) => {
      res.json({
        data: {
          search: {
            nodes: [
              { __typename: 'Repository', id: 1, name: 'vim', full_name: 'someuser/vim', owner: { login: 'someuser' } },
              null
            ],
            pageInfo: { startCursor: null, endCursor: null, hasNextPage: false, hasPreviousPage: false },
            repositoryCount: 1
          }
        }
      });
    });
    
    app.listen(4567, () => console.log('fake GitHub API on :4567'));
  2. Start it in a separate terminal:

    node fake_github.js
  3. In a Rails console (bin/rails console), point a client at the fake server and call Proxy#repos:

    client = Gitlab::GithubImport::Client.new('fake-token', host: 'http://localhost:4567')
    
    proxy = Gitlab::GithubImport::Clients::Proxy.new('fake-token')
    proxy.instance_variable_set(:@client, client)
    
    result = proxy.repos('vim', { relation_type: 'organization', organization_login: 'someorg' })
  4. Confirm the fix: no Sawyer::Error is raised, result[:repos] has exactly 1 entry (the nil node was dropped), it's a plain Hash, and result[:repos].first[:id] returns 1.

To see the crash this MR fixes, repeat step 3 against master (before this change) — it raises Sawyer::Error when the nil/Sawyer::Resource mix reaches the serializer.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Rodrigo Tomonari

Merge request reports

Loading
Loading