Skip to content

feat(varlock): add code env scanner and audit command#569

Open
danish-fareed wants to merge 4 commits intodmno-dev:mainfrom
danish-fareed:feat/audit-and-code-env-scanner
Open

feat(varlock): add code env scanner and audit command#569
danish-fareed wants to merge 4 commits intodmno-dev:mainfrom
danish-fareed:feat/audit-and-code-env-scanner

Conversation

@danish-fareed
Copy link
Copy Markdown

@danish-fareed danish-fareed commented Apr 8, 2026

Summary

  • Added a zero-dependency, multi-language env-var scanner used by varlock audit, with bounded concurrency and comment/string masking to reduce false positives while preserving line/column references.
  • Added varlock audit schema/code drift detection with CI-friendly exit codes and correct --path scan-root behavior for file and directory inputs.
  • Aligned audit decorators to Varlock semantics:
    • Root function decorator # @auditIgnorePaths(...) is collected via getRootDecFns, merged across calls/imports, flattened from positional arr args, normalized, and passed as additive scanner excludes.
    • Item decorator # @auditIgnore suppresses only unused-in-schema reporting when strictly true; # @auditIgnore=false does not suppress.
  • Kept missing-in-schema reporting unchanged and added the new hint text for external-tool-only schema items.
  • Added coverage for decorator behavior and scanner additive excludes (defaults preserved + custom excludes appended).

Validation

  • bun run --filter varlock typecheck
  • bun run --filter varlock test src/cli/commands/test/audit.command.test.ts
  • bun run --filter varlock test src/cli/helpers/test/env-var-scanner.test.ts
  • bun run --filter varlock test:ci

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 8, 2026

⚠️ No Changeset found

Latest commit: 63a9967

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@philmillman
Copy link
Copy Markdown
Member

thanks @danish-fareed, we'll have a look soon!

@philmillman philmillman requested a review from Copilot April 8, 2026 20:05
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 8, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@varlock/ci-env-info@569

commit: 38b8375

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new codebase env-var scanner and an audit CLI command to compare env var usage in source code against keys declared in .env.schema, plus wiring the scanner into varlock init as a fallback schema scaffold source.

Changes:

  • Introduces a multi-language env var reference scanner with ignored-directory support, masking, and bounded concurrency.
  • Adds varlock audit command + helper diffing logic, with tests and CLI wiring.
  • Updates varlock init to optionally scaffold schema items from scanned code references when no example/sample env file is present.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/varlock/src/env-graph/test/resolvers.test.ts Normalizes CRLF-sensitive string assertions in resolver tests.
packages/varlock/src/cli/helpers/test/env-var-scanner.test.ts Adds focused tests for scanner detection + masking + ignored dirs behavior.
packages/varlock/src/cli/helpers/infer-schema.ts Exports inferItemDecorators and makes valueStr optional for reuse in init scaffolding.
packages/varlock/src/cli/helpers/env-var-scanner.ts New scanner implementation (multi-language regexes, masking, glob discovery, concurrency).
packages/varlock/src/cli/helpers/audit-diff.ts Adds schema/code key diff helper used by audit command and tests.
packages/varlock/src/cli/commands/test/audit.command.test.ts Adds tests for audit behavior and scan-root path handling.
packages/varlock/src/cli/commands/init.command.ts Falls back to scanning code to inject new schema keys when no example env file exists.
packages/varlock/src/cli/commands/audit.command.ts New varlock audit command implementation and output/exit-code behavior.
packages/varlock/src/cli/cli-executable.ts Registers audit subcommand for the CLI executable.
packages/varlock-website/src/content/docs/reference/cli-commands.mdx Documents the new varlock audit command and exit codes.

@theoephraim
Copy link
Copy Markdown
Member

A quick first pass and this is looking really good! Thanks so much for the contribution.

Couple small things come to mind in terms of audit behaviour.

If the user end up building auditing into their workflows, we may want a way for the user to mark certain vars as being acknowledged as not being detected. For example you may have some vars that ambiently affect other tools without necessarily appearing in code. Similarly we may want the user to be able to record paths/globs to ignore during an audit somehow within their schema (or some other config location) without having to pass them into the the audit command every time.

@danish-fareed
Copy link
Copy Markdown
Author

A quick first pass and this is looking really good! Thanks so much for the contribution.

Couple small things come to mind in terms of audit behaviour.

If the user end up building auditing into their workflows, we may want a way for the user to mark certain vars as being acknowledged as not being detected. For example you may have some vars that ambiently affect other tools without necessarily appearing in code. Similarly we may want the user to be able to record paths/globs to ignore during an audit somehow within their schema (or some other config location) without having to pass them into the the audit command every time.

Both of those are great points. Here's what I'm planning to implement using the existing decorator syntax:

A new item-level # @ignoreUnused=true decorator (open to # @ambient=true if you prefer the naming). The audit command will suppress "unused" warnings for any vars tagged with it, so things like Prisma or AWS CLI vars don't create noise.

New top-level # @ignorePaths=path1,path2 decorator on the schema file itself. The audit command will pick these up automatically and merge them with the default ignore list (.git, node_modules, etc.), so users don't have to keep passing --ignore-paths on every run.

Let me know if you'd prefer different naming or want the ignore paths to live somewhere other than the schema

@theoephraim
Copy link
Copy Markdown
Member

Probably keeping audit in the decorator names will help clarify things.

Maybe something like@auditIgnore for specific items (the =true is implied when a bare decorator is used). Not sure if you need "unused"? unless audit is checking multiple aspects, in which case @auditIgnore=unused could make sense? Another thing we've been noodling on is a more generic tagging system so @tag(audit-ignore) and then a root decorator could say @auditIgnore(tags=audit-ignore). A bit more verbose but you could imagine having a prisma tag, and then telling it to ignore all prisma vars, etc...

Then for the root ignore decorator, I would make it a function. Again include "audit" maybe @auditIgnorePaths(glob1, glob2). Functions are semantically intended to be called more than once and can merge values together - you could have several files that are imported and it should combine the lists all together - versus a @dec=val means that only a single value with most precedence wins.

Any other ideas come to mind?

@danish-fareed
Copy link
Copy Markdown
Author

That makes perfect sense! Using a function for @auditIgnorePaths(glob1, glob2) is a great call so they merge correctly across imported files. And @auditIgnore is the perfect lightweight solution for specific items.
The generic tagging system idea sounds awesome for the future

Update audit to support root-level @auditIgnorePaths() merging and item-level @auditIgnore suppression with strict true checks. This keeps missing-in-schema reporting unchanged while preserving default scanner ignores and adding additive exclude coverage.
Switch masking to code-unit iteration to preserve index stability with astral characters and mask Go raw-string literals to avoid false positives in audit scans.
@danish-fareed
Copy link
Copy Markdown
Author

implemented your audit decorator suggestions and pushed updates. @auditIgnorePaths(...) now merges across files, @auditIgnore suppresses only unused warnings (strict true), missing-key behavior is unchanged, and all local checks are passing. Review thoroughly when you get time.

@theoephraim
Copy link
Copy Markdown
Member

Thanks for all this - will try to get it out sometime next week!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants