@gajae-code/utils 0.14.0 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,5 +17,16 @@ export declare function parseShellEnvFile(filePath: string): Record<string, stri
17
17
  * Ignores lines that are empty or start with '#'. Trims whitespace.
18
18
  * Allows values to be quoted with single or double quotes.
19
19
  * Returns an object of key-value pairs.
20
+ *
21
+ * The trust guards (`trustedAgentDirOverrideFor`, `trustedConfigDirName`,
22
+ * `filterCredentialInheritedEnv`) decide provenance by comparing
23
+ * `process.env` against this parse, so the accepted syntax must be a superset
24
+ * of what Bun's own dotenv loader honors in `cwd/.env`: `export KEY=value`,
25
+ * whitespace around `=`, and `#` comments after unquoted values (quotes keep
26
+ * their `#`). Values that Bun would expand (`$VAR`, `${VAR}`, backticks,
27
+ * command substitution) are kept as their literal text: the trust rule only
28
+ * needs the parser to see the key at all, and an operator environment value
29
+ * cannot equal attacker-written expansion text, so a literal parse stays
30
+ * conservative.
20
31
  */
21
32
  export declare function parseEnvFile(filePath: string): Record<string, string>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/utils",
4
- "version": "0.14.0",
4
+ "version": "0.14.1",
5
5
  "description": "Shared utilities for pi packages",
6
6
  "homepage": "https://gajae-code.com",
7
7
  "author": "Yeachan-Heo",
@@ -31,7 +31,7 @@
31
31
  "fmt": "biome format --write ."
32
32
  },
33
33
  "dependencies": {
34
- "@gajae-code/natives": "0.14.0",
34
+ "@gajae-code/natives": "0.14.1",
35
35
  "beautiful-mermaid": "^1.1.3",
36
36
  "handlebars": "^4.7.9",
37
37
  "winston": "^3.19.0",
package/src/env-file.ts CHANGED
@@ -38,6 +38,30 @@ function stripInlineShellComment(value: string): string {
38
38
  return value.trimEnd();
39
39
  }
40
40
 
41
+ /**
42
+ * Strips an unquoted trailing `# comment` from a dotenv value the way Bun's
43
+ * dotenv loader does: an unescaped `#` starts a comment regardless of the
44
+ * preceding character (`a#b` loads as `a`), while `#` inside quotes or after a
45
+ * backslash escape survives. Used only by `parseEnvFile`; shell files use
46
+ * `stripInlineShellComment`, whose POSIX rule requires whitespace before `#`.
47
+ */
48
+ function stripInlineDotenvComment(value: string): string {
49
+ let quote: '"' | "'" | undefined;
50
+ for (let i = 0; i < value.length; i++) {
51
+ const char = value[i];
52
+ if (char === "\\") {
53
+ i++;
54
+ continue;
55
+ }
56
+ if ((char === '"' || char === "'") && (!quote || quote === char)) {
57
+ quote = quote ? undefined : char;
58
+ continue;
59
+ }
60
+ if (char === "#" && !quote) return value.slice(0, i).trimEnd();
61
+ }
62
+ return value.trimEnd();
63
+ }
64
+
41
65
  /**
42
66
  * Parses simple POSIX shell environment assignments from files such as
43
67
  * ~/.zshrc without executing user shell code. Supports `export KEY=value` and
@@ -81,6 +105,17 @@ export function parseShellEnvFile(filePath: string): Record<string, string> {
81
105
  * Ignores lines that are empty or start with '#'. Trims whitespace.
82
106
  * Allows values to be quoted with single or double quotes.
83
107
  * Returns an object of key-value pairs.
108
+ *
109
+ * The trust guards (`trustedAgentDirOverrideFor`, `trustedConfigDirName`,
110
+ * `filterCredentialInheritedEnv`) decide provenance by comparing
111
+ * `process.env` against this parse, so the accepted syntax must be a superset
112
+ * of what Bun's own dotenv loader honors in `cwd/.env`: `export KEY=value`,
113
+ * whitespace around `=`, and `#` comments after unquoted values (quotes keep
114
+ * their `#`). Values that Bun would expand (`$VAR`, `${VAR}`, backticks,
115
+ * command substitution) are kept as their literal text: the trust rule only
116
+ * needs the parser to see the key at all, and an operator environment value
117
+ * cannot equal attacker-written expansion text, so a literal parse stays
118
+ * conservative.
84
119
  */
85
120
  export function parseEnvFile(filePath: string): Record<string, string> {
86
121
  const result: Record<string, string> = {};
@@ -91,13 +126,15 @@ export function parseEnvFile(filePath: string): Record<string, string> {
91
126
  // Skip comments and blank lines
92
127
  if (!trimmed || trimmed.startsWith("#")) continue;
93
128
 
94
- const eqIndex = trimmed.indexOf("=");
95
- if (eqIndex === -1) continue;
129
+ const match = /^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/.exec(trimmed);
130
+ if (!match) continue;
96
131
 
97
- const key = trimmed.slice(0, eqIndex).trim();
132
+ const key = match[1];
98
133
  if (!isValidEnvName(key)) continue;
99
134
 
100
- let value = trimmed.slice(eqIndex + 1).trim();
135
+ // Strip an unquoted trailing `# comment` the way Bun's dotenv loader
136
+ // does (`KEY=v#note` loads as `v`); quoted `#` survives.
137
+ let value = stripInlineDotenvComment(match[2] ?? "").trim();
101
138
 
102
139
  // Remove surrounding quotes (" or ')
103
140
  if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {