Treat the WASM/WASI build target as cfg(unix) so filesystem tools need no per-tool mode-bit patches
まだ誰も着手していません。
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 35/100
- issue の種類
- 機能追加
- 明瞭さ
- 説明が足りない
- 活発さ
- 静か
- 技術スタック
- rust, wasm
調査の方向性
uutils/coreutils' src/uucore/src/lib/features/fs.rs から始め、registry/native/patches にある参照先の WASI パッチを which.rs と builtins のエントリポイントと比較します。ここで説明されている target-spec、build-std、preview2 の代替案を調査します。互換性と保守に関する影響を含め、1 つの方向性を選択して文書化すれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Summary
We build coreutils (ls, stat, chmod, …) for wasm32-wasip1. Because that
target is not cfg(unix), every crate's #[cfg(unix)] filesystem code —
the code that reads real st_mode permission bits — is compiled out, and the
#[cfg(not(unix))] fallback (which fabricates permissions from a single
readonly boolean) is compiled in. To get native-Linux-accurate output we've
had to hand-patch each tool to bypass that fallback and fetch mode bits from the
sidecar via a host_fs.path_mode import (landed in #268 / #269).
This issue tracks the larger question: should we make the WASM build target
present as cfg(unix) (a Linux-like target) so these tools "just work" with no
per-tool patches, instead of maintaining a growing pile of #[cfg(target_os = "wasi")] shims?
Why a non-Linux target breaks filesystem tools
uucore has two implementations of display_permissions, cfg-gated:
#[cfg(unix)] // reads REAL bits
pub fn display_permissions(md, ...) -> String {
display_permissions_unix(md.mode() as mode_t, ...) // st_mode
}
#[cfg(not(unix))] // WASI lands HERE — fabricates
pub fn display_permissions(md, display_file_type) -> String {
let write = if md.permissions().readonly() { '-' } else { 'w' };
format!("{file_type}r{write}xr{write}xr{write}x") // r & x HARDCODED on
}
Upstream root cause (uutils/coreutils, uucore 0.5.0):
https://github.com/uutils/coreutils/blob/main/src/uucore/src/lib/features/fs.rs
Consequences of being cfg(not(unix)):
md.mode()isn't even callable —std::os::unix::fs::MetadataExtdoesn't
exist in the WASIstd.- Rust's own
std::os::wasi::fs::MetadataExtdeliberately exposes
dev/ino/nlink/size/atim/…but nomode(), because WASI preview1's
filestatstruct has no mode field. So the bits are absent at thestdlayer
regardless of cfg. - Net effect:
ls -lprinted-rwxrwxrwx(or-r-xr-xr-xif readonly) for
every file — a uniform string derived from one boolean.
Note this is degradation, not deliberate stripping: the tools have "WASI
support," it's just a lossy fallback nobody wired to a host that has the bits.
Evidence: the per-tool workarounds this forces (all at 8145b07)
Each of these exists only because the target isn't cfg(unix):
ls— inject ahost_fs.path_modeimport +mode_for_pathand swap
display_permissions→display_permissions_unix:
https://github.com/rivet-dev/secure-exec/blob/8145b07ebcd1f6553a417a009091c53d7610a04f/registry/native/patches/crates/uu_ls/0001-wasi-host-fs-mode-display.patch#L16-L74stat:
https://github.com/rivet-dev/secure-exec/blob/8145b07ebcd1f6553a417a009091c53d7610a04f/registry/native/patches/crates/uu_stat/0001-wasi-metadata-compat.patchchmod:
https://github.com/rivet-dev/secure-exec/blob/8145b07ebcd1f6553a417a009091c53d7610a04f/registry/native/patches/crates/uu_chmod/0001-wasi-compat.patch- First-party shims hit the same wall —
whichand the shell builtins each
carry their own#[cfg(target_os = "wasi")]host_fsextern:
https://github.com/rivet-dev/secure-exec/blob/8145b07ebcd1f6553a417a009091c53d7610a04f/registry/native/crates/libs/shims/src/which.rs#L16-L58
https://github.com/rivet-dev/secure-exec/blob/8145b07ebcd1f6553a417a009091c53d7610a04f/registry/native/crates/libs/builtins/src/lib.rs#L14-L27 - And the C side already has the mirror-image fix in wasi-libc (which Rust can't
reach, because Rust std bypasses libcstat()on wasip1):
https://github.com/rivet-dev/secure-exec/blob/8145b07ebcd1f6553a417a009091c53d7610a04f/registry/native/patches/wasi-libc/0016-host-fs-mode-and-chmod.patch
Every new fs-touching Rust tool we add will need another such patch.
Options
A. Force cfg(unix) on the current target (cheap, does NOT work)
Passing --cfg unix via RUSTFLAGS flips the cfg on our crates, but the
#[cfg(unix)] path does use std::os::unix::fs::MetadataExt, which the
precompiled WASI std doesn't contain → unresolved import. And even if it
resolved, the WASI Metadata's underlying filestat has no st_mode to
return. Rejected.
B. Custom Linux-like target spec + -Z build-std (the real "treat it like native")
Define a target derived from wasm32-wasip1 with target-family = ["unix", …]
and recompile std/core so Rust's fs routes through the libc-backed unix fs
backend (calls libc stat(), reads st_mode). Then the wasi-libc mode patch
(0016) flows up into Rust automatically and all #[cfg(unix)] tool code works —
no per-tool patches. Blast radius, however, is large:
- Nightly + build-std on every build; per-Rust-version maintenance of a bespoke
target. cfg(unix)flips the entire dep graph, not just perms — signals, process,
users/groups (getpwuid), termios, mmap, net — much of which calls libc
symbols WASI libc doesn't implement → link/ENOSYSbreakage to chase.- The fs backend (
target_os = "wasi") andMetadataExt(target_family = unix) are gated on different cfgs and don't cleanly compose; effectively a
std fork.
C. Move the runtime to WASI preview2 / wasi:filesystem (the clean long-term fix)
preview2 carries richer metadata than preview1's filestat. Migrating (or
upstreaming a wasi MetadataExt::mode() backed by an extended filestat) would
let these tools read real bits natively and let us delete all the patches —
without pretending to be unix.
Ask / decision needed
Decide between: (B) invest in a Linux-like custom target + build-std so fs tools
need zero patches, vs. (C) target preview2, vs. (status quo) keep adding small
per-tool host_fs patches. Leaning C long-term; B is the "make it native" ask
but has broad blast radius. Capturing so the tradeoff is explicit before the
patch pile grows.
Related PRs: #268 (filesystem native-parity: wasi-libc + sidecar host_fs),
#269 (coreutils stat/chmod/ls real permission bits).
- 主要言語
- TypeScript
- スター
- 1k
- フォーク
- 54
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
- Dockerfile または Docker Compose ファイルあり
- プルリクエストのテンプレートなし
- コントリビューションガイドなし
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
rivet-dev/dynamic-apps のほかの issue
-
Build cache ignores maxResponseBytes, potentially reusing an outdated response limit対応中かも @Utkarshpandey0001 が 29 日前に担当しました。 オープン
難易度 3/5 1〜2日 初心者へのやさしさ 78/100
rivet-dev/dynamic-apps#297 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 58/100
rivet-dev/dynamic-apps#280 · コメント 2 件 ·
-
Make agentOS runtime classifier content-based (match Linux exec semantics), not extension-based対応中かも @mittal-parth が 34 日前に担当しました。 オープン
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
rivet-dev/dynamic-apps#275 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 55/100
rivet-dev/dynamic-apps#272 ·
-
難易度 5/5 1週間以上 初心者へのやさしさ 42/100
rivet-dev/dynamic-apps#178 ·
rivet-dev/dynamic-apps の issue をすべて見る
似ている issue
-
"Contains" page watch never matches when its text has a trailing space対応中かも @RaphaelFakhri が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 77/100
CopilotKit/openmuse#184 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
メンテナーはふだん 1 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 67/100
bootstrap-vue-next/bootstrap-vue-next#3357 ·
メンテナーはふだん 1 日以内に返信
-
[quality] tide.ts: six mutation survivors in the merge-queue gate, draft refusal, fork-403 workflow-file diagnosis and getPull's fork flag are unpinned by any test対応中かも @hivecommons-hive が今日担当しました。 オープンagent/quality needs-kind stage/040-covered-by-pr testing
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
cncf/prow-github-actions#517 · コメント 1 件 ·
メンテナーはふだん 2 日以内に返信
-
Unsampled pageload span is profiled when profileLifecycle is 'trace' (browser UI profiling)対応中かも @Jxxunnn が今日担当しました。 オープンBrowser Waiting for: Product Owner
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
getsentry/sentry-javascript#25497 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信