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

Enforce requiring API key to initialise notifier #280

Merged
merged 9 commits into from
May 24, 2018

Conversation

fractalwrench
Copy link
Contributor

@fractalwrench fractalwrench commented May 18, 2018

Goal

Avoid instantiating the Notifier in an invalid state (without an API key).

Changeset

Changed

  • Nullability annotations on API
  • Gate all required methods in Bugsnag.m with a check to see if the notifier has been initialised, and NOP if not.
  • Avoid initialising notifier if the supplied API key is nil.
  • Attempting to set a non-nil API key as nil is ignored

Tests

Added a unit test for API key setter override.

Discussion

Much of the discussion for this changeset took place here: bugsnag/bugsnag-react-native#237

Review

For the submitter, initial self-review:

  • Commented on code changes inline explain the reasoning behind the approach
  • Reviewed the test cases added for completeness and possible points for discussion
  • A changelog entry was added for the goal of this pull request
  • Check the scope of the changeset - is everything in the diff required for the pull request?
  • This pull request is ready for:
    • Initial review of the intended approach, not yet feature complete
    • Structural review of the classes, functions, and properties modified
    • Final review

For the pull request reviewer(s), this changeset has been reviewed for:

  • Consistency across platforms for structures or concepts added or modified
  • Consistency between the changeset and the goal stated above
  • Internal consistency with the rest of the library - is there any overlap between existing interfaces and any which have been added?
  • Usage friction - is the proposed change in usage cumbersome or complicated?
  • Performance and complexity - are there any cases of unexpected O(n^3) when iterating, recursing, flat mapping, etc?
  • Concurrency concerns - if components are accessed asynchronously, what issues will arise
  • Thoroughness of added tests and any missing edge cases
  • Idiomatic use of the language

Alter the API key annotation to Nonnull rather than Nullable. If the API key is set as nil, the
value is ignored and a warning logged.
Gates all methods in Bugsnag.m so that they no-op and log a warning if the notifier has not been
initialised. Also avoids initialising the notifier if the API key is not supplied.
@fractalwrench fractalwrench requested a review from a team May 18, 2018 10:01
Copy link
Contributor

@snmaynard snmaynard left a comment

Choose a reason for hiding this comment

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

Would be good to have some tests for the behaviour.

Source/Bugsnag.m Outdated
bsg_g_bugsnag_notifier =
[[BugsnagNotifier alloc] initWithConfiguration:configuration];
[bsg_g_bugsnag_notifier start];
if (configuration != nil && configuration.apiKey != nil) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Might be nicer to have a configuration based validation method. [configuration isValid] for example, rather than the Bugsnag class having to know what that means.

@snmaynard
Copy link
Contributor

By tests I mean, that configuration isValid works as expected and that you can't start bugsnag if that function returns false.

@fractalwrench
Copy link
Contributor Author

Added a test to BugsnagConfiguration to encapsulate the API key check.

Copy link

@martin308 martin308 left a comment

Choose a reason for hiding this comment

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

Left a couple of comments, a larger question I have is: it looks like the bugsnagStarted method only does a nil check on the notifier and so it is possible that the notifier won't be started as it is assigned to the variable before being started, does this matter?

@@ -231,4 +246,9 @@ - (NSDictionary *)sessionApiHeaders {
kHeaderApiSentAt: [BSG_RFC3339DateTool stringFromDate:[NSDate new]]
};
}

- (BOOL)hasValidApiKey {
return _apiKey != nil && ![@"" isEqualToString:_apiKey];

Choose a reason for hiding this comment

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

could we just use return [_apiKey length] == 0;?

Copy link
Contributor

Choose a reason for hiding this comment

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

Flipped the boolean but yeah, [_apiKey length] > 0 is the ticket here.


- (NSString *)apiKey {
return _apiKey;
}

Choose a reason for hiding this comment

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

could we remove this as it is just the default generated by @synthesize?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it needs to be specified since setApiKey is overridden.

@@ -69,7 +69,7 @@ typedef NSDictionary *_Nullable (^BugsnagBeforeNotifyHook)(
/**
* The API key of a Bugsnag project
*/
@property(readwrite, retain, nullable) NSString *apiKey;
@property(readwrite, retain, nonnull) NSString *apiKey;

Choose a reason for hiding this comment

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

is this a breaking change? Do we need to increment the major version number?

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a breaking change in Swift at least, as anyone fetching the value would need to update their code with the appropriate number of ? and !. Its also not enforced, as BugsnagConfiguration().apiKey could be nil.

We should not make this change just yet and instead design/think more about the interface, such as automatic API key detection from Info.plist or having a recommended constructor which takes an non-null API key as an argument. This change is also not required for this fix.

}

- (void)setApiKey:(NSString *)apiKey {
if (apiKey != nil) {
Copy link
Contributor

Choose a reason for hiding this comment

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

if (apiKey.length > 0) would be more comprehensive here and catch both the nil and the empty string case.

@@ -231,4 +246,9 @@ - (NSDictionary *)sessionApiHeaders {
kHeaderApiSentAt: [BSG_RFC3339DateTool stringFromDate:[NSDate new]]
};
}

- (BOOL)hasValidApiKey {
return _apiKey != nil && ![@"" isEqualToString:_apiKey];
Copy link
Contributor

Choose a reason for hiding this comment

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

Flipped the boolean but yeah, [_apiKey length] > 0 is the ticket here.

XCTAssertFalse([config hasValidApiKey]);

config.apiKey = @"5adf89e0aaa";
XCTAssertTrue([config hasValidApiKey]);
Copy link
Contributor

Choose a reason for hiding this comment

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

config.apiKey = "" should also be false.

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 covered by L122, as config defaults to @""

@fractalwrench
Copy link
Contributor Author

@martin308 good catch with bugsnagStarted - I've altered this so that it checks a boolean property which is set to true when the notifier has been started, rather than checking for nil.

I have addressed all other inline feedback.

@@ -161,7 +177,7 @@ + (void)clearTabWithName:(NSString *)tabName {
}

+ (BOOL)bugsnagStarted {
if (self.notifier == nil) {
if (!self.notifier.started) {

Choose a reason for hiding this comment

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

Does this handle the notifier being nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, as nil will be coerced to false.

@fractalwrench fractalwrench requested a review from a team May 23, 2018 08:57
Since we already had it through synthesized properties, keeps it in
case its used.
kattrali
kattrali previously approved these changes May 24, 2018
Copy link
Contributor

@bengourley bengourley left a comment

Choose a reason for hiding this comment

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

The merge invalidated the last review due to conflicts. I'm approving the merge conflict resolution here, not the code changes 👍

@fractalwrench fractalwrench merged commit 5ed93f5 into master May 24, 2018
@fractalwrench fractalwrench deleted the api-key-init-fixes branch May 24, 2018 08:35
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.

5 participants