Skip to content

fix: edit the compose YAML in place when adding or removing the tunnel - #37

Merged
SamsonNegedu merged 1 commit into
mainfrom
fix/preserve-compose-on-tunnel-edit
Nov 1, 2026
Merged

SamsonNegedu merged 1 commit into
mainfrom
fix/preserve-compose-on-tunnel-edit

Conversation

@SamsonNegedu

Copy link
Copy Markdown
Owner

Summary

Adding or removing the tunnel rewrote the user's whole compose file, and the rewrite changed what it meant. ./secrets:/run/secrets:ro became secrets:/run/secrets:ro, which Compose reads as a named volume, so the container lost its bind mount. It ran on tunnel changes and on every save of a tunneled app's compose file.

The tunnel code now edits the YAML in place and touches only its own service and the networks it needs.

 InjectTunnel / RemoveTunnel
-  ParseCompose -> typed ComposeFile -> mutate -> MarshalComposeFile   # lossy
+  yaml.Node tree -> add/replace/delete "tunnel" service -> render      # rest untouched
internal/docker/compose_edit.go   InjectTunnelIntoCompose, RemoveTunnelFromCompose
removed                           MarshalComposeFile, InjectTunnelContainer,
                                  RemoveTunnelService, ExtractNetworks
call sites moved (6)              CreateApp (quick, custom), UpdateApp (re-inject quick, custom),
                                  enable custom tunnel, enable quick tunnel,
                                  quick-tunnel job, tunnel cleanup

Also fixed by this:

  • :z and other volume options, top-level secrets:/configs:, volume definitions (external, name), list-form command:, comments and flow-style lists are no longer dropped.
  • Apps with no networks stay on Compose's implicit default network. The old path wrote networks: default: name: _default, so every such app shared one network called _default.
  • The network the tunnel joins is now deterministic (first network a service names, in file order). It was random with several.

Evidence

  • Before: ./secrets:/run/secrets:ro came out as secrets:/run/secrets:ro, ./cfg:/cfg:z as cfg:/cfg (reproduced with a throwaway test, since removed).
    After: TestInjectTunnelKeepsEverythingElseInTheFile asserts the bind mounts, options, comments, secrets and volume specs survive injection unchanged, and compares every original web key.
  • New tests cover: sidecar contents, implicit default network, the app's own network, network_mode services left alone, quick-tunnel config, replacing an existing tunnel in place, removal, a nil container config, and invalid input.
  • go build, go vet and go test ./... pass on top of the latest main.
  • Not run: a real docker compose up deploy.

Merge Danger

Door: two-way

Blast Radius: Moderate

  • Files already rewritten by the old code stay damaged. Check their ./ mounts by hand. This PR only stops new damage.
  • New and edited tunneled apps get a 2-space-indented file and an implicit default network instead of _default. Existing apps with an explicit default network keep using it.
  • Not covered by tests: compose files that use YAML anchors or merge keys on services with no networks (those services are left alone, not attached to the tunnel's network).

Injecting the tunnel parsed the file into a typed model and wrote that
back, which rewrote './secrets:/run/secrets:ro' as 'secrets:/run/secrets:ro'
(a named volume), dropped volume options such as ':z', top-level secrets,
configs and volume definitions, comments and flow-style lists. This also
ran on every save of a tunneled app's compose file.

Tunnel injection and removal now edit the YAML tree and touch only the
tunnel service and the networks it needs. The lossy write path
(MarshalComposeFile, InjectTunnelContainer, RemoveTunnelService,
ExtractNetworks) is removed.

Apps with no networks keep Compose's implicit default network. The old
path wrote a top-level 'default' network named '_default'.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@SamsonNegedu
SamsonNegedu merged commit e16b45c into main Nov 1, 2026
10 checks passed
Sign up for free to 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