fix(coil): tell the truth about the one macOS prompt an update raises - #95

Merged
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note
Aug 12, 2026
Merged

fix(coil): tell the truth about the one macOS prompt an update raises#95
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note

Conversation

@radroid

Copy link
Copy Markdown
Owner

The first-update note said the builds were unsigned and to expect screen-recording and automation prompts. All three claims were wrong.

What was actually true

They have been signed since #70/PR #85. Verified on the installed 0.0.33-coil.105: its designated requirement is identifier "dev.curlycloud.t3coil" and certificate leaf = H"5d665789…", matches docs/coil/mac-signing/designated-requirement.txt byte-for-byte, and codesign --verify --deep --strict still returns valid on disk / satisfies its Designated Requirementafter an in-app update. The staging cp -R and the rm -rf + mv swap do not damage it.

The app requests neither screen recording nor automation. There is no desktopCapturer, getDisplayMedia, osascript or Apple Event use anywhere in apps/desktop/src.

The dialog users actually get is App Management"wants access to data from other apps" — and it has an unrelated cause. macOS blocks one app from modifying another's bundle unless both are signed by the same development team, and installing an update is exactly that modification: the swap replaces the bundle in /Applications. These builds carry a self-signed certificate with no team identifier, so there is no team for macOS to match against.

Why this was worth a PR rather than a wording tweak

The stale note kept describing the symptom of a bug PR #85 had already fixed. It pointed the diagnosis at the signature and away from the missing team identifier — which is where it went, until the dialog was read literally. A note that is confidently wrong about a permission prompt is worse than no note.

What the new copy does

Quotes the dialog's own words, because recognition is the whole job of a note shown once, and says it is asked once. That last part is observed rather than assumed: allowing it survived builds 102 through 105, which is what the stable designated requirement predicted.

NSUpdateSecurityPolicy is recorded in the comment as a dead end — its AllowProcesses map is keyed by team identifier, so it needs precisely the thing this build lacks. Retiring the dialog for good means a paid Developer ID, which would also retire the quarantine step on the download page.

Guarding it

Tests now pin the dialog's wording and assert the note does not contain "unsigned", so this cannot quietly rot back into being wrong. The Windows and repeat-suppression cases were re-pointed at the new substring.

Also fixed a stale cross-reference in updateDelivery/config.ts, which quoted the old sentence when explaining why the marker is a file.

Verification

  • apps/web: 236 files, 2221 tests, all pass (2 new)
  • apps/web and apps/desktop typecheck: 0 errors

🤖 Generated with Claude Code

The first-update note said the builds were unsigned and to expect screen-recording
and automation prompts. All three claims were wrong.
They have been signed since #70/PR #85 — verified on the installed 0.0.33-coil.105,
whose designated requirement matches the recorded one byte-for-byte and still
satisfies itself after an in-app update. The app requests neither screen recording
nor automation: there is no desktopCapturer, getDisplayMedia, osascript or Apple
Event use anywhere in apps/desktop/src.
The dialog users actually get is App Management — "wants access to data from other
apps" — and it has a different cause. macOS blocks one app modifying another's
bundle unless both are signed by the same development team, and installing an
update is exactly that: the swap replaces the bundle in /Applications. The builds
carry a self-signed certificate with no team identifier, so there is no team to
match.
This mattered more than a wording nit. The stale note kept describing the symptom
of a bug PR #85 had already fixed, so it pointed the diagnosis at the signature
and away from the missing team — which is where it went, until the dialog was
read literally.
The new copy quotes the dialog's own words, because recognition is the entire job
of a note shown once, and says it is asked once. That last part is now observed,
not assumed: allowing it survived builds 102 to 105, which is what the stable
designated requirement predicted.
NSUpdateSecurityPolicy is recorded as a dead end in the comment — its
AllowProcesses map is keyed by team identifier, so it needs the one thing this
build lacks. Removing the dialog for good means a paid Developer ID.
Tests now pin the dialog's wording and assert the note does NOT say "unsigned",
so this cannot quietly rot back.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 13c038df-36e7-43fb-855b-2185a9c93e0a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@radroid
radroid merged commit 565830d into mainAug 12, 2026
2 checks passed
@radroid
radroid deleted the coil/update-toast-permission-note branch August 12, 2026 19:00
Sign up for freeto 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.

1 participant

@radroid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(coil): tell the truth about the one macOS prompt an update raises - #95

Merged
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note
Aug 12, 2026
Merged

fix(coil): tell the truth about the one macOS prompt an update raises#95
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note

Conversation

@radroid

Copy link
Copy Markdown
Owner

The first-update note said the builds were unsigned and to expect screen-recording and automation prompts. All three claims were wrong.

What was actually true

They have been signed since #70/PR #85. Verified on the installed 0.0.33-coil.105: its designated requirement is identifier "dev.curlycloud.t3coil" and certificate leaf = H"5d665789…", matches docs/coil/mac-signing/designated-requirement.txt byte-for-byte, and codesign --verify --deep --strict still returns valid on disk / satisfies its Designated Requirementafter an in-app update. The staging cp -R and the rm -rf + mv swap do not damage it.

The app requests neither screen recording nor automation. There is no desktopCapturer, getDisplayMedia, osascript or Apple Event use anywhere in apps/desktop/src.

The dialog users actually get is App Management"wants access to data from other apps" — and it has an unrelated cause. macOS blocks one app from modifying another's bundle unless both are signed by the same development team, and installing an update is exactly that modification: the swap replaces the bundle in /Applications. These builds carry a self-signed certificate with no team identifier, so there is no team for macOS to match against.

Why this was worth a PR rather than a wording tweak

The stale note kept describing the symptom of a bug PR #85 had already fixed. It pointed the diagnosis at the signature and away from the missing team identifier — which is where it went, until the dialog was read literally. A note that is confidently wrong about a permission prompt is worse than no note.

What the new copy does

Quotes the dialog's own words, because recognition is the whole job of a note shown once, and says it is asked once. That last part is observed rather than assumed: allowing it survived builds 102 through 105, which is what the stable designated requirement predicted.

NSUpdateSecurityPolicy is recorded in the comment as a dead end — its AllowProcesses map is keyed by team identifier, so it needs precisely the thing this build lacks. Retiring the dialog for good means a paid Developer ID, which would also retire the quarantine step on the download page.

Guarding it

Tests now pin the dialog's wording and assert the note does not contain "unsigned", so this cannot quietly rot back into being wrong. The Windows and repeat-suppression cases were re-pointed at the new substring.

Also fixed a stale cross-reference in updateDelivery/config.ts, which quoted the old sentence when explaining why the marker is a file.

Verification

  • apps/web: 236 files, 2221 tests, all pass (2 new)
  • apps/web and apps/desktop typecheck: 0 errors

🤖 Generated with Claude Code

The first-update note said the builds were unsigned and to expect screen-recording
and automation prompts. All three claims were wrong.
They have been signed since #70/PR #85 — verified on the installed 0.0.33-coil.105,
whose designated requirement matches the recorded one byte-for-byte and still
satisfies itself after an in-app update. The app requests neither screen recording
nor automation: there is no desktopCapturer, getDisplayMedia, osascript or Apple
Event use anywhere in apps/desktop/src.
The dialog users actually get is App Management — "wants access to data from other
apps" — and it has a different cause. macOS blocks one app modifying another's
bundle unless both are signed by the same development team, and installing an
update is exactly that: the swap replaces the bundle in /Applications. The builds
carry a self-signed certificate with no team identifier, so there is no team to
match.
This mattered more than a wording nit. The stale note kept describing the symptom
of a bug PR #85 had already fixed, so it pointed the diagnosis at the signature
and away from the missing team — which is where it went, until the dialog was
read literally.
The new copy quotes the dialog's own words, because recognition is the entire job
of a note shown once, and says it is asked once. That last part is now observed,
not assumed: allowing it survived builds 102 to 105, which is what the stable
designated requirement predicted.
NSUpdateSecurityPolicy is recorded as a dead end in the comment — its
AllowProcesses map is keyed by team identifier, so it needs the one thing this
build lacks. Removing the dialog for good means a paid Developer ID.
Tests now pin the dialog's wording and assert the note does NOT say "unsigned",
so this cannot quietly rot back.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 13c038df-36e7-43fb-855b-2185a9c93e0a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@radroid
radroid merged commit 565830d into mainAug 12, 2026
2 checks passed
@radroid
radroid deleted the coil/update-toast-permission-note branch August 12, 2026 19:00
Sign up for freeto 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.

1 participant

