Repository navigation
v0.10.8
evnx v0.10.8
The patch for evnx validate (package R-validate): counts that count what they
say, one finding per problem, a --fix that tells a repair from a placeholder,
and the checks the review asked for — environment names, Docker files beside
the env file, and .gitignore.
- In a git repository, an env file already tracked by git is an error
(exit 1); one that.gitignoredoes not cover is a warning (exit 0). Outside
a repository nothing changes (D-27, DEC-VA1). - An unknown issue type in
--ignoreor[validate] ignoreis exit 2, listing
the valid types (I-038). It was accepted and ignored nothing. - JSON:
fixedandsummary.fixed_counthold only completed repairs; the
variables--fixcould only add with a placeholder are in the new
needs_inputarray andsummary.needs_input, and keep their
placeholder_valuefinding inissues(I-037).dry_runis new.
required_presentcounts the declared variables that are present (I-034). SECRET_KEY=changemeis one finding (the placeholder), not also
weak_secret, so error counts can drop (I-035).--fixno longer generates a value for a key a provider issues
(STRIPE_KEY,AWS_SECRET_ACCESS_KEY,VERCEL_TOKEN, …), even with
--rotate-weak-secrets; those findings areauto_fixable: false(I-260).
validate
required_presentcounts declared variables that are there (I-034). It
wasmin(variables in .env, variables in .env.example): two of eight missing
plus one extra read 7 of 8, and a file of extras alone read as complete.- One problem, one finding (I-035). A placeholder in a secret-shaped name
is reported as a placeholder only; "too weak or predictable" is for a real
value.--ignore placeholder_valuestill leaves the weak-secret finding. --fixseparates "Fixed" from "Needs your input" (I-037). A variable it
could only add with a placeholder is listed once, under "Needs your input",
not counted as fixed and not repeated as a fresh error; the run exits 1 until
it is filled in. A missing variable gets the template's value (8080,
localhost, or empty forOPTIONAL_X=), and the generic placeholder only
when its name looks like a secret (D-25). It wasyour_value_herefor every
name.--fix --dry-runshows what--fixwould change and writes nothing — no
.envchange, no backup. The report and exit code are the file's as it
stands; a secret it would generate is not shown (S1).--fail-on warning|error, and[validate] fail_onin.evnx.toml:
warningmakes warnings exit 1. The flag wins;--exit-zerostill wins over
both (S2).- An unknown
--ignoretype is an error (I-038), and--formattakes any
case, asscananddoctoralready did (--format JSON). - With a contract,
--strictmeasures against[vars](I-039), as its help
always said: the message names[vars]and suggests declaring the name, not
adding it to.env.example. A variable whoseenvironmentsexclude this
file is reported too — "declared for production only, but set in
.env.staging" (I-043). environmentsnames are checked (I-042): a name that matches no
.env.<name>file and no common name warns, with the one it was probably
meant to be (prodution→production), and so does a file named close to a
listed one (.env.prodagainst"production"). Exit code unchanged.- Docker files are looked for beside the env file, then in each folder up to
the repository root, then the current directory (I-046), and
compose.yaml/compose.ymlcount (I-257). It looked only in the current
directory, and only fordocker-compose.*,DockerfileandContainerfile. .gitignore(D-27, DEC-VA1): new findingsenv_not_ignored(warning)
andenv_tracked(error), from the same git checkdoctoruses.- An empty template value that is missing from
.envsays how to make it
optional:evnx spec init, thenrequired = false(I-036, D-29). --fixwrites.envatomically through the shared writer: the file keeps its
mode, a symlinked.envis written through, and a file others can read gets
the samechmodwarning every other command gives. The backup is written at
the original's mode from the start.DEBUG=True's advice says "Use true or 1"; it said "true or 0" (I-261).--fixinvents only what nothing else holds (I-260, DEC-VA4..VA6). It
generated 64 random hex characters for every secret-shaped name holding a
placeholder, soSTRIPE_KEY=changemebecame a fake Stripe key that then
passed validate. It now generates only for the app's own secrets — an exact
list:SECRET_KEY,DJANGO_SECRET_KEY,FLASK_SECRET_KEY,
SECRET_KEY_BASE,JWT_SECRET,NEXTAUTH_SECRET,AUTH_SECRET,
BETTER_AUTH_SECRET,SESSION_SECRET,COOKIE_SECRET,APP_SECRET— and
for passwords (*_PASSWORD,*_PASSWD,*_PWD). Any other key keeps its
placeholder and is reported, with "get it from where it is issued";
--rotate-weak-secretsfollows the same rule. A missing secret of that kind
is generated in one run instead of a placeholder and a second--fix.
add
evnx add custom NAME --optional(I-036, DEC-VA2). With a[vars]
contract it writesrequired = false— whatadd customdeclares by
default; the flag says so — and an(optional)comment in.env.example.
Without a contract the variable is still added, and the run says how to make
it optional. It conflicts with--required.
doctor
docker_configrecognisescompose.yamlandcompose.yml(I-257,
DEC-VA3).
Docs
- README and GETTING_STARTED:
--strictdoes not make warnings exit 1 —
both said it did;--fail-on warningdoes. The GETTING_STARTED sample output
is real output; the one it replaced was a format evnx never printed. Both
list--fix --dry-runand[validate] fail_on.
Shared code
One definition each, where commands had their own:
core::args::one_of: a value from a fixed list, any case, or an error listing
them — validate's--format,--ignoreand--fail-on, scan's--format
and--severity, doctor's--format. scan's and doctor's messages are
unchanged.core::project: the Docker file list and the upward walk to the repository
root, for validate and doctor (DEC-VA3).core::safe_write::backup: the numbered.bakthat never overwrites an
earlier one, at the original's mode.utils::fs::backup_file(never called;
it wrote.backup) is removed.core::classify::may_generateandAPP_SECRETS: which secrets evnx may
generate (I-260), beside the name and placeholder rules it already holds.core::env_name::abbreviation_ofandmeant, and
core::spec::environment_problems, for the environment-name check; the
--env-nameerror's "did you mean" uses the same abbreviation rule as
before.
Library
commands::validate::runtakesvalidate::Options.IssueTypegains
UnknownEnvironment,EnvNotIgnored,EnvTrackedandIssueType::ALL;
ValidationResultgainsdry_runandneeds_input,Summarygains
needs_input,core::config::ValidatePolicygainsfail_on.
validate::fixer::write_fixed_filereturns the backup path and the
safe_write::Written;fixer::fill_for_missingandFixAction::AddSecret
are new.
Installation
Linux / macOS (shell script)
curl -sSL https://raw.githubusercontent.com/urwithajit9/evnx/main/scripts/install.sh | bashHomebrew (macOS and Linux)
brew install urwithajit9/evnx/evnxScoop (Windows, user-local)
scoop bucket add evnx https://github.com/urwithajit9/scoop-evnx
scoop install evnxWinget (Windows, system-wide)
winget install urwithajit9.evnxnpm / Node.js
npm install -g @evnx/cliPython (pipx)
pipx install evnxCargo
cargo install evnx --all-features
cargo installcompiles from source withdefault = [], so plain
cargo install evnxgives you a binary without theauth,
vaultandcloudcommands. Every other channel above ships them
already — the binaries are built with--all-features.
Checksums
SHA256 checksums are provided for each binary. Verify after download:
sha256sum -c evnx-*.tar.gz.sha256What's Changed
- validate 0.10.8 (R-validate): fixed vs needs your input, --dry-run, --fail-on, environments, Docker files and .gitignore; one value-list check by @urwithajit9 in #197
- chore(release): 0.10.8 by @urwithajit9 in #198
Full Changelog: v0.10.7...v0.10.8
npm / Node.js
npm install -g @evnx/cli # global install
npx @evnx/cli --version # zero-install usage
npm install --save-dev @evnx/cli # project dev dependency