Skip to content

Navigation Menu

Sign in
Sign up

A permission error on the cookie DB is reported as "never signed in" #146

Open

Description

Symptom

On a machine where Slack is installed and signed in to three workspaces,
--add-workspace fails with:

slk -- Add Workspace
Reading your signed-in workspaces from the Slack desktop app.
 Slack is installed but has never signed in on this machine.
Error: slack cookie database not found

The cookie DB is present and well-populated. Nothing about the message points
at the actual problem, which cost a fair bit of digging to find.

Environment

  • macOS 27.0 (26A5388g), arm64
  • slk 0.15.0 (90247454096943de49c5a0e7408fa0258852f9fc)
  • Slack 4.51.185, installed from the Mac App Store (the sandboxed
    com.tinyspeck.slackmacgap build, carrying Contents/_MASReceipt)
  • iTerm2, without Full Disk Access

What is actually happening

configDirForOS resolves correctly: ~/Library/Application Support/Slack does
not exist for the App Store build, so it falls through to the container path,
and the profile really is there. The problem is that macOS TCC protects
~/Library/Containers/<bundle-id>/Data, and it distinguishes stat from
open:

$ stat -f '%Sp %z bytes' ~/Library/Containers/com.tinyspeck.slackmacgap/Data/Library/Application\ Support/Slack/Cookies
-rw------- 20480 bytes
$ head -c 16 ~/Library/Containers/com.tinyspeck.slackmacgap/Data/Library/Application\ Support/Slack/Cookies
head: /Users/.../Slack/Cookies: Operation not permitted

stat succeeds, so readCookieRow's os.Stat guard passes. open then fails
with EPERM inside copyToTemp, which maps every os.Open error to the same
sentinel:

// internal/slackdesktop/cookiedb.go
func copyToTemp(src string) (string, error) {
	in, err := os.Open(src)
	if err != nil {
		return "", ErrCookieDBMissing // <-- EPERM lands here too
	}

ErrCookieDBMissing is then rendered by desktopErrorMessage as "Slack is
installed but has never signed in on this machine", which is the opposite of
the truth: signed in, but unreadable.

storage/root-state.json is unreadable for the same reason, so Workspaces()
would report ErrNotSignedIn and mislead in the same way.

Worth noting for the eventual fix message: this is not interactively
recoverable. kTCCServiceSystemPolicyAppData is nominally a promptable
service, but resetting it produced no dialog:

$ tccutil reset SystemPolicyAppData com.googlecode.iterm2
Successfully reset SystemPolicyAppData approval status for com.googlecode.iterm2
$ head -c 16 ~/Library/Containers/com.tinyspeck.slackmacgap/.../Cookies
head: ...: Operation not permitted

so the user has to know to grant the terminal Full Disk Access in System
Settings, or to switch to the standalone Slack build. Neither is discoverable
from the current message.

Suggested fix

Distinguish the two cases in copyToTemp (and in readCookieRow's stat
guard), e.g. propagate fs.ErrPermission as a distinct ErrCookieDBUnreadable
rather than collapsing it into ErrCookieDBMissing, and add a
desktopErrorMessage case along the lines of:

Slack's session is present but slk cannot read it. This is the sandboxed Mac
App Store build of Slack, whose data lives under ~/Library/Containers and is
protected by macOS. Grant your terminal Full Disk Access in System Settings >
Privacy & Security, or install the standalone build from slack.com.

Detecting the App Store case is already cheap: sandboxedProfile() in
password_darwin.go does exactly that check.

I searched open and closed issues for "full disk access", "App Store" and
"operation not permitted" and found nothing covering this. Happy to be pointed
at a duplicate.

No PR attached. I have worked around it locally by moving to the standalone
build.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      AltStyle によって変換されたページ (->オリジナル) /