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

RFC for injecting server secrets + refactoring auth code [azuredevops bintray bitbucket] #3410

Closed
wants to merge 4 commits into from

Conversation

paulmelnikow
Copy link
Member

I started some work on #3393 and thought I'd ask for some feedback before I applied it to all the services.

Come to think of it, it may actually make sense to keep the old version working so this can be done in a more gradual way.

@paulmelnikow paulmelnikow added service-badge Accepted and actionable changes, features, and bugs core Server, BaseService, GitHub auth labels May 2, 2019
@paulmelnikow
Copy link
Member Author

@calebcartwright @chris48s would be great to hear your thoughts on this.

@paulmelnikow paulmelnikow changed the title RFC for injecting server secrets [azuredevops bintray bitbucket] RFC for injecting server secrets + refactoring auth code [azuredevops bintray bitbucket] May 2, 2019
@shields-ci
Copy link

shields-ci commented May 2, 2019

Warnings
⚠️ This PR modified the server but none of its tests.
That's okay so long as it's refactoring existing code.
⚠️

This PR modified helper functions in lib/ but not accompanying tests.
That's okay so long as it's refactoring existing code.

⚠️ This PR modified service code for azure-devops but not its test code.
That's okay so long as it's refactoring existing code.
⚠️ This PR modified service code for bintray but not its test code.
That's okay so long as it's refactoring existing code.
⚠️

📚 Remember to ensure any changes to serverSecrets in server.js are reflected in the server secrets documentation

⚠️

📚 Remember to ensure any changes to serverSecrets in services/bintray/bintray.service.js are reflected in the server secrets documentation

⚠️

📚 Remember to ensure any changes to serverSecrets in services/bitbucket/bitbucket-pull-request.service.js are reflected in the server secrets documentation

⚠️

📚 Remember to ensure any changes to serverSecrets in services/azure-devops/azure-devops-helpers.js are reflected in the server secrets documentation

Messages
📖 ✨ Thanks for your contribution to Shields, @paulmelnikow!

Generated by 🚫 dangerJS against 1f03994

services/auth.js Outdated
}
}

function optionalAuth(serviceInstance, userKey, passKey) {
Copy link
Member

Choose a reason for hiding this comment

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

Could we use named params/object here, or do we want consumers to explicitly declare value for the userKey arg when they don't need (like in the case of Azure DevOps)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Nice idea! Updated.

@@ -152,35 +145,6 @@ t.create('pr (server, not found)')
message: 'not found',
})

t.create('pr (auth)')
Copy link
Member

Choose a reason for hiding this comment

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

What's the thinking behind removing these tests, and would you anticipate removing the same types of tests in other services?

Copy link
Member

Choose a reason for hiding this comment

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

Sorry I was reading from the bottom up, I see this validation is now handled above in the new spec file 👍

@calebcartwright
Copy link
Member

I've still not gone through this fully yet, but wanted to go ahead and share that I like the looks of it and the direction!

I don't really have a preference one way or the other, but what do we see as the pros/cons of implementing the auth/secret access capabilities via helper functions that are imported (which is very similar to the existing server secrets approach) vs. incorporating these capabilities in service class hierarchy (for example adding the auth functions somewhere in the BaseService class tree, or extending the existing _request* functions, etc.)?

@paulmelnikow
Copy link
Member Author

Hmm, interesting, I could see how adding requiredAuth and optionalAuth as methods on BaseService could make calling this a bit easier. On the other hand, I'm reluctant to add to any more lines of code than necessary to base.js, especially for something that's so specific to a minority of the services.

I also thought about adding an auth helper object that would tuck all this stuff into a namespace, but wasn't thrilled about adding allocation overhead to every request. Though as I think about it more, in the context of all the work that is done for every request, this is probably a pointless optimization to consider.

Something that goes back to #963 that I'd like to do is create one instance of a service for the life of the server. Since all the request-specific state is already passed through method calls, this is fine; the stuff being passed into the constructor is mostly the same. The reason this hasn't been possible is that the _sendAndCacheRequest function has a timeout built into it, starting from the time a specific request comes in. Though after the timeout is reworked in #3368 I expect that could change. After that's done, the auth helper could be created in the constructor, and reused across each invocation of the service.

@paulmelnikow paulmelnikow temporarily deployed to shields-staging-pr-3410 May 6, 2019 03:27 Inactive
@paulmelnikow
Copy link
Member Author

I could try a second version of this that:

  1. Requires services to declare the secrets they use. This is good for documentation!
  2. When a service declares it uses secrets, the BaseService constructor could attach to new instances an auth helper object.
  3. The auth helper object would have access to the declared secrets (getSecret and tryGetSecret) and would also provide optionalAuth and requiredAuth as convenience methods.
  4. As a further optimization, after Modernizing the request code #3368 this code will only run once in the lifetime of the server.

@calebcartwright
Copy link
Member

Sounds intriguing!

paulmelnikow added a commit that referenced this pull request Jul 5, 2019
paulmelnikow added a commit that referenced this pull request Jul 5, 2019
Cherrypicked from #3410, which needs to be reworked.
paulmelnikow added a commit that referenced this pull request Jul 5, 2019
…handler

Cherry-picked from #3410; should simplify reworking it.
@paulmelnikow paulmelnikow added the blocker PRs and epics which block other work label Jul 5, 2019
paulmelnikow added a commit that referenced this pull request Jul 5, 2019
Cherry-picked from #3410; should simplify reworking it.
paulmelnikow added a commit that referenced this pull request Jul 5, 2019
Cherry-picked from #3410; should simplify reworking it.
paulmelnikow added a commit that referenced this pull request Jul 5, 2019
This encapsulates the fetch methods slightly better. Cherry-picked from #3410, which needs to be reworked. This change should simplify dropping in the new auth method when that happens.
paulmelnikow added a commit that referenced this pull request Jul 6, 2019
…handler (#3650)

Cherry-picked from #3410; should simplify reworking it.
paulmelnikow added a commit that referenced this pull request Jul 10, 2019
This is a reworking of #3410 based on some feedback @calebcartwright left on that PR.

The goals of injecting the secrets are threefold:

1. Simplify testing
2. Be consistent with all of the other config (which is injected)
3. Encapsulate the sensitive auth-related code in one place so it can be studied and tested thoroughly

- Rather than add more code to BaseService to handle authorization logic, it delegates that to an AuthHelper class.
- When the server starts, it fetches the credentials from `config` and injects them into `BaseService.register()` which passes them to `invoke()`.
- In `invoke()` the service's auth configuration is checked (`static get auth()`, much like `static get route()`).
- If the auth config is present, an AuthHelper instance is created and attached to the new instance.
- Then within the service, the password, basic auth config, or bearer authentication can be accessed via e.g. `this.authHelper.basicAuth` and passed to `this._requestJson()` and friends.
- Everything is being done very explicitly, so it should be very clear where and how the configured secrets are being used.
- Testing different configurations of services can now be done by injecting the config into `invoke()` in `.spec` files instead of mocking global state in the service tests as was done before. See the new Jira spec files for a good example of this.

Ref #3393
@paulmelnikow paulmelnikow deleted the inject-server-secrets branch October 2, 2019 19:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blocker PRs and epics which block other work core Server, BaseService, GitHub auth service-badge Accepted and actionable changes, features, and bugs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants