file-entry-cache
Advanced tools
+1
-1
@@ -1,1 +0,1 @@ | ||
| "use strict";var k=Object.create;var g=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var v=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var z=(o,e)=>{for(var s in e)g(o,s,{get:e[s],enumerable:!0})},y=(o,e,s,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of w(e))!A.call(o,t)&&t!==s&&g(o,t,{get:()=>e[t],enumerable:!(i=C(e,t))||i.enumerable});return o};var p=(o,e,s)=>(s=o!=null?k(v(o)):{},y(e||!o||!o.__esModule?g(s,"default",{value:o,enumerable:!0}):s,o)),D=o=>y(g({},"__esModule",{value:!0}),o);var K={};z(K,{FileEntryCache:()=>m,create:()=>f,createFromFile:()=>_,default:()=>d});module.exports=D(K);var F=p(require("crypto"),1),u=p(require("fs"),1),c=p(require("path"),1),l=require("flat-cache");function _(o,e){let s=c.default.basename(o),i=c.default.dirname(o);return f(s,i,e)}function f(o,e,s){let i={...s,cache:{cacheId:o,cacheDir:e}},t=new m(i);if(e){let r=`${e}/${o}`;u.default.existsSync(r)&&(t.cache=(0,l.createFromFile)(r,i.cache))}return t}var d=class{static create=f;static createFromFile=_},m=class{_cache=new l.FlatCache({useClone:!1});_useCheckSum=!1;_hashAlgorithm="md5";_cwd=process.cwd();_strictPaths=!1;_logger;_useAbsolutePathAsKey=!1;constructor(e){e?.cache&&(this._cache=new l.FlatCache(e.cache)),e?.useCheckSum&&(this._useCheckSum=e.useCheckSum),e?.hashAlgorithm&&(this._hashAlgorithm=e.hashAlgorithm),e?.cwd&&(this._cwd=e.cwd),e?.strictPaths!==void 0&&(this._strictPaths=e.strictPaths),e?.useAbsolutePathAsKey!==void 0&&(this._useAbsolutePathAsKey=e.useAbsolutePathAsKey),e?.logger&&(this._logger=e.logger)}get cache(){return this._cache}set cache(e){this._cache=e}get logger(){return this._logger}set logger(e){this._logger=e}get useCheckSum(){return this._useCheckSum}set useCheckSum(e){this._useCheckSum=e}get hashAlgorithm(){return this._hashAlgorithm}set hashAlgorithm(e){this._hashAlgorithm=e}get cwd(){return this._cwd}set cwd(e){this._cwd=e}get strictPaths(){return this._strictPaths}set strictPaths(e){this._strictPaths=e}get useAbsolutePathAsKey(){return this._useAbsolutePathAsKey}set useAbsolutePathAsKey(e){this._useAbsolutePathAsKey=e}getHash(e){return F.default.createHash(this._hashAlgorithm).update(e).digest("hex")}createFileKey(e){let s=e;return this._useAbsolutePathAsKey&&this.isRelativePath(e)&&(s=this.getAbsolutePathWithCwd(e,this._cwd)),s}isRelativePath(e){return!c.default.isAbsolute(e)}deleteCacheFile(){return this._cache.removeCacheFile()}destroy(){this._cache.destroy()}removeEntry(e){let s=this.createFileKey(e);this._cache.removeKey(s)}reconcile(){let{items:e}=this._cache;for(let s of e)this.getFileDescriptor(s.key).notFound&&this._cache.removeKey(s.key);this._cache.save()}hasFileChanged(e){let s=!1,i=this.getFileDescriptor(e);return(!i.err||!i.notFound)&&i.changed&&(s=!0),s}getFileDescriptor(e,s){this._logger?.debug({filePath:e,options:s},"Getting file descriptor");let i,t={key:this.createFileKey(e),changed:!1,meta:{}};this._logger?.trace({key:t.key},"Created file key");let r=this._cache.getKey(t.key);r?this._logger?.trace({metaCache:r},"Found cached meta"):this._logger?.trace("No cached meta found"),t.meta=r?{...r}:{};let a=this.getAbsolutePath(e);this._logger?.trace({absolutePath:a},"Resolved absolute path");let n=s?.useCheckSum??this._useCheckSum;this._logger?.debug({useCheckSum:n},"Using checksum setting");try{if(i=u.default.statSync(a),t.meta.size=i.size,t.meta.mtime=i.mtime.getTime(),this._logger?.trace({size:t.meta.size,mtime:t.meta.mtime},"Read file stats"),n){let h=u.default.readFileSync(a);t.meta.hash=this.getHash(h),this._logger?.trace({hash:t.meta.hash},"Calculated file hash")}}catch(h){this._logger?.error({filePath:e,error:h},"Error reading file"),this.removeEntry(e);let b=!1;return h.message.includes("ENOENT")&&(b=!0,this._logger?.debug({filePath:e},"File not found")),{key:t.key,err:h,notFound:b,meta:{}}}return r?(n===!1&&r?.mtime!==t.meta?.mtime&&(t.changed=!0,this._logger?.debug({filePath:e,oldMtime:r.mtime,newMtime:t.meta.mtime},"File changed: mtime differs")),r?.size!==t.meta?.size&&(t.changed=!0,this._logger?.debug({filePath:e,oldSize:r.size,newSize:t.meta.size},"File changed: size differs")),n&&r?.hash!==t.meta?.hash&&(t.changed=!0,this._logger?.debug({filePath:e,oldHash:r.hash,newHash:t.meta.hash},"File changed: hash differs")),this._cache.setKey(t.key,t.meta),t.changed?this._logger?.info({filePath:e},"File has changed"):this._logger?.debug({filePath:e},"File unchanged"),t):(t.changed=!0,this._cache.setKey(t.key,t.meta),this._logger?.debug({filePath:e},"File not in cache, marked as changed"),t)}normalizeEntries(e){let s=[];if(e){for(let t of e){let r=this.getFileDescriptor(t);s.push(r)}return s}let i=this.cache.keys();for(let t of i){let r=this.getFileDescriptor(t);!r.notFound&&!r.err&&s.push(r)}return s}analyzeFiles(e){let s={changedFiles:[],notFoundFiles:[],notChangedFiles:[]},i=this.normalizeEntries(e);for(let t of i)t.notFound?s.notFoundFiles.push(t.key):t.changed?s.changedFiles.push(t.key):s.notChangedFiles.push(t.key);return s}getUpdatedFiles(e){let s=[],i=this.normalizeEntries(e);for(let t of i)t.changed&&s.push(t.key);return s}getFileDescriptorsByPath(e){let s=[],i=this._cache.keys();for(let t of i)if(t.startsWith(e)){let r=this.getFileDescriptor(t);s.push(r)}return s}getAbsolutePath(e){if(this.isRelativePath(e)){let s=e.replace(/\0/g,""),i=c.default.resolve(this._cwd,s);if(this._strictPaths){let t=c.default.normalize(i),r=c.default.normalize(this._cwd);if(!(t===r||t.startsWith(r+c.default.sep)))throw new Error(`Path traversal attempt blocked: "${e}" resolves outside of working directory "${this._cwd}"`)}return i}return e}getAbsolutePathWithCwd(e,s){if(this.isRelativePath(e)){let i=e.replace(/\0/g,""),t=c.default.resolve(s,i);if(this._strictPaths){let r=c.default.normalize(t),a=c.default.normalize(s);if(!(r===a||r.startsWith(a+c.default.sep)))throw new Error(`Path traversal attempt blocked: "${e}" resolves outside of working directory "${s}"`)}return t}return e}renameCacheKeys(e,s){let i=this._cache.keys();for(let t of i)if(t.startsWith(e)){let r=t.replace(e,s),a=this._cache.getKey(t);this._cache.removeKey(t),this._cache.setKey(r,a)}}};0&&(module.exports={FileEntryCache,create,createFromFile}); | ||
| "use strict";var C=Object.create;var g=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var A=Object.getPrototypeOf,v=Object.prototype.hasOwnProperty;var z=(c,e)=>{for(var s in e)g(c,s,{get:e[s],enumerable:!0})},y=(c,e,s,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of w(e))!v.call(c,t)&&t!==s&&g(c,t,{get:()=>e[t],enumerable:!(i=k(e,t))||i.enumerable});return c};var p=(c,e,s)=>(s=c!=null?C(A(c)):{},y(e||!c||!c.__esModule?g(s,"default",{value:c,enumerable:!0}):s,c)),D=c=>y(g({},"__esModule",{value:!0}),c);var K={};z(K,{FileEntryCache:()=>m,create:()=>f,createFromFile:()=>_,default:()=>d});module.exports=D(K);var F=p(require("crypto"),1),u=p(require("fs"),1),o=p(require("path"),1),l=require("flat-cache");function _(c,e){let s=o.default.basename(c),i=o.default.dirname(c);return f(s,i,e)}function f(c,e,s){let i={...s,cache:{cacheId:c,cacheDir:e}},t=new m(i);if(e){let r=`${e}/${c}`;u.default.existsSync(r)&&(t.cache=(0,l.createFromFile)(r,i.cache))}return t}var d=class{static create=f;static createFromFile=_},m=class{_cache=new l.FlatCache({useClone:!1});_useCheckSum=!1;_hashAlgorithm="md5";_cwd=process.cwd();_restrictAccessToCwd=!1;_logger;_useAbsolutePathAsKey=!1;constructor(e){e?.cache&&(this._cache=new l.FlatCache(e.cache)),e?.useCheckSum&&(this._useCheckSum=e.useCheckSum),e?.hashAlgorithm&&(this._hashAlgorithm=e.hashAlgorithm),e?.cwd&&(this._cwd=e.cwd),e?.restrictAccessToCwd!==void 0&&(this._restrictAccessToCwd=e.restrictAccessToCwd),e?.useAbsolutePathAsKey!==void 0&&(this._useAbsolutePathAsKey=e.useAbsolutePathAsKey),e?.logger&&(this._logger=e.logger)}get cache(){return this._cache}set cache(e){this._cache=e}get logger(){return this._logger}set logger(e){this._logger=e}get useCheckSum(){return this._useCheckSum}set useCheckSum(e){this._useCheckSum=e}get hashAlgorithm(){return this._hashAlgorithm}set hashAlgorithm(e){this._hashAlgorithm=e}get cwd(){return this._cwd}set cwd(e){this._cwd=e}get restrictAccessToCwd(){return this._restrictAccessToCwd}set restrictAccessToCwd(e){this._restrictAccessToCwd=e}get useAbsolutePathAsKey(){return this._useAbsolutePathAsKey}set useAbsolutePathAsKey(e){this._useAbsolutePathAsKey=e}getHash(e){return F.default.createHash(this._hashAlgorithm).update(e).digest("hex")}createFileKey(e){let s=e;return this._useAbsolutePathAsKey&&this.isRelativePath(e)&&(s=this.getAbsolutePathWithCwd(e,this._cwd)),s}isRelativePath(e){return!o.default.isAbsolute(e)}deleteCacheFile(){return this._cache.removeCacheFile()}destroy(){this._cache.destroy()}removeEntry(e){let s=this.createFileKey(e);this._cache.removeKey(s)}reconcile(){let{items:e}=this._cache;for(let s of e)this.getFileDescriptor(s.key).notFound&&this._cache.removeKey(s.key);this._cache.save()}hasFileChanged(e){let s=!1,i=this.getFileDescriptor(e);return(!i.err||!i.notFound)&&i.changed&&(s=!0),s}getFileDescriptor(e,s){this._logger?.debug({filePath:e,options:s},"Getting file descriptor");let i,t={key:this.createFileKey(e),changed:!1,meta:{}};this._logger?.trace({key:t.key},"Created file key");let r=this._cache.getKey(t.key);r?this._logger?.trace({metaCache:r},"Found cached meta"):this._logger?.trace("No cached meta found"),t.meta=r?{...r}:{};let n=this.getAbsolutePath(e);this._logger?.trace({absolutePath:n},"Resolved absolute path");let a=s?.useCheckSum??this._useCheckSum;this._logger?.debug({useCheckSum:a},"Using checksum setting");try{if(i=u.default.statSync(n),t.meta.size=i.size,t.meta.mtime=i.mtime.getTime(),this._logger?.trace({size:t.meta.size,mtime:t.meta.mtime},"Read file stats"),a){let h=u.default.readFileSync(n);t.meta.hash=this.getHash(h),this._logger?.trace({hash:t.meta.hash},"Calculated file hash")}}catch(h){this._logger?.error({filePath:e,error:h},"Error reading file"),this.removeEntry(e);let b=!1;return h.message.includes("ENOENT")&&(b=!0,this._logger?.debug({filePath:e},"File not found")),{key:t.key,err:h,notFound:b,meta:{}}}return r?(a===!1&&r?.mtime!==t.meta?.mtime&&(t.changed=!0,this._logger?.debug({filePath:e,oldMtime:r.mtime,newMtime:t.meta.mtime},"File changed: mtime differs")),r?.size!==t.meta?.size&&(t.changed=!0,this._logger?.debug({filePath:e,oldSize:r.size,newSize:t.meta.size},"File changed: size differs")),a&&r?.hash!==t.meta?.hash&&(t.changed=!0,this._logger?.debug({filePath:e,oldHash:r.hash,newHash:t.meta.hash},"File changed: hash differs")),this._cache.setKey(t.key,t.meta),t.changed?this._logger?.info({filePath:e},"File has changed"):this._logger?.debug({filePath:e},"File unchanged"),t):(t.changed=!0,this._cache.setKey(t.key,t.meta),this._logger?.debug({filePath:e},"File not in cache, marked as changed"),t)}normalizeEntries(e){let s=[];if(e){for(let t of e){let r=this.getFileDescriptor(t);s.push(r)}return s}let i=this.cache.keys();for(let t of i){let r=this.getFileDescriptor(t);!r.notFound&&!r.err&&s.push(r)}return s}analyzeFiles(e){let s={changedFiles:[],notFoundFiles:[],notChangedFiles:[]},i=this.normalizeEntries(e);for(let t of i)t.notFound?s.notFoundFiles.push(t.key):t.changed?s.changedFiles.push(t.key):s.notChangedFiles.push(t.key);return s}getUpdatedFiles(e){let s=[],i=this.normalizeEntries(e);for(let t of i)t.changed&&s.push(t.key);return s}getFileDescriptorsByPath(e){let s=[],i=this._cache.keys();for(let t of i)if(t.startsWith(e)){let r=this.getFileDescriptor(t);s.push(r)}return s}getAbsolutePath(e){if(this.isRelativePath(e)){let s=e.replace(/\0/g,""),i=o.default.resolve(this._cwd,s);if(this._restrictAccessToCwd){let t=o.default.normalize(i),r=o.default.normalize(this._cwd);if(!(t===r||t.startsWith(r+o.default.sep)))throw new Error(`Path traversal attempt blocked: "${e}" resolves outside of working directory "${this._cwd}"`)}return i}return e}getAbsolutePathWithCwd(e,s){if(this.isRelativePath(e)){let i=e.replace(/\0/g,""),t=o.default.resolve(s,i);if(this._restrictAccessToCwd){let r=o.default.normalize(t),n=o.default.normalize(s);if(!(r===n||r.startsWith(n+o.default.sep)))throw new Error(`Path traversal attempt blocked: "${e}" resolves outside of working directory "${s}"`)}return t}return e}renameCacheKeys(e,s){let i=this._cache.keys();for(let t of i)if(t.startsWith(e)){let r=t.replace(e,s),n=this._cache.getKey(t);this._cache.removeKey(t),this._cache.setKey(r,n)}}};0&&(module.exports={FileEntryCache,create,createFromFile}); |
+8
-8
@@ -30,3 +30,3 @@ import { Buffer } from 'node:buffer'; | ||
| /** Restrict file access to within cwd boundaries (default: true) */ | ||
| strictPaths?: boolean; | ||
| restrictAccessToCwd?: boolean; | ||
| /** Whether to use absolute path as cache key (default: false) */ | ||
@@ -100,3 +100,3 @@ useAbsolutePathAsKey?: boolean; | ||
| private _cwd; | ||
| private _strictPaths; | ||
| private _restrictAccessToCwd; | ||
| private _logger?; | ||
@@ -163,3 +163,3 @@ private _useAbsolutePathAsKey; | ||
| */ | ||
| get strictPaths(): boolean; | ||
| get restrictAccessToCwd(): boolean; | ||
| /** | ||
@@ -169,3 +169,3 @@ * Set whether to restrict paths to cwd boundaries | ||
| */ | ||
| set strictPaths(value: boolean); | ||
| set restrictAccessToCwd(value: boolean); | ||
| /** | ||
@@ -269,7 +269,7 @@ * Get whether to use absolute path as cache key | ||
| * Get the Absolute Path. If it is already absolute it will return the path as is. | ||
| * When strictPaths is enabled, ensures the resolved path stays within cwd boundaries. | ||
| * When restrictAccessToCwd is enabled, ensures the resolved path stays within cwd boundaries. | ||
| * @method getAbsolutePath | ||
| * @param filePath - The file path to get the absolute path for | ||
| * @returns {string} | ||
| * @throws {Error} When strictPaths is true and path would resolve outside cwd | ||
| * @throws {Error} When restrictAccessToCwd is true and path would resolve outside cwd | ||
| */ | ||
@@ -279,3 +279,3 @@ getAbsolutePath(filePath: string): string; | ||
| * Get the Absolute Path with a custom working directory. If it is already absolute it will return the path as is. | ||
| * When strictPaths is enabled, ensures the resolved path stays within the provided cwd boundaries. | ||
| * When restrictAccessToCwd is enabled, ensures the resolved path stays within the provided cwd boundaries. | ||
| * @method getAbsolutePathWithCwd | ||
@@ -285,3 +285,3 @@ * @param filePath - The file path to get the absolute path for | ||
| * @returns {string} | ||
| * @throws {Error} When strictPaths is true and path would resolve outside the provided cwd | ||
| * @throws {Error} When restrictAccessToCwd is true and path would resolve outside the provided cwd | ||
| */ | ||
@@ -288,0 +288,0 @@ getAbsolutePathWithCwd(filePath: string, cwd: string): string; |
+8
-8
@@ -30,3 +30,3 @@ import { Buffer } from 'node:buffer'; | ||
| /** Restrict file access to within cwd boundaries (default: true) */ | ||
| strictPaths?: boolean; | ||
| restrictAccessToCwd?: boolean; | ||
| /** Whether to use absolute path as cache key (default: false) */ | ||
@@ -100,3 +100,3 @@ useAbsolutePathAsKey?: boolean; | ||
| private _cwd; | ||
| private _strictPaths; | ||
| private _restrictAccessToCwd; | ||
| private _logger?; | ||
@@ -163,3 +163,3 @@ private _useAbsolutePathAsKey; | ||
| */ | ||
| get strictPaths(): boolean; | ||
| get restrictAccessToCwd(): boolean; | ||
| /** | ||
@@ -169,3 +169,3 @@ * Set whether to restrict paths to cwd boundaries | ||
| */ | ||
| set strictPaths(value: boolean); | ||
| set restrictAccessToCwd(value: boolean); | ||
| /** | ||
@@ -269,7 +269,7 @@ * Get whether to use absolute path as cache key | ||
| * Get the Absolute Path. If it is already absolute it will return the path as is. | ||
| * When strictPaths is enabled, ensures the resolved path stays within cwd boundaries. | ||
| * When restrictAccessToCwd is enabled, ensures the resolved path stays within cwd boundaries. | ||
| * @method getAbsolutePath | ||
| * @param filePath - The file path to get the absolute path for | ||
| * @returns {string} | ||
| * @throws {Error} When strictPaths is true and path would resolve outside cwd | ||
| * @throws {Error} When restrictAccessToCwd is true and path would resolve outside cwd | ||
| */ | ||
@@ -279,3 +279,3 @@ getAbsolutePath(filePath: string): string; | ||
| * Get the Absolute Path with a custom working directory. If it is already absolute it will return the path as is. | ||
| * When strictPaths is enabled, ensures the resolved path stays within the provided cwd boundaries. | ||
| * When restrictAccessToCwd is enabled, ensures the resolved path stays within the provided cwd boundaries. | ||
| * @method getAbsolutePathWithCwd | ||
@@ -285,3 +285,3 @@ * @param filePath - The file path to get the absolute path for | ||
| * @returns {string} | ||
| * @throws {Error} When strictPaths is true and path would resolve outside the provided cwd | ||
| * @throws {Error} When restrictAccessToCwd is true and path would resolve outside the provided cwd | ||
| */ | ||
@@ -288,0 +288,0 @@ getAbsolutePathWithCwd(filePath: string, cwd: string): string; |
+1
-1
@@ -1,1 +0,1 @@ | ||
| import f from"crypto";import l from"fs";import o from"path";import{createFromFile as b,FlatCache as m}from"flat-cache";function y(a,e){let s=o.basename(a),r=o.dirname(a);return p(s,r,e)}function p(a,e,s){let r={...s,cache:{cacheId:a,cacheDir:e}},t=new u(r);if(e){let i=`${e}/${a}`;l.existsSync(i)&&(t.cache=b(i,r.cache))}return t}var g=class{static create=p;static createFromFile=y},u=class{_cache=new m({useClone:!1});_useCheckSum=!1;_hashAlgorithm="md5";_cwd=process.cwd();_strictPaths=!1;_logger;_useAbsolutePathAsKey=!1;constructor(e){e?.cache&&(this._cache=new m(e.cache)),e?.useCheckSum&&(this._useCheckSum=e.useCheckSum),e?.hashAlgorithm&&(this._hashAlgorithm=e.hashAlgorithm),e?.cwd&&(this._cwd=e.cwd),e?.strictPaths!==void 0&&(this._strictPaths=e.strictPaths),e?.useAbsolutePathAsKey!==void 0&&(this._useAbsolutePathAsKey=e.useAbsolutePathAsKey),e?.logger&&(this._logger=e.logger)}get cache(){return this._cache}set cache(e){this._cache=e}get logger(){return this._logger}set logger(e){this._logger=e}get useCheckSum(){return this._useCheckSum}set useCheckSum(e){this._useCheckSum=e}get hashAlgorithm(){return this._hashAlgorithm}set hashAlgorithm(e){this._hashAlgorithm=e}get cwd(){return this._cwd}set cwd(e){this._cwd=e}get strictPaths(){return this._strictPaths}set strictPaths(e){this._strictPaths=e}get useAbsolutePathAsKey(){return this._useAbsolutePathAsKey}set useAbsolutePathAsKey(e){this._useAbsolutePathAsKey=e}getHash(e){return f.createHash(this._hashAlgorithm).update(e).digest("hex")}createFileKey(e){let s=e;return this._useAbsolutePathAsKey&&this.isRelativePath(e)&&(s=this.getAbsolutePathWithCwd(e,this._cwd)),s}isRelativePath(e){return!o.isAbsolute(e)}deleteCacheFile(){return this._cache.removeCacheFile()}destroy(){this._cache.destroy()}removeEntry(e){let s=this.createFileKey(e);this._cache.removeKey(s)}reconcile(){let{items:e}=this._cache;for(let s of e)this.getFileDescriptor(s.key).notFound&&this._cache.removeKey(s.key);this._cache.save()}hasFileChanged(e){let s=!1,r=this.getFileDescriptor(e);return(!r.err||!r.notFound)&&r.changed&&(s=!0),s}getFileDescriptor(e,s){this._logger?.debug({filePath:e,options:s},"Getting file descriptor");let r,t={key:this.createFileKey(e),changed:!1,meta:{}};this._logger?.trace({key:t.key},"Created file key");let i=this._cache.getKey(t.key);i?this._logger?.trace({metaCache:i},"Found cached meta"):this._logger?.trace("No cached meta found"),t.meta=i?{...i}:{};let c=this.getAbsolutePath(e);this._logger?.trace({absolutePath:c},"Resolved absolute path");let n=s?.useCheckSum??this._useCheckSum;this._logger?.debug({useCheckSum:n},"Using checksum setting");try{if(r=l.statSync(c),t.meta.size=r.size,t.meta.mtime=r.mtime.getTime(),this._logger?.trace({size:t.meta.size,mtime:t.meta.mtime},"Read file stats"),n){let h=l.readFileSync(c);t.meta.hash=this.getHash(h),this._logger?.trace({hash:t.meta.hash},"Calculated file hash")}}catch(h){this._logger?.error({filePath:e,error:h},"Error reading file"),this.removeEntry(e);let d=!1;return h.message.includes("ENOENT")&&(d=!0,this._logger?.debug({filePath:e},"File not found")),{key:t.key,err:h,notFound:d,meta:{}}}return i?(n===!1&&i?.mtime!==t.meta?.mtime&&(t.changed=!0,this._logger?.debug({filePath:e,oldMtime:i.mtime,newMtime:t.meta.mtime},"File changed: mtime differs")),i?.size!==t.meta?.size&&(t.changed=!0,this._logger?.debug({filePath:e,oldSize:i.size,newSize:t.meta.size},"File changed: size differs")),n&&i?.hash!==t.meta?.hash&&(t.changed=!0,this._logger?.debug({filePath:e,oldHash:i.hash,newHash:t.meta.hash},"File changed: hash differs")),this._cache.setKey(t.key,t.meta),t.changed?this._logger?.info({filePath:e},"File has changed"):this._logger?.debug({filePath:e},"File unchanged"),t):(t.changed=!0,this._cache.setKey(t.key,t.meta),this._logger?.debug({filePath:e},"File not in cache, marked as changed"),t)}normalizeEntries(e){let s=[];if(e){for(let t of e){let i=this.getFileDescriptor(t);s.push(i)}return s}let r=this.cache.keys();for(let t of r){let i=this.getFileDescriptor(t);!i.notFound&&!i.err&&s.push(i)}return s}analyzeFiles(e){let s={changedFiles:[],notFoundFiles:[],notChangedFiles:[]},r=this.normalizeEntries(e);for(let t of r)t.notFound?s.notFoundFiles.push(t.key):t.changed?s.changedFiles.push(t.key):s.notChangedFiles.push(t.key);return s}getUpdatedFiles(e){let s=[],r=this.normalizeEntries(e);for(let t of r)t.changed&&s.push(t.key);return s}getFileDescriptorsByPath(e){let s=[],r=this._cache.keys();for(let t of r)if(t.startsWith(e)){let i=this.getFileDescriptor(t);s.push(i)}return s}getAbsolutePath(e){if(this.isRelativePath(e)){let s=e.replace(/\0/g,""),r=o.resolve(this._cwd,s);if(this._strictPaths){let t=o.normalize(r),i=o.normalize(this._cwd);if(!(t===i||t.startsWith(i+o.sep)))throw new Error(`Path traversal attempt blocked: "${e}" resolves outside of working directory "${this._cwd}"`)}return r}return e}getAbsolutePathWithCwd(e,s){if(this.isRelativePath(e)){let r=e.replace(/\0/g,""),t=o.resolve(s,r);if(this._strictPaths){let i=o.normalize(t),c=o.normalize(s);if(!(i===c||i.startsWith(c+o.sep)))throw new Error(`Path traversal attempt blocked: "${e}" resolves outside of working directory "${s}"`)}return t}return e}renameCacheKeys(e,s){let r=this._cache.keys();for(let t of r)if(t.startsWith(e)){let i=t.replace(e,s),c=this._cache.getKey(t);this._cache.removeKey(t),this._cache.setKey(i,c)}}};export{u as FileEntryCache,p as create,y as createFromFile,g as default}; | ||
| import f from"crypto";import l from"fs";import c from"path";import{createFromFile as b,FlatCache as m}from"flat-cache";function y(n,e){let s=c.basename(n),r=c.dirname(n);return p(s,r,e)}function p(n,e,s){let r={...s,cache:{cacheId:n,cacheDir:e}},t=new u(r);if(e){let i=`${e}/${n}`;l.existsSync(i)&&(t.cache=b(i,r.cache))}return t}var g=class{static create=p;static createFromFile=y},u=class{_cache=new m({useClone:!1});_useCheckSum=!1;_hashAlgorithm="md5";_cwd=process.cwd();_restrictAccessToCwd=!1;_logger;_useAbsolutePathAsKey=!1;constructor(e){e?.cache&&(this._cache=new m(e.cache)),e?.useCheckSum&&(this._useCheckSum=e.useCheckSum),e?.hashAlgorithm&&(this._hashAlgorithm=e.hashAlgorithm),e?.cwd&&(this._cwd=e.cwd),e?.restrictAccessToCwd!==void 0&&(this._restrictAccessToCwd=e.restrictAccessToCwd),e?.useAbsolutePathAsKey!==void 0&&(this._useAbsolutePathAsKey=e.useAbsolutePathAsKey),e?.logger&&(this._logger=e.logger)}get cache(){return this._cache}set cache(e){this._cache=e}get logger(){return this._logger}set logger(e){this._logger=e}get useCheckSum(){return this._useCheckSum}set useCheckSum(e){this._useCheckSum=e}get hashAlgorithm(){return this._hashAlgorithm}set hashAlgorithm(e){this._hashAlgorithm=e}get cwd(){return this._cwd}set cwd(e){this._cwd=e}get restrictAccessToCwd(){return this._restrictAccessToCwd}set restrictAccessToCwd(e){this._restrictAccessToCwd=e}get useAbsolutePathAsKey(){return this._useAbsolutePathAsKey}set useAbsolutePathAsKey(e){this._useAbsolutePathAsKey=e}getHash(e){return f.createHash(this._hashAlgorithm).update(e).digest("hex")}createFileKey(e){let s=e;return this._useAbsolutePathAsKey&&this.isRelativePath(e)&&(s=this.getAbsolutePathWithCwd(e,this._cwd)),s}isRelativePath(e){return!c.isAbsolute(e)}deleteCacheFile(){return this._cache.removeCacheFile()}destroy(){this._cache.destroy()}removeEntry(e){let s=this.createFileKey(e);this._cache.removeKey(s)}reconcile(){let{items:e}=this._cache;for(let s of e)this.getFileDescriptor(s.key).notFound&&this._cache.removeKey(s.key);this._cache.save()}hasFileChanged(e){let s=!1,r=this.getFileDescriptor(e);return(!r.err||!r.notFound)&&r.changed&&(s=!0),s}getFileDescriptor(e,s){this._logger?.debug({filePath:e,options:s},"Getting file descriptor");let r,t={key:this.createFileKey(e),changed:!1,meta:{}};this._logger?.trace({key:t.key},"Created file key");let i=this._cache.getKey(t.key);i?this._logger?.trace({metaCache:i},"Found cached meta"):this._logger?.trace("No cached meta found"),t.meta=i?{...i}:{};let o=this.getAbsolutePath(e);this._logger?.trace({absolutePath:o},"Resolved absolute path");let a=s?.useCheckSum??this._useCheckSum;this._logger?.debug({useCheckSum:a},"Using checksum setting");try{if(r=l.statSync(o),t.meta.size=r.size,t.meta.mtime=r.mtime.getTime(),this._logger?.trace({size:t.meta.size,mtime:t.meta.mtime},"Read file stats"),a){let h=l.readFileSync(o);t.meta.hash=this.getHash(h),this._logger?.trace({hash:t.meta.hash},"Calculated file hash")}}catch(h){this._logger?.error({filePath:e,error:h},"Error reading file"),this.removeEntry(e);let d=!1;return h.message.includes("ENOENT")&&(d=!0,this._logger?.debug({filePath:e},"File not found")),{key:t.key,err:h,notFound:d,meta:{}}}return i?(a===!1&&i?.mtime!==t.meta?.mtime&&(t.changed=!0,this._logger?.debug({filePath:e,oldMtime:i.mtime,newMtime:t.meta.mtime},"File changed: mtime differs")),i?.size!==t.meta?.size&&(t.changed=!0,this._logger?.debug({filePath:e,oldSize:i.size,newSize:t.meta.size},"File changed: size differs")),a&&i?.hash!==t.meta?.hash&&(t.changed=!0,this._logger?.debug({filePath:e,oldHash:i.hash,newHash:t.meta.hash},"File changed: hash differs")),this._cache.setKey(t.key,t.meta),t.changed?this._logger?.info({filePath:e},"File has changed"):this._logger?.debug({filePath:e},"File unchanged"),t):(t.changed=!0,this._cache.setKey(t.key,t.meta),this._logger?.debug({filePath:e},"File not in cache, marked as changed"),t)}normalizeEntries(e){let s=[];if(e){for(let t of e){let i=this.getFileDescriptor(t);s.push(i)}return s}let r=this.cache.keys();for(let t of r){let i=this.getFileDescriptor(t);!i.notFound&&!i.err&&s.push(i)}return s}analyzeFiles(e){let s={changedFiles:[],notFoundFiles:[],notChangedFiles:[]},r=this.normalizeEntries(e);for(let t of r)t.notFound?s.notFoundFiles.push(t.key):t.changed?s.changedFiles.push(t.key):s.notChangedFiles.push(t.key);return s}getUpdatedFiles(e){let s=[],r=this.normalizeEntries(e);for(let t of r)t.changed&&s.push(t.key);return s}getFileDescriptorsByPath(e){let s=[],r=this._cache.keys();for(let t of r)if(t.startsWith(e)){let i=this.getFileDescriptor(t);s.push(i)}return s}getAbsolutePath(e){if(this.isRelativePath(e)){let s=e.replace(/\0/g,""),r=c.resolve(this._cwd,s);if(this._restrictAccessToCwd){let t=c.normalize(r),i=c.normalize(this._cwd);if(!(t===i||t.startsWith(i+c.sep)))throw new Error(`Path traversal attempt blocked: "${e}" resolves outside of working directory "${this._cwd}"`)}return r}return e}getAbsolutePathWithCwd(e,s){if(this.isRelativePath(e)){let r=e.replace(/\0/g,""),t=c.resolve(s,r);if(this._restrictAccessToCwd){let i=c.normalize(t),o=c.normalize(s);if(!(i===o||i.startsWith(o+c.sep)))throw new Error(`Path traversal attempt blocked: "${e}" resolves outside of working directory "${s}"`)}return t}return e}renameCacheKeys(e,s){let r=this._cache.keys();for(let t of r)if(t.startsWith(e)){let i=t.replace(e,s),o=this._cache.getKey(t);this._cache.removeKey(t),this._cache.setKey(i,o)}}};export{u as FileEntryCache,p as create,y as createFromFile,g as default}; |
+2
-2
| { | ||
| "name": "file-entry-cache", | ||
| "version": "11.0.0-beta.5", | ||
| "version": "11.0.0", | ||
| "description": "A lightweight cache for file metadata, ideal for processes that work on a specific set of files and only need to reprocess files that have changed since the last run", | ||
@@ -33,3 +33,3 @@ "type": "module", | ||
| "@biomejs/biome": "^2.2.5", | ||
| "@types/node": "^24.7.1", | ||
| "@types/node": "^24.7.2", | ||
| "@vitest/coverage-v8": "^3.2.4", | ||
@@ -36,0 +36,0 @@ "pino": "^10.0.0", |
+139
-47
@@ -75,2 +75,19 @@ [<img align="center" src="https://cacheable.org/symbol.svg" alt="Cacheable" />](https://github.com/jaredwray/cacheable) | ||
| Using `create()` with options for more control: | ||
| ```javascript | ||
| import fileEntryCache from 'file-entry-cache'; | ||
| // Create cache with options | ||
| const cache = fileEntryCache.create('myCache', './.cache', { | ||
| useCheckSum: true, // Use checksums for more reliable change detection | ||
| cwd: '/path/to/project', // Custom working directory | ||
| restrictAccessToCwd: false, // Allow access outside cwd (use with caution) | ||
| useAbsolutePathAsKey: false // Store relative paths in cache | ||
| }); | ||
| let fileDescriptor = cache.getFileDescriptor('./src/file.txt'); | ||
| console.log(fileDescriptor.changed); // true | ||
| console.log(fileDescriptor.meta.hash); // checksum hash | ||
| ``` | ||
| Save it to Disk and Reconcile files that are no longer found | ||
@@ -89,5 +106,13 @@ ```javascript | ||
| import fileEntryCache from 'file-entry-cache'; | ||
| // Basic usage | ||
| const cache = fileEntryCache.createFromFile('/path/to/cache/file'); | ||
| let fileDescriptor = cache.getFileDescriptor('./src/file.txt'); | ||
| console.log(fileDescriptor.changed); // false as it has not changed from the saved cache. | ||
| // With options | ||
| const cache2 = fileEntryCache.createFromFile('/path/to/cache/file', { | ||
| useCheckSum: true, | ||
| cwd: '/path/to/project' | ||
| }); | ||
| ``` | ||
@@ -99,7 +124,59 @@ | ||
| **BREAKING CHANGES:** | ||
| - **`strictPaths` now defaults to `true`** - Path traversal protection is enabled by default for security. To restore v10 behavior, explicitly set `strictPaths: false` | ||
| - **`create()` and `createFromFile()` now use `CreateOptions` object** - The function signatures have changed to accept an options object instead of individual parameters for better extensibility and clarity. | ||
| **Old API (v10):** | ||
| ```javascript | ||
| // v10 - positional parameters | ||
| const cache = fileEntryCache.create(cacheId, cacheDirectory, useCheckSum, cwd); | ||
| const cache2 = fileEntryCache.createFromFile(filePath, useCheckSum, cwd); | ||
| ``` | ||
| **New API (v11):** | ||
| ```javascript | ||
| // v11 - options object | ||
| const cache = fileEntryCache.create(cacheId, cacheDirectory, { | ||
| useCheckSum: true, | ||
| cwd: '/path/to/project', | ||
| restrictAccessToCwd: false | ||
| }); | ||
| const cache2 = fileEntryCache.createFromFile(filePath, { | ||
| useCheckSum: true, | ||
| cwd: '/path/to/project', | ||
| restrictAccessToCwd: false | ||
| }); | ||
| ``` | ||
| - **Renamed `strictPaths` to `restrictAccessToCwd`** - For better clarity and self-documentation, the option that restricts file access to the current working directory has been renamed. | ||
| **Migration:** | ||
| ```javascript | ||
| // Old | ||
| const cache = new FileEntryCache({ strictPaths: true }); | ||
| cache.strictPaths = false; | ||
| // New | ||
| const cache = new FileEntryCache({ restrictAccessToCwd: true }); | ||
| cache.restrictAccessToCwd = false; | ||
| ``` | ||
| - **Renamed `currentWorkingDirectory` to `cwd`** - For consistency with common conventions and brevity, the property has been renamed to `cwd`. | ||
| **Migration:** | ||
| ```javascript | ||
| // Old | ||
| const cache = new FileEntryCache({ currentWorkingDirectory: '/path/to/project' }); | ||
| cache.currentWorkingDirectory = '/new/path'; | ||
| // New | ||
| const cache = new FileEntryCache({ cwd: '/path/to/project' }); | ||
| cache.cwd = '/new/path'; | ||
| ``` | ||
| **NEW FEATURES:** | ||
| - **Added `cwd` option** - You can now specify a custom current working directory for resolving relative paths | ||
| - **Added `strictPaths` option** - Provides protection against path traversal attacks (enabled by default) | ||
| - **Added `restrictAccessToCwd` option** - Provides protection against path traversal attacks (disabled by default for backwards compatibility) | ||
| - **Added `useAbsolutePathAsKey` option** - When `true`, cache keys use absolute paths instead of the provided paths. Default is `false` for better cache portability with relative paths | ||
| - **Added `logger` option** - Support for Pino-compatible logger instances to enable debugging and monitoring of cache operations. See [Logger Support](#logger-support) section for details | ||
| - **Improved cache portability** - When using relative paths with the same `cwd`, cache files are portable across different environments | ||
@@ -120,5 +197,14 @@ | ||
| # Global Default Functions | ||
| - `create(cacheId: string, cacheDirectory?: string, useCheckSum?: boolean, cwd?: string)` - Creates a new instance of the `FileEntryCache` class | ||
| - `createFromFile(cachePath: string, useCheckSum?: boolean, cwd?: string)` - Creates a new instance of the `FileEntryCache` class and loads the cache from a file. | ||
| - `create(cacheId: string, cacheDirectory?: string, options?: CreateOptions)` - Creates a new instance of the `FileEntryCache` class | ||
| - `createFromFile(filePath: string, options?: CreateOptions)` - Creates a new instance of the `FileEntryCache` class and loads the cache from a file. | ||
| ## CreateOptions Type | ||
| All options from `FileEntryCacheOptions` except `cache`: | ||
| - `useCheckSum?` - If `true` it will use a checksum to determine if the file has changed. Default is `false` | ||
| - `hashAlgorithm?` - The algorithm to use for the checksum. Default is `md5` | ||
| - `cwd?` - The current working directory for resolving relative paths. Default is `process.cwd()` | ||
| - `restrictAccessToCwd?` - If `true` restricts file access to within `cwd` boundaries. Default is `false` | ||
| - `useAbsolutePathAsKey?` - If `true` uses absolute paths as cache keys. Default is `false` | ||
| - `logger?` - A logger instance for debugging. Default is `undefined` | ||
| # FileEntryCache Options (FileEntryCacheOptions) | ||
@@ -129,3 +215,3 @@ - `useModifiedTime?` - If `true` it will use the modified time to determine if the file has changed. Default is `true` | ||
| - `cwd?` - The current working directory for resolving relative paths. Default is `process.cwd()` | ||
| - `strictPaths?` - If `true` restricts file access to within `cwd` boundaries, preventing path traversal attacks. Default is `true` | ||
| - `restrictAccessToCwd?` - If `true` restricts file access to within `cwd` boundaries, preventing path traversal attacks. Default is `true` | ||
| - `logger?` - A logger instance compatible with Pino logger interface for debugging and monitoring. Default is `undefined` | ||
@@ -149,5 +235,6 @@ - `cache.ttl?` - The time to live for the cache in milliseconds. Default is `0` which means no expiration | ||
| - `cwd: string` - The current working directory for resolving relative paths. Default is `process.cwd()` | ||
| - `strictPaths: boolean` - If `true` restricts file access to within `cwd` boundaries. Default is `true` | ||
| - `restrictAccessToCwd: boolean` - If `true` restricts file access to within `cwd` boundaries. Default is `true` | ||
| - `useAbsolutePathAsKey: boolean` - If `true` uses absolute paths as cache keys. Default is `false` to maintain better cache portability | ||
| - `logger: ILogger | undefined` - A logger instance for debugging and monitoring cache operations | ||
| - `createFileKey(filePath: string): string` - Returns the cache key for the file path (returns the path exactly as provided). | ||
| - `createFileKey(filePath: string): string` - Returns the cache key for the file path (returns the path exactly as provided when `useAbsolutePathAsKey` is `false`, otherwise returns the absolute path). | ||
| - `deleteCacheFile(): boolean` - Deletes the cache file from disk | ||
@@ -163,4 +250,4 @@ - `destroy(): void` - Destroys the cache. This will clear the cache in memory. If using cache persistence it will stop the interval. | ||
| - `getFileDescriptorsByPath(filePath: string): FileEntryDescriptor[]` will return an array of `FileEntryDescriptor` objects that starts with the path prefix specified. | ||
| - `getAbsolutePath(filePath: string): string` - Resolves a relative path to absolute using the configured `cwd`. Returns absolute paths unchanged. When `strictPaths` is enabled, throws an error if the path resolves outside `cwd`. | ||
| - `getAbsolutePathWithCwd(filePath: string, cwd: string): string` - Resolves a relative path to absolute using a custom working directory. When `strictPaths` is enabled, throws an error if the path resolves outside the provided `cwd`. | ||
| - `getAbsolutePath(filePath: string): string` - Resolves a relative path to absolute using the configured `cwd`. Returns absolute paths unchanged. When `restrictAccessToCwd` is enabled, throws an error if the path resolves outside `cwd`. | ||
| - `getAbsolutePathWithCwd(filePath: string, cwd: string): string` - Resolves a relative path to absolute using a custom working directory. When `restrictAccessToCwd` is enabled, throws an error if the path resolves outside the provided `cwd`. | ||
@@ -185,5 +272,8 @@ # Get File Descriptor | ||
| // Custom working directory | ||
| const cache2 = fileEntryCache.create('cache2', './cache', false, '/project/root'); | ||
| // Or with options object | ||
| // Custom working directory using options object | ||
| const cache2 = fileEntryCache.create('cache2', './cache', { | ||
| cwd: '/project/root' | ||
| }); | ||
| // Or using the class constructor directly | ||
| const cache3 = new FileEntryCache({ cwd: '/project/root' }); | ||
@@ -203,3 +293,5 @@ | ||
| // On machine A (project at /home/user/project) | ||
| const cacheA = fileEntryCache.create('build-cache', './cache', false, '/home/user/project'); | ||
| const cacheA = fileEntryCache.create('build-cache', './cache', { | ||
| cwd: '/home/user/project' | ||
| }); | ||
| cacheA.getFileDescriptor('./src/index.js'); // Resolves to /home/user/project/src/index.js | ||
@@ -209,3 +301,5 @@ cacheA.reconcile(); | ||
| // On machine B (project at /workspace/project) | ||
| const cacheB = fileEntryCache.create('build-cache', './cache', false, '/workspace/project'); | ||
| const cacheB = fileEntryCache.create('build-cache', './cache', { | ||
| cwd: '/workspace/project' | ||
| }); | ||
| cacheB.getFileDescriptor('./src/index.js'); // Resolves to /workspace/project/src/index.js | ||
@@ -221,7 +315,5 @@ // Cache hit! File hasn't changed since machine A | ||
| // Development machine | ||
| const devCache = fileEntryCache.create( | ||
| '.buildcache', | ||
| './cache', // cache directory | ||
| true // Use checksums for content-based comparison | ||
| ); | ||
| const devCache = fileEntryCache.create('.buildcache', './cache', { | ||
| useCheckSum: true // Use checksums for content-based comparison | ||
| }); | ||
@@ -237,8 +329,6 @@ // Process files using relative paths | ||
| // CI/CD Pipeline or another developer's machine | ||
| const ciCache = fileEntryCache.create( | ||
| '.buildcache', | ||
| './node_modules/.cache', | ||
| true, // Same checksum setting | ||
| process.cwd() // Different absolute path, same relative structure | ||
| ); | ||
| const ciCache = fileEntryCache.create('.buildcache', './node_modules/.cache', { | ||
| useCheckSum: true, // Same checksum setting | ||
| cwd: process.cwd() // Different absolute path, same relative structure | ||
| }); | ||
@@ -259,3 +349,6 @@ // Same relative path works across environments | ||
| // Original location: /projects/my-app | ||
| const cache1 = fileEntryCache.create('.cache', './cache', true, '/projects/my-app'); | ||
| const cache1 = fileEntryCache.create('.cache', './cache', { | ||
| useCheckSum: true, | ||
| cwd: '/projects/my-app' | ||
| }); | ||
| cache1.getFileDescriptor('./src/app.js'); | ||
@@ -265,3 +358,6 @@ cache1.reconcile(); | ||
| // After moving project to: /archived/2024/my-app | ||
| const cache2 = fileEntryCache.create('.cache', './cache', true, '/archived/2024/my-app'); | ||
| const cache2 = fileEntryCache.create('.cache', './cache', { | ||
| useCheckSum: true, | ||
| cwd: '/archived/2024/my-app' | ||
| }); | ||
| cache2.getFileDescriptor('./src/app.js'); // Still finds cached entry! | ||
@@ -287,3 +383,3 @@ // Cache valid as long as relative structure unchanged | ||
| The `strictPaths` option provides security against path traversal attacks by restricting file access to within the configured `cwd` boundaries. **This is enabled by default (since v11)** to ensure secure defaults when processing untrusted input or when running in security-sensitive environments. | ||
| The `restrictAccessToCwd` option provides security against path traversal attacks by restricting file access to within the configured `cwd` boundaries. **This is enabled by default (since v11)** to ensure secure defaults when processing untrusted input or when running in security-sensitive environments. | ||
@@ -293,3 +389,3 @@ ## Basic Usage | ||
| ```javascript | ||
| // strictPaths is enabled by default for security | ||
| // restrictAccessToCwd is enabled by default for security | ||
| const cache = new FileEntryCache({ | ||
@@ -312,3 +408,3 @@ cwd: '/project/root' | ||
| cwd: '/project/root', | ||
| strictPaths: false // Explicitly disable protection | ||
| restrictAccessToCwd: false // Explicitly disable protection | ||
| }); | ||
@@ -319,3 +415,3 @@ ``` | ||
| When `strictPaths` is enabled: | ||
| When `restrictAccessToCwd` is enabled: | ||
| - **Path Traversal Prevention**: Blocks attempts to access files outside the working directory using `../` sequences | ||
@@ -330,12 +426,8 @@ - **Null Byte Protection**: Automatically removes null bytes from paths to prevent injection attacks | ||
| // Secure build tool configuration | ||
| const cache = fileEntryCache.create( | ||
| '.buildcache', | ||
| './cache', | ||
| true, // useCheckSum | ||
| process.cwd() | ||
| ); | ||
| const cache = fileEntryCache.create('.buildcache', './cache', { | ||
| useCheckSum: true, | ||
| cwd: process.cwd(), | ||
| restrictAccessToCwd: true // Enable strict path checking for security | ||
| }); | ||
| // Enable strict path checking for security | ||
| cache.strictPaths = true; | ||
| // Process user-provided file paths safely | ||
@@ -362,3 +454,3 @@ function processUserFile(userProvidedPath) { | ||
| cwd: process.env.GITHUB_WORKSPACE || process.cwd(), | ||
| strictPaths: true, // Prevent access outside workspace | ||
| restrictAccessToCwd: true, // Prevent access outside workspace | ||
| useCheckSum: true // Content-based validation | ||
@@ -378,11 +470,11 @@ }); | ||
| // Start with relaxed mode for trusted operations | ||
| cache.strictPaths = false; | ||
| cache.restrictAccessToCwd = false; | ||
| processInternalFiles(); | ||
| // Enable strict mode for untrusted input | ||
| cache.strictPaths = true; | ||
| cache.restrictAccessToCwd = true; | ||
| processUserUploadedPaths(); | ||
| // Return to relaxed mode if needed | ||
| cache.strictPaths = false; | ||
| cache.restrictAccessToCwd = false; | ||
| ``` | ||
@@ -392,3 +484,3 @@ | ||
| **As of v11, `strictPaths` is enabled by default** to provide secure defaults. This means: | ||
| **As of v11, `restrictAccessToCwd` is enabled by default** to provide secure defaults. This means: | ||
| - Path traversal attempts using `../` are blocked | ||
@@ -405,7 +497,7 @@ - File access is restricted to within the configured `cwd` | ||
| cwd: process.cwd(), | ||
| strictPaths: false // Restore v10 behavior | ||
| restrictAccessToCwd: false // Restore v10 behavior | ||
| }); | ||
| ``` | ||
| However, we strongly recommend keeping `strictPaths: true` and adjusting your code to work within the security boundaries, especially when processing any untrusted input. | ||
| However, we strongly recommend keeping `restrictAccessToCwd: true` and adjusting your code to work within the security boundaries, especially when processing any untrusted input. | ||
@@ -412,0 +504,0 @@ # Using Checksums to Determine if a File has Changed (useCheckSum) |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
64104
6.67%3
-25%630
17.1%