Skip to content

Reject sensitive values redaction cannot protect - #1057

Draft
theoephraim wants to merge 6 commits into
mainfrom
strict-sensitive-value-rules
Draft

Reject sensitive values redaction cannot protect#1057
theoephraim wants to merge 6 commits into
mainfrom
strict-sensitive-value-rules

Conversation

@theoephraim

@theoephraim theoephraim commented Sep 1, 2026

Copy link
Copy Markdown
Member

DO NOT MERGE YET - this adds breaking changes that converst some protections we implemented as warnings into errors. We will wait for the next major version since this could be breaking for some folks.


Follow-up to #1054. That PR introduced the rules but kept every one that @defaultSensitive could trip as a warning, so nothing inherited from the default could fail a load in a minor release. This is the breaking release those escalations were deferred to.

What changes

The value #1054 now
number or boolean error if explicit, warning if inherited error
composite with non-string elements error if explicit, warning if inherited error
under 3 characters error if explicit, warning if inherited error
under 12 characters warning warning (unchanged)
@currentEnv item error if explicit, warning if inherited error
non-sensitive value containing a sensitive one warning error

Why error rather than demote

#1054 said the boolean demotion "belongs in a breaking release," and this branch tried it (ca6b84f8, reverted in a20280c4). It was the wrong call, for two reasons.

The schema stops saying what it means. @defaultSensitive=true claims everything is sensitive; with demotion, PORT=3000 quietly isn't. You could no longer read .env.schema and know what is public without knowing varlock's rules. Erroring forces every non-secret number and boolean to carry an explicit @sensitive=false, which is the state the file should be in. This matters more as agents make most edits: an error with a one-line fix is the best interface an agent can be given, and a silent demotion is the worst. This is now written down as a design principle in AGENTS.md.

Demotion needed a lot of subtle machinery to be safe. The effective dataType infers from whichever source wins, .env.local included, so demoting on it would have flipped an untyped API_KEY= public (and @static, and inlinable) in exactly one environment when a local placeholder was 12345. Making it safe meant a schema-level type getter, a typegen mirror, a new sensitivity source, and a test for the trap - and the first version of the getter was wrong anyway (a default parameter kicked in on an explicit undefined). Erroring handles that trap correctly for free: an inherited-sensitive number is rejected wherever it shows up.

The inherited-case error tip points at @defaultSensitive=false at the top of the file, since that is the real fix when a hand-written schema has many of these at once.

Arrays and objects

A sensitive composite must be made of strings. That's the only rule consistent with how runtime redaction works: it registers each element individually, and only string ones, so a @type=array(number) has nothing in the map and its elements print in cleartext. The joined form is registered, but that only protects the value printed whole, not any element on its own. So a composite of numbers or booleans is treated exactly like a bare number: demoted when inherited, an error when explicit. A free-form object or untyped record can't be judged at the type level and falls through to the value-time check.

Cleanup

With the explicit/inherited split gone, the schema-time type checks and the value-time leaf check were two mechanisms answering one question. They're now one method, checkValueIsRedactable, run after coercion on the value that would actually be registered:

  • checkSensitiveIsPlausible, the _sensitiveIsImplausible flag, and the flag(explicit, implicit) helper are gone
  • the containment check's length-based tip branch is gone; both sides use one stringForms() helper that mirrors resetRedactionMap exactly
  • SHORT_SENSITIVE_VALUE_LENGTH is no longer imported by env-graph.ts
  • the env-flag rule moved into the same method as the type and length rules, so there is now exactly one place that answers "can this sensitive item actually be protected?"
  • ConfigItem.addValidationError() owns the "safe to re-run" dedupe that the containment check used to do by hand, and both call sites use it

Not done here, worth its own PR: getTypeGenInfo() carries a ~45-line reimplementation of resolveSensitiveSource (with three deliberate differences: schema-only defs, skipping dynamic decorators, swallowing errors). Extracting a shared pure computeSensitivity(defs, opts) would remove the duplication, but it is pre-existing behavior with its own subtleties and does not belong in a rules-change PR.

One consequence of moving the type checks to value time: an explicitly sensitive @type=number with no value yet doesn't error until a value exists. That's correct (an empty item isn't leaking anything) and the message is the same once one does.

Migration

@defaultSensitive=true is the default, so a hand-written schema with no @defaultSensitive line now fails on its ports and feature flags. The fix is @defaultSensitive=false at the top of the file with an explicit @sensitive on each real secret, which is what varlock init generates. Schemas from init are unaffected.

Zero fixture changes were needed outside the sensitivity test file itself: #1054 already gave incidental fixtures @defaultSensitive=false.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

bumpy-frog

The changes in this PR will be included in the next version bump.

major Major releases

  • @varlock/1password-plugin 2.0.4 → 3.0.0 (dep)
  • @varlock/akeyless-plugin 2.0.1 → 3.0.0 (dep)
  • @varlock/astro-integration 1.4.1 → 2.0.0 (dep)
  • @varlock/aws-secrets-plugin 1.2.3 → 2.0.0 (dep)
  • @varlock/aws-sigv4-plugin 0.0.0 → 1.0.0 (dep)
  • @varlock/azure-key-vault-plugin 1.2.3 → 2.0.0 (dep)
  • @varlock/bitwarden-plugin 2.0.1 → 3.0.0 (dep)
  • @varlock/cloudflare-integration 1.5.1 → 2.0.0 (dep)
  • @varlock/dashlane-plugin 2.1.1 → 3.0.0 (dep)
  • @varlock/doppler-plugin 2.0.1 → 3.0.0 (dep)
  • @varlock/expo-integration 1.2.1 → 2.0.0 (dep)
  • @varlock/google-secret-manager-plugin 1.2.2 → 2.0.0 (dep)
  • @varlock/hashicorp-vault-plugin 2.1.1 → 3.0.0 (dep)
  • @varlock/infisical-plugin 2.1.1 → 3.0.0 (dep)
  • @varlock/keepass-plugin 2.0.2 → 3.0.0 (dep)
  • @varlock/keeper-plugin 2.0.1 → 3.0.0 (dep)
  • @varlock/kubernetes-plugin 1.0.1 → 2.0.0 (dep)
  • @varlock/native-helper-darwin 1.18.0 → 2.0.0
  • @varlock/native-helper-linux-arm64 1.18.0 → 2.0.0
  • @varlock/native-helper-linux-x64 1.18.0 → 2.0.0
  • @varlock/native-helper-win32-x64 1.18.0 → 2.0.0
  • @varlock/nextjs-integration 1.2.2 → 2.0.0 (dep)
  • @varlock/nuxt-integration 0.1.1 → 1.0.0 (dep)
  • @varlock/pass-plugin 1.0.2 → 2.0.0 (dep)
  • @varlock/passbolt-plugin 2.0.1 → 3.0.0 (dep)
  • @varlock/proton-pass-plugin 2.0.1 → 3.0.0 (dep)
  • @varlock/vite-integration 1.5.1 → 2.0.0 (dep)
  • varlock 1.18.0 → 2.0.0

Bump files in this PR

Click here if you want to add another bump file to this PR


This comment is maintained by bumpy.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

📦 Bundle size

✅ shrinks the bundle by 10.6 KB (−0.2%)

Metric main This PR Δ
Total dist 4438.8 KB 4428.2 KB −10.6 KB (−0.2%)
JS 1687.9 KB 1684.5 KB −3.4 KB (−0.2%)
Sourcemaps 2642.7 KB 2636.3 KB −6.4 KB (−0.2%)
Type defs 108.2 KB 107.4 KB −0.8 KB (−0.8%)
Other 0.0 KB 0.0 KB

dist/ only; native binaries are versioned separately and not counted here.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Important

The replacement value-time validation drops the documented builtin exemption, causing user-declared VARLOCK_IS_CI values to fail validation.

Reviewed changes in 79984534, including the stricter sensitive-value validation, containment checks, test updates, migration guidance, and release note.

  • Redactability validation: Consolidates scalar, composite, and short-value checks after coercion and promotes inherited violations to errors.
  • Sensitive containment: Promotes sensitive strings embedded in public values from warnings to errors and shares string-form collection across both sides.
  • Current environment: Rejects sensitive @currentEnv items regardless of how sensitivity was assigned.
  • Documentation and tests: Documents the breaking migration and updates sensitivity coverage for explicit and inherited values.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using azure/gpt-5.6-sol𝕏

},
));
}
if (this.isSensitive) this.checkValueIsRedactable();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This now validates builtins even though the previous checkSensitiveIsPlausible() guard and the updated docs exempt them. A schema declaration such as VARLOCK_IS_CI=false inherits sensitivity, reaches this call, and now ends in error with a boolean cannot be sensitive; please preserve the builtin exemption here and add a validation-state regression assertion.

@pkg-pr-new

pkg-pr-new Bot commented Sep 1, 2026

Copy link
Copy Markdown

Open in StackBlitz

varlock

npm i https://pkg.pr.new/dmno-dev/varlock@1057

@varlock/astro-integration

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/astro-integration@1057

@varlock/cloudflare-integration

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/cloudflare-integration@1057

@varlock/expo-integration

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/expo-integration@1057

@varlock/nextjs-integration

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/nextjs-integration@1057

@varlock/nuxt-integration

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/nuxt-integration@1057

@varlock/vite-integration

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/vite-integration@1057

@varlock/native-helper-darwin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/native-helper-darwin@1057

@varlock/native-helper-linux-arm64

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/native-helper-linux-arm64@1057

@varlock/native-helper-linux-x64

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/native-helper-linux-x64@1057

@varlock/native-helper-win32-x64

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/native-helper-win32-x64@1057

@varlock/1password-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/1password-plugin@1057

@varlock/akeyless-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/akeyless-plugin@1057

@varlock/aws-secrets-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/aws-secrets-plugin@1057

@varlock/aws-sigv4-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/aws-sigv4-plugin@1057

@varlock/azure-key-vault-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/azure-key-vault-plugin@1057

@varlock/bitwarden-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/bitwarden-plugin@1057

@varlock/dashlane-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/dashlane-plugin@1057

@varlock/doppler-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/doppler-plugin@1057

@varlock/google-secret-manager-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/google-secret-manager-plugin@1057

@varlock/hashicorp-vault-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/hashicorp-vault-plugin@1057

@varlock/infisical-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/infisical-plugin@1057

@varlock/keepass-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/keepass-plugin@1057

@varlock/keeper-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/keeper-plugin@1057

@varlock/kubernetes-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/kubernetes-plugin@1057

@varlock/pass-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/pass-plugin@1057

@varlock/passbolt-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/passbolt-plugin@1057

@varlock/proton-pass-plugin

npm i https://pkg.pr.new/dmno-dev/varlock/@varlock/proton-pass-plugin@1057

commit: 8d6044b

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 1, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
varlock-website bbfdf3c Commit Preview URL

Branch Preview URL
Sep 02 2026, 06:11 AM

@theoephraim theoephraim added the BREAKING This is a breaking change in varlock core - merge when doing a new major release label Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BREAKING This is a breaking change in varlock core - merge when doing a new major release core:varlock core:website maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant