Sandboxed MacOS app with user-selected read-write entitlement won't allow me to write to SQLite database files.

My app allows users to create, read, update, and delete one or more sqlite database files. It reads from the db file but it won't allow writing to it. The logs give this error when trying to write to myFile1.sqlite (I am using ".sqlite" as the file extension):

  • Sandbox: MyApp Helpe(16378) deny(1) file-write-create /Users/steve/Documents/myFile1.sqlite-journal
  • Violation: deny(1) file-write-create /Users/steve/Documents/myFile1.sqlite-journal


When writing to a SQLite database, behind the scenes it creates (then deletes) a temporary file with the same name as the database file but with "-journal" appended to the extension. So if the db file name is myFile.sqlite, a temporary myFile.sqlite-journal file will be created then deleted when I write to the database. It is this file that causes the issue because it is not added to the sandbox because the user did not select it.


This is a known issue that has a resolution documented below.


I built the app with Electron.js not with XCode. I can add properties to info.plist but I can't figure out exactly what to add if anything.


----------------------------------------------------------------------------------------------------------------------------------------------

Relevant docs referencing sqlite journal file:

https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html

Scroll about half way down to the section called "Related Items". I've copy/pasted the relevant text below.


RELATED ITEMS

The related items feature of App Sandbox lets your app access files that have the same name as a user-chosen file, but a different extension. This feature consists of two parts: a list of related extensions in the application’s Info.plist file and code to tell the sandbox what you’re doing.


There are two common scenarios where this makes sense:


Scenario 1: (unrelated to my issue)


Scenario 2:

Your app needs to be able to open or save multiple related files with the same name and different extensions (for example, to automatically open a subtitle file with the same name as a movie file, or to allow for a SQLite journal file).


To gain access to that secondary file, create a class that conforms to the NSFilePresenter protocol. This object should provide the main file’s URL as its primaryPresentedItemURL property, and should provide the secondary file’s URL as its presentedItemURL property.


After the user opens the main file, your file presenter object should call the addFilePresenter: class method on the NSFileCoordinator class to register itself.


Note: In the case of a SQLite journal file, beginning in 10.8.2, journal files, write-ahead logging files, and shared memory files are automatically added to the related items list if you open a SQLite database, so this step is unnecessary.


In both scenarios, you must make a small change to the application’s Info.plist file. Your app should already declare a Document Types (CFBundleDocumentTypes) array that declares the file types your app can open.


For each file type dictionary in that array, if that file type should be treated as a potentially related type for open and save purposes, add the key NSIsRelatedItemType with a boolean value of YES.

Replies

How does Javascript access an SQLite file?

I'm using an Node.js package called SQLite3 to interact with the database. Part of it's process in writing to the database includes creating a temporary file in the same directory as the database file with the same name appended with -journal. I am not sure exactly how it works but my understanding is the temp file is a copy of the original database, and if there is a connection failure during the write it will just put the original version back in place. Without this you could end up with a corrupted database.

That was more of a rhetorical question. You need to figure out the exact mechanism of how JavaScript, maybe in a web view, is accessing the local disk. The sandbox APIs have support for related files. SQLite journal files are mentioned by name. And apparently this support is now built in. But all that probably only applies to a native app. You are going to have to reverse engineer all of that. There is no guarantee it is even possible.