Skip to content

Commit 74c1502

Browse files
committed
feat: 彻底移除端口映射特性
端口映射与产品核心约束(全流量必须走隧道,不允许直连外网)相冲突, 移除后网络策略更纯粹,维护面更小。 后端变更: - 删除 host_forwarding_linux.go / _other.go(iptables DNAT+SNAT 实现) - 删除 container_proxy_provider 的端口映射调用和 bridge 断开逻辑中的兼容补丁 - 删除 worker_firewall_linux.go 的 allowedPorts 参数、bridgeGW 白名单、端口映射 ACCEPT 规则 - 删除数据库 host_ports 字段、HostPorts 类型、UpdateHostPorts 方法 - 删除 admin API 的 PUT /v1/admin/hosts/{hostID}/ports 路由和 UpdatePorts handler - 删除 agentapi.PortMapping 和 HostNetworkSpec.PortMappings - 删除 runtime 中 HostPorts→PortMappings 转换和 Docker -p 参数 - 更新测试文件 前端变更: - 删除 port-manager.tsx 组件 - 删除 create-host-dialog.tsx 中的端口映射表单 - 删除 use-hosts.ts 中的 HostPort 接口和 useUpdateHostPorts hook - 删除 $hostId.tsx 中的 PortManager 引用 文档变更: - 所有"端口映射"文案改为"SSH 端口"或"服务端口"
1 parent 8823f94 commit 74c1502

25 files changed

