mirror of
https://github.com/acaloiaro/ess
synced 2026-07-21 18:29:08 +00:00
feat: Add .envrc support
This commit is contained in:
parent
3497414a7c
commit
09381ed0fe
9 changed files with 331 additions and 51 deletions
13
.envrc
Normal file
13
.envrc
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then
|
||||
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs="
|
||||
fi
|
||||
|
||||
watch_file flake.nix
|
||||
watch_file flake.lock
|
||||
watch_file go.lock
|
||||
|
||||
if ! use flake . --impure
|
||||
then
|
||||
echo "devenv could not be built. The devenv environment was not loaded." >&2
|
||||
fi
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1 +1,4 @@
|
|||
/gomod2nix-template
|
||||
.direnv
|
||||
.devenv
|
||||
.pre-commit-config.yaml
|
||||
|
|
|
|||
45
README.md
45
README.md
|
|
@ -6,14 +6,45 @@ Automatically keep `.env` files in sync with `env.sample`
|
|||
|
||||
---
|
||||
|
||||
`ess` checks whether the local repository contains an `.env` file (configurable), scrubs it of secrets/
|
||||
values, and makes the scrubbed version available as `env.sample` (configurable).
|
||||
`ess` transforms environment files containing secrets (e.g. `.env`, `.envrc`) into sample environment files (e.g.
|
||||
`env.sample`) that may be safely checked into git.
|
||||
|
||||
This process can be run manually, or automatically as a git-hook, ensuring that all application environment variables
|
||||
are safely and automatically documented without leaking secrets.
|
||||
`ess` may be run manually by running the cli executable, or automatically by installing the pre-commit hook with `ess install`
|
||||
in any git repository. Installing `ess` as a git hook ensures that project environment files are automatically and safely
|
||||
revision controlled when they change.
|
||||
|
||||
Crucially, `ess` allows comments in `env` files, which are carried over to `env.sample`. This lets
|
||||
developers add thorough environment variable documentation to source control.
|
||||
Doing so allows environment configurations to be shared across teams without leaking secrets.
|
||||
|
||||
## How it works
|
||||
|
||||
By default, `ess` checks the local directory for environment files named `.env`. The env file name is controlled by
|
||||
the `--env-file` switch. Next, the environment file is parsed for environment variables. Environment variables
|
||||
may be of the following forms:
|
||||
|
||||
```
|
||||
# Standard environment variables
|
||||
FOO=bar baz
|
||||
FOO="bar baz"
|
||||
FOO='bar baz'
|
||||
|
||||
# Envrc environment variable
|
||||
export FOO=bar baz
|
||||
export FOO="bar baz"
|
||||
export FOO='bar baz'
|
||||
```
|
||||
|
||||
By default, variable values are replaced with innert values named after the variable, e.g. `FOO=bar` is replaced by `FOO=<FOO>`.
|
||||
|
||||
Example values may be provided with the `--example` switch, e.g. `--exmaple=FOO="enter your foo here"` will set `FOO`'s
|
||||
value as follows `FOO="enter your foo here"` in the sample file.
|
||||
|
||||
Finally, when all variables are replaced, the sample file is written with the sanitized variable values, along with all
|
||||
non-variable strings from the file. By default the sample file is named `env.sample`, which is controlled by the `--env-sample`
|
||||
switch.
|
||||
|
||||
Because `ess` permits non-variable strings in environment files, it means that both comments and script code (in the case
|
||||
of `.envrc` files) is included in environment sample files. This allows environment files to not only be checked into git, but
|
||||
documented with comments.
|
||||
|
||||
# Installation & Usage
|
||||
|
||||
|
|
@ -212,7 +243,7 @@ repos:
|
|||
args: [--example=FOO="Provide your foo here", --example=BAR="You can fetch bars from https://example.com/bars"]
|
||||
```
|
||||
|
||||
Example env file
|
||||
Example environment file
|
||||
`.env`
|
||||
```
|
||||
FOO=the_value_of_my_secret_foo
|
||||
|
|
|
|||
233
flake.lock
233
flake.lock
|
|
@ -1,15 +1,50 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"devenv": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
"flake-compat": "flake-compat",
|
||||
"nix": "nix",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"pre-commit-hooks": "pre-commit-hooks"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1705309234,
|
||||
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
|
||||
"lastModified": 1688058187,
|
||||
"narHash": "sha256-ipDcc7qrucpJ0+0eYNlwnE+ISTcq4m03qW+CWUshRXI=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "c8778e3dc30eb9043e218aaa3861d42d4992de77",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "v0.6.3",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1673956053,
|
||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1667395993,
|
||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
|
||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -18,11 +53,49 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1660459072,
|
||||
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gomod2nix": {
|
||||
"inputs": {
|
||||
"flake-utils": [
|
||||
"flake-utils"
|
||||
],
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
|
|
@ -41,27 +114,144 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"lowdown-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1633514407,
|
||||
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
|
||||
"owner": "kristapsdz",
|
||||
"repo": "lowdown",
|
||||
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "kristapsdz",
|
||||
"repo": "lowdown",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix": {
|
||||
"inputs": {
|
||||
"lowdown-src": "lowdown-src",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-regression": "nixpkgs-regression"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1676545802,
|
||||
"narHash": "sha256-EK4rZ+Hd5hsvXnzSzk2ikhStJnD63odF7SzsQ8CuSPU=",
|
||||
"owner": "domenkozar",
|
||||
"repo": "nix",
|
||||
"rev": "7c91803598ffbcfe4a55c44ac6d49b2cf07a527f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "domenkozar",
|
||||
"ref": "relaxed-flakes",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1705133751,
|
||||
"narHash": "sha256-rCIsyE80jgiOU78gCWN3A0wE0tR2GI5nH6MlS+HaaSQ=",
|
||||
"lastModified": 1706487304,
|
||||
"narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9b19f5e77dd906cb52dade0b7bd280339d2a1f3d",
|
||||
"rev": "90f456026d284c22b3e3497be980b2e47d0b28ac",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-regression": {
|
||||
"locked": {
|
||||
"lastModified": 1643052045,
|
||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1678872516,
|
||||
"narHash": "sha256-/E1YwtMtFAu2KUQKV/1+KFuReYPANM2Rzehk84VxVoc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9b8e5abb18324c7fe9f07cb100c3cd4a29cda8b8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-22.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1706487304,
|
||||
"narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "90f456026d284c22b3e3497be980b2e47d0b28ac",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"flake-utils": "flake-utils",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1686050334,
|
||||
"narHash": "sha256-R0mczWjDzBpIvM3XXhO908X5e2CQqjyh/gFbwZk/7/Q=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "6881eb2ae5d8a3516e34714e7a90d9d95914c4dc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"devenv": "devenv",
|
||||
"gomod2nix": "gomod2nix",
|
||||
"nixpkgs": "nixpkgs"
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"systems": "systems_2"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
|
|
@ -78,6 +268,21 @@
|
|||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
|
|
|||
73
flake.nix
73
flake.nix
|
|
@ -1,29 +1,54 @@
|
|||
{
|
||||
description = "Automatically keep .env files in sync with env.sample";
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||
systems.url = "github:nix-systems/default";
|
||||
devenv.url = "github:cachix/devenv/v0.6.3";
|
||||
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||
inputs.gomod2nix.url = "github:nix-community/gomod2nix";
|
||||
inputs.gomod2nix.inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.gomod2nix.inputs.flake-utils.follows = "flake-utils";
|
||||
gomod2nix = {
|
||||
url = "github:nix-community/gomod2nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, gomod2nix }:
|
||||
(flake-utils.lib.eachDefaultSystem
|
||||
(system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
devenv,
|
||||
systems,
|
||||
gomod2nix,
|
||||
...
|
||||
} @ inputs: let
|
||||
forEachSystem = nixpkgs.lib.genAttrs (import systems);
|
||||
in {
|
||||
devShells = forEachSystem (system: let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in {
|
||||
default = devenv.lib.mkShell {
|
||||
inherit inputs pkgs;
|
||||
modules = [
|
||||
{
|
||||
packages = with pkgs; [
|
||||
automake
|
||||
go_1_21
|
||||
gomod2nix.legacyPackages.${system}.gomod2nix
|
||||
gotools
|
||||
golangci-lint
|
||||
go-tools
|
||||
gopls
|
||||
pre-commit
|
||||
flyctl
|
||||
];
|
||||
|
||||
# The current default sdk for macOS fails to compile go projects, so we use a newer one for now.
|
||||
# This has no effect on other platforms.
|
||||
callPackage = pkgs.darwin.apple_sdk_11_0.callPackage or pkgs.callPackage;
|
||||
in
|
||||
{
|
||||
packages.default = callPackage ./. {
|
||||
inherit (gomod2nix.legacyPackages.${system}) buildGoApplication;
|
||||
};
|
||||
devShells.default = callPackage ./shell.nix {
|
||||
inherit (gomod2nix.legacyPackages.${system}) mkGoEnv gomod2nix;
|
||||
};
|
||||
})
|
||||
);
|
||||
pre-commit.hooks.gomod2nix = {
|
||||
enable = true;
|
||||
pass_filenames = false;
|
||||
name = "gomod2nix";
|
||||
description = "Run gomod2nix before commit";
|
||||
entry = "${gomod2nix.legacyPackages.${system}.gomod2nix}/bin/gomod2nix";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -2,4 +2,6 @@ module github.com/acaloiaro/ess
|
|||
|
||||
go 1.21
|
||||
|
||||
replace github.com/hashicorp/go-envparse v0.1.0 => github.com/acaloiaro/go-envparse v0.3.0
|
||||
|
||||
require github.com/hashicorp/go-envparse v0.1.0
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -1,2 +1,2 @@
|
|||
github.com/hashicorp/go-envparse v0.1.0 h1:bE++6bhIsNCPLvgDZkYqo3nA+/PFI51pkrHdmPSDFPY=
|
||||
github.com/hashicorp/go-envparse v0.1.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc=
|
||||
github.com/acaloiaro/go-envparse v0.3.0 h1:TGHMQ6VK8ABhqalxaRTU2gj75dCDorQq6YTxGVI5X+4=
|
||||
github.com/acaloiaro/go-envparse v0.3.0/go.mod h1:OHheN1GoygLlAkTlXLXvAdnXdZxy8JUweQ1rAXx1xnc=
|
||||
|
|
|
|||
|
|
@ -2,5 +2,6 @@ schema = 3
|
|||
|
||||
[mod]
|
||||
[mod."github.com/hashicorp/go-envparse"]
|
||||
version = "v0.1.0"
|
||||
hash = "sha256-MkHaxEZDHVz84IImaC8+s4lAgNLhsaAMSkVmt55JC3M="
|
||||
version = "v0.3.0"
|
||||
hash = "sha256-pbffSgC8BDtvkQAyI6ILkrMleI8m2JtedV0PL64Ok3I="
|
||||
replaced = "github.com/acaloiaro/go-envparse"
|
||||
|
|
|
|||
4
main.go
4
main.go
|
|
@ -125,9 +125,9 @@ func sync(dir string) {
|
|||
os.Exit(0)
|
||||
}
|
||||
|
||||
envFile, err := envparse.Parse(envFileReader)
|
||||
envFile, err := envparse.ParsePermissive(envFileReader)
|
||||
if err != nil {
|
||||
fmt.Println("unable to parse env file:", err)
|
||||
fmt.Fprintf(os.Stderr, "unable to parse env file (%s): %v", envFilePath, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue