不小心把包含灵敏信息的代码提交到线上了怎么办…
为了避免这种状况再次发生,靠记忆来约束自己是靠不住的,所以完成一个快速扫描灵敏代码的钩子,然后通过东西来约束自己就显得非常有必要。
下面是快速完成流程:
-
commitlint+husky
标准git提交; - 触发git hooks钩子
pre-commit
; - child_process进程获取commit信息;
- 获取提交文件内容;
- 代码过滤;
- 扫描出灵敏信息停止commit。
一、commitlint+husky
这个网上太多资料,简略讲下流程。按次序履行以下流程
1. 履行命令
npm install --save-dev husky @commitlint/cli @commitlint/config-conventional
npx husky install
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'
2. 根目录新建commitlint.config.js
/*
标准commit日志
https://commitlint.js.org
*/
const types = [
'build', // 主要意图是修正项目构建体系(例如glup,webpack,rollup的装备等)的提交
'ci', // 修正项意图继续集成流程(Kenkins、Travis等)的提交
'chore', // 构建进程或辅助东西的改变
'docs', // 文档提交(documents)
'feat', // 新增功用(feature)
'fix', // 修复 bug
'pref', // 功用、体验相关的提交
'refactor', // 代码重构
'revert', // 回滚某个更早的提交
'style', // 不影响程序逻辑的代码修正、主要是款式方面的优化、修正
'test', // 测验相关的开发,
],
typeEnum = {
rules: {
'type-enum': [2, 'always', types],
},
value: () => {
return types;
},
};
module.exports = {
extends: ['@commitlint/config-conventional'],
/*
Level [0..2]: 0 disables the rule. For 1 it will be considered a warning for 2 an error.
https://commitlint.js.org/#/reference-rules
*/
rules: {
'type-enum': typeEnum.rules['type-enum'],
'subject-full-stop': [0, 'never'],
'subject-case': [0, 'never'],
},
};
3. 验证
git add .
git commit -m "提交测验" # 错误
git commit -m "feat: 提交测验" # 正确
二、pre-commit钩子
上面现已完成了commit-msg
的检测及约束,接下来是本次要点用到的钩子pre-commit
来完成代码扫描功用。
1. 新增pre-commit的husky
创立对应husky文件。
npx husky add .husky/pre-commit 'npm run pre-commit'
2. package.json
上面的命令除了新增pre-commit
的husky文件,还增加了内容,触发pre-commit
的时分履行npm run pre-commit
,所以要在scripts
中新增以下代码
"pre-commit": "node pre-commit.js",
3. pre-commit.js
然后接下来就是创立pre-commit.js
,并完成事务逻辑。
touch pre-commit.js
随意在pre-commit.js
新增点内容如console.log('pre-commit');
履行git add . && git commit -m "asd"
能够看到新增内容的输出及不契合提交规矩的正告信息,表明想要完成的需求的基础条件都已具备了。
接下来完成commit
相关文件内容的提取。
三、获取commit信息
获取git进程信息,能够直接用node的子进程器child_process
来完成。
commit基本信息
新增以下代码
const childProcess = require('child_process');
// 提交记录
const commitStages = childProcess.execSync('git diff --name-status HEAD~3', {
encoding: 'utf8',
});
console.log('提交记录:', commitStages);
然后履行node pre-commit.js
能够看到控制台输出这次提交的相关文件列表。
% node pre-commit.js
M .gitignore
D pre-commit.js
D src/test copy.js
D src/test.js
获取到提交的文件列表,接下来的就好办了。
四、获取文件内容
依据控制台输出,能够看到被追寻的文件前都有一个大写字母+一段空格。
简略解释下大写字母的含义:M:修正,D:删去 A:新增
接下来处理文件问题
1. 获取契合文件类型的文件列表
由于git commit
的时分还会有其他信息,所以要依据契合提交的文件类型过滤。
/**
* @description 获取类型清单
* @param {*} arr
* @param {*} type M:修正,D:删去 A:新增
* @returns
*/
const getArrList = (str, type) => {
const arr = str.split('\n');
return arr.filter(item => {
const regex = new RegExp(`[${type}].*`);
if (regex.test(item)) {
return item !== undefined;
}
});
};
2. 移除文件类型前缀及空格
// 格式化--移除 M [fileName].[fileType]之间的空格
const formatList = (arr, type) => {
return arr.map(item => {
return item.replace(/\s/, '').replace(type, '');
});
};
3. 获取过滤的文件列表
依据上面两个函数,能够过滤出修正和新增的文件,删去的不需求扫描,因此不过滤。。
// M:修正,D:删去 A:新增
const typeList = ['M', 'A'];
let fileList = [];
typeList.forEach(type => {
let arr = getArrList(commitStages, type);
arr = formatList(arr, type);
// 提交文件list
fileList = fileList.concat(arr);
});
接着履行node pre-commit.js
能够看到控制台输出提交的文件list及其间非删去文件的list。
% node pre-commit.js
M .gitignore
D pre-commit.js
D src/test copy.js
D src/test.js
非删去文件 .gitignore
拿到最终需求过滤的文件list,接下来往下走。
五、代码过滤
1. 代码扫描
-
fs模块解析文件
先运用
fs.readFileSync
解析,获取文件代码内容const codes = fs.readFileSync(fileName, { encoding: 'utf-8' });
-
然后界说灵敏词汇
const censetiveWords = ['hahahha']
-
接着扫描代码
/** * 扫描代码:是否有关键字 */ let flag = false; // 是否有关键字 for (const code of words.filter(str => str)) { flag = codes.includes(code); if (flag) { console.log(`${fileName} 检测到灵敏代码 ${code}!!!`); break; } }
2. 停止commit
程序
假如上面的程序扫描到灵敏词汇,履行停止提交程序。
if (flag) {
// 退出进程
process.exit(1);
}
由于是node环境,能够直接运用process
来停止进程。
接下来功用验证。
3. 验证
-
随意新建一个文件
src/test.js
,增加内容console.log('这是需求检测的代码 baidu.com');
-
pre-commit.js
增加灵敏词汇// 灵敏关键字 const censetiveWords = ['baidu.com'];
-
提交commit
% git add . % git commit -m "feat: test" > hy-cli@0.0.1 pre-commit > node pre-commit.js src/test.js 检测到灵敏代码 baidu.com!!! husky - pre-commit hook exited with code 1 (error)
能够看到控制台现已输出灵敏代码的正告信息,并退出
git commit
的进程husky - pre-commit hook exited with code 1 (error)
。至此完成完好功用,并自测通过。
六、.gitignore
上面完成了所有git追寻文件的过滤,但是在界说censetiveWords
的时分,界说的当时文件也会被检测到,所以扫描代码的时分也要把当时文件剔除掉。
所以还有两点要注意
1. 不扫描当时文件
在扫描代码之前,增加判断
// 当时文件pre-commit.js--已撤销git盯梢
const currentPath = __filename
// 扫描文件
const __path = __dirname + '/' + fileName
if (__path !== currentPath) {
// 代码扫描
}
2. 当时文件不追寻
当时文件不会提交到线上,界说的灵敏词汇天然也就不会被上传
# .gitignore
# 灵敏代码检测
pre-commit.js
总结
此次完成归根于一次代码上传失误事端,除了当时的完成,信任也有更好的方案规避这类问题~
人总是懒散的,能依靠东西规避的问题,尽量不要靠人为去约束。
最终是完成源码,其实很简略:
const fs = require('fs');
const childProcess = require('child_process');
/**
* __dirname 当时文件夹途径
* __filename 当时文件途径
*/
// 提交记录
// PS: 假如是新项目第一次提交,能够 HEAD~3 换成 HEAD~1
const commitStages = childProcess.execSync('git diff --name-status HEAD~3', {
encoding: 'utf8',
});
/**
* @description 获取类型清单
* @param {*} arr
* @param {*} type M:修正,D:删去 A:新增
* @returns
*/
const getArrList = (str, type) => {
const arr = str.split('\n');
return arr.filter(item => {
const regex = new RegExp(`[${type}].*`);
if (regex.test(item)) {
return item !== undefined;
}
});
};
// 格式化--移除 M [fileName].[fileType]之间的空格
const formatList = (arr, type) => {
return arr.map(item => {
return item.replace(/\s/, '').replace(type, '');
});
};
/**
* @returns 获取commit files
* PS:不过滤删去的文件
*/
function commitFiles() {
const typeList = ['M', 'A'];
let fileList = [];
typeList.forEach(type => {
let arr = getArrList(commitStages, type);
arr = formatList(arr, type);
// 提交文件list
fileList = fileList.concat(arr);
});
return fileList;
}
// 灵敏关键字扫描
function scaner(fileList = [], words = []) {
// const wordsStr = JSON.stringify(words)
// 当时文件--已撤销git盯梢
const currentPath = __filename
// 文件扫描
for (const fileName of fileList) {
const __path = __dirname + '/' + fileName
if (__path !== currentPath) {
const codes = fs.readFileSync(__path, { encoding: 'utf-8' });
/**
* 扫描代码:是否有关键字
*/
let flag = false; // 是否有关键字
for (const code of words.filter(str => str)) {
flag = codes.includes(code);
if (flag) {
console.log(`${fileName} 检测到灵敏代码 ${code}!!!`);
break;
}
}
if (flag) {
// 退出进程
process.exit(1);
}
}
}
}
// 灵敏关键字
const censetiveWords = ['commit'];
scaner(commitFiles(), censetiveWords);