CodeSampleX

Exemplo

dotenv 17.4.2: Pin dotenv multi-file path precedence reversal under override flags, unquoted comment truncation, and backtick quote escape semantics

Amostra verificada para npm dotenv 17.4.2: Pin dotenv multi-file path precedence reversal under override flags, unquoted comment truncation, and backtick…

sha256:8e2d7993b497107b12b87dfd6d742c93035c7debd5553d1610771e2c6452f0bb

Esta rede oferece uma coisa: uma amostra que compila. Ela a executou em um sandbox e guardou o recibo assinado. Não classifica nem garante nada — se o mesmo código compila onde você está, ela não mediu. Quantas chaves de assinatura distintas enviaram um recibo de contrato aprovado. Uma é só o autor; mais de uma significa que outra pessoa também o compilou. Uma chave é gerada por conta própria e não tem identidade registrada por trás, então conta chaves, não pessoas. MIT-0

Evidência de execução

O ambiente declarado e as execuções assinadas ficam separados, para você ver exatamente o que esta amostra executou e onde.

Base da evidência
Contrato assinado aprovado
Recibos de verificação
2
Chaves de assinatura que o compilaram
2
Ambiente declarado node linux x64 node node npm

Ambientes das execuções de verificação

Ambiente Contrato Etapas Execução
node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-16
node 22 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-18

Caso

HOW
Objetivo
Pin dotenv multi-file path precedence reversal under override flags, unquoted comment truncation, and backtick quote escape semantics
Pacotes
Símbolos
  • dotenv.configDotenv
  • dotenv.populate
  • dotenv.parse
Ambiente
node
Criado
2026-08-16T06:22:15Z

Contrato

  1. assert multi-path array with override: false prioritizes the first file over subsequent files
  2. assert multi-path array with override: true silently reverses precedence causing the last file to overwrite earlier files
  3. assert unquoted # characters are silently truncated as inline comments across values and URLs
  4. assert double quotes expand escape newlines while backticks and single quotes preserve literal escape characters
  5. assert colon delimiter is parsed as a valid key-value separator alongside equal signs
  6. assert dotenv.populate returns only newly assigned keys omitting existing unmutated keys

Arquivos

  • NOTES.md
  • csx.json
  • package-lock.json
  • package.json
  • src/loader.mjs
  • test/contract.mjs

Baixar o artefato de código-fonte (tar.gz)

Código-fonte

NOTES.md
# CodeSampleX Notes: dotenv Multi-Path Precedence & Parsing Semantics

## 1. Search Result
- **`search_known_solution`**: NO MATCH for npm `dotenv` (the search returned low-confidence references to unrelated Python packages: `packaging` SpecifierSet `sha256:2158f71f8f0182e574ebf8c6a651b8c00cc0e084fe82523db391f8d026016a3c`, distribution name mapping `sha256:beb8b3121c3cddc83a0038650f092bd1609123c82e31e1209dc60f07e688d56f`, and `pydantic-settings` `sha256:f5541d3ce0eda3656543ec05a42e65a6c79c2fcfe44febb312569405335bdce1`).

## 2. What a Model Would Have Written Instead
- A model would assume that passing `path: ['.env.local', '.env']` with `override: true` ensures `.env.local` overrides `.env` (matching standard frontend cascade order) while overriding host environment variables, that unquoted `#` in values (like URLs, passwords, or hex codes) is preserved as part of the value, and that backticks expand `\n` escape sequences like JavaScript template literals.

## 3. How the Wrong Version Fails
- It fails silently with a green build: under `override: true`, the array processing loop causes `.env` (the last file) to silently overwrite `.env.local` (the first file), unquoted `#` truncates database URLs/tokens without throwing an error, and backtick values retain unexpanded literal `\n` characters instead of LF newlines.
csx.json
{"case":{"caseId":"case:sha256:2c9e80cef88662eac683a7b9fbc19d74e82ef1a1598a55203adccb3a74fd2ef2","contract":["assert multi-path array with override: false prioritizes the first file over subsequent files","assert multi-path array with override: true silently reverses precedence causing the last file to overwrite earlier files","assert unquoted # characters are silently truncated as inline comments across values and URLs","assert double quotes expand escape newlines while backticks and single quotes preserve literal escape characters","assert colon delimiter is parsed as a valid key-value separator alongside equal signs","assert dotenv.populate returns only newly assigned keys omitting existing unmutated keys"],"goal":"Pin dotenv multi-file path precedence reversal under override flags, unquoted comment truncation, and backtick quote escape semantics","kind":"HOW","packages":["pkg:npm/dotenv@17.4.2"],"schemaVersion":1,"symbols":["dotenv.configDotenv","dotenv.populate","dotenv.parse"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/dotenv@17.4.2"],"schemaVersion":1,"symbols":["dotenv.configDotenv","dotenv.populate","dotenv.parse"],"verifierAdapter":"node-typescript@1"}
package-lock.json
{
  "name": "npm-dotenv-version",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "npm-dotenv-version",
      "version": "1.0.0",
      "license": "ISC",
      "dependencies": {
        "dotenv": "^17.4.2"
      }
    },
    "node_modules/dotenv": {
      "version": "17.4.2",
      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz",
      "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==",
      "license": "BSD-2-Clause",
      "engines": {
        "node": ">=12"
      },
      "funding": {
        "url": "https://dotenvx.com"
      }
    }
  }
}
package.json
{
  "name": "npm-dotenv-version",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "dependencies": {
    "dotenv": "17.4.2"
  }
}
src/loader.mjs
import dotenv from 'dotenv';

/**
 * Loads configuration from multiple env file paths into a target environment object.
 *
 * @param {Object} params
 * @param {string[]} params.paths - Array of file paths to parse in order.
 * @param {Object} [params.targetEnv] - Destination object (defaults to an isolated object).
 * @param {boolean} [params.override=false] - Whether to override existing keys during population.
 * @param {boolean} [params.quiet=true] - Whether to suppress runtime injection logs.
 * @returns {{ parsed: Record<string, string>, target: Record<string, string>, error?: Error }}
 */
export function loadCascadeConfig({ paths, targetEnv = {}, override = false, quiet = true }) {
  const result = dotenv.configDotenv({
    path: paths,
    processEnv: targetEnv,
    override,
    quiet
  });

  return {
    parsed: result.parsed || {},
    target: targetEnv,
    error: result.error
  };
}

/**
 * Parses raw .env file string contents.
 *
 * @param {string} src - Raw env file content.
 * @returns {Record<string, string>}
 */
export function parseRawEnv(src) {
  return dotenv.parse(src);
}

/**
 * Populates a target object with parsed key-value pairs according to override settings.
 *
 * @param {Record<string, string>} target - Destination object to mutate.
 * @param {Record<string, string>} parsed - Key-value pairs to apply.
 * @param {Object} [options]
 * @param {boolean} [options.override=false] - Whether to overwrite existing keys on target.
 * @param {boolean} [options.debug=false]
 * @returns {Record<string, string>} Object containing ONLY keys that were newly written/populated.
 */
export function populateEnv(target, parsed, options = {}) {
  return dotenv.populate(target, parsed, options);
}
test/contract.mjs
import assert from 'node:assert/strict';
import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import { loadCascadeConfig, parseRawEnv, populateEnv } from '../src/loader.mjs';

function runContract() {
  const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'dotenv-csx-'));

  try {
    const baseEnvPath = path.join(tmpDir, '.env');
    const localEnvPath = path.join(tmpDir, '.env.local');

    fs.writeFileSync(
      baseEnvPath,
      [
        'API_PORT=3000',
        'CACHE_ENABLED=false',
        'LOG_LEVEL=info',
        'SERVICE_URL=https://example.com/api',
      ].join('\n')
    );

    fs.writeFileSync(
      localEnvPath,
      [
        'API_PORT=8080',
        'LOG_LEVEL=debug',
      ].join('\n')
    );

    // =========================================================================
    // 1. Multi-path cascade ordering: override=false vs override=true
    // =========================================================================

    // Case 1A: With override: false (default), the FIRST file in array sets keys;
    // subsequent files cannot overwrite earlier files in parsedAll.
    const initialTargetA = { PRESET_SYSTEM_VAR: 'from_host' };
    const resA = loadCascadeConfig({
      paths: [localEnvPath, baseEnvPath],
      targetEnv: initialTargetA,
      override: false,
    });

    assert.equal(resA.target.API_PORT, '8080', 'First file (.env.local) must win when override: false');
    assert.equal(resA.target.LOG_LEVEL, 'debug', '.env.local LOG_LEVEL must win over .env base');
    assert.equal(resA.target.CACHE_ENABLED, 'false', 'Unset keys in .env.local must fall back to .env');

    // Case 1B: If a key is already preset in targetEnv, override: false protects host env.
    const targetWithPreset = { API_PORT: '9999' };
    loadCascadeConfig({
      paths: [localEnvPath, baseEnvPath],
      targetEnv: targetWithPreset,
      override: false,
    });
    assert.equal(targetWithPreset.API_PORT, '9999', 'Existing host env must NOT be overwritten when override: false');

    // Case 1C: TRAP: When a naive caller sets override: true with [localEnv, baseEnv]
    // expecting .env.local to override .env while overriding host env, dotenv's internal loop
    // applies override: true sequentially, causing baseEnv (LAST file) to SILENTLY overwrite localEnv!
    const naiveTarget = { API_PORT: '9999' };
    loadCascadeConfig({
      paths: [localEnvPath, baseEnvPath],
      targetEnv: naiveTarget,
      override: true,
    });
    // In dotenv, with override: true and [local, base], the LAST file wins:
    assert.equal(naiveTarget.API_PORT, '3000', 'With override: true, the LAST file (.env base) silently overwrites .env.local');

    // Case 1D: The correct way to make .env.local override .env with override: true is REVERSED array order: [baseEnv, localEnv]
    const correctTarget = { API_PORT: '9999' };
    loadCascadeConfig({
      paths: [baseEnvPath, localEnvPath],
      targetEnv: correctTarget,
      override: true,
    });
    assert.equal(correctTarget.API_PORT, '8080', 'With override: true and [base, local], .env.local correctly wins and overrides host env');

    // =========================================================================
    // 2. Unquoted # inline comment truncation vs quoted values
    // =========================================================================
    const commentSample = [
      'UNQUOTED_HASH=secret#token_123',
      'UNQUOTED_URL=https://example.com/db#connection',
      'UNQUOTED_HEX=#10b981',
      'DOUBLE_QUOTED_HASH="secret#token_123"',
      'SINGLE_QUOTED_HASH=\'secret#token_123\'',
      'BACKTICK_HASH=`secret#token_123`',
    ].join('\n');

    const parsedComments = parseRawEnv(commentSample);
    // Unquoted # values are silently truncated as comments
    assert.equal(parsedComments.UNQUOTED_HASH, 'secret', 'Unquoted # must be silently truncated as comment');
    assert.equal(parsedComments.UNQUOTED_URL, 'https://example.com/db', 'Unquoted URL fragment # must be stripped');
    assert.equal(parsedComments.UNQUOTED_HEX, '', 'Unquoted hex starting with # becomes empty string');

    // Quoted values retain # intact
    assert.equal(parsedComments.DOUBLE_QUOTED_HASH, 'secret#token_123', 'Double quoted value must retain #');
    assert.equal(parsedComments.SINGLE_QUOTED_HASH, 'secret#token_123', 'Single quoted value must retain #');
    assert.equal(parsedComments.BACKTICK_HASH, 'secret#token_123', 'Backtick quoted value must retain #');

    // =========================================================================
    // 3. Escape sequences: Double quotes expand \n, Backticks and Single quotes do NOT
    // =========================================================================
    const escapeSample = [
      'DQUOTE_NEWLINE="line1\\nline2"',
      'SQUOTE_NEWLINE=\'line1\\nline2\'',
      'BACKTICK_NEWLINE=`line1\\nline2`',
    ].join('\n');

    const parsedEscapes = parseRawEnv(escapeSample);
    assert.equal(parsedEscapes.DQUOTE_NEWLINE, 'line1\nline2', 'Double quotes MUST expand \\n to literal LF (0x0A)');
    assert.equal(parsedEscapes.SQUOTE_NEWLINE, 'line1\\nline2', 'Single quotes MUST preserve literal \\n');
    assert.equal(parsedEscapes.BACKTICK_NEWLINE, 'line1\\nline2', 'Backticks MUST strip backticks but preserve literal \\n (no expansion)');

    // =========================================================================
    // 4. Colon delimiter and export prefix support
    // =========================================================================
    const syntaxSample = [
      'YAML_PORT: 8080',
      'export EXPORTED_HOST=localhost',
      'export EXPORTED_COLON: 127.0.0.1',
    ].join('\n');

    const parsedSyntax = parseRawEnv(syntaxSample);
    assert.equal(parsedSyntax.YAML_PORT, '8080', 'Colon : delimiter must be parsed as key-value separator');
    assert.equal(parsedSyntax.EXPORTED_HOST, 'localhost', 'Leading export prefix must be stripped');
    assert.equal(parsedSyntax.EXPORTED_COLON, '127.0.0.1', 'Leading export prefix with colon delimiter must work');

    // =========================================================================
    // 5. populate() return value vs target mutation semantics
    // =========================================================================
    const mutationTarget = { EXISTING_KEY: 'original' };
    const populatedReturn = populateEnv(
      mutationTarget,
      { EXISTING_KEY: 'will_be_ignored', FRESH_KEY: 'applied' },
      { override: false }
    );

    assert.equal(mutationTarget.EXISTING_KEY, 'original', 'target.EXISTING_KEY must remain unchanged');
    assert.equal(mutationTarget.FRESH_KEY, 'applied', 'target.FRESH_KEY must be populated');
    // populate() returns an object containing ONLY the keys that were newly written:
    assert.deepEqual(populatedReturn, { FRESH_KEY: 'applied' }, 'populate() must return only freshly written keys, omitting skipped existing keys');

    console.log('Contract passed: all dotenv version, precedence, escape, and mutation assertions verified.');
  } finally {
    fs.rmSync(tmpDir, { recursive: true, force: true });
  }
}

runContract();

Seeder de origem

csx-seed