8000 fix(op,minimald): fetch a box build's web sources in its classifier leaf (0.7 backport) by norrietaylor · Pull Request #3101 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content

fix(op,minimald): fetch a box build's web sources in its classifier leaf (0.7 backport) - #3101

Open
norrietaylor wants to merge 1 commit into
release/0.7.xfrom
fix/backport-t124-0.7.x
Open

norrietaylor wants to merge 1 commit into
release/0.7.xfrom
fix/backport-t124-0.7.x

Conversation

@norrietaylor
Copy link
Copy Markdown
Member

Backports #2795 (c7f6ddd67) to release/0.7.x, as one cherry-pick -x commit.

Refs #3058. This fixes that issue for host-address boxes, the default network mode, but does not close it.

On v0.7.3-rc1 every web source leaves from the daemon, so on a VM host the node-plane baseline drops the frames and the first launch of a box with such a package waits about four minutes and then fails. With this change, a box with a classifier leaf fetches its web sources in that leaf, and the box's egress rules decide the fetch.

Adaptation

The picked code did not compile on this line. Two names changed, and nothing else:

Main This line Why
sandbox::config sandbox2::config The line predates #2106
crate::box_ops::{BuildPlacement, BuildTap} crate::session_sop::{BuildPlacement, BuildTap} box_ops does not exist here

No other commit is needed. #2720 and #2723 are already on the line.

Still open

  • An own_ip box has no classifier leaf, so its web sources still leave from the daemon and are dropped, even when the box allows the host. This is #2802.
  • gs:// sources still leave from the daemon, also #2802.

Testing

Real microVM on macOS arm64, comparing a build of this branch with a build of 81f7ce2c. The branch was rebased after testing over 161a18cf, which changes only .github/workflows/release.yml.

Box and package 81f7ce2c This branch
Default, project package with a storage.googleapis.com source Failed after 242 s, 4 node-plane drops Worked in 6 s, 0 drops
Default, claude-code at pkgs 08b41ede Failed after 248 s, 4 drops Worked in 131 s, 0 drops
--deny-all-egress Not run Fails at once and names the host, 0 drops
--network own_ip --allow-dns-hosts storage.googleapis.com Not run Failed after 212 s, 4 drops, as above

"Worked" means exec exited 0 and the log showed the fetch in the box's leaf. The extracted file was not confirmed in the box, and claude was not launched.

  • just fmt-check, just check-version, just clippy, just deny, just test, just doctest and just zoned-link-check pass, at the macOS scope.
  • just ci stops at clippy-strict, which compares against main. Against origin/release/0.7.x it reports 4 hits, all in T124's remote_storage.rs, the code as main has it. They are left as they are.
  • just test-cross: clippy passes. Tests were run with --no-fail-fast, because the recipe stops at the first failing target. Failures in checkouts, common (shell_harnesses), minimal, minimald and sandbox2 also occur on 81f7ce2c, and none is unique to this branch. All of T124's tests pass.
  • Not run: just e2e, just test-vm, and the root lane.

After the release, git cherry lists this commit, and its fix is on main as #2795.

A web-source fetch for a build placed for a box opens each connection
from a socket created in that box's classifier leaf, through a loopback
relay, and asks its name query from the same leaf. The box's egress
verdict then decides the fetch (NET-155). On a VM host the frames carry
the box mark, so the host gate decides them by the box's rules and not
by the node-plane baseline. The cache lookup and the content-hash check
stay as they are.

A fetch that the box's rules refuse fails the build with the source
host. The node-plane fetch record no longer lists a web source fetched
in a box's leaf. A gs:// source, and a web source of a box with no leaf,
still leave from the daemon and are recorded.

Backports [#2795](#2795) to the 0.7 line.
The change is T124 from main with these names adapted, because the line
predates two moves on main:

- sandbox::config is sandbox2::config, in op and in minimald's tests.
  The line predates the crate rename in
  [#2106](#2106).
- box_ops::{BuildPlacement, BuildTap} is session_sop::{BuildPlacement,
  BuildTap}, in the new test in minimald's session/tests.rs. main's
  box_actor/tests.rs is that file on the line.

(cherry picked from commit c7f6ddd)
@norrietaylor
norrietaylor requested a review from a team as a code owner November 6, 2026 18:38
@coderabbitai
coderabbitai Bot commented Nov 6, 2026
Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: 7903845d-c807-4784-aaff-1dc66b96c497

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@minimal-foundry
minimal-foundry Bot commented Nov 6, 2026 •
Copy link
Copy Markdown
Contributor

Reviewed: 2 findings, none blocking at a5de64e67ff7.

Address the comments on the diff.

Clobber: not checked in depth. If that was not intentional, restore the earlier change.

@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — advisory review

Verdict COMMENT — 2 findings, 2 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

Comment thread crates/op/src/specs.rs
Comment on lines +375 to +392
pub(crate) fn strip_urls(text: &str) -> String {
let mut out = String::with_capacity(text.len());
let mut rest = text;
while let Some(at) = rest.find("://") {
let start = rest[..at]
.rfind(|c: char| !(c.is_ascii_alphanumeric() || matches!(c, '+' | '-' | '.')))
.map_or(0, |i| i + 1);
let end = rest[at..]
.find(|c: char| c.is_whitespace() || matches!(c, '"' | '\'' | '<' | '>' | '(' | ')'))
.map_or(rest.len(), |i| at + i);
out.push_str(&rest[..start]);
if start == at {
// No scheme before the `://`: not a URL.
out.push_str(&rest[start..end]);
} else {
match stripped_url(&rest[start..end]) {
8000 Some(url) => out.push_str(&url),
None => out.push_str("<url>"),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HIGH · correctness · confidence 0.50 · in strip_urls

strip_urls ends a URL at the first ( or ). A URL with parentheses in its path, such as https://h/a_(1).tar.gz?sig=abc, is cut at the (. The text after it, including the signed query, stays in the output. The output goes to the build stderr and to a daemon log line. Parse the URL up to whitespace or quote, and drop only a trailing ) that wraps it.

What the reviewer checked

specs.rs:383 .find(|c: char| c.is_whitespace() || matches!(c, '"' | ''' | '<' | '>' | '(' | ')'))

Hand this to an agent
Act on a code-review finding.

File:       crates/op/src/specs.rs
Lines:      375-392
Category:   correctness
Severity:   high (reviewer confidence 0.50)

Finding:
`strip_urls` ends a URL at the first `(` or `)`. A URL with parentheses in its path, such as `https://h/a_(1).tar.gz?sig=abc`, is cut at the `(`. The text after it, including the signed query, stays in the output. The output goes to the build stderr and to a daemon log line. Parse the URL up to whitespace or quote, and drop only a trailing `)` that wraps it.

First verify this against the code yourself. It is model output and
may be wrong. If it is wrong, or the tradeoff was deliberate, say so
and change nothing.

👍 useful · 👎 noise — react to tell the reviewer. Replying works too, and says more.

Comment on lines +632 to +640
if !addrs.is_empty() {
Lookup::Found(addrs)
} else if answered {
Lookup::Answered(no_such_name.unwrap_or_else(|| {
io::Error::new(io::ErrorKind::NotFound, format!("{host} has no address"))
}))
} else {
Lookup::Unanswered(last.unwrap_or_else(|| {
io::Error::other(format!("the name server {server} did not answer"))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOW · correctness · confidence 0.50 · in lookup_at

In lookup_at, a lost or failed A query is hidden when the AAAA query answers with no records. answered becomes true, so the result is Lookup::Answered and lookup_in_cgroup does not ask the next name server. The download then fails with "has no address" for a host that has an A record. Treat a lookup as answered only when no query failed, or fall through to the next server when a query failed.

What the reviewer checked

A query error sets last and continues. AAAA NoError sets answered = true. With empty addrs, else if answered returns Lookup::Answered.

Hand this to an agent
Act on a code-review finding.

File:       crates/common/src/remote_storage.rs
Lines:      632-640
Category:   correctness
Severity:   low (reviewer confidence 0.50)

Finding:
In `lookup_at`, a lost or failed A query is hidden when the AAAA query answers with no records. `answered` becomes true, so the result is `Lookup::Answered` and `lookup_in_cgroup` does not ask the next name server. The download then fails with "has no address" for a host that has an A record. Treat a lookup as answered only when no query failed, or fall through to the next server when a query failed.

First verify this against the code yourself. It is model output and
may be wrong. If it is wrong, or the tradeoff was deliberate, say so
and change nothing.

👍 useful · 👎 noise — react to tell the reviewer. Replying works too, and says more.

@msample
msample commented Nov 6, 2026
Copy link
Copy Markdown
Member

This agrees with the arch as written. Rule 11 of the owner ruling on gominimal/arch#167 (https://github.com/gominimal/arch/issues/167#issuecomment-6695894260) keeps #2795 and this backport as the temporary solution until build boxes are available. The two minimal-foundry findings (strip_urls stops at (, and lookup_at can hide a failed A query) are also in #2795's code on main. Fix them on main, then cherry-pick the fix to this line.

This branch has not been deployed

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

2 participants

0