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

Gracefully handle a missing subprocess module #775

Merged
merged 2 commits into from
Jan 23, 2020

Conversation

brandur
Copy link
Contributor

@brandur brandur commented Jan 22, 2020

As reported in #773, it seems that certain sandboxed environments like
CloudFlare Workers don't provide a subprocess module, and that causes
Node to throw when we try to require it.

Because the only thing we need subprocess for is getting uname, here
we extend the already-existing infrastructure built to gracefully handle
errors to also be able to handle this new error case.

Fixes #773.

r? @rattrayalex-stripe (Or recommend another reviewer if you like.)
cc @stripe/api-libraries

As reported in #773, it seems that certain sandboxed environments like
CloudFlare Workers don't provide a `subprocess` module, and that causes
Node to throw when we try to require it.

Because the only thing we need `subprocess` for is getting `uname`, here
we extend the already-existing infrastructure built to gracefully handle
errors to also be able to handle this new error case.

Fixes #773.
@brandur-stripe brandur-stripe force-pushed the brandur-handle-missing-subprocess branch from 64b4b9f to 9e1f489 Compare January 22, 2020 20:42
@brandur-stripe
Copy link
Contributor

Had a brief conversation about this with @ob-stripe just now, and he mentioned that the alternative to this fix might be to suggest people stub out subprocess themselves when it's not available. I don't have a super strong opinion on it, so I'll leave to DX Products to decide.

utils.safeExec('hello', myCb);
expect(actualErr.toString()).to.equal(
new Error('exec not available').toString()
);
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 love if someone who is familiar with Node convention could check whether they like this. Basically I found that errors are not treated as equal by Chai even if they have the same error message, so fell back to this toString() solution, but there might be a better way.

Copy link
Contributor

Choose a reason for hiding this comment

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

This works. We should upgrade our testing library to Jest.

Copy link
Contributor

@rattrayalex-stripe rattrayalex-stripe left a comment

Choose a reason for hiding this comment

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

Yes this looks correct/appropriate. Nice for us to handle it.

lib/utils.js Outdated Show resolved Hide resolved
utils.safeExec('hello', myCb);
expect(actualErr.toString()).to.equal(
new Error('exec not available').toString()
);
Copy link
Contributor

Choose a reason for hiding this comment

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

This works. We should upgrade our testing library to Jest.

Co-Authored-By: Alex Rattray (Stripe) <[email protected]>
@brandur-stripe
Copy link
Contributor

Thank you Alex for going above and beyond the line of duty!

ptal @ob-stripe Going to hand off to you for a final decision on whether this is the right way to go for the library.

@ob-stripe
Copy link
Contributor

This PR makes it so safeExec doesn't crash, but it still returns an error, right? Wouldn't this prevent requests from being sent because uname -a will still fail to execute?

ptal @brandur-stripe

@brandur-stripe
Copy link
Contributor

brandur-stripe commented Jan 23, 2020

Good question OB. If you look carefully at how getClientUserAgentSeeded is implemented, it actually doesn't care if safeExec errored out; the only effect is to replace the uname component with "UNKNOWN" because a real uname was null and not available:

    utils.safeExec('uname -a', (err, uname) => {
      const userAgent = {};
      for (const field in seed) {
        userAgent[field] = encodeURIComponent(seed[field]);
      }

      // URI-encode in case there are unusual characters in the system's uname.
      userAgent.uname = encodeURIComponent(uname || 'UNKNOWN');

      if (this._appInfo) {
        userAgent.application = this._appInfo;
      }

      cb(JSON.stringify(userAgent));
    });
  },

Not sure if that's the best design, but it'll work at least.

ptal @ob-stripe

Copy link
Contributor

@ob-stripe ob-stripe left a comment

Choose a reason for hiding this comment

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

Works for me. Thanks for the explanation!

@brandur-stripe
Copy link
Contributor

Thanks Olivier!

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

Successfully merging this pull request may close these issues.

Feature Request: Support for Cloudflare Workers
5 participants