Lines changed: 233 additions & 698 deletions
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
---
2+
phase: quick
3+
plan: 260511-o15
4+
type: execute
5+
wave: 1
6+
depends_on: []
7+
files_modified:
8+
- internal/network/types.go
9+
- internal/agentapi/contracts.go
10+
- internal/network/container_proxy_provider.go
11+
- internal/network/worker_firewall_linux.go
12+
- internal/runtime/runtime_service.go
13+
- internal/runtime/tasks/worker.go
14+
- internal/controlplane/http/admin_hosts.go
15+
- internal/controlplane/http/router.go
16+
- internal/store/repository/models.go
17+
- internal/store/repository/queries.go
18+
- internal/network/worker_firewall_linux_test.go
19+
- internal/controlplane/http/admin_hosts_test.go
20+
- internal/controlplane/http/admin_egress_ip_probe_test.go
21+
- web/admin/src/components/hosts/create-host-dialog.tsx
22+
- web/admin/src/hooks/use-hosts.ts
23+
- web/admin/src/routes/_dashboard/hosts/$hostId.tsx
24+
- cmd/cloud-claude/local.go
25+
- tests/scripts/uat-vscode-remote-ssh.sh
26+
- docs/zh/guide/configuration.md
27+
- docs/zh/guide/cloud-claude-local.md
28+
autonomous: true
29+
requirements: []
30+
must_haves:
31+
truths:
32+
- "端口映射相关代码、数据库模型、API 路由、前端组件和文案全部移除"
33+
- "编译通过,测试通过,前端构建通过"
34+
- "所有引用 HostPorts / PortMappings 的地方已清理完毕"
35+
artifacts:
36+
- path: "internal/network/host_forwarding_linux.go"
37+
provides: "已删除"
38+
- path: "internal/network/host_forwarding_other.go"
39+
provides: "已删除"
40+
- path: "internal/store/migrations/0016_host_ports.sql"
41+
provides: "已删除"
42+
- path: "internal/network/container_proxy_provider_linux.go"
43+
provides: "已删除"
44+
- path: "internal/network/container_proxy_provider_other.go"
45+
provides: "已删除"
46+
- path: "web/admin/src/components/hosts/port-manager.tsx"
47+
provides: "已删除"
48+
key_links:
49+
- from: "internal/network/types.go"
50+
to: "internal/runtime/runtime_service.go"
51+
via: "HostNetworkSpec 不再包含 PortMappings"
52+
- from: "internal/store/repository/models.go"
53+
to: "internal/store/repository/queries.go"
54+
via: "HostPorts 类型和字段已移除"
55+
---
56+
57+
## Objective
58+
59+
彻底移除 Cloud CLI Proxy 中的端口映射(Port Mapping)特性,包括后端代码、数据库模型、网络层兼容补丁、API 路由、前端组件及相关文案。
60+
61+
Purpose: 端口映射特性与产品核心约束(全流量必须走隧道,不允许直连外网)相冲突,移除后网络策略更纯粹,维护面更小。
62+
Output: 所有端口映射相关代码、模型、API、UI 和文档文案清理完毕,项目编译和测试通过。
63+
64+
## Execution Context
65+
66+
@.claude/get-shit-done/workflows/execute-plan.md
67+
@.claude/get-shit-done/templates/summary.md
68+
69+
## Context
70+
71+
@./CLAUDE.md
72+
73+
## Tasks
74+
75+
<task type="auto">
76+
<name>Task 1: 删除端口映射专用文件</name>
77+
<files>
78+
internal/network/host_forwarding_linux.go
79+
internal/network/host_forwarding_other.go
80+
internal/store/migrations/0016_host_ports.sql
81+
internal/network/container_proxy_provider_linux.go
82+
internal/network/container_proxy_provider_other.go
83+
web/admin/src/components/hosts/port-manager.tsx
84+
</files>
85+
<action>
86+
使用 `git rm` 删除以下 6 个文件:
87+
1. `internal/network/host_forwarding_linux.go` — iptables DNAT+SNAT+FORWARD 实现
88+
2. `internal/network/host_forwarding_other.go` — 非 Linux 平台的 stub
89+
3. `internal/store/migrations/0016_host_ports.sql` — host_ports 表迁移
90+
4. `internal/network/container_proxy_provider_linux.go` — 带端口白名单的防火墙实现
91+
5. `internal/network/container_proxy_provider_other.go` — 非 Linux stub
92+
6. `web/admin/src/components/hosts/port-manager.tsx` — 端口映射 UI 组件
93+
94+
删除后运行 `go build ./...` 确认无因缺失文件导致的编译错误(预期会有引用错误,在 Task 2 中修复)。
95+
</action>
96+
<verify>
97+
<automated>test $(git status --short | grep -c "^D internal/network/host_forwarding") -eq 2 &amp;&amp; test $(git status --short | grep -c "^D internal/store/migrations/0016_host_ports.sql") -eq 1 &amp;&amp; test $(git status --short | grep -c "^D internal/network/container_proxy_provider") -eq 2 &amp;&amp; test $(git status --short | grep -c "^D web/admin/src/components/hosts/port-manager.tsx") -eq 1</automated>
98+
</verify>
99+
<done>6 个端口映射专用文件已从 git 中删除,且 `go build ./...` 无因文件缺失导致的错误</done>
100+
</task>
101+
102+
<task type="auto">
103+
<name>Task 2: 清理后端代码中的 PortMappings / HostPorts 引用</name>
104+
<files>
105+
internal/network/types.go
106+
internal/agentapi/contracts.go
107+
internal/network/container_proxy_provider.go
108+
internal/network/worker_firewall_linux.go
109+
internal/runtime/runtime_service.go
110+
internal/runtime/tasks/worker.go
111+
internal/controlplane/http/admin_hosts.go
112+
internal/controlplane/http/router.go
113+
internal/store/repository/models.go
114+
internal/store/repository/queries.go
115+
internal/network/worker_firewall_linux_test.go
116+
internal/controlplane/http/admin_hosts_test.go
117+
internal/controlplane/http/admin_egress_ip_probe_test.go
118+
</files>
119+
<action>
120+
按以下清单逐个文件清理端口映射相关代码,每改完一个文件运行 `go build ./...` 确认编译通过:
121+
122+
1. `internal/network/types.go` — 从 `HostNetworkSpec` 结构体中移除 `PortMappings` 字段及其类型定义。
123+
2. `internal/agentapi/contracts.go` — 移除 `PortMappings` 字段和相关 struct 定义。
124+
3. `internal/network/container_proxy_provider.go` — 移除端口转发调用和 bridge disconnect 逻辑中与 port mapping 相关的分支。
125+
4. `internal/network/worker_firewall_linux.go` — 移除 `allowedPorts` 参数、bridgeGW 例外逻辑、mapped port ACCEPT 规则。
126+
5. `internal/runtime/runtime_service.go` — 移除 `HostPorts` 到 `PortMappings` 的转换逻辑。
127+
6. `internal/runtime/tasks/worker.go` — 移除端口映射验证逻辑;统一 Docker 启动参数,不再使用 `-p` 端口映射(非 Linux 也不再映射)。
128+
7. `internal/controlplane/http/admin_hosts.go` — 移除 `UpdatePorts` handler;从 host 创建逻辑中移除 `HostPorts` 相关字段。
129+
8. `internal/controlplane/http/router.go` — 移除 `PUT /v1/admin/hosts/{hostID}/ports` 路由注册。
130+
9. `internal/store/repository/models.go` — 移除 `HostPorts` 类型、`Host.HostPorts` 字段、`HostPort` struct。
131+
10. `internal/store/repository/queries.go` — 移除 `UpdateHostPorts` 函数和所有 `host_ports` 相关 SQL 查询。
132+
11. `internal/network/worker_firewall_linux_test.go` — 移除 `WithAllowedPorts` 相关测试用例。
133+
12. `internal/controlplane/http/admin_hosts_test.go` — 移除 `UpdateHostPorts` 相关 stub 和测试。
134+
13. `internal/controlplane/http/admin_egress_ip_probe_test.go` — 更新断言,移除对 HostPorts 的期望。
135+
136+
清理原则:
137+
- 只删不改逻辑语义,不引入新行为。
138+
- 若某函数签名因移除参数导致调用点变化,同步修改所有调用点。
139+
- 若 import 因删除代码而变为未使用,同步移除。
140+
</action>
141+
<verify>
142+
<automated>go build ./... &amp;&amp; go test ./internal/network/... ./internal/controlplane/http/... ./internal/runtime/... ./internal/store/... -count=1</automated>
143+
</verify>
144+
<done>后端所有 PortMappings / HostPorts 引用已清理,`go build ./...` 和对应包测试全部通过</done>
145+
</task>
146+
147+
<task type="auto">
148+
<name>Task 3: 清理前端代码和文档文案</name>
149+
<files>
150+
web/admin/src/components/hosts/create-host-dialog.tsx
151+
web/admin/src/hooks/use-hosts.ts
152+
web/admin/src/routes/_dashboard/hosts/$hostId.tsx
153+
cmd/cloud-claude/local.go
154+
tests/scripts/uat-vscode-remote-ssh.sh
155+
docs/zh/guide/configuration.md
156+
docs/zh/guide/cloud-claude-local.md
157+
</files>
158+
<action>
159+
按以下清单清理前端和文案:
160+
161+
1. `web/admin/src/components/hosts/create-host-dialog.tsx` — 移除 `hostPorts` state、端口映射验证逻辑、表单中端口映射输入 JSX、提交时包含的 `host_ports` 字段。
162+
2. `web/admin/src/hooks/use-hosts.ts` — 移除 `HostPort` interface、`host_ports` 字段、`useUpdateHostPorts` hook。
163+
3. `web/admin/src/routes/_dashboard/hosts/$hostId.tsx` — 移除 `PortManager` 组件 import 和使用;将三列布局改为两列布局(移除第三列);清理相关文案。
164+
4. `cmd/cloud-claude/local.go` — 将文案 "端口映射" 改为 "SSH 端口"。
165+
5. `tests/scripts/uat-vscode-remote-ssh.sh` — 将 "容器端口映射" 改为 "容器 SSH 端口"。
166+
6. `docs/zh/guide/configuration.md` — 将章节标题 "Docker Compose 端口映射" 改为 "Docker Compose 服务端口";清理正文中的端口映射描述。
167+
7. `docs/zh/guide/cloud-claude-local.md` — 将 "SSH 端口映射" 改为 "SSH 端口"。
168+
169+
每改完前端文件后运行 `cd web/admin && npm run build`(或 `pnpm build` / `yarn build`,以项目实际 lockfile 为准)确认构建通过。
170+
</action>
171+
<verify>
172+
<automated>cd web/admin &amp;&amp; npm run build &amp;&amp; grep -r "端口映射" web/admin/src/ cmd/cloud-claude/local.go tests/scripts/uat-vscode-remote-ssh.sh docs/zh/guide/ || echo "No remaining 端口映射 references"</automated>
173+
</verify>
174+
<done>前端端口映射 UI 和 hook 已移除,文案中 "端口映射" 已替换为 "SSH 端口" 或 "服务端口",前端构建通过</done>
175+
</task>
176+
177+
## Threat Model
178+
179+
## Trust Boundaries
180+
181+
| Boundary | Description |
182+
|----------|-------------|
183+
| 宿主机防火墙规则 | 移除端口映射后,防火墙规则更精简,减少暴露面 |
184+
185+
## STRIDE Threat Register
186+
187+
| Threat ID | Category | Component | Disposition | Mitigation Plan |
188+
|-----------|----------|-----------|-------------|-----------------|
189+
| T-quick-01 | Information Disclosure | 残留端口映射文案/代码 | mitigate | 本计划全面清理所有引用,Task 2/3 的 grep 验证确保无残留 |
190+
| T-quick-02 | Denial of Service | 误删非端口映射代码 | mitigate | 每次修改后运行编译和测试,确保只删不改逻辑语义 |
191+
192+
## Verification
193+
194+
- `go build ./...` 通过
195+
- `go test ./internal/network/... ./internal/controlplane/http/... ./internal/runtime/... ./internal/store/... -count=1` 通过
196+
- `cd web/admin && npm run build` 通过
197+
- `grep -r "PortMappings\|HostPorts\|host_ports\|端口映射" --include="*.go" --include="*.ts" --include="*.tsx" --include="*.md" --include="*.sh" .` 无残留(预期仅命中本 PLAN.md 和 git 历史)
198+
199+
## Success Criteria
200+
201+
- [ ] 6 个端口映射专用文件已从仓库删除
202+
- [ ] 后端 13 个文件中的 PortMappings / HostPorts / host_ports 引用全部清理
203+
- [ ] 前端 3 个文件中的端口映射 UI 和 hook 全部清理
204+
- [ ] 4 个文案文件中的 "端口映射" 已替换为准确描述
205+
- [ ] Go 编译通过,相关包测试通过
206+
- [ ] 前端构建通过
207+
- [ ] 全局搜索确认无残留引用
208+
209+
## Output
210+
211+
After completion, create `.planning/quick/260511-o15-api/260511-o15-SUMMARY.md`

