8000 T148 — A native own-address box reaches a host exposure under the current table · Issue #2937 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content
Dismiss alert

T148 — A native own-address box reaches a host exposure under the current table #2937

Closed

Description

@norrietaylor

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.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.

Covers:

  • NET-160
  • NET-161
  • NET-162

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)
    • cargo nextest run -p minimald native_own_ip_host_exposure_needs_the_box_to_name_the_host
    • cargo nextest run -p minimald native_own_ip_follows_the_current_host_exposures_table
    • cargo nextest run -p minimald native_own_ip_exposure_removal_ends_established_flows
    • cargo nextest run -p minimald native_own_ip_exposure_on_minimal_listener_refused
    • cargo nextest run -p minimald native_own_ip_exposure_shadowed_by_a_later_minimal_listener
    • cargo nextest run -p minimald native_own_ip_runtime_published_box_port_held_until_it_unbinds

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

Activity

  1. added
    kind:taskA task the plan skill rendered; the body carries ## Task
    on Nov 3, 2026
  2. added
    size:M200 to 500 net lines; one PR
    model:standardA standard model: work that needs care, or routine work that is large
    on Nov 3, 2026
  3. minimal-foundry commented on Nov 3, 2026

    @minimal-foundry
    Contributor

    Done. #2970 merged.

    branch agent/2937-a-native-own-address-box-reaches-a-host-exposure · epic #1437 · PR #2970

    round outcome job
    1 pushed 6c1e7728
    2 pushed 31973578
    3 refused: T148 is blocked by still-open #2689. The plan's order is the point of having one.
    3 pushed 113975d6
    4 pushed c9b15050
    5 pushed a10abbf3
    6 changed nothing: Revise round 6 closes out round 5 (43dcaf9). I read the two arch C1 threads on crates/minimald/src/net/gvproxy_network.rs (comments 4472514675 and 4472514689) against this head. Commit 43dcaf9 remov 1508a3a5
    7 pushed 3fc154a6
    8 pushed b15c43eb

    Updated 2026-11-05T00:42:53.624Z.

  4. added
    size:L500 to 900 net lines; one PR, and the ceiling
    on Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind:taskA task the plan skill rendered; the body carries ## Taskmodel:standardA standard model: work that needs care, or routine work that is largesize:L500 to 900 net lines; one PR, and the ceilingsize:M200 to 500 net lines; one PR

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      0