## Summary
- Fix use-after-free bug when parsing `ca` option from `.npmrc`
- The `ca` string was being stored directly from the parser's arena
without duplication
- Since the parser arena is freed at the end of `loadNpmrc`, this
created a dangling pointer
## The Bug
In `src/ini.zig`, the `ca` string wasn't being duplicated like all other
string properties:
```zig
// Lines 983-986 explicitly warn about this:
// Need to be very, very careful here with strings.
// They are allocated in the Parser's arena, which of course gets
// deinitialized at the end of the scope.
// We need to dupe all strings
// Line 981: Parser arena is freed here
defer parser.deinit();
// Line 1016-1020: THE BUG - string not duped!
if (out.asProperty("ca")) |query| {
if (query.expr.asUtf8StringLiteral()) |str| {
install.ca = .{
.str = str, // ← Dangling pointer after parser.deinit()!
};
```
All other string properties in the same function correctly duplicate:
- `registry` (line 996): `try allocator.dupe(u8, str)`
- `cache` (line 1002): `try allocator.dupe(u8, str)`
- `cafile` (line 1037): `asStringCloned(allocator)`
- `ca` array items (line 1026): `asStringCloned(allocator)`
## User Impact
When a user has `ca=<certificate>` in their `.npmrc` file:
1. The certificate string is parsed and stored
2. The parser arena is freed
3. `install.ca.str` becomes a dangling pointer
4. Later TLS/SSL operations access freed memory
5. Could cause crashes, undefined behavior, or security issues
## Test plan
- Code inspection confirms this matches the pattern used for all other
string properties
- The fix adds `try allocator.dupe(u8, str)` to match `cache`,
`registry`, etc.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
Fixes environment variable expansion in quoted `.npmrc` values and adds
support for the `?` optional modifier.
### Changes
**Simplified quoted value handling:**
- Removed unnecessary `isProperlyQuoted` check that added complexity
without benefit
- When JSON.parse succeeds for quoted strings, expand env vars in the
result
- When JSON.parse fails for single-quoted strings like `'${VAR}'`, still
expand env vars
**Added `?` modifier support (matching npm behavior):**
- `${VAR}` - if VAR is undefined, leaves as `${VAR}` (no expansion)
- `${VAR?}` - if VAR is undefined, expands to empty string
This applies consistently to both quoted and unquoted values.
### Examples
```ini
# Env var found - all expand to the value
token = ${NPM_TOKEN}
token = "${NPM_TOKEN}"
token = '${NPM_TOKEN}'
# Env var NOT found - left as-is
token = ${NPM_TOKEN} # → ${NPM_TOKEN}
token = "${NPM_TOKEN}" # → ${NPM_TOKEN}
token = '${NPM_TOKEN}' # → ${NPM_TOKEN}
# Optional modifier (?) - expands to empty if not found
token = ${NPM_TOKEN?} # → (empty)
token = "${NPM_TOKEN?}" # → (empty)
auth = "Bearer ${TOKEN?}" # → Bearer
```
### Test Plan
- Added 8 new tests for the `?` modifier covering quoted and unquoted
values
- Verified all expected values match `npm config get` behavior
- All 30 ini tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
### What does this PR do?
Adds support for `publicHoistPattern` in `bunfig.toml` and
`public-hoist-pattern` from `.npmrc`. This setting allows you to select
transitive packages to hoist to the root node_modules making them
available for all workspace packages.
```toml
[install]
# can be a string
publicHoistPattern = "@types*"
# or an array
publicHoistPattern = [ "@types*", "*eslint*" ]
```
`publicHoistPattern` only affects the isolated linker.
---
Adds `hoistPattern`. `hoistPattern` is the same as `publicHoistPattern`,
but applies to the `node_modules/.bun/node_modules` directory instead of
the root node_modules. Also the default value of `hoistPattern` is `*`
(everything is hoisted to `node_modules/.bun/node_modules` by default).
---
Fixes a determinism issue constructing the
`node_modules/.bun/node_modules` directory.
---
closes#23481closes#6160closes#23548
### How did you verify your code works?
Added tests for
- [x] only include patterns
- [x] only exclude patterns
- [x] mix of include and exclude
- [x] errors for unexpected expression types
- [x] excluding direct dependency (should still include)
- [x] match all with `*`
- [x] string and array expression types
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
### What does this PR do?
This PR implements support for the `email` field in `.npmrc` files for
registry scope authentication. Some private registries (particularly
Nexus) require the email field to be specified in the registry
configuration alongside username/password or token authentication.
The email field can now be specified in `.npmrc` files like:
```ini
//registry.example.com/:email=user@example.com
//registry.example.com/:username=myuser
//registry.example.com/:_password=base64encodedpassword
```
### How did you verify your code works?
1. **Built Bun successfully** - Confirmed the code compiles without
errors using `bun bd --debug`
2. **Wrote comprehensive unit tests** - Added two test cases to
`test/cli/install/npmrc.test.ts`:
- Test for standalone email field parsing
- Test for email combined with username/password authentication
3. **Verified tests pass** - Ran `bun bd test
test/cli/install/npmrc.test.ts -t "email"` and confirmed both tests
pass:
```
✓ 2 pass
✓ 0 fail
✓ 6 expect() calls
```
4. **Code changes include**:
- Added `email` field to `NpmRegistry` struct in `src/api/schema.zig`
- Updated `encode()` and `decode()` methods to handle the email field
- Modified `ini.zig` to parse and store the email field from `.npmrc`
- Removed email from the unsupported options warning (certfile and
keyfile remain unsupported)
- Updated all `NpmRegistry` struct initializations to include the email
field
- Updated `loadNpmrcFromJS` test API to return the email field
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>