cmd/cloud-claude/local.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ func runLocalStatus(cmd *cobra.Command, args []string) error {
125125
fmt.Printf("容器: %s\n", status.Name)
126126
fmt.Printf("状态: %s\n", status.Status)
127127
fmt.Printf("镜像: %s\n", status.Image)
128-
fmt.Printf("端口映射: %s\n", status.PortMapping)
128+
fmt.Printf("SSH 端口: %s\n", status.PortMapping)
129129
fmt.Printf("创建时间: %s\n", status.CreatedAt)
130130

131131
return nil

docs/zh/guide/cloud-claude-local.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ cloud-claude local up
3131
cloud-claude local status
3232
```
3333

34-
显示本地容器状态、SSH 端口映射和 sing-box 隧道状态。
34+
显示本地容器状态、SSH 端口和 sing-box 隧道状态。
3535

3636
### 4. 停止容器
3737

docs/zh/guide/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ bash deploy/scripts/setup-env.sh
4141
|------|------|--------|------|
4242
| `ADMIN_PORT` || `3000` | 管理后台前端端口(映射到容器 80 端口) |
4343

44-
### Docker Compose 端口映射
44+
### Docker Compose 服务端口
4545

4646
| 变量 | 默认值 | 说明 |
4747
|------|--------|------|

internal/agentapi/contracts.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,6 @@ type HostActionRequest struct {
6262
ClaudeAccountID string `json:"claude_account_id,omitempty"`
6363
// BindMounts 携带宿主机目录 bind mount 配置,由 Runtime Service 从 repository.HostMounts 映射而来。
6464
BindMounts []BindMount `json:"bind_mounts,omitempty"`
65-
// PortMappings 携带宿主机到容器的端口映射配置,由 Runtime Service 从 repository.HostPorts 映射而来。
66-
PortMappings []PortMapping `json:"port_mappings,omitempty"`
67-
}
68-
69-
// PortMapping 描述 docker create -p 的端口映射契约。
70-
type PortMapping struct {
71-
HostPort int `json:"host_port"`
72-
ContainerPort int `json:"container_port"`
73-
Protocol string `json:"protocol,omitempty"`
7465
}
7566

7667
type TaskStatusUpdate struct {

internal/controlplane/http/admin_hosts.go

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ type AdminHostStore interface {
4040
ListRunningHosts(ctx context.Context) ([]repository.Host, error)
4141
GetHostWithClaudeAccount(ctx context.Context, hostID string) (repository.HostWithClaudeAccount, error) // Phase 33 D-22
4242
UpdateHostMounts(ctx context.Context, hostID string, mounts repository.HostMounts) error
43-
UpdateHostPorts(ctx context.Context, hostID string, ports repository.HostPorts) error
4443
}
4544

4645
type AdminHostsHandler struct {
@@ -155,7 +154,6 @@ func (h *AdminHostsHandler) Create() nethttp.Handler {
155154
CPULimit float64 `json:"cpu_limit"`
156155
DiskLimitGB int `json:"disk_limit_gb"`
157156
HostMounts repository.HostMounts `json:"host_mounts"`
158-
HostPorts repository.HostPorts `json:"host_ports"`
159157
}
160158
if err := json.NewDecoder(r.Body).Decode(&body); err != nil || body.UserID == "" {
161159
writeJSON(w, nethttp.StatusBadRequest, map[string]string{"error": "user_id is required"})
@@ -230,7 +228,6 @@ func (h *AdminHostsHandler) Create() nethttp.Handler {
230228
CPULimit: body.CPULimit,
231229
DiskLimitGB: body.DiskLimitGB,
232230
HostMounts: expandHostMountSources(body.HostMounts),
233-
HostPorts: body.HostPorts,
234231
})
235232
if err == nil {
236233
break
@@ -1067,49 +1064,6 @@ func (h *AdminHostsHandler) UpdateMounts() nethttp.Handler {
10671064
})
10681065
}
10691066

1070-
func (h *AdminHostsHandler) UpdatePorts() nethttp.Handler {
1071-
return nethttp.HandlerFunc(func(w nethttp.ResponseWriter, r *nethttp.Request) {
1072-
hostID := r.PathValue("hostID")
1073-
var body struct {
1074-
Ports repository.HostPorts `json:"ports"`
1075-
}
1076-
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
1077-
writeJSON(w, nethttp.StatusBadRequest, map[string]string{"error": "invalid request body"})
1078-
return
1079-
}
1080-
for _, p := range body.Ports {
1081-
if p.HostPort <= 0 || p.HostPort > 65535 {
1082-
writeJSON(w, nethttp.StatusBadRequest, map[string]string{"error": fmt.Sprintf("invalid host port: %d", p.HostPort)})
1083-
return
1084-
}
1085-
if p.ContainerPort <= 0 || p.ContainerPort > 65535 {
1086-
writeJSON(w, nethttp.StatusBadRequest, map[string]string{"error": fmt.Sprintf("invalid container port: %d", p.ContainerPort)})
1087-
return
1088-
}
1089-
if p.Protocol != "" && p.Protocol != "tcp" && p.Protocol != "udp" {
1090-
writeJSON(w, nethttp.StatusBadRequest, map[string]string{"error": fmt.Sprintf("invalid protocol: %s (must be tcp or udp)", p.Protocol)})
1091-
return
1092-
}
1093-
}
1094-
if err := h.store.UpdateHostPorts(r.Context(), hostID, body.Ports); err != nil {
1095-
h.logger.Error("update host ports failed", "host_id", hostID, "error", err)
1096-
writeJSON(w, nethttp.StatusInternalServerError, map[string]string{"error": "update ports failed"})
1097-
return
1098-
}
1099-
if h.events != nil {
1100-
hid := hostID
1101-
if _, err := h.events.RecordEvent(r.Context(), repository.RecordEventParams{
1102-
HostID: &hid, Level: "info", Type: "admin.host.update_ports",
1103-
Message: "管理员更新主机端口映射配置",
1104-
Metadata: map[string]any{"operator": "admin", "port_count": len(body.Ports)},
1105-
}); err != nil {
1106-
h.logger.Error("record event failed", "type", "admin.host.update_ports", "error", err)
1107-
}
1108-
}
1109-
writeJSON(w, nethttp.StatusOK, map[string]string{"status": "ok"})
1110-
})
1111-
}
1112-
11131067
// syncContainerPassword updates the Linux user password inside a running container via docker exec.
11141068
// Exposed as a package-level var so unit tests can inject a fake implementation (Phase 29.1).
11151069
var syncContainerPassword = func(containerName, user, password string) error {

internal/controlplane/http/admin_hosts_test.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,6 @@ func (s *stubHostStore) UpdateHostMounts(_ context.Context, _ string, _ reposito
7373
return nil
7474
}
7575

76-
func (s *stubHostStore) UpdateHostPorts(_ context.Context, _ string, _ repository.HostPorts) error {
77-
return nil
78-
}
7976

8077
func TestAdminHostsHandler(t *testing.T) {
8178
now := time.Now().Truncate(time.Second)

internal/controlplane/http/router.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,6 @@ func NewRouter(deps Dependencies) nethttp.Handler {
257257
mux.Handle("GET /v1/admin/hosts/{hostID}/logs", adminGuard(hostsHandler.GetLogs()))
258258
mux.Handle("DELETE /v1/admin/hosts/{hostID}", adminGuard(hostsHandler.Delete()))
259259
mux.Handle("PUT /v1/admin/hosts/{hostID}/mounts", adminGuard(hostsHandler.UpdateMounts()))
260-
mux.Handle("PUT /v1/admin/hosts/{hostID}/ports", adminGuard(hostsHandler.UpdatePorts()))
261260

262261
vncProxy := NewAdminVNCProxyHandler(deps.Logger, deps.AdminHosts)
263262
// VNC 入口页 (vnc.html) 带 ?token= 认证;子资源(CSS/JS/图片)

internal/network/container_proxy_provider.go

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func (p *ContainerProxyProvider) PrepareHost(ctx context.Context, spec HostNetwo
105105
return fmt.Errorf("gateway: configure worker routes/DNS: %w", err)
106106
}
107107

108-
if err := applyWorkerFirewall(ctx, workerName, gwIP, bridgeGW, spec.PortMappings); err != nil {
108+
if err := applyWorkerFirewall(ctx, workerName, gwIP, bridgeGW); err != nil {
109109
p.teardownGateway(ctx, hostID)
110110
return fmt.Errorf("gateway: apply worker firewall: %w", err)
111111
}
@@ -133,17 +133,6 @@ func (p *ContainerProxyProvider) PrepareHost(ctx context.Context, spec HostNetwo
133133
"dns_server", result.ActualDNS,
134134
)
135135

136-
if len(spec.PortMappings) > 0 {
137-
if err := ensurePortMapChain(ctx); err != nil {
138-
p.teardownGateway(ctx, hostID)
139-
return fmt.Errorf("gateway: setup portmap chain: %w", err)
140-
}
141-
if err := setupPortForwarding(ctx, hostID, bridgeGW, gwIP, spec.PortMappings); err != nil {
142-
p.teardownGateway(ctx, hostID)
143-
return fmt.Errorf("gateway: setup port forwarding: %w", err)
144-
}
145-
}
146-
147136
if cpID, _ := os.Hostname(); cpID != "" {
148137
if err := dockerNetworkConnect(ctx, netName, cpID, ""); err != nil {
149138
p.logger.Warn("container-proxy: connect control-plane to isolated network failed (VNC may not work)",
@@ -174,7 +163,6 @@ func (p *ContainerProxyProvider) teardownGateway(ctx context.Context, hostID str
174163
workerName := workerContainerName(hostID)
175164

176165
cleanupWorkerFirewall(ctx, workerName)
177-
teardownPortForwarding(ctx, hostID)
178166

179167
if cpID, _ := os.Hostname(); cpID != "" {
180168
_ = exec.CommandContext(ctx, "docker", "network", "disconnect", "-f", netName, cpID).Run()

0 commit comments

Comments
 (0)