@radroid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(coil): tell the truth about the one macOS prompt an update raises - #95

Merged
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note
Aug 12, 2026
Merged

fix(coil): tell the truth about the one macOS prompt an update raises#95
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note

Conversation

@radroid

Copy link
Copy Markdown
Owner

The first-update note said the builds were unsigned and to expect screen-recording and automation prompts. All three claims were wrong.

What was actually true

They have been signed since #70/PR #85. Verified on the installed 0.0.33-coil.105: its designated requirement is identifier "dev.curlycloud.t3coil" and certificate leaf = H"5d665789…", matches docs/coil/mac-signing/designated-requirement.txt byte-for-byte, and codesign --verify --deep --strict still returns valid on disk / satisfies its Designated Requirementafter an in-app update. The staging cp -R and the rm -rf + mv swap do not damage it.

The app requests neither screen recording nor automation. There is no desktopCapturer, getDisplayMedia, osascript or Apple Event use anywhere in apps/desktop/src.

The dialog users actually get is App Management"wants access to data from other apps" — and it has an unrelated cause. macOS blocks one app from modifying another's bundle unless both are signed by the same development team, and installing an update is exactly that modification: the swap replaces the bundle in /Applications. These builds carry a self-signed certificate with no team identifier, so there is no team for macOS to match against.

Why this was worth a PR rather than a wording tweak

The stale note kept describing the symptom of a bug PR #85 had already fixed. It pointed the diagnosis at the signature and away from the missing team identifier — which is where it went, until the dialog was read literally. A note that is confidently wrong about a permission prompt is worse than no note.

What the new copy does

Quotes the dialog's own words, because recognition is the whole job of a note shown once, and says it is asked once. That last part is observed rather than assumed: allowing it survived builds 102 through 105, which is what the stable designated requirement predicted.

NSUpdateSecurityPolicy is recorded in the comment as a dead end — its AllowProcesses map is keyed by team identifier, so it needs precisely the thing this build lacks. Retiring the dialog for good means a paid Developer ID, which would also retire the quarantine step on the download page.

Guarding it

Tests now pin the dialog's wording and assert the note does not contain "unsigned", so this cannot quietly rot back into being wrong. The Windows and repeat-suppression cases were re-pointed at the new substring.

Also fixed a stale cross-reference in updateDelivery/config.ts, which quoted the old sentence when explaining why the marker is a file.

Verification

  • apps/web: 236 files, 2221 tests, all pass (2 new)
  • apps/web and apps/desktop typecheck: 0 errors

🤖 Generated with Claude Code

The first-update note said the builds were unsigned and to expect screen-recording
and automation prompts. All three claims were wrong.
They have been signed since #70/PR #85 — verified on the installed 0.0.33-coil.105,
whose designated requirement matches the recorded one byte-for-byte and still
satisfies itself after an in-app update. The app requests neither screen recording
nor automation: there is no desktopCapturer, getDisplayMedia, osascript or Apple
Event use anywhere in apps/desktop/src.
The dialog users actually get is App Management — "wants access to data from other
apps" — and it has a different cause. macOS blocks one app modifying another's
bundle unless both are signed by the same development team, and installing an
update is exactly that: the swap replaces the bundle in /Applications. The builds
carry a self-signed certificate with no team identifier, so there is no team to
match.
This mattered more than a wording nit. The stale note kept describing the symptom
of a bug PR #85 had already fixed, so it pointed the diagnosis at the signature
and away from the missing team — which is where it went, until the dialog was
read literally.
The new copy quotes the dialog's own words, because recognition is the entire job
of a note shown once, and says it is asked once. That last part is now observed,
not assumed: allowing it survived builds 102 to 105, which is what the stable
designated requirement predicted.
NSUpdateSecurityPolicy is recorded as a dead end in the comment — its
AllowProcesses map is keyed by team identifier, so it needs the one thing this
build lacks. Removing the dialog for good means a paid Developer ID.
Tests now pin the dialog's wording and assert the note does NOT say "unsigned",
so this cannot quietly rot back.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 13c038df-36e7-43fb-855b-2185a9c93e0a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@radroid
radroid merged commit 565830d into mainAug 12, 2026
2 checks passed
@radroid
radroid deleted the coil/update-toast-permission-note branch August 12, 2026 19:00
Sign up for freeto 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.

1 participant

@radroid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(coil): tell the truth about the one macOS prompt an update raises - #95

Merged
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note
Aug 12, 2026
Merged

fix(coil): tell the truth about the one macOS prompt an update raises#95
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note

Conversation

@radroid

Copy link
Copy Markdown
Owner

The first-update note said the builds were unsigned and to expect screen-recording and automation prompts. All three claims were wrong.

What was actually true

They have been signed since #70/PR #85. Verified on the installed 0.0.33-coil.105: its designated requirement is identifier "dev.curlycloud.t3coil" and certificate leaf = H"5d665789…", matches docs/coil/mac-signing/designated-requirement.txt byte-for-byte, and codesign --verify --deep --strict still returns valid on disk / satisfies its Designated Requirementafter an in-app update. The staging cp -R and the rm -rf + mv swap do not damage it.

The app requests neither screen recording nor automation. There is no desktopCapturer, getDisplayMedia, osascript or Apple Event use anywhere in apps/desktop/src.

The dialog users actually get is App Management"wants access to data from other apps" — and it has an unrelated cause. macOS blocks one app from modifying another's bundle unless both are signed by the same development team, and installing an update is exactly that modification: the swap replaces the bundle in /Applications. These builds carry a self-signed certificate with no team identifier, so there is no team for macOS to match against.

Why this was worth a PR rather than a wording tweak

The stale note kept describing the symptom of a bug PR #85 had already fixed. It pointed the diagnosis at the signature and away from the missing team identifier — which is where it went, until the dialog was read literally. A note that is confidently wrong about a permission prompt is worse than no note.

What the new copy does

Quotes the dialog's own words, because recognition is the whole job of a note shown once, and says it is asked once. That last part is observed rather than assumed: allowing it survived builds 102 through 105, which is what the stable designated requirement predicted.

NSUpdateSecurityPolicy is recorded in the comment as a dead end — its AllowProcesses map is keyed by team identifier, so it needs precisely the thing this build lacks. Retiring the dialog for good means a paid Developer ID, which would also retire the quarantine step on the download page.

Guarding it

Tests now pin the dialog's wording and assert the note does not contain "unsigned", so this cannot quietly rot back into being wrong. The Windows and repeat-suppression cases were re-pointed at the new substring.

Also fixed a stale cross-reference in updateDelivery/config.ts, which quoted the old sentence when explaining why the marker is a file.

Verification

  • apps/web: 236 files, 2221 tests, all pass (2 new)
  • apps/web and apps/desktop typecheck: 0 errors

🤖 Generated with Claude Code

The first-update note said the builds were unsigned and to expect screen-recording
and automation prompts. All three claims were wrong.
They have been signed since #70/PR #85 — verified on the installed 0.0.33-coil.105,
whose designated requirement matches the recorded one byte-for-byte and still
satisfies itself after an in-app update. The app requests neither screen recording
nor automation: there is no desktopCapturer, getDisplayMedia, osascript or Apple
Event use anywhere in apps/desktop/src.
The dialog users actually get is App Management — "wants access to data from other
apps" — and it has a different cause. macOS blocks one app modifying another's
bundle unless both are signed by the same development team, and installing an
update is exactly that: the swap replaces the bundle in /Applications. The builds
carry a self-signed certificate with no team identifier, so there is no team to
match.
This mattered more than a wording nit. The stale note kept describing the symptom
of a bug PR #85 had already fixed, so it pointed the diagnosis at the signature
and away from the missing team — which is where it went, until the dialog was
read literally.
The new copy quotes the dialog's own words, because recognition is the entire job
of a note shown once, and says it is asked once. That last part is now observed,
not assumed: allowing it survived builds 102 to 105, which is what the stable
designated requirement predicted.
NSUpdateSecurityPolicy is recorded as a dead end in the comment — its
AllowProcesses map is keyed by team identifier, so it needs the one thing this
build lacks. Removing the dialog for good means a paid Developer ID.
Tests now pin the dialog's wording and assert the note does NOT say "unsigned",
so this cannot quietly rot back.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 13c038df-36e7-43fb-855b-2185a9c93e0a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@radroid
radroid merged commit 565830d into mainAug 12, 2026
2 checks passed
@radroid
radroid deleted the coil/update-toast-permission-note branch August 12, 2026 19:00
Sign up for freeto 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.

1 participant

@radroid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(coil): tell the truth about the one macOS prompt an update raises - #95

Merged
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note
Aug 12, 2026
Merged

fix(coil): tell the truth about the one macOS prompt an update raises#95
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note

Conversation

@radroid

Copy link
Copy Markdown
Owner

The first-update note said the builds were unsigned and to expect screen-recording and automation prompts. All three claims were wrong.

What was actually true

They have been signed since #70/PR #85. Verified on the installed 0.0.33-coil.105: its designated requirement is identifier "dev.curlycloud.t3coil" and certificate leaf = H"5d665789…", matches docs/coil/mac-signing/designated-requirement.txt byte-for-byte, and codesign --verify --deep --strict still returns valid on disk / satisfies its Designated Requirementafter an in-app update. The staging cp -R and the rm -rf + mv swap do not damage it.

The app requests neither screen recording nor automation. There is no desktopCapturer, getDisplayMedia, osascript or Apple Event use anywhere in apps/desktop/src.

The dialog users actually get is App Management"wants access to data from other apps" — and it has an unrelated cause. macOS blocks one app from modifying another's bundle unless both are signed by the same development team, and installing an update is exactly that modification: the swap replaces the bundle in /Applications. These builds carry a self-signed certificate with no team identifier, so there is no team for macOS to match against.

Why this was worth a PR rather than a wording tweak

The stale note kept describing the symptom of a bug PR #85 had already fixed. It pointed the diagnosis at the signature and away from the missing team identifier — which is where it went, until the dialog was read literally. A note that is confidently wrong about a permission prompt is worse than no note.

What the new copy does

Quotes the dialog's own words, because recognition is the whole job of a note shown once, and says it is asked once. That last part is observed rather than assumed: allowing it survived builds 102 through 105, which is what the stable designated requirement predicted.

NSUpdateSecurityPolicy is recorded in the comment as a dead end — its AllowProcesses map is keyed by team identifier, so it needs precisely the thing this build lacks. Retiring the dialog for good means a paid Developer ID, which would also retire the quarantine step on the download page.

Guarding it

Tests now pin the dialog's wording and assert the note does not contain "unsigned", so this cannot quietly rot back into being wrong. The Windows and repeat-suppression cases were re-pointed at the new substring.

Also fixed a stale cross-reference in updateDelivery/config.ts, which quoted the old sentence when explaining why the marker is a file.

Verification

  • apps/web: 236 files, 2221 tests, all pass (2 new)
  • apps/web and apps/desktop typecheck: 0 errors

🤖 Generated with Claude Code

The first-update note said the builds were unsigned and to expect screen-recording
and automation prompts. All three claims were wrong.
They have been signed since #70/PR #85 — verified on the installed 0.0.33-coil.105,
whose designated requirement matches the recorded one byte-for-byte and still
satisfies itself after an in-app update. The app requests neither screen recording
nor automation: there is no desktopCapturer, getDisplayMedia, osascript or Apple
Event use anywhere in apps/desktop/src.
The dialog users actually get is App Management — "wants access to data from other
apps" — and it has a different cause. macOS blocks one app modifying another's
bundle unless both are signed by the same development team, and installing an
update is exactly that: the swap replaces the bundle in /Applications. The builds
carry a self-signed certificate with no team identifier, so there is no team to
match.
This mattered more than a wording nit. The stale note kept describing the symptom
of a bug PR #85 had already fixed, so it pointed the diagnosis at the signature
and away from the missing team — which is where it went, until the dialog was
read literally.
The new copy quotes the dialog's own words, because recognition is the entire job
of a note shown once, and says it is asked once. That last part is now observed,
not assumed: allowing it survived builds 102 to 105, which is what the stable
designated requirement predicted.
NSUpdateSecurityPolicy is recorded as a dead end in the comment — its
AllowProcesses map is keyed by team identifier, so it needs the one thing this
build lacks. Removing the dialog for good means a paid Developer ID.
Tests now pin the dialog's wording and assert the note does NOT say "unsigned",
so this cannot quietly rot back.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 13c038df-36e7-43fb-855b-2185a9c93e0a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@radroid
radroid merged commit 565830d into mainAug 12, 2026
2 checks passed
@radroid
radroid deleted the coil/update-toast-permission-note branch August 12, 2026 19:00
Sign up for freeto 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.

1 participant

@radroid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(coil): tell the truth about the one macOS prompt an update raises - #95

Merged
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note
Aug 12, 2026
Merged

fix(coil): tell the truth about the one macOS prompt an update raises#95
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note

Conversation

@radroid

Copy link
Copy Markdown
Owner

The first-update note said the builds were unsigned and to expect screen-recording and automation prompts. All three claims were wrong.

What was actually true

They have been signed since #70/PR #85. Verified on the installed 0.0.33-coil.105: its designated requirement is identifier "dev.curlycloud.t3coil" and certificate leaf = H"5d665789…", matches docs/coil/mac-signing/designated-requirement.txt byte-for-byte, and codesign --verify --deep --strict still returns valid on disk / satisfies its Designated Requirementafter an in-app update. The staging cp -R and the rm -rf + mv swap do not damage it.

The app requests neither screen recording nor automation. There is no desktopCapturer, getDisplayMedia, osascript or Apple Event use anywhere in apps/desktop/src.

The dialog users actually get is App Management"wants access to data from other apps" — and it has an unrelated cause. macOS blocks one app from modifying another's bundle unless both are signed by the same development team, and installing an update is exactly that modification: the swap replaces the bundle in /Applications. These builds carry a self-signed certificate with no team identifier, so there is no team for macOS to match against.

Why this was worth a PR rather than a wording tweak

The stale note kept describing the symptom of a bug PR #85 had already fixed. It pointed the diagnosis at the signature and away from the missing team identifier — which is where it went, until the dialog was read literally. A note that is confidently wrong about a permission prompt is worse than no note.

What the new copy does

Quotes the dialog's own words, because recognition is the whole job of a note shown once, and says it is asked once. That last part is observed rather than assumed: allowing it survived builds 102 through 105, which is what the stable designated requirement predicted.

NSUpdateSecurityPolicy is recorded in the comment as a dead end — its AllowProcesses map is keyed by team identifier, so it needs precisely the thing this build lacks. Retiring the dialog for good means a paid Developer ID, which would also retire the quarantine step on the download page.

Guarding it

Tests now pin the dialog's wording and assert the note does not contain "unsigned", so this cannot quietly rot back into being wrong. The Windows and repeat-suppression cases were re-pointed at the new substring.

Also fixed a stale cross-reference in updateDelivery/config.ts, which quoted the old sentence when explaining why the marker is a file.

Verification

  • apps/web: 236 files, 2221 tests, all pass (2 new)
  • apps/web and apps/desktop typecheck: 0 errors

🤖 Generated with Claude Code

The first-update note said the builds were unsigned and to expect screen-recording
and automation prompts. All three claims were wrong.
They have been signed since #70/PR #85 — verified on the installed 0.0.33-coil.105,
whose designated requirement matches the recorded one byte-for-byte and still
satisfies itself after an in-app update. The app requests neither screen recording
nor automation: there is no desktopCapturer, getDisplayMedia, osascript or Apple
Event use anywhere in apps/desktop/src.
The dialog users actually get is App Management — "wants access to data from other
apps" — and it has a different cause. macOS blocks one app modifying another's
bundle unless both are signed by the same development team, and installing an
update is exactly that: the swap replaces the bundle in /Applications. The builds
carry a self-signed certificate with no team identifier, so there is no team to
match.
This mattered more than a wording nit. The stale note kept describing the symptom
of a bug PR #85 had already fixed, so it pointed the diagnosis at the signature
and away from the missing team — which is where it went, until the dialog was
read literally.
The new copy quotes the dialog's own words, because recognition is the entire job
of a note shown once, and says it is asked once. That last part is now observed,
not assumed: allowing it survived builds 102 to 105, which is what the stable
designated requirement predicted.
NSUpdateSecurityPolicy is recorded as a dead end in the comment — its
AllowProcesses map is keyed by team identifier, so it needs the one thing this
build lacks. Removing the dialog for good means a paid Developer ID.
Tests now pin the dialog's wording and assert the note does NOT say "unsigned",
so this cannot quietly rot back.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 13c038df-36e7-43fb-855b-2185a9c93e0a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@radroid
radroid merged commit 565830d into mainAug 12, 2026
2 checks passed
@radroid
radroid deleted the coil/update-toast-permission-note branch August 12, 2026 19:00
Sign up for freeto 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.

1 participant

@radroid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(coil): tell the truth about the one macOS prompt an update raises - #95

Merged
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note
Aug 12, 2026
Merged

fix(coil): tell the truth about the one macOS prompt an update raises#95
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note

Conversation

@radroid

Copy link
Copy Markdown
Owner

The first-update note said the builds were unsigned and to expect screen-recording and automation prompts. All three claims were wrong.

What was actually true

They have been signed since #70/PR #85. Verified on the installed 0.0.33-coil.105: its designated requirement is identifier "dev.curlycloud.t3coil" and certificate leaf = H"5d665789…", matches docs/coil/mac-signing/designated-requirement.txt byte-for-byte, and codesign --verify --deep --strict still returns valid on disk / satisfies its Designated Requirementafter an in-app update. The staging cp -R and the rm -rf + mv swap do not damage it.

The app requests neither screen recording nor automation. There is no desktopCapturer, getDisplayMedia, osascript or Apple Event use anywhere in apps/desktop/src.

The dialog users actually get is App Management"wants access to data from other apps" — and it has an unrelated cause. macOS blocks one app from modifying another's bundle unless both are signed by the same development team, and installing an update is exactly that modification: the swap replaces the bundle in /Applications. These builds carry a self-signed certificate with no team identifier, so there is no team for macOS to match against.

Why this was worth a PR rather than a wording tweak

The stale note kept describing the symptom of a bug PR #85 had already fixed. It pointed the diagnosis at the signature and away from the missing team identifier — which is where it went, until the dialog was read literally. A note that is confidently wrong about a permission prompt is worse than no note.

What the new copy does

Quotes the dialog's own words, because recognition is the whole job of a note shown once, and says it is asked once. That last part is observed rather than assumed: allowing it survived builds 102 through 105, which is what the stable designated requirement predicted.

NSUpdateSecurityPolicy is recorded in the comment as a dead end — its AllowProcesses map is keyed by team identifier, so it needs precisely the thing this build lacks. Retiring the dialog for good means a paid Developer ID, which would also retire the quarantine step on the download page.

Guarding it

Tests now pin the dialog's wording and assert the note does not contain "unsigned", so this cannot quietly rot back into being wrong. The Windows and repeat-suppression cases were re-pointed at the new substring.

Also fixed a stale cross-reference in updateDelivery/config.ts, which quoted the old sentence when explaining why the marker is a file.

Verification

  • apps/web: 236 files, 2221 tests, all pass (2 new)
  • apps/web and apps/desktop typecheck: 0 errors

🤖 Generated with Claude Code

The first-update note said the builds were unsigned and to expect screen-recording
and automation prompts. All three claims were wrong.
They have been signed since #70/PR #85 — verified on the installed 0.0.33-coil.105,
whose designated requirement matches the recorded one byte-for-byte and still
satisfies itself after an in-app update. The app requests neither screen recording
nor automation: there is no desktopCapturer, getDisplayMedia, osascript or Apple
Event use anywhere in apps/desktop/src.
The dialog users actually get is App Management — "wants access to data from other
apps" — and it has a different cause. macOS blocks one app modifying another's
bundle unless both are signed by the same development team, and installing an
update is exactly that: the swap replaces the bundle in /Applications. The builds
carry a self-signed certificate with no team identifier, so there is no team to
match.
This mattered more than a wording nit. The stale note kept describing the symptom
of a bug PR #85 had already fixed, so it pointed the diagnosis at the signature
and away from the missing team — which is where it went, until the dialog was
read literally.
The new copy quotes the dialog's own words, because recognition is the entire job
of a note shown once, and says it is asked once. That last part is now observed,
not assumed: allowing it survived builds 102 to 105, which is what the stable
designated requirement predicted.
NSUpdateSecurityPolicy is recorded as a dead end in the comment — its
AllowProcesses map is keyed by team identifier, so it needs the one thing this
build lacks. Removing the dialog for good means a paid Developer ID.
Tests now pin the dialog's wording and assert the note does NOT say "unsigned",
so this cannot quietly rot back.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 13c038df-36e7-43fb-855b-2185a9c93e0a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@radroid
radroid merged commit 565830d into mainAug 12, 2026
2 checks passed
@radroid
radroid deleted the coil/update-toast-permission-note branch August 12, 2026 19:00
Sign up for freeto 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.

1 participant

@radroid
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(coil): tell the truth about the one macOS prompt an update raises - #95

Merged
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note
Aug 12, 2026
Merged

fix(coil): tell the truth about the one macOS prompt an update raises#95
radroid merged 1 commit into
mainfrom
coil/update-toast-permission-note

Conversation

@radroid

Copy link
Copy Markdown
Owner

The first-update note said the builds were unsigned and to expect screen-recording and automation prompts. All three claims were wrong.

What was actually true

They have been signed since #70/PR #85. Verified on the installed 0.0.33-coil.105: its designated requirement is identifier "dev.curlycloud.t3coil" and certificate leaf = H"5d665789…", matches docs/coil/mac-signing/designated-requirement.txt byte-for-byte, and codesign --verify --deep --strict still returns valid on disk / satisfies its Designated Requirementafter an in-app update. The staging cp -R and the rm -rf + mv swap do not damage it.

The app requests neither screen recording nor automation. There is no desktopCapturer, getDisplayMedia, osascript or Apple Event use anywhere in apps/desktop/src.

The dialog users actually get is App Management"wants access to data from other apps" — and it has an unrelated cause. macOS blocks one app from modifying another's bundle unless both are signed by the same development team, and installing an update is exactly that modification: the swap replaces the bundle in /Applications. These builds carry a self-signed certificate with no team identifier, so there is no team for macOS to match against.

Why this was worth a PR rather than a wording tweak

The stale note kept describing the symptom of a bug PR #85 had already fixed. It pointed the diagnosis at the signature and away from the missing team identifier — which is where it went, until the dialog was read literally. A note that is confidently wrong about a permission prompt is worse than no note.

What the new copy does

Quotes the dialog's own words, because recognition is the whole job of a note shown once, and says it is asked once. That last part is observed rather than assumed: allowing it survived builds 102 through 105, which is what the stable designated requirement predicted.

NSUpdateSecurityPolicy is recorded in the comment as a dead end — its AllowProcesses map is keyed by team identifier, so it needs precisely the thing this build lacks. Retiring the dialog for good means a paid Developer ID, which would also retire the quarantine step on the download page.

Guarding it

Tests now pin the dialog's wording and assert the note does not contain "unsigned", so this cannot quietly rot back into being wrong. The Windows and repeat-suppression cases were re-pointed at the new substring.

Also fixed a stale cross-reference in updateDelivery/config.ts, which quoted the old sentence when explaining why the marker is a file.

Verification

  • apps/web: 236 files, 2221 tests, all pass (2 new)
  • apps/web and apps/desktop typecheck: 0 errors

🤖 Generated with Claude Code

The first-update note said the builds were unsigned and to expect screen-recording
and automation prompts. All three claims were wrong.
They have been signed since #70/PR #85 — verified on the installed 0.0.33-coil.105,
whose designated requirement matches the recorded one byte-for-byte and still
satisfies itself after an in-app update. The app requests neither screen recording
nor automation: there is no desktopCapturer, getDisplayMedia, osascript or Apple
Event use anywhere in apps/desktop/src.
The dialog users actually get is App Management — "wants access to data from other
apps" — and it has a different cause. macOS blocks one app modifying another's
bundle unless both are signed by the same development team, and installing an
update is exactly that: the swap replaces the bundle in /Applications. The builds
carry a self-signed certificate with no team identifier, so there is no team to
match.
This mattered more than a wording nit. The stale note kept describing the symptom
of a bug PR #85 had already fixed, so it pointed the diagnosis at the signature
and away from the missing team — which is where it went, until the dialog was
read literally.
The new copy quotes the dialog's own words, because recognition is the entire job
of a note shown once, and says it is asked once. That last part is now observed,
not assumed: allowing it survived builds 102 to 105, which is what the stable
designated requirement predicted.
NSUpdateSecurityPolicy is recorded as a dead end in the comment — its
AllowProcesses map is keyed by team identifier, so it needs the one thing this
build lacks. Removing the dialog for good means a paid Developer ID.
Tests now pin the dialog's wording and assert the note does NOT say "unsigned",
so this cannot quietly rot back.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 13c038df-36e7-43fb-855b-2185a9c93e0a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@radroid
radroid merged commit 565830d into mainAug 12, 2026
2 checks passed
@radroid
radroid deleted the coil/update-toast-permission-note branch August 12, 2026 19:00
Sign up for freeto 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.

1 participant

@radroid