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

Renames #149

Merged
merged 30 commits into from
Jun 29, 2015
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
378e389
Try the dumb guy route first.
joshaber Jun 18, 2015
04233f8
RAC em up.
joshaber Jun 18, 2015
c74ecf9
Use the source's name as the new name.
joshaber Jun 18, 2015
7faed9e
Early exits.
joshaber Jun 18, 2015
221519e
Check the bundle ID at our new destination.
joshaber Jun 18, 2015
22e785a
Try the dumb guy route first.
joshaber Jun 18, 2015
ceb4f34
RAC em up.
joshaber Jun 18, 2015
3be9c89
Use the source's name as the new name.
joshaber Jun 18, 2015
62a3967
Early exits.
joshaber Jun 18, 2015
747e183
Check the bundle ID at our new destination.
joshaber Jun 18, 2015
81c0841
Logging.
joshaber Jun 18, 2015
5b05c23
Only do the dance when installing.
joshaber Jun 18, 2015
52a6dc2
More logging.
joshaber Jun 18, 2015
72345d4
Serialize whether we're allowed to rename.
joshaber Jun 18, 2015
5d8ffc9
Use -installItemToURL:fromURL:.
joshaber Jun 18, 2015
6779322
Deliver an updated request.
joshaber Jun 19, 2015
0c8394f
Rename after moving.
joshaber Jun 19, 2015
e3aa7a6
Only rename if needed.
joshaber Jun 19, 2015
dab5bf2
Merge branch 'renames-rebase' into renames
joshaber Jun 19, 2015
3a4428c
Fix the tests.
joshaber Jun 19, 2015
178648f
Let the abort use the old request.
joshaber Jun 19, 2015
d0634fc
Naming and docs.
joshaber Jun 19, 2015
dbf4306
Fix the tests.
joshaber Jun 19, 2015
d8a1185
Let the abort use the old request.
joshaber Jun 19, 2015
54f765b
Naming and docs.
joshaber Jun 19, 2015
ae89c0a
Be more explicit.
joshaber Jun 22, 2015
b30ee65
Be more explicit.
joshaber Jun 22, 2015
46e0447
Do the rename first.
joshaber Jun 23, 2015
8eb2517
Do the rename first.
joshaber Jun 23, 2015
1e71daa
Merge branch 'renames-rebase' into renames
joshaber Jun 23, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Squirrel/NSBundle+SQRLVersionExtensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,7 @@
// Info.plist, or nil if the key is not present.
@property (nonatomic, copy, readonly) NSString *sqrl_bundleVersion;

/// The value of the `kCFBundleExecutableKey` key.
@property (nonatomic, copy, readonly) NSString *sqrl_executableName;

@end
4 changes: 4 additions & 0 deletions Squirrel/NSBundle+SQRLVersionExtensions.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ - (NSString *)sqrl_bundleVersion {
return [self objectForInfoDictionaryKey:(id)kCFBundleVersionKey];
}

- (NSString *)sqrl_executableName {
return [self objectForInfoDictionaryKey:(id)kCFBundleExecutableKey];
}

