@melihmucuk/leash 1.0.6 → 1.0.7

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.
@@ -143,6 +143,27 @@ var CommandAnalyzer = class {
143
143
  const expanded = this.pathValidator.expand(path);
144
144
  return resolveBase ? resolve2(resolveBase, expanded) : expanded;
145
145
  }
146
+ /**
147
+ * Strip heredoc content from command before analyzing redirects.
148
+ * Handles: <<EOF, <<'EOF', <<"EOF", <<-EOF
149
+ */
150
+ stripHeredocs(command) {
151
+ const heredocStart = /<<-?\s*(['"]?)(\w+)\1/g;
152
+ let result = command;
153
+ let match;
154
+ while ((match = heredocStart.exec(command)) !== null) {
155
+ const delimiter = match[2];
156
+ const endPattern = new RegExp(`\\n\\t*${delimiter}\\s*(?:\\n|$)`);
157
+ const startIndex = match.index;
158
+ const contentAfterStart = command.slice(match.index + match[0].length);
159
+ const endMatch = endPattern.exec(contentAfterStart);
160
+ if (endMatch) {
161
+ const endIndex = match.index + match[0].length + endMatch.index + endMatch[0].length;
162
+ result = result.slice(0, startIndex) + result.slice(endIndex);
163
+ }
164
+ }
165
+ return result;
166
+ }
146
167
  isPathAllowed(path, allowDevicePaths, resolveBase) {
147
168
  const resolved = this.resolvePath(path, resolveBase);
148
169
  if (this.pathValidator.isWithinWorkingDir(resolved)) return true;
@@ -269,7 +290,8 @@ var CommandAnalyzer = class {
269
290
  return commands;
270
291
  }
271
292
  checkRedirects(command) {
272
- const matches = command.matchAll(REDIRECT_PATTERN);
293
+ const strippedCommand = this.stripHeredocs(command);
294
+ const matches = strippedCommand.matchAll(REDIRECT_PATTERN);
273
295
  for (const match of matches) {
274
296
  const path = match[1] || match[2] || match[3];
275
297
  if (!path || path.startsWith("&")) {
@@ -143,6 +143,27 @@ var CommandAnalyzer = class {
143
143
  const expanded = this.pathValidator.expand(path);
144
144
  return resolveBase ? resolve2(resolveBase, expanded) : expanded;
145
145
  }
146
+ /**
147
+ * Strip heredoc content from command before analyzing redirects.
148
+ * Handles: <<EOF, <<'EOF', <<"EOF", <<-EOF
149
+ */
150
+ stripHeredocs(command) {
151
+ const heredocStart = /<<-?\s*(['"]?)(\w+)\1/g;
152
+ let result = command;
153
+ let match;
154
+ while ((match = heredocStart.exec(command)) !== null) {
155
+ const delimiter = match[2];
156
+ const endPattern = new RegExp(`\\n\\t*${delimiter}\\s*(?:\\n|$)`);
157
+ const startIndex = match.index;
158
+ const contentAfterStart = command.slice(match.index + match[0].length);
159
+ const endMatch = endPattern.exec(contentAfterStart);
160
+ if (endMatch) {
161
+ const endIndex = match.index + match[0].length + endMatch.index + endMatch[0].length;
162
+ result = result.slice(0, startIndex) + result.slice(endIndex);
163
+ }
164
+ }
165
+ return result;
166
+ }
146
167
  isPathAllowed(path, allowDevicePaths, resolveBase) {
147
168
  const resolved = this.resolvePath(path, resolveBase);
148
169
  if (this.pathValidator.isWithinWorkingDir(resolved)) return true;
@@ -269,7 +290,8 @@ var CommandAnalyzer = class {
269
290
  return commands;
270
291
  }
271
292
  checkRedirects(command) {
272
- const matches = command.matchAll(REDIRECT_PATTERN);
293
+ const strippedCommand = this.stripHeredocs(command);
294
+ const matches = strippedCommand.matchAll(REDIRECT_PATTERN);
273
295
  for (const match of matches) {
274
296
  const path = match[1] || match[2] || match[3];
275
297
  if (!path || path.startsWith("&")) {
@@ -141,6 +141,27 @@ var CommandAnalyzer = class {
141
141
  const expanded = this.pathValidator.expand(path);
142
142
  return resolveBase ? resolve2(resolveBase, expanded) : expanded;
143
143
  }
144
+ /**
145
+ * Strip heredoc content from command before analyzing redirects.
146
+ * Handles: <<EOF, <<'EOF', <<"EOF", <<-EOF
147
+ */
148
+ stripHeredocs(command) {
149
+ const heredocStart = /<<-?\s*(['"]?)(\w+)\1/g;
150
+ let result = command;
151
+ let match;
152
+ while ((match = heredocStart.exec(command)) !== null) {
153
+ const delimiter = match[2];
154
+ const endPattern = new RegExp(`\\n\\t*${delimiter}\\s*(?:\\n|$)`);
155
+ const startIndex = match.index;
156
+ const contentAfterStart = command.slice(match.index + match[0].length);
157
+ const endMatch = endPattern.exec(contentAfterStart);
158
+ if (endMatch) {
159
+ const endIndex = match.index + match[0].length + endMatch.index + endMatch[0].length;
160
+ result = result.slice(0, startIndex) + result.slice(endIndex);
161
+ }
162
+ }
163
+ return result;
164
+ }
144
165
  isPathAllowed(path, allowDevicePaths, resolveBase) {
145
166
  const resolved = this.resolvePath(path, resolveBase);
146
167
  if (this.pathValidator.isWithinWorkingDir(resolved)) return true;
@@ -267,7 +288,8 @@ var CommandAnalyzer = class {
267
288
  return commands;
268
289
  }
269
290
  checkRedirects(command) {
270
- const matches = command.matchAll(REDIRECT_PATTERN);
291
+ const strippedCommand = this.stripHeredocs(command);
292
+ const matches = strippedCommand.matchAll(REDIRECT_PATTERN);
271
293
  for (const match of matches) {
272
294
  const path = match[1] || match[2] || match[3];
273
295
  if (!path || path.startsWith("&")) {
package/dist/pi/leash.js CHANGED
@@ -141,6 +141,27 @@ var CommandAnalyzer = class {
141
141
  const expanded = this.pathValidator.expand(path);
142
142
  return resolveBase ? resolve2(resolveBase, expanded) : expanded;
143
143
  }
144
+ /**
145
+ * Strip heredoc content from command before analyzing redirects.
146
+ * Handles: <<EOF, <<'EOF', <<"EOF", <<-EOF
147
+ */
148
+ stripHeredocs(command) {
149
+ const heredocStart = /<<-?\s*(['"]?)(\w+)\1/g;
150
+ let result = command;
151
+ let match;
152
+ while ((match = heredocStart.exec(command)) !== null) {
153
+ const delimiter = match[2];
154
+ const endPattern = new RegExp(`\\n\\t*${delimiter}\\s*(?:\\n|$)`);
155
+ const startIndex = match.index;
156
+ const contentAfterStart = command.slice(match.index + match[0].length);
157
+ const endMatch = endPattern.exec(contentAfterStart);
158
+ if (endMatch) {
159
+ const endIndex = match.index + match[0].length + endMatch.index + endMatch[0].length;
160
+ result = result.slice(0, startIndex) + result.slice(endIndex);
161
+ }
162
+ }
163
+ return result;
164
+ }
144
165
  isPathAllowed(path, allowDevicePaths, resolveBase) {
145
166
  const resolved = this.resolvePath(path, resolveBase);
146
167
  if (this.pathValidator.isWithinWorkingDir(resolved)) return true;
@@ -267,7 +288,8 @@ var CommandAnalyzer = class {
267
288
  return commands;
268
289
  }
269
290
  checkRedirects(command) {
270
- const matches = command.matchAll(REDIRECT_PATTERN);
291
+ const strippedCommand = this.stripHeredocs(command);
292
+ const matches = strippedCommand.matchAll(REDIRECT_PATTERN);
271
293
  for (const match of matches) {
272
294
  const path = match[1] || match[2] || match[3];
273
295
  if (!path || path.startsWith("&")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@melihmucuk/leash",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "type": "module",
5
5
  "description": "Security guardrails for AI coding agents",
6
6
  "bin": {