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

Standardize behaviour of no_proxy environmental variable #1223

Merged
merged 8 commits into from
Feb 13, 2023

Conversation

felixlut
Copy link
Contributor

The behaviour of the no_proxy environmental variable is famously inconsistent, but this change should follow how it usually works (i.e., that no_proxy=domain.com matches its subdomains, such as some.domain.com).

Resolves #1172

@felixlut felixlut requested a review from a team as a code owner October 25, 2022 20:07
@@ -51,7 +51,7 @@ export function checkBypass(reqUrl: URL): boolean {
.split(',')
.map(x => x.trim().toUpperCase())
.filter(x => x)) {
if (upperReqHosts.some(x => x === upperNoProxyItem)) {
if (upperReqHosts.some(x => x.includes(upperNoProxyItem))) {
Copy link
Contributor

@aibaars aibaars Oct 27, 2022

Choose a reason for hiding this comment

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

I think it would be safer to use endsWith instead of includes to avoid bad actors from bypassing the proxy. For example if we set no_proxy=mycompany.com then a domain like mycompany.com.evil.org should not bypass the proxy.

Suggested change
if (upperReqHosts.some(x => x.includes(upperNoProxyItem))) {
if (upperReqHosts.some(x => x.endsWith(upperNoProxyItem))) {

The above would still let domains like evilmycompany.com bypass the proxy. Perhaps a better formulation would be

Suggested change
if (upperReqHosts.some(x => x.includes(upperNoProxyItem))) {
if (upperReqHosts.some(x => x === upperNoProxyItem || x.endsWith('.' + upperNoProxyItem))) {

In addition we might want to strip off a leading . to ensure that no_proxy=example.com and no_proxy=.example.com are treated the same.

I think the following should work:

  // Compare request host against noproxy
  for (const upperNoProxyItem of noProxy
    .split(',')
    .map(x => x.trim().toUpperCase())
    .map(x => x.charAt(0) === '.' ? x.substr(1) : x)
    .filter(x => x)) {
    if (upperReqHosts.some(x => x === upperNoProxyItem || x.endsWith('.' + upperNoProxyItem))) {
      return true
    }
  }

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 for @aibaars suggestions too, ensWith + '.' sounds good
NIT: I'd consider a small refactoring of the block from line 54, it's becoming a bit dense with filters

@felixlut Could you add a test-case that covers the change in https://github.com/actions/toolkit/blob/main/packages/http-client/__tests__/proxy.test.ts ?

PS the PR validation currently fails due to some older packages, I'll take a look in a different PR

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 like your suggestions, and sure I can add a test-case. I'll try to find time over the weekend!

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 implemented the suggested changes (in addition to some other suggestions from the article I posted above), as well as test-cases for each of them. Namely the following was added:

  • * matching all hosts
  • Strip leading dots (.domain.com --> domain.com)

@felixlut felixlut requested review from fhammerl and aibaars and removed request for fhammerl and aibaars October 30, 2022 16:03
@felixlut felixlut changed the title Match no_proxy environmental variable to partial domains Standardize behaviour of no_proxy environmental variable Oct 30, 2022
Copy link
Contributor

@aibaars aibaars left a comment

Choose a reason for hiding this comment

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

This looks good to me. @fhammerl , could you have a look at this?

@TingluoHuang
Copy link
Member

@fhammerl We also need to make the actions/runner follow the same rule if we take this change.

@fhammerl
Copy link
Contributor

fhammerl commented Nov 1, 2022

@TingluoHuang actions/runner for sure, can you think of any other services where we use noproxy?

@TingluoHuang
Copy link
Member

@fhammerl

@TingluoHuang actions/runner for sure, can you think of any other services where we use noproxy?

No

@aibaars
Copy link
Contributor

aibaars commented Nov 1, 2022

@fhammerl Could you update and merge #1226 ? I think that PR is meant to unblock the audit failure.

@felixlut
Copy link
Contributor Author

felixlut commented Nov 6, 2022

Haven't seen any activity in here for a couple of days. Just checking, there is nothing I should do now? This PR is just blocked until #1230 is merged?

1 similar comment
@felixlut
Copy link
Contributor Author

felixlut commented Nov 6, 2022

Haven't seen any activity in here for a couple of days. Just checking, there is nothing I should do now? This PR is just blocked until #1230 is merged?

Copy link
Contributor

@fhammerl fhammerl left a comment

Choose a reason for hiding this comment

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

Great tests, thanks for the refactoring too.

LGTM

We're holding off with merging it for now as the 'audit' check is failing.
We'll fix that first on main, then merge this branch.

@felixlut
Copy link
Contributor Author

@fhammerl any update?

@fhammerl
Copy link
Contributor

We're migrating the project over to Node16, will merge this PR right after.

@gendergap
Copy link

We're migrating the project over to Node16, will merge this PR right after.

Could you please reference the PR for that migration so that people waiting for this can track the progress?

@vmjoseph
Copy link
Contributor

@felixlut Would you mind committing one more time so that our checks can re-run? Once those clear we can get this ready to merge.

@felixlut
Copy link
Contributor Author

felixlut commented Feb 4, 2023

@vmjoseph Any update on this?

@felixlut
Copy link
Contributor Author

felixlut commented Feb 7, 2023

Any update on this? @fhammerl @aibaars

Copy link
Contributor

@vmjoseph vmjoseph left a comment

Choose a reason for hiding this comment

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

Looks like there's a linting error.

packages/http-client/__tests__/proxy.test.ts Outdated Show resolved Hide resolved
@fhammerl
Copy link
Contributor

fhammerl commented Feb 9, 2023

Hey @felixlut
This is a long lived PR now, thanks for sticking by!

We'd like to follow the no_proxy system we've established in actions/runner

The runner rules today:

  1. ✅ Support matching for subdomains (the meat of this PR)
  2. ❌ Do NOT strip leading period in no_proxy entry (aka no_proxy=.github.com should bypass proxy for sub.github.com, but not for vanilla github.com urls)
  3. ❌ Do NOT support * wildcard

This would bring the behaviour to that of wget's if I understand the table correctly.

With those changes, I can get this PR merged ASAP.

Let me know if that works for you

@felixlut
Copy link
Contributor Author

felixlut commented Feb 9, 2023

Sounds good to me, as you say, the subdomains was the reason i opened this! I can make the required rollbacks later tonight, or more likely tomorrow!

const bypass = pm.checkBypass(new URL('https://anything.whatsoever.com'))
expect(bypass).toBeFalsy()
})

Copy link
Contributor

Choose a reason for hiding this comment

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

Can We add one more test to chech a subdomain is supported when no_proxy has a leading dot?

  it('checkBypass returns true if host with subdomain in no_proxy defined with leading "."', () => {
    process.env['no_proxy'] = '.myserver.com'
    const bypass = pm.checkBypass(new URL('https://sub.myserver.com'))
    expect(bypass).toBeTruthy()
  })

Copy link
Contributor Author

@felixlut felixlut Feb 10, 2023

Choose a reason for hiding this comment

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

Ye sure!

Another question also, since you want the no_proxy to be the same as in the actions/runner, do you also want me to re-structure the code to be more similar to how they handle it (see ref)?
Obviously it's not the same language, but might be easier to keep consistency between them if they are implemented using the same logic, just with different languages.

Might be overkill, but I'm willing to do it if that makes it easier maintainable for you guys!

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd prefer to keep PRs for the functional changes and refactoring changes separate, but really appreciate you asking 👍

Also, here's a good set of unit tests from the runner code if needed

Copy link
Contributor Author

@felixlut felixlut Feb 12, 2023

Choose a reason for hiding this comment

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

I''ve added the test you wrote, as well a new one for checking partial domains (such that no_proxy=myserver.com won't let evilmyserver.com through).

This required some extra logic

@fhammerl fhammerl merged commit d2b7d85 into actions:main Feb 13, 2023
@fhammerl
Copy link
Contributor

@felixlut Thanks again for this, I'll ping you as we publish it 👍

@felixlut felixlut deleted the partial-no-proxy branch February 14, 2023 16:37
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.

no_proxy matching agains parts of the host name is not supported
6 participants