Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions .claude/skills/aube-bump/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,18 @@ applies. Reverting was correct. Let the tests arbitrate; don't defend a graft.
Grep after every bump — if one vanished, a resolution was wrong:

```sh
grep -rn "workspace_markers\|lockfile_basename\|EmbedderProfile\|read_branded_pnpm_config\|env_prefix\|cache_namespace\|engine_context\|env_overlay\|path_prepends\|runtime_node\|cold_path" vendor/aube/crates
grep -rn "workspace_markers\|lockfile_basename\|virtual_store_subdir\|branded_env_alias_enabled\|read_branded_pnpm_config\|env_prefix\|cache_namespace\|engine_context\|env_overlay\|path_prepends\|runtime_node\|cold_path" vendor/aube/crates
```

- **Embedder profile plumbing** — `env_prefix`, `cache_namespace`, `lockfile_basename`,
`workspace_markers`, `read_branded_pnpm_config` gating. Holds the brand + config boundary. Largely
upstreamed, so it usually converges rather than conflicts.
`workspace_markers`, `virtual_store_subdir`, `read_branded_pnpm_config` gating. Holds the brand +
config boundary. Largely upstreamed, so it usually converges rather than conflicts. The profile type
is `Embedder` (`aube-util/src/identity.rs`), reached via `aube_util::embedder()`.
`virtual_store_subdir` earns its place in the grep: the v1.35 bump auto-merged two upstream call sites
that hardcoded `aube_store::VIRTUAL_STORE_SUBDIR` (`"virtual-store"`) over nub's profile-named leaf,
with **no conflict markers** — it would have shipped silently. `branded_env_alias_enabled`
(`aube-util/src/env.rs`) is the single switch gating every `AUBE_*` alias in `settings.toml`, so each
bump's new branded settings inherit the boundary from it alone.
- **Linker** — GVS, collective hidden tree as the sole phantom mechanism, per-package
force-materialization (`diskMaterializePackages`), workspace-spanning hoisted planning, memoized
clonedir probes, whole-dir `clonefile` on macOS, direct-exec of native bins.
Expand Down
82 changes: 58 additions & 24 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 11 additions & 3 deletions crates/nub-cli/src/pm_engine/vite_compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,17 @@ pub(crate) fn vite_lt_8_1(version: &str) -> bool {
/// embedder-namespaced to `~/.cache/nub/pm`). This is the realpath prefix of
/// every store-resident served module, so it is the value Vite must allow. The
/// leaf name comes from the active embedder (`store` under nub), matching what
/// `aube_store::Store::virtual_store_dir` writes, so the two never drift. The
/// embedder profile is registered by the time install runs, so
/// `aube_store::dirs::cache_dir()` resolves the nub namespace.
/// `aube_store::Store::virtual_store_dir` writes. The embedder profile is
/// registered by the time install runs, so `aube_store::dirs::cache_dir()`
/// resolves the nub namespace.
///
/// Only the DEFAULT location is reproduced here. aube v1.35.0 added the
/// `globalVirtualStoreDir` / `cacheDir` settings, which relocate the real store
/// at runtime; the resolver for those (`commands::settings_context::
/// global_virtual_store_dir`) is `pub(crate)` to the aube crate, so nub cannot
/// consult it without widening that surface. A project that sets either setting
/// therefore gets a `.modules.yaml` naming the default path rather than the
/// relocated one, and Vite would not be told to allow the real store.
Comment on lines +241 to +247

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.

⚠️ The gap is real but the framing understates it, and the pub(crate) visibility is not the blocker. aube v1.35.0 already writes .modules.yaml itself with the settings-resolved store (install/gvs.rs::write_modules_metadata, called from install/finalize.rs:235 whenever !virtual_store_only), and when the file is absent it writes a single-key pretty-printed JSON object — which is_nub_modules_yaml accepts as nub's own stub. Since vite_compat::apply runs after the engine returns, nub does not merely fail to consult the resolver: it overwrites a correct value with the default one.

Technical details
# nub's `.modules.yaml` writer clobbers the engine's settings-resolved value

## Affected sites
- `crates/nub-cli/src/pm_engine/vite_compat.rs:248-250``global_virtual_store_dir()` reproduces only `cache_dir().join(embedder().virtual_store_subdir)`.
- `crates/nub-cli/src/pm_engine/vite_compat.rs:264-280``write_modules_yaml`; the `is_nub_modules_yaml` guard is what lets the clobber through.
- `crates/nub-cli/src/pm_engine/vite_compat.rs:286-294``is_nub_modules_yaml` returns `true` for any single-key JSON object with `virtualStoreDir`, which is exactly the shape `write_modules_metadata` emits via `serde_json::to_vec_pretty` on the absent-file path.
- `crates/nub-cli/src/pm_engine/install_family.rs:892``vite_compat::apply` runs post-engine, so nub always writes last.
- `vendor/aube/crates/aube/src/commands/install/finalize.rs:229-237` — engine-side write, using `store.virtual_store_dir()` under GVS+`Isolated` and `aube_dir` otherwise.
- `vendor/aube/crates/aube/src/commands/settings_context.rs:544` — the settings-aware resolver, which honors `globalVirtualStoreDir` then falls back to `resolved_cache_dir(cwd).join(embedder().virtual_store_subdir)`.

When the two values diverge:

| Situation | engine writes | nub overwrites with | effect |
| --- | --- | --- | --- |
| defaults | default global store | same | none |
| `cacheDir` or `globalVirtualStoreDir` set | the relocated store | the default store | Vite is told to allow a path it never serves from, and the real store stays disallowed → `403 … outside of Vite serving allow list` |
| GVS off (`next`, `react-native`, `hoisted`) | project-local `node_modules/.store` | the global store | benign; the project-local path is inside the workspace root and allowed anyway |

Also note the engine writes one file per physical importer while nub writes only the
workspace root's, so in a monorepo the root file and the member files disagree after
nub's pass.

## Required outcome
- A project that relocates its store via `cacheDir` or `globalVirtualStoreDir` ends up with a `.modules.yaml` naming the real store.
- nub never replaces a `virtualStoreDir` written by the engine with a less-informed value.

## Suggested approach
The cheapest correct change needs no visibility widening: treat an existing
`virtualStoreDir` as authoritative and leave the file alone, since the engine has
already written the resolved path by the time `apply` runs. If nub's Unit A is retired
entirely in favour of upstream's writer (see the review body), this resolves itself.

## Open questions for the human
- Is nub's Unit A still needed at all now that the engine writes the same file for every importer with the resolved path?

fn global_virtual_store_dir() -> Option<PathBuf> {
aube_store::dirs::cache_dir().map(|c| c.join(aube_util::embedder().virtual_store_subdir))
}
Expand Down
6 changes: 6 additions & 0 deletions vendor/aube/.github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
"matchManagers": ["cargo"],
"matchPackageNames": ["/^sigstore-/"],
"groupName": "sigstore crates"
},
{
"description": "decmpfs 0.1.2 fails to compile for musl targets (FICLONE ioctl request typed c_ulong, which is c_int on musl). Hold at 0.1.0 until upstream fixes it.",
"matchManagers": ["cargo"],
"matchPackageNames": ["decmpfs"],
"allowedVersions": "<=0.1.0"
}
]
}
2 changes: 1 addition & 1 deletion vendor/aube/.github/workflows/auto-merge-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
permissions:
contents: read
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
fetch-tags: true
Expand Down
Loading
Loading