Failed call to github api with cloudquery plugin error

Not sure how much help y’all would be able to provide for this, but I’m getting a failed call to the GitHub API:

Error: failed to sync v3 source github: unexpected error from sync client receive: rpc error: code = Unknown desc = failed to sync records: failed to sync unmanaged client: failed to discover repositories: Get "https://<enterprise_github>/api/v3/orgs/<org>/repos?per_page=100": oauth2: cannot fetch token: 404 Not Found

But I’m definitely able to do a manual workflow to call that same API with curl and get back proper results:

curl -L -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ghs_<token>" -H "X-GitHub-Api-Version: 2022-11-28" "https://<enterprise_github>/api/v3/orgs/<org>/repos?per_page=100"

I guess I’m hoping if any of you are familiar with or have any past experience with this error of the GitHub plugin.

I was using this guide Generating an Installation Access Token for a GitHub App to manually go from the generated JWT to the access_token using the installation_ids… And that works, so I don’t know what’s going on with the plugin.

Hi @neat-kingfish, how are you referencing the private key in the spec?
Can you share the configuration spec without any private information?
I’m assuming you’ve also configured the correct URLs for enterprise_github?
I’m also assuming you’re following this guide to use the private key to create a JWT to later use to obtain the installation access token?

my spec looks like this

kind: source
spec:
  name: github
  path: cloudquery/github
  registry: cloudquery
  version: "v8.0.0"
  destinations: ["postgresql"]
  spec:
    app_auth:
    - org: "{{ organization }}"
      private_key_path: "${PRIVATE_KEY_PATH}"
      app_id: "${APP_ID}"
      installation_id: "{{ installation_id }}"
    orgs: ["{{ organization }}"]
    enterprise:
      base_url: "https://{{ ghes_url }}/api/v3/"
      upload_url: "https://{{ ghes_url }}/api/uploads/"
  tables:
    - github_repositories

I use Jinja to swap in the values for organization, installation_id, and the ghes_url. In my code, I use the private key to generate the JWT like you linked in the aforementioned docs in order to produce the access token so that I can make a call to /api/v3/app/installations to generate all the installations, which lets me feed in the organization and installation_id to the Jinja template for that ${PRIVATE_KEY_PATH} variable.

I provision the same private key (which was used to generate the access token, to be absolutely pedantic) with the following code

aws secretsmanager get-secret-value --secret-id ${data.aws_secretsmanager_secret.github_key[0].arn} | jq -rc .SecretString | sed 's:KEY-----:KEY-----\\n:;s:-----END:\\n-----END:' > ./github_key.pem && export PRIVATE_KEY_PATH=./github_key.pem

I want to clarify that I’m not misunderstanding anything. The configuration and spec doesn’t require that I supply the access token, right?

The private key should be enough as the Go GitHub client should generate those tokens. I’m going over the GitHub Go client code to see if something pops up.

OK, I think I got it. Looks like we need

https://github.com/beatlabs/github-auth?tab=readme-ov-file#enterprise

and the plugin doesn’t do that.

isn’t that what this is?

Yeah, but it’s not used with doing app auth in the plugin correctly. It’s a bug in the plugin.

Should have been more clear.

Can you open the issue on my behalf since you would be able to describe it better?

Yeah, I’m opening a PR with a fix now. I’ll create a release candidate for you to verify if that’s ok with you.

The fix is a small one: #16827 - CloudQuery Pull Request.

The release candidate is building; I’ll let you know when it’s ready.

Can you try v8.0.1-rc1? Please note you’ll need to use the CloudQuery registry and be authenticated (if not already).

I’ll go ahead and do an official release; I think it’s pretty safe to do.

v8.0.1 is out, so you could use that one too.

Thanks so much.

Ok, sorry for the delay in feedback – I had to implement the login workflow. I have a new issue:

{
    "level": "error",
    "module": "cli",
    "error": "failed to sync v3 source github: unexpected error from sync client receive: rpc error: code = Unknown desc = failed to sync records: failed to sync unmanaged client: failed to discover repositories: Get \"https://<redacted>/api/v3/orgs/<redacted>/repos?per_page=100\": oauth2: cannot fetch token: 406 Not Acceptable\nResponse: ",
    "time": "2024-02-23T15:06:07Z",
    "message": "exiting with error"
}

So, something about the headers needs changing, I guess.

Ah ok, so at least some progress. The docs do say something about 406.
Let me take a look one sec.
OK, I think I know what might be the issue. I think we need to trim /api/v3/ from the base URL when passing to that module.
In the spec, the base URL is with /api/v3/, but the endpoint for generating the tokens is https://<host>/app/installations/<id>/access_tokens.
Sorry for the back and forth; I can’t really test this as we don’t have a GitHub Enterprise setup.
https://github.com/cloudquery/cloudquery/pull/16834 should fix it.
v8.0.2 is published with this fix.

Will that fail if the base URL doesn’t have the /api/v3/ suffix? Since it’s optional in the spec.

Nvm, I read the API.

TrimSuffix returns s without the provided trailing suffix string. If s doesn't end with suffix, s is returned unchanged.

I’m about to try the new version. But for what it’s worth, I still have api/v3 when I successfully make access tokens via curl:

curl --request POST --url "https://blah/api/v3/app/installations/<blah>/access_tokens" \
--header "Accept: application/vnd.github+json" \
--header "Authorization: Bearer <blah>" \
--header "X-GitHub-Api-Version: 2022-11-28"

The library we use doesn’t have /api/v3/ in the base URL:

and when it tries to get tokens

Maybe I’m getting this wrong, and I’ll revert that release if it makes things worse.

yeah i don’t think that was it

oauth2: cannot fetch token: 406 Not Acceptable\nResponse: ",

got the same. I was afk earlier, but I think I can work with you via release candidates now that I have the login workflow. You can see how the public GitHub and enterprise have different URL paths in these two docs:

GitHub REST API

GitHub Enterprise REST API

See the examples of curl:

curl -L \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <YOUR-TOKEN>" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/orgs/ORG/repos

vs

curl -L \
  -H "Accept: application/vnd.github+json" \
  -H "Authorization: Bearer <YOUR-TOKEN>" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  http(s)://HOSTNAME/api/v3/orgs/ORG/repos

Got it, I agree. I reverted that fix.
Let me try and figure out where that error might be coming from.

I think that I might have found an issue on my end regarding configuration.

I noticed that for me, my JWT expiration has to be 9m30s instead of 10m, and it seems to be hardcoded at 10m in the module you’re using.

Here is the link to the code.

I’m reaching though since the error appears to be a header problem. I’m trying to figure out if this is really the root cause.

Thanks for looking on your end too – I’ll see if I can deduce if the JWT expiration can be experimented with on my end.

Thanks, that’s helpful! Let me know what you find.