@end
71 changes: 58 additions & 13 deletions Squirrel/SQRLInstaller.m
Original file line number Diff line number Diff line change
Expand Up @@ -268,21 +268,36 @@ - (RACSignal *)installRequest:(SQRLShipItRequest *)request {
return [[[[self
prepareAndValidateUpdateBundleURLForRequest:request]
flattenMap:^(NSURL *updateBundleURL) {
return [[[[[[[self
return [[[[self
acquireTargetBundleURLForRequest:request]
concat:[self installItemToURL:request.targetBundleURL fromURL:updateBundleURL]]
concat:[RACSignal return:request.updateBundleURL]]
concat:[RACSignal return:updateBundleURL]]
concat:[RACSignal defer:^{
return [RACSignal return:self.ownedBundle.temporaryURL];
}]]
flattenMap:^(NSURL *location) {
return [[[self
deleteOwnedBundleAtURL:location]
doError:^(NSError *error) {
NSLog(@"Couldn't remove owned bundle at location %@, error %@", location, error.sqrl_verboseDescription);
then:^{
if (!request.allowRename) return [RACSignal return:request.targetBundleURL];

return [self renamedTargetIfNeededWithTargetURL:request.targetBundleURL sourceURL:updateBundleURL];
}]
flattenMap:^(NSURL *newTargetURL) {
SQRLShipItRequest *updatedRequest = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:request.updateBundleURL targetBundleURL:newTargetURL bundleIdentifier:request.bundleIdentifier launchAfterInstallation:request.launchAfterInstallation allowRename:request.allowRename];
return [[[[[[[self
installItemToURL:request.targetBundleURL fromURL:updateBundleURL]
then:^{
if ([request.targetBundleURL isEqual:newTargetURL]) return [RACSignal empty];

return [self installItemToURL:newTargetURL fromURL:request.targetBundleURL];
}]
concat:[RACSignal return:request.updateBundleURL]]
concat:[RACSignal return:updateBundleURL]]
concat:[RACSignal defer:^{
return [RACSignal return:self.ownedBundle.temporaryURL];
}]]
flattenMap:^(NSURL *location) {
return [[[self
deleteOwnedBundleAtURL:location]
doError:^(NSError *error) {
NSLog(@"Couldn't remove owned bundle at location %@, error %@", location, error.sqrl_verboseDescription);
}]
catchTo:[RACSignal empty]];
}]
catchTo:[RACSignal empty]];
concat:[RACSignal return:updatedRequest]];
}]
doCompleted:^{
self.ownedBundle = nil;
Expand Down Expand Up @@ -413,6 +428,36 @@ - (RACSignal *)verifyBundleAtURL:(NSURL *)bundleURL usingSignature:(SQRLCodeSign

#pragma mark Installation

/// Check if the target should be renamed and provide the renamed URL.
///
/// targetURL - The URL for the target. Cannot be nil.
/// sourceURL - The URL for the source. Cannot be nil.
///
/// Returns a signal which will send the URL for the renamed target. If a rename
/// isn't needed then it will send `targetURL`.
- (RACSignal *)renamedTargetIfNeededWithTargetURL:(NSURL *)targetURL sourceURL:(NSURL *)sourceURL {
return [RACSignal defer:^{
NSBundle *sourceBundle = [NSBundle bundleWithURL:sourceURL];
NSString *targetExecutableName = targetURL.lastPathComponent.stringByDeletingPathExtension;
NSString *sourceExecutableName = sourceBundle.sqrl_executableName;

// If they're already the same then we're good.
if ([targetExecutableName isEqual:sourceExecutableName]) {
Copy link
Member

Choose a reason for hiding this comment

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

Similarly should this compare last components rather than executable names?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same as above. The plist is more canonical than whatever the name of the zipped thing is, I think.

return [RACSignal return:targetURL];
}

NSString *newAppName = [sourceExecutableName stringByAppendingPathExtension:@"app"];
Copy link
Member

Choose a reason for hiding this comment

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

Can we use sourceURL.lastPathComponent here?

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 think the bundle's executable name is more canonical than what the zipped thing is.

Copy link
Member

Choose a reason for hiding this comment

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

@mdiep could you tie break on this one

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know why these would ever be different at this point. It seems a little weird to me that this is even a key in the Info.plist. But given that it's there, I agree that it seems more canonical than the URL.

NSURL *newTargetURL = [targetURL.URLByDeletingLastPathComponent URLByAppendingPathComponent:newAppName];

// If there's already something there then don't rename to it.
if ([NSFileManager.defaultManager fileExistsAtPath:newTargetURL.path]) {
Copy link
Member

Choose a reason for hiding this comment

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

This is a minor ToC-ToU race, to prevent it I’d like to flip the order of installation and rename.

In my head, I’ve been modelling the file system as a datastore whose entries are protected by code sign requirements; entries that don’t exist have no protecting requirement (only BSD and ACL permissions).

If we can safely (i.e. don't rename from the current entry to the new one if the new one already exists) the existing bundle to the requested name, the install is then from the update bundle (whose name is irrelevant at that point) to the file system entry of the target bundle, as before.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah so I started down that route originally. The problem we run into is that the ShipIt job has a hard-coded path that includes the original bundle path:

[arguments addObject:[squirrelBundle URLForResource:@"ShipIt" withExtension:nil].path];

So I think we could end up in a situation where:

  1. We rename.
  2. Something fails.
  3. launchd can't find ShipIt to retry the update installation or recover since the bundle's been renamed.

Now, we have the same problem if we rename after installation, except that we're less likely to run into a problem at that point (though still possible).

But for that matter, I'm not sure how swapping the order solves the potential ToC-ToU race. We still have to check for existence before renaming, regardless of when the rename happens.

Copy link
Member

Choose a reason for hiding this comment

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

launchd can't find ShipIt to retry the update installation or recover since the bundle's been renamed.

That’s a great point, I hadn’t considered that 😢

But for that matter, I'm not sure how swapping the order solves the potential ToC-ToU race. We still have to check for existence before renaming, regardless of when the rename happens.

It would be handled by instead of doing a rename(2) into the unoccupied file system location, doing a move-if-not-exist (I actually couldn’t find a way to do this atomically since link(2) doesn’t work with directories). This moves the codesign reservation from the old name to the new name and the install continues as normal. If the move failed we’d fall back to updating in place.

My concern is renaming could be exploited to replace a different app, which the update is named for but doesn’t meet the codesign requirements of.

return [RACSignal return:targetURL];
}

return [RACSignal return:newTargetURL];
}];
}

- (RACSignal *)installItemToURL:(NSURL *)targetURL fromURL:(NSURL *)sourceURL {
NSParameterAssert(targetURL != nil);
NSParameterAssert(sourceURL != nil);
Expand Down
8 changes: 7 additions & 1 deletion Squirrel/SQRLShipItRequest.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,12 @@ extern NSString * const SQRLShipItRequestPropertyErrorKey;
// installing. Can be nil.
// launchAfterInstallation - Whether the updated application should be launched
// after installation.
// allowRename - Should the target be renamed if it doesn't match
// the update?
//
// Returns a request which can be written to disk for ShipIt to read and
// perform.
- (instancetype)initWithUpdateBundleURL:(NSURL *)updateBundleURL targetBundleURL:(NSURL *)targetBundleURL bundleIdentifier:(NSString *)bundleIdentifier launchAfterInstallation:(BOOL)launchAfterInstallation;
- (instancetype)initWithUpdateBundleURL:(NSURL *)updateBundleURL targetBundleURL:(NSURL *)targetBundleURL bundleIdentifier:(NSString *)bundleIdentifier launchAfterInstallation:(BOOL)launchAfterInstallation allowRename:(BOOL)allowRename;
Copy link
Member

Choose a reason for hiding this comment

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

I think I’d like to call this useUpdateBundleName so that it’s clearer what the final name will be, rename here could imply using or not using rename(2).

Alternatively, we could be even more descriptive and make it a targetPathComponent: NSString? parameter. This would indicate the lastPathComponent on top of the targetBundleURL.stringByRemovingLastPathComponent that we’re requesting the update service to put the update into.


// The URL to the downloaded update's app bundle.
@property (nonatomic, copy, readonly) NSURL *updateBundleURL;
Expand All @@ -93,4 +95,8 @@ extern NSString * const SQRLShipItRequestPropertyErrorKey;
// Whether to launch the application after an update is successfully installed.
@property (nonatomic, assign, readonly) BOOL launchAfterInstallation;

// Whether the app should be renamed if the update has a different name than the
// existing app.
@property (nonatomic, assign, readonly) BOOL allowRename;

@end
3 changes: 2 additions & 1 deletion Squirrel/SQRLShipItRequest.m
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,13 @@ - (id)initWithDictionary:(NSDictionary *)dictionary error:(NSError **)error {
return self;
}

- (instancetype)initWithUpdateBundleURL:(NSURL *)updateBundleURL targetBundleURL:(NSURL *)targetBundleURL bundleIdentifier:(NSString *)bundleIdentifier launchAfterInstallation:(BOOL)launchAfterInstallation {
- (instancetype)initWithUpdateBundleURL:(NSURL *)updateBundleURL targetBundleURL:(NSURL *)targetBundleURL bundleIdentifier:(NSString *)bundleIdentifier launchAfterInstallation:(BOOL)launchAfterInstallation allowRename:(BOOL)allowRename {
return [self initWithDictionary:@{
@keypath(self.updateBundleURL): updateBundleURL,
@keypath(self.targetBundleURL): targetBundleURL,
@keypath(self.bundleIdentifier): bundleIdentifier ?: NSNull.null,
@keypath(self.launchAfterInstallation): @(launchAfterInstallation),
@keypath(self.allowRename): @(allowRename),
} error:NULL];
}

Expand Down
8 changes: 6 additions & 2 deletions Squirrel/SQRLUpdater.m
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,11 @@ - (RACSignal *)prepareUpdateForInstallation:(SQRLDownloadedUpdate *)update {
return [[[[RACSignal
defer:^{
NSRunningApplication *currentApplication = NSRunningApplication.currentApplication;
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:update.bundle.bundleURL targetBundleURL:currentApplication.bundleURL bundleIdentifier:currentApplication.bundleIdentifier launchAfterInstallation:NO];
NSBundle *appBundle = [NSBundle bundleWithURL:currentApplication.bundleURL];
// Only allow a rename if the user hasn't renamed the app.
BOOL allowRename = [appBundle.sqrl_executableName isEqual:currentApplication.bundleURL.lastPathComponent.stringByDeletingPathExtension];
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the same logic as above?

+       // If they're already the same then we're good.
+       if ([targetExecutableName isEqual:sourceExecutableName]) {
+           return [RACSignal return:targetURL];
+       

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not quite. This is checking to see if the existing app bundle's name matches its CFBundleExecutable name. I.e., has the user renamed the app?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, right. 👍 Can you add a comment to that effect?


SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:update.bundle.bundleURL targetBundleURL:currentApplication.bundleURL bundleIdentifier:currentApplication.bundleIdentifier launchAfterInstallation:NO allowRename:allowRename];
return [request writeUsingURL:self.shipItStateURL];
}]
then:^{
Expand All @@ -542,7 +546,7 @@ - (RACSignal *)relaunchToInstallUpdate {
return [[[[[[[[SQRLShipItRequest
readUsingURL:self.shipItStateURL]
map:^(SQRLShipItRequest *request) {
return [[SQRLShipItRequest alloc] initWithUpdateBundleURL:request.updateBundleURL targetBundleURL:request.targetBundleURL bundleIdentifier:request.bundleIdentifier launchAfterInstallation:YES];
return [[SQRLShipItRequest alloc] initWithUpdateBundleURL:request.updateBundleURL targetBundleURL:request.targetBundleURL bundleIdentifier:request.bundleIdentifier launchAfterInstallation:YES allowRename:request.allowRename];
}]
flattenMap:^(SQRLShipItRequest *request) {
return [[request
Expand Down
9 changes: 5 additions & 4 deletions Squirrel/ShipIt-main.m
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ static void installRequest(RACSignal *readRequestSignal, SQRLDirectoryManager *d

RACSignal *action;
if (attempt > SQRLShipItMaximumInstallationAttempts) {
action = [[[installer.abortInstallationCommand
action = [[[[installer.abortInstallationCommand
execute:request]
initially:^{
NSLog(@"Too many attempts to install, aborting update");
Expand All @@ -86,7 +86,8 @@ static void installRequest(RACSignal *readRequestSignal, SQRLDirectoryManager *d
// Exit successfully so launchd doesn't restart us
// again.
return [RACSignal empty];
}];
}]
concat:[RACSignal return:request]];
} else {
action = [[[[installer.installUpdateCommand
execute:request]
Expand Down Expand Up @@ -114,8 +115,8 @@ static void installRequest(RACSignal *readRequestSignal, SQRLDirectoryManager *d
// Launch regardless of whether installation succeeds or fails.
action = [[action
deliverOn:RACScheduler.mainThreadScheduler]
finally:^{
NSURL *bundleURL = request.targetBundleURL;
doNext:^(SQRLShipItRequest *finalRequest) {
NSURL *bundleURL = finalRequest.targetBundleURL;
if (bundleURL == nil) {
NSLog(@"Missing target bundle URL, cannot launch application");
return;
Expand Down
18 changes: 9 additions & 9 deletions SquirrelTests/SQRLInstallerSpec.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@
});

it(@"should install an update using ShipIt", ^{
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO allowRename:NO];

[self installWithRequest:request remote:YES];

expect(self.testApplicationBundleVersion).toEventually(equal(SQRLTestApplicationUpdatedShortVersionString));
});

it(@"should install an update in process", ^{
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO allowRename:NO];

[self installWithRequest:request remote:NO];

Expand All @@ -60,7 +60,7 @@
NSArray *apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:bundleIdentifier];
expect(@(apps.count)).to(equal(@0));

SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:YES];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:YES allowRename:NO];

[self installWithRequest:request remote:YES];

Expand All @@ -72,7 +72,7 @@
NSURL *diskImageURL = [self createAndMountDiskImageNamed:@"TestApplication 2.1" fromDirectory:updateURL.URLByDeletingLastPathComponent];
updateURL = [diskImageURL URLByAppendingPathComponent:updateURL.lastPathComponent];

SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO allowRename:NO];

[self installWithRequest:request remote:YES];

Expand All @@ -83,7 +83,7 @@
NSURL *diskImageURL = [self createAndMountDiskImageNamed:@"TestApplication" fromDirectory:self.testApplicationURL.URLByDeletingLastPathComponent];
NSURL *targetURL = [diskImageURL URLByAppendingPathComponent:self.testApplicationURL.lastPathComponent];

SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:targetURL bundleIdentifier:nil launchAfterInstallation:NO];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:targetURL bundleIdentifier:nil launchAfterInstallation:NO allowRename:NO];

[self installWithRequest:request remote:YES];

Expand Down Expand Up @@ -118,7 +118,7 @@
});

it(@"should not install an update after too many attempts", ^{
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:targetURL bundleIdentifier:nil launchAfterInstallation:NO];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:targetURL bundleIdentifier:nil launchAfterInstallation:NO allowRename:NO];
[self installWithRequest:request remote:YES];

__block NSError *error;
Expand All @@ -129,7 +129,7 @@
});

it(@"should relaunch even after failing to install an update", ^{
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:targetURL bundleIdentifier:nil launchAfterInstallation:YES];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:targetURL bundleIdentifier:nil launchAfterInstallation:YES allowRename:NO];
[self installWithRequest:request remote:YES];

expect(@([NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.github.Squirrel.TestApplication"].count)).toEventually(equal(@1));
Expand All @@ -149,7 +149,7 @@
expect(@(modeOfURL(updateURL))).to(equal(@0777));
expect(@(modeOfURL([updateURL URLByAppendingPathComponent:@"Contents/MacOS/TestApplication"]))).to(equal(@0777));

SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO allowRename:NO];

[self installWithRequest:request remote:YES];

Expand Down Expand Up @@ -178,7 +178,7 @@
// accessing the property.
targetURL = self.testApplicationURL;

SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO];
SQRLShipItRequest *request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO allowRename:NO];

[self installWithRequest:request remote:YES];

Expand Down
2 changes: 1 addition & 1 deletion SquirrelTests/SQRLShipItRequestSpec.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
directoryManager = SQRLDirectoryManager.currentApplicationManager;

NSURL *updateURL = [self createTestApplicationUpdate];
request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO];
request = [[SQRLShipItRequest alloc] initWithUpdateBundleURL:updateURL targetBundleURL:self.testApplicationURL bundleIdentifier:nil launchAfterInstallation:NO allowRename:NO];
expect(request).notTo(beNil());

expect(request.targetBundleURL).to(equal(self.testApplicationURL));
Expand Down