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

feat: Add account-related methods #73

Merged
merged 1 commit into from
Jan 28, 2021
Merged

Conversation

pgrzesik
Copy link
Contributor

Adds account-related methods as described in linked issue.

I've made a decision to depend on injected sdk instance, which is supposed to be an instance of ServerlessSDK from @serverless/platform-client library. It is aimed to be temporary solution, which will be cleaned up when components, enterprise-plugin and serverless will be moved into one repository.

Closes: #72

@pgrzesik pgrzesik self-assigned this Jan 27, 2021
@pgrzesik pgrzesik added the enhancement New feature or request label Jan 27, 2021
@codecov
Copy link

codecov bot commented Jan 27, 2021

Codecov Report

Merging #73 (3bddaff) into master (f7d2da6) will increase coverage by 0.96%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #73      +/-   ##
==========================================
+ Coverage   89.17%   90.14%   +0.96%     
==========================================
  Files           8        9       +1     
  Lines         194      213      +19     
==========================================
+ Hits          173      192      +19     
  Misses         21       21              
Impacted Files Coverage Δ
config.js 92.63% <ø> (ø)
account.js 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f7d2da6...3bddaff. Read the comment docs.

const jwtDecode = require('jwt-decode');
const _ = require('lodash');

const logout = () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

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 made a decision to drop manipulation of enterprise section as it seems to be "legacy" part of the configuration - please correct me if I'm wrong here.

// TODO: ADD EXPLANATION TO NOT INTERACT WITH `enterprise` config scope
};

const refreshToken = async (sdk) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

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 decided to skip saving expiresAt field as it seems we're not using it anywhere and the expiration date is always derived from idToken anyway. Please let me know if you feel like we're still supposed to save it

return;
}

const tokens = await sdk.session.refreshToken(loggedInUser.refreshToken);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

account.js Outdated

if (loggedInUser.idToken) {
const accessKeyTitle = title || `serverless_${Math.round(+new Date() / 1000)}`;
const createdAccessKeyResponse = await sdk.accessKeys.create(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

account.js Outdated
configUtils.set(data);
};

const getAccessKeyForOrg = async (sdk, orgName, title) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

@medikoo medikoo left a comment

Choose a reason for hiding this comment

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

Looks great @pgrzesik 👍 I have just few minor concerns

account.js Outdated
};

const getAccessKeyForOrg = async (sdk, orgName, title) => {
if (process.env.SERVERLESS_ACCESS_KEY) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if this should be handled here, and not where getAccessKeyForOrg is called.

I'd rather see this function to unconditionally retrieve access key for org, and to be invoked when such access key is needed (not injected via env var).

What do you think?

Copy link
Contributor Author

@pgrzesik pgrzesik Jan 28, 2021

Choose a reason for hiding this comment

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

That's a good question - the potential problem here is that all clients of that method would have to account for that fact and implement a potential wrapper that will first check if there's a value injected via SERVERLESS_ACCESS_KEY env var. I think it should be centralized in one place, but I'm no longer sure if utils in the best place, I'll explain in another comment.

account.js Outdated Show resolved Hide resolved
account.js Outdated
const loggedInUser = configUtils.getLoggedInUser();

if (!loggedInUser) {
throw new Error('Could not find logged in user. Please log in.');
Copy link
Contributor

Choose a reason for hiding this comment

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

I take this signals programmer error (not something we envision with correct utils usage). In such case, it'll be better to shorten message to simply: Could not find logged in user ("Please log in." suggests it's intended to be presented in valid scenarios to users, and such error should not be thrown with regular Error constructor)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great point - how would you go about it then? I've adapted to the approach that we currently have in platform-sdk, where such errors are thrown with instructions for users to logout/login (reference: https://github.com/serverless/platform-sdk/blob/master/src/accessKeys/accessKeys.js#L66) and aren't being handled in any specific way.

Copy link
Contributor

@medikoo medikoo Jan 28, 2021

Choose a reason for hiding this comment

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

If those errors handle valid scenarios, and are intended to host messages to be shown to users. Then they should be thrown with ServerlessError (in such case we should move serverless-error utility to this repository).

If those errors are to point errors in our internal flow (and by no means can be triggered by valid user flow), then they should not contain any user facing messaging, but simply state what's wrong.

Copy link
Contributor

Choose a reason for hiding this comment

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

So my recommendation depends on what kind of error it is (user or programmer?). It's not perfectly clear to me

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you and sorry for not being clear. These errors can be triggered by valid flow as far as I'm concerned and they should be visible to users. However, at this point I think it makes more sense to move this function to enterprise-plugin as it's going to be the only client. I'll remove it from this PR, sorry for the confusion

account.js Outdated

if (loggedInUser.idToken) {
const accessKeyTitle = title || `serverless_${Math.round(+new Date() / 1000)}`;
const createdAccessKeyResponse = await sdk.accessKeys.create(
Copy link
Contributor

Choose a reason for hiding this comment

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

*Reponse suggests it's a HTTP Response object, and in such case response body will be placed on response.body.

If it's already a parsed response body. I would simply name var accessKeyData.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good call 👍

account.js Outdated
Comment on lines 91 to 96
throw new Error(
`Could not find an access key for organization ${orgName}. Log out and log in again to create a new access key for this organization.`
);
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here, it'll be good clarify if it's a programmer or user error, and configure it as one.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Please see my other comment about approach to errors

@pgrzesik
Copy link
Contributor Author

pgrzesik commented Jan 28, 2021

Thanks @medikoo for a review 🙇 I've started thinking again about proper placement for getAccessKeyForOrg method. A few of your suggestions make a lot of sense (about env var handling and error handling), however, that would require the clients of this method to create yet another wrapper for it to provide client specific functionality (honoring env var for example) - which makes me think - are serverless/utils a proper place for this method? The only client at the moment for it will be enterprise-plugin, and if we're going to have to wrap it there anyway, maybe we should just implement it directly in plugin? What do you think?

EDIT: I've also added reconfiguration of sdk with idToken as an accessKey when fetching a new one to ensure that we're calling API with up-to-date token.

@medikoo
Copy link
Contributor

medikoo commented Jan 28, 2021

The only client at the moment for it will be enterprise-plugin, and if we're going to have to wrap it there anyway, maybe we should just implement it directly in plugin? What do you think?

if it's just for enterprise-plugin I would probably keep there.

Otherwise this utils project is more a common (not really utils) project. It's to host all functionalities that are used by more than one of our CLI packages.

Relying on env vars here is fine. I was just questioning util design, but I don't know all the places where it's used.

@pgrzesik
Copy link
Contributor Author

Thanks for a review, as mentioned, I've decided to remove getAccessKeyForOrg from this PR for now and move the implementation directly to enterprise-plugin.

Copy link
Contributor

@medikoo medikoo left a comment

Choose a reason for hiding this comment

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

Looks great 👍

@pgrzesik pgrzesik merged commit c77df3c into master Jan 28, 2021
@pgrzesik pgrzesik deleted the add-account-related-methods branch January 28, 2021 22:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add account-related methods
2 participants