Repository navigation
Closed
Labels
kind:taskA task the plan skill rendered; the body carries ## TaskA task the plan skill rendered; the body carries ## Taskmodel:standardA standard model: work that needs care, or routine work that is largeA standard model: work that needs care, or routine work that is largesize:L500 to 900 net lines; one PR, and the ceiling500 to 900 net lines; one PR, and the ceilingsize:M200 to 500 net lines; one PR200 to 500 net lines; one PR
Description
Task
| slice | size | difficulty | model | who | estimated lines |
|---|---|---|---|---|---|
| host.min.internal reaches only the design's openings | L | needs care | standard | an agent | 700 (300 code, 400 tests) |
On a native Linux host, an own-address box that names
host.min.internalreaches a port the user's table opens, reaches it no more once the entry is removed, a box that does not name the host never reaches it, and an entry at a port one of Minimal's own listeners holds opens nothing.
Covers:
- NET-160
- NET-161
- NET-162
Layers:
- relay:
- crates/client-config/src/host_exposures.rs: parses the
[host-exposures]table of the clientconfig.toml, each entry a port and aprotothat istcpwhen the entry names none, and reads it again when the file changes - crates/client-config/src/lib.rs: exports the table reader
- crates/minvmd/Cargo.toml: depends on the shared reader in
client-config - crates/minimald/src/box_actor/ports.rs: a
min net exposeforward holds its published port as a Minimal listener, and releases it at unexpose - crates/minimald/src/net/policy.rs: a
PortForwarderat 127.0.0.1 carries its Minimal-listener hold until its unbind succeeds - crates/minimald/src/net/gvproxy_network.rs: a published box port is held as a Minimal listener from the bind until the forwarder unbinds, so a table entry cannot reach it through the alias
- crates/minvmd/src/net/host_exposures.rs: reads the table through the shared
client-configreader, so one reader serves both daemons and a bad entry is handled one way - crates/minimald/Cargo.toml: depends on
client-config, so the native relay reads the table - Cargo.lock: records the new dependency edge
- crates/minimald/src/net/switch.rs: the native relay admits a flow from an own-address box to
host.min.internalonly at a port the current table opens, and only when the box'segress.allow_dns_hostsnameshost.min.internalor itsallow_subnetscovers the alias; a change to the table decides each later flow, and an exposure removed ends the established flows to it; a native host-address box is untouched (it shares the host's namespace, design §7.1 Lanes) cargo nextest run -p minimald native_own_ip_host_exposure_needs_the_box_to_name_the_hostcargo nextest run -p minimald native_own_ip_follows_the_current_host_exposures_tablecargo nextest run -p minimald native_own_ip_exposure_removal_ends_established_flowscargo nextest run -p minimald native_own_ip_exposure_on_minimal_listener_refusedcargo nextest run -p minimald native_own_ip_exposure_shadowed_by_a_later_minimal_listenercargo nextest run -p minimald native_own_ip_runtime_published_box_port_held_until_it_unbinds
- crates/client-config/src/host_exposures.rs: parses the
Waits on:
Plan block
### T148 — A native own-address box reaches a host exposure under the current table, and never Minimal's own listener
slice: S21
kind: task
covers: NET-160, NET-161, NET-162
size: L
est: 300 code, 400 tests
executor: agent
difficulty: needs care
model: standard
diagnostics: `min bug` bundles carry the native daemon log, where each refused flow from an own-address box to `host.min.internal` names the box, the port and whether the table or the box's rules refused it
observability: the native relay's rate-limited refusal line names the rule `host-alias` and the box; each table reload is logged at debug with its entry count
layers:
- relay:
- crates/client-config/src/host_exposures.rs: parses the `[host-exposures]` table of the client `config.toml`, each entry a port and a `proto` that is `tcp` when the entry names none, and reads it again when the file changes
- crates/client-config/src/lib.rs: exports the table reader
- crates/minvmd/Cargo.toml: depends on the shared reader in `client-config`
- crates/minimald/src/box_actor/ports.rs: a `min net expose` forward holds its published port as a Minimal listener, and releases it at unexpose
- crates/minimald/src/net/policy.rs: a `PortForwarder` at 127.0.0.1 carries its Minimal-listener hold until its unbind succeeds
- crates/minimald/src/net/gvproxy_network.rs: a published box port is held as a Minimal listener from the bind until the forwarder unbinds, so a table entry cannot reach it through the alias
- crates/minvmd/src/net/host_exposures.rs: reads the table through the shared `client-config` reader, so one reader serves both daemons and a bad entry is handled one way
- crates/minimald/Cargo.toml: depends on `client-config`, so the native relay reads the table
- Cargo.lock: records the new dependency edge
- crates/minimald/src/net/switch.rs: the native relay admits a flow from an own-address box to `host.min.internal` only at a port the current table opens, and only when the box's `egress.allow_dns_hosts` names `host.min.internal` or its `allow_subnets` covers the alias; a change to the table decides each later flow, and an exposure removed ends the established flows to it; a native host-address box is untouched (it shares the host's namespace, design §7.1 Lanes)
test: cargo nextest run -p minimald native_own_ip_host_exposure_needs_the_box_to_name_the_host
test: cargo nextest run -p minimald native_own_ip_follows_the_current_host_exposures_table
test: cargo nextest run -p minimald native_own_ip_exposure_removal_ends_established_flows
test: cargo nextest run -p minimald native_own_ip_exposure_on_minimal_listener_refused
test: cargo nextest run -p minimald native_own_ip_exposure_shadowed_by_a_later_minimal_listener
test: cargo nextest run -p minimald native_own_ip_runtime_published_box_port_held_until_it_unbinds
produces: none
consumes: none
proof: On a native Linux host, an own-address box that names `host.min.internal` reaches a port the user's table opens, reaches it no more once the entry is removed, a box that does not name the host never reaches it, and an entry at a port one of Minimal's own listeners holds opens nothing.
depends on:
- blocked by #2689
Reacted by minimal-foundry
Metadata
Metadata
Assignees
Labels
kind:taskA task the plan skill rendered; the body carries ## TaskA task the plan skill rendered; the body carries ## Taskmodel:standardA standard model: work that needs care, or routine work that is largeA standard model: work that needs care, or routine work that is largesize:L500 to 900 net lines; one PR, and the ceiling500 to 900 net lines; one PR, and the ceilingsize:M200 to 500 net lines; one PR200 to 500 net lines; one PR
Activity
minimal-foundry commentedon Nov 3, 2026
Done. #2970 merged.
branch
agent/2937-a-native-own-address-box-reaches-a-host-exposure· epic #1437 · PR #29706c1e772831973578113975d6c9b15050a10abbf31508a3a53fc154a6b15c43ebUpdated 2026-11-05T00:42:53.624Z.