Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use @actions/github as a wrapper around octokit in order to support proxies #100

Merged
merged 7 commits into from Jul 10, 2020

Conversation

robertbrignull
Copy link
Contributor

This PR makes us use @actions/github which is a wrapper around octokit and mainly just helps with the initialisation. Some of it we were doing already, like setting the API URL, some of it we were not like handling proxies. By using this wrapper it takes care of more things for us.

For info, here's where the proxy handling behaviour was introduced: actions/toolkit#314, and here's where the checkout action started using it which is how I found out about this: actions/checkout#144.

There is a slight difference in behaviour that I had to account for, which is that this new constructor fails if you don't provide it with an authentication token. This was making the tests fail because the client is constructed as a constant at the top level, so it ran and failed before we could stub it out with something else. I worked around this by changing the constant for a function to generate an API client. Constructing a new one each time is not a big loss of efficiency so I'm not too worried.

When doing the above I encountered some errors with sinon because it requires you to call sinon.restore() after your tests, and if a test errors early then it wouldn't call this and would cause later tests to fail. By moving that call to a method that runs after every test we avoid this issue of interference.

I haven't tested this to be sure, and I will do before merging, but I think it'll work with just these changes.
You can also see that the checkout action defines some integration tests that use a proxy so we should copy those. I will look at that, but wanted to put the PR up first.

Merge / deployment checklist

  • Confirm this change is backwards compatible with existing workflows.
  • Confirm the readme has been updated if necessary.

Copy link
Contributor

@sampart sampart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sinon.stub(api, "client").value(ok);
let client = new github.GitHub('123');
const spyGetContents = sinon.stub(client.repos, "getContents").resolves(Promise.resolve(dummyResponse));
sinon.stub(api, "getApiClient").value(() => client);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth moving these 3 lines to a function as they're repeated in 3 different places? You could take the dummyResponse as a parameter and return the spy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea, and will make it easier to document what's going on there too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done this but it turned out to be harder than I expected it to be. Sinon, octokit, and toolkit/github don't make their types very easy to work with or access, so there's a lot of any floating around. I'm not hugely happy with it but I couldn't find anything better to do, and it's not any worse than it was before where there weren't any types.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, still worth doing. Thanks for fighting with the type system for us!

@robertbrignull
Copy link
Contributor Author

note the bug that CodeQL found: https://github.com/github/codeql-action/security/code-scanning/634?query=ref%3Arefs%2Fheads%2Fgithub_proxy

That's not a bug. You can see later on there's a if (attempt < backoffPeriods.length) and this guards all the accesses to backoffPeriods[attempt].

@sampart
Copy link
Contributor

sampart commented Jul 7, 2020

That's not a bug

Ah, cool, thanks for clarifying. Do you want to close the alert as a false positive?

@robertbrignull
Copy link
Contributor Author

Do you want to close the alert as a false positive?

Just done so. Thanks for the reminder. I forgot you can do that now.

@robertbrignull
Copy link
Contributor Author

I think this is now good to go. I've copied the tests from https://github.com/actions/checkout/blob/master/.github/workflows/test.yml so we can test with a proxy automatically in actions. I also verified that if you remove the

env:
  https_proxy: http://squid-proxy:3128

then all http requests fail, which is nice because it shows that all requests have to go through the proxy and thus we shouldn't fall into a degenerate case where if we simply ignore the http_proxy value then things will spuriously succeed.

runs-on: ubuntu-latest
env:
https_proxy: http://no-such-proxy:3128
no_proxy: api.github.com,github.com,github-production-release-asset-2e65be.s3.amazonaws.com
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I'm entirely happy with this value having to include github-production-release-asset-2e65be.s3.amazonaws.com. This is a consequence of https://github.com/actions/http-client/blob/master/proxy.ts (which we use for downloading the codeql-bundle) not supporting any form of wildcards, so the domain has to be explicit. Maybe this is fine if this domain is for all of github, but I'm worried about it changing when we update the bundle, or just at random.

The options that I see at the moment are to just not include this test, or to go with this hardcoded value and raise a PR on https://github.com/actions/http-client to improve support there.

@chrisgavin or @tibbes, do you have any thoughts here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does seem a little bit dodgy.

Perhaps another option is to use mitmproxy with a script that blocks everything except S3 URLs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After more thought and trying to get this working, I think in fact it's more fair to say that we only partially support no_proxy. As far as I can tell there isn't really a format spec for this, but more a general convention between implementations, and the one we're using seems to be on the minimal side.

I'm going to remove this test and instead open an issue to improve this support and add the test back in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants