Repository navigation
fix(homebrew): post_install cannot migrate legacy gateway.toml because Pathname#write refuses to overwrite #3746
Description
User Story
As a macOS user upgrading a Homebrew install of OpenShell, I want post_install to migrate my generated gateway.toml, so the upgrade completes and the gateway uses the current config.
Problem Statement
The formula's post_install migrates a legacy, formula-generated var/openshell/gateway.toml with gateway_config.write gateway_config_contents. Homebrew's Pathname#write refuses to replace an existing file. Library/Homebrew/extend/pathname/write_mkpath_extension.rb does this:
raise "Will not overwrite #{self}" if exist? && !offset && !mode&.match?(/^a\+?$/)The migration branch only runs when the file already exists, so it always raises. post_install then aborts, and the old config stays in place. The steps after it also never run: the VM-driver entitlements write and codesign.
The call is in tasks/scripts/release.py on main, in the else branch that matches legacy_empty_gateway_config_contents / legacy_ipv6_gateway_config_contents. It also ships in the v0.1.1 openshell.rb release asset at line 132. The same formula already uses atomic_write for the entitlements plist, which overwrites safely.
Impact / Why This Matters
- Any Homebrew user whose
gateway.tomlexactly matches one of the two legacy v1 configs hits this on upgrade. Those configs are exactly what earlier formulas generated, so this is the normal upgrade path, not an edge case. brew upgradeorbrew reinstallreports "The post-install step did not complete successfully".- The gateway keeps the legacy config. For the IPv6 variant that means
bind_address = "[::1]:17670", which the migration exists to remove. - The driver-vm signing step is skipped.
- Downstream installers that check brew's exit status fail. NVIDIA/NemoClaw's
scripts/install-openshell.shstops with status 69 ([macOS/WSL2][Onboard][Regression] OpenShell dashboard forward times out and blocks sandbox onboarding NemoClaw#11963 has the report).
Acceptance Criteria
- Upgrading over either legacy v1 config rewrites
var/openshell/gateway.tomlto the current contents, andpost_installcompletes. - A user-edited config (one that matches neither legacy config) is still left untouched.
python/openshell/release_formula_test.pyasserts the overwrite-safe call. It currently assertsgateway_config.write gateway_config_contents(line 103), which locks the bug in.
Suggested fix: use gateway_config.atomic_write gateway_config_contents in the migration branch. The first-install branch can stay as write, because the file does not exist there.
Reproduction Steps
- On Apple Silicon macOS, install an OpenShell Homebrew formula that generated the legacy config. For example 0.0.106, which wrote:
[openshell] version = 1 [openshell.gateway] bind_address = "[::1]:17670"
- Upgrade to a formula that contains the migration. 0.0.116 reproduces it, and the v0.1.1 formula has the same code.
- Run
brew postinstall --debug --verbose nvidia/openshell/openshell.
Expected: gateway.toml is migrated and post_install completes.
Actual: RuntimeError: Will not overwrite /opt/homebrew/var/openshell/gateway.toml, and post_install aborts.
Confirming the diagnosis: after I replaced the file by hand, brew postinstall completed and signed openshell-driver-vm with the hypervisor entitlement.
Environment
- macOS 26.6, Apple M5 (arm64)
- Homebrew 6.0.22
- OpenShell upgraded from 0.0.106 to 0.0.116 through the
nvidia/openshelltap (the pinned formula NemoClaw installs) - Code checked on
NVIDIA/OpenShellmainata3ed8c7and in the v0.1.1openshell.rbrelease asset
Logs
==> Postinstalling openshell
==> /opt/homebrew/Cellar/openshell/0.0.116/bin/openshell-gateway generate-certs
Warning: The post-install step did not complete successfully
...
RuntimeError: Will not overwrite /opt/homebrew/var/openshell/gateway.toml
I'm not vouched yet, so I haven't opened a PR. The change is the one-line write → atomic_write swap above, plus the matching test assertion.
Activity
sandeepstele commentedon Sep 27, 2026
A note on scope: Homebrew only enables the overwrite guard inside install and post-install contexts.
WriteMkpathExtensionis prepended byPathname.activate_extensions!, whichpostinstall.rbcalls. A quickbrew rubycheck therefore overwrites happily unless it enables the extensions first:I tested the suggested change locally on
main(a3ed8c7):tasks/scripts/release.py: the migration branch now callsgateway_config.atomic_write gateway_config_contents. The first-installwritestays.python/openshell/release_formula_test.py: the test asserts theatomic_writemigration call and that exactly one plainwriteremains.test_generate_homebrew_formula_uses_channel_urls_and_exact_versionpasses with the change and fails against the currentrelease.py.drew commentedon Sep 27, 2026
Implementation Plan
Issue type:
fixComplexity: Low
Confidence: High — the Homebrew overwrite guard and failing call are identified.
Summary
Use Homebrew's overwrite-safe
atomic_writeonly when replacing an exact package-generated legacy gateway config. Keep first-install creation and user-edited config handling unchanged.Scope
tasks/scripts/release.py: replace the migration branch'swritecall withatomic_write.python/openshell/release_formula_test.py: assert one first-installwriteand the migrationatomic_writein generated output.architecture/build.md: record the package migration invariant.Implementation Steps
Test Plan
Risks & Open Questions
Documentation Impact
Revision 1 — initial plan
drew commentedon Sep 27, 2026
Implementation Complete
PR: #3752
The formula now uses
atomic_writeonly when replacing an exact package-generated schema-v1 gateway config. First-install creation and user-edited configs are unchanged. The formula test checks both write paths.Tests
mise run pre-commit: passed.mise run test: passed, including 257 Python tests.mise run ci: Go gateway tests failed because this host has/etc/openshell/gateways/default, which conflicts with their empty-system-directory assumption. This is unrelated to the formula change.Docs updated
architecture/build.md: documented the exact-match atomic migration rule.The issue will auto-close when the PR merges.
fix(homebrew): overwrite generated gateway config during migration (N…