We Are Forking dotenvy into dotenv-ng

We encountered a dotenvy bug where bcrypt fragments such as $2a$10$... were interpreted as variable substitutions, silently changing the value.

Since the required fix targets an unreleased API, we forked dotenvy 0.15.7 and released dotenv-ng 1.0.

It includes a rewritten parser, literal dollar signs by default, round-trip rendering, structured errors, and property tests.

Feedback on the API and dotenv compatibility is welcome.

Blog post: We Are Forking dotenvy into dotenv-ng | SecretSpec
Crate: crates.io: Rust Package Registry

I'm not sure I understand the "bug" that is the cause of your fork.

Here's a small copypaste from a shell:

% cat t
TEST="foo:$2a$10$TWoviNHS27HJMw1PKe4tBeIMlms6tWdYS9hKoHANKCQhluDlEt/gu"
%. ./t
% echo $TEST
foo:a/gu

So the correct value of that environment is actually foo:a/gu (unless some rahter obscurely named variables happens to be defined).

A .env file is not really supposed to be "automatically" written by a program, at least originally it was intendet to be sourced in the shell before running programs. There are shell extensions doing this automatically when cd-ing to a directory that contains a .env file.

If someone wants the actual variable to contain that string with the verbatim dollar signs, the .env file should use single quotes, not double.

Edit: This is actually mentioned in a reply to the 2024 "bug report". That reply was submitted the same day as the issue was submitted.

You’re right that dotenvy and a shell interpret double quotes as allowing substitution, and single quotes would preserve this particular value.

The problem was (for secretspec) that dotenvy made substitution mandatory. A secrets importer cannot safely assume every dollar-prefixed fragment is a reference, especially because there is no universal .env specification, and different loaders implement different semantics.

Dotenv-ng therefore makes substitution configurable: callers wanting interpolation can enable it via substitution(true), while it's safer not to do that by default.

Not sure I am completely understanding the situation here. Do I understand correctly that you are not the author of dotenvy, and that your need for a new feature was met with a fix that implied upgrading to a not-yet-released version with a different API? And thus you decided to fork it as a new crate to have this change ?

Note that OP is talking about dotenvy, not the dotenv library. dotenvy is a maintained fork of dotenv.