Github项目因NPM依赖包版本低存在安全漏洞

下午邮箱收到一连串GitHub推送的警告信息,说因为NPM依赖包版本低存在安全漏洞。上次出现这一问题我是挨个项目的升级NPM依赖包。由于该NPM依赖包牵扯项目太多,于是我换了一种解决思路。

GitHub邮件提示多个项目因npm依赖包版本低导致项目存在安全漏洞

噩梦产因

首先梳理一下我的所有项目仓库。我的一小部分私有项目在Gitee码云,GitHub有我大部分公开项目。其中我的个人博客网站的后端代码和前端代码是分开的,他们分别托管在Gitee码云和GitHub上。这两个仓库都是私有的,如果前端和后端两个仓库的功能完善到相对成熟且有分享的价值地步,我在考虑是否公开。

正如我在前面一篇文章中提到了观点,国内Gitee码云是我为了后端代码相对安全和稳妥的维护的选择,绝大部分前端项目的代码都托管在GitHub上。GOMA和Airglass两个前端项目都是在GitHub上维护着。我的前端项目大部分都使用到基于NodeJS开发的第三方构建工具,所以毋庸置疑的牵扯到NPM包的使用和维护。大部分前端构建需用到的NPM依赖包在我的大部分项目中都出现了,比如webpack/rollup/gulp等等构建工具系列,loader/babel/typescript等等解析插件系列,包括这些NPM包本身依赖的NPM包就更是重复重复再重复。

一个NPM升级所有项目都存在安全漏洞

综上情况,当一个螺丝钉级别的NPM包在升级了版本,我的任何一个项目中所有依赖了这个NPM包(无限循环NPM包依赖)的NPM包,就会报警说存在安全漏洞。等待我的就是全部项目逐一升级依赖的噩梦!

解决方案

在解决问题之前,先认清一点:解决问题的方案和问题本身都是本不应该存在的,而解决问题的方案有时候看起来只不过是拆了东墙补西墙羊毛出在羊身上的无奈之举。了解这些就像了解我因为活着所以就要解决因活着而产生的问题。我无法左右的实事:

  1. 我无法阻止项目中所依赖的NPM包的作者对包做必要的升级;
  2. 我无法对因作者升级而产生的安全漏洞视而不见或置之不理;
  3. 我无法让解决方案一劳永逸,就像我们总要被迫不停买新款;

综上三点,我释然了。我只要解决一个痛点就行——统一管理NPM包,再出现这种情况而无需对所有项目一一升级。其实话说回来,问题的矛头并不在升级NPM包的作者或者NODE+NPM的关系,而是因为我没有合理管理NPM包和使用不当造成的。偶尔我想调整所有项目的构建代码,对于构建手段相似的项目,我也要逐一修改的。所以当务之急我真正需要解决的将源代码仓库和构建工具仓库代码分离。

源代码仓库与构建代码仓库分离模式

如上图所示。项目仓库中只版本管理源代码或者必要的配置文件,不牵扯NPM包。再单独拿出一个仓库版本管理用于将源代码构建成可直接使用的生成代码,这个仓库直接与NPM包对话,其中某个依赖的NPM包升级了或者纯粹我想优化构建方式,只需修改构建仓库中的代码即可,而无需像以前那样每一个仓库都修改一遍存放在各个仓库相似的构建代码。

构建仓库想要服务好所有源代码仓库,应对纷繁复杂的构建需求,就需要完善而全面的构建配置清单。目前我的全部前端项目的构建工作主要依赖Webpack、Rollup和Gulp这三位大将的帮助。配置清单应该根据具体业务或者其他考虑各自发挥和设计,没有统一的硬性标准。

写好构建仓库的配置清单(不要看到配置清单就觉得只能有一份哦),借助npm run命令,可以很方便的自动将项目仓库中的源代码构建和输出。就拿我的部分命令为例:

  • 下边是用webpack构建一次用于生产环境的代码,wb就是webpack build的缩写,因为npm run webpack_build虽然语义明晰但熟悉之后反倒觉得麻烦。

    npm run wb
    
  • ww可想而知就是webpack watch的缩写了。执行下方命令就能构建便于在开发环境中调试代码,当然这取决于我怎么写配置清单文件。

    npm run ww
    
  • 再比如我有些项目使用Rollup构建,rb就是rollup build的缩写。

    npm run rb
    
  • 所以rw就是rollup watch的缩写喽。

    npm run rw
    

    再来看一下我的配置文件,我将要使用webpack和rollup构建的项目分在了两个配置文件中,配置文件的内容与构建工具的使用方式的有分不开的关联的。Webpack和Rollup官方给出的配置项也是不同的,这里截取两个构建工具部分配置项:

  • Webpack部分配置项

    {
      entry: {...},
      output: {...},
      mode: "...",
      module: {
        rules: [...]
      }
      plugins: [...],
      ...
    }
    
  • Rollup部分配置项

    {
      input: "...",
      output: {
        file: "...",
        format: "...",
        ...
      },
      plugins: [...],
      watch: {...},
      ...
    }
    

我发现他们连入口文件的属性名和属性值的含义都不同,可想其他配置项也很难全部复用。因为配置项的不同所以使用Webpack构建的项目和使用Rollup构建的项目应该分别对待。但大体上我把配置文件看作是所有项目的集合,项目中至少包含一个构建过程(既有输入又有输出我称为一个构建过程),一个用Webpack构建的项目配置对象大概是这样的:

{
  rootPath: path.join(__dirname, "../projects/goma-cover/"),
  baseName: "index",
  library: "goma",
  libraryTarget: "umd",
  pages: [
    {
      input: "index.ts",
      output: {
        path: "../../sh/app/project/goma-cover/"
      },
    }
  ]
}

一个使用Rollup构建的项目的配置对象大概是这样的:


{
  name: "FUI",
  input: path.resolve(__dirname, "../projects/airglass-fui/index.js"),
  output: path.resolve(__dirname, "../sh/app/project/airglass-fui/js/main.js"),
  version: "1.0.0",
  year: "2019"
}

以上列出的我的项目的配置文件对其他人在做的项目应该没有太多的借鉴意义。但借鉴我的解决思路还是可以有的。

授权账号 » 
原创声明 » 未经授权,请勿复制转载,谢谢配合
联系方式 » 
微信:huazi19930927
邮箱:lanserdi@163.com
发布日期 » 2019年8月28日 周三
Github账号登录以留言