Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
9 changes: 9 additions & 0 deletions internal/devbox/devbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -629,10 +629,19 @@ func (d *Devbox) execPrintDevEnv(ctx context.Context, usePrintDevEnvCache bool)
spinny.Start()
}

// Allow unfree/insecure packages to evaluate when the user opts in via
// devbox.json's "env" (the process environment is handled separately
// inside PrintDevEnv). See https://github.com/jetify-com/devbox/issues/2196.
configEnv := d.cfg.Env()
allowUnfree, _ := strconv.ParseBool(configEnv["NIXPKGS_ALLOW_UNFREE"])
allowInsecure, _ := strconv.ParseBool(configEnv["NIXPKGS_ALLOW_INSECURE"])

vaf, err := d.nix.PrintDevEnv(ctx, &nix.PrintDevEnvArgs{
FlakeDir: d.flakeDir(),
PrintDevEnvCachePath: d.nixPrintDevEnvCachePath(),
UsePrintDevEnvCache: usePrintDevEnvCache,
AllowUnfree: allowUnfree,
AllowInsecure: allowInsecure,
})
if spinny != nil {
spinny.Stop()
Expand Down
7 changes: 7 additions & 0 deletions internal/nix/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,10 @@ func IsInsecureAllowed() bool {
allowed, _ := strconv.ParseBool(os.Getenv("NIXPKGS_ALLOW_INSECURE"))
return allowed
}

// IsUnfreeAllowed reports whether the user has opted into unfree packages by
// setting the NIXPKGS_ALLOW_UNFREE environment variable to a truthy value.
func IsUnfreeAllowed() bool {
allowed, _ := strconv.ParseBool(os.Getenv("NIXPKGS_ALLOW_UNFREE"))
return allowed
}
39 changes: 38 additions & 1 deletion internal/nix/nix.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ type PrintDevEnvArgs struct {
FlakeDir string
PrintDevEnvCachePath string
UsePrintDevEnvCache bool

// AllowUnfree and AllowInsecure report whether the user has opted into
// unfree or insecure packages through the resolved devbox config (for
// example via NIXPKGS_ALLOW_UNFREE in devbox.json's "env"). They are in
// addition to the same variables read from the process environment.
AllowUnfree bool
AllowInsecure bool
}

// PrintDevEnv calls `nix print-dev-env -f <path>` and returns its output. The output contains
Expand Down Expand Up @@ -75,9 +82,27 @@ func (*NixInstance) PrintDevEnv(ctx context.Context, args *PrintDevEnvArgs) (*Pr
ref := flake.Ref{Type: flake.TypePath, Path: flakeDirResolved}

if len(data) == 0 {
// Honor unfree/insecure opt-in from either the process environment
// or the resolved devbox config.
allowUnfree := args.AllowUnfree || IsUnfreeAllowed()
allowInsecure := args.AllowInsecure || IsInsecureAllowed()

cmd := Command("print-dev-env", "--json")
if featureflag.ImpurePrintDevEnv.Enabled() {
if usePrintDevEnvImpure(allowUnfree, allowInsecure) {
cmd.Args = append(cmd.Args, "--impure")
// Only inject the allow-* variables the user actually opted
// into. When impure mode is enabled solely via the feature
// flag, cmd.Env is left inheriting the parent environment.
if allowUnfree || allowInsecure {
env := os.Environ()
if allowUnfree {
env = allowUnfreeEnv(env)
}
if allowInsecure {
env = allowInsecureEnv(env)
}
cmd.Env = env
}
}
cmd.Args = append(cmd.Args, ref)
slog.Debug("running print-dev-env cmd", "cmd", cmd)
Expand All @@ -100,6 +125,18 @@ func (*NixInstance) PrintDevEnv(ctx context.Context, args *PrintDevEnvArgs) (*Pr
return &out, nil
}

// usePrintDevEnvImpure reports whether `nix print-dev-env` should be run with
// the --impure flag. By default print-dev-env runs in pure mode, which ignores
// the NIXPKGS_ALLOW_UNFREE and NIXPKGS_ALLOW_INSECURE environment variables.
// When the user has opted into unfree or insecure packages, we run with
// --impure so those variables take effect, matching what devbox already does
// when building and installing packages. Pure mode is kept otherwise because
// --impure disables Nix's evaluation caching, which makes the command slower.
// See https://github.com/jetify-com/devbox/issues/2196.
func usePrintDevEnvImpure(allowUnfree, allowInsecure bool) bool {
return featureflag.ImpurePrintDevEnv.Enabled() || allowUnfree || allowInsecure
}

func savePrintDevEnvCache(path string, out PrintDevEnvOut) error {
data, err := json.Marshal(out)
if err != nil {
Expand Down
56 changes: 56 additions & 0 deletions internal/nix/nix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,62 @@ import (
"testing"
)

func TestIsUnfreeAllowed(t *testing.T) {
cases := map[string]bool{
"": false,
"0": false,
"false": false,
"1": true,
"true": true,
}
for value, want := range cases {
t.Run(value, func(t *testing.T) {
t.Setenv("NIXPKGS_ALLOW_UNFREE", value)
if got := IsUnfreeAllowed(); got != want {
t.Errorf("IsUnfreeAllowed() with NIXPKGS_ALLOW_UNFREE=%q = %v, want %v", value, got, want)
}
})
}
}

// TestUsePrintDevEnvImpure verifies the fix for
// https://github.com/jetify-com/devbox/issues/2196: print-dev-env must run
// with --impure whenever the user opts into unfree or insecure packages so
// those environment variables are honored.
func TestUsePrintDevEnvImpure(t *testing.T) {
Comment thread
mikeland73 marked this conversation as resolved.
cases := []struct {
name string
allowUnfree bool
allowInsecure bool
want bool
}{
{name: "neither opted in", want: false},
{name: "unfree opted in", allowUnfree: true, want: true},
{name: "insecure opted in", allowInsecure: true, want: true},
{name: "both opted in", allowUnfree: true, allowInsecure: true, want: true},
}
for _, tt := range cases {
t.Run(tt.name, func(t *testing.T) {
// Keep the result independent of any ambient feature-flag env.
t.Setenv("DEVBOX_FEATURE_IMPURE_PRINT_DEV_ENV", "0")
if got := usePrintDevEnvImpure(tt.allowUnfree, tt.allowInsecure); got != tt.want {
t.Errorf("usePrintDevEnvImpure(%v, %v) = %v, want %v",
tt.allowUnfree, tt.allowInsecure, got, tt.want)
}
})
}
}

// TestUsePrintDevEnvImpureFeatureFlag verifies that the IMPURE_PRINT_DEV_ENV
// feature flag forces impure mode even when the user hasn't opted into unfree
// or insecure packages.
func TestUsePrintDevEnvImpureFeatureFlag(t *testing.T) {
t.Setenv("DEVBOX_FEATURE_IMPURE_PRINT_DEV_ENV", "1")
if !usePrintDevEnvImpure(false, false) {
t.Error("usePrintDevEnvImpure(false, false) = false with feature flag set, want true")
}
}

func TestParseInsecurePackagesFromExitError(t *testing.T) {
errorText := `
at /nix/store/xwl0am98klc8mz074jdyvpnyc6vwzlla-source/lib/customisation.nix:267:17:
Expand Down
Loading