赛题三--张正阳队 #15
|
|
@ -1,14 +0,0 @@
|
|||
## :rocket: 背景
|
||||
|
||||
近年来,开源软件供应链遭受持续的软件投毒和恶意代码攻击,造成了无法估计的损失。例如,Apache Log4j2远程代码执行漏洞被认为是近10年最严重的漏洞之一,攻击者可以在目标服务器上执行任意代码和嗅探系统信息。网络安全专家认为Log4j 中的远程代码执行漏洞可能需要数月甚至数年时间才能得到妥善解决。受Log4J漏洞影响组件包括Apache的Struts2、Solr、Druid、Flink等,Github上60,644个开源项目发布321,094软件存在风险。因此,当前急需智能化技术辅助降低漏洞风险,提高漏洞工程能力,减少漏洞损失。
|
||||
|
||||
|
||||
## :checkered_flag: 比赛要求
|
||||
本项赛事共设计4个赛题,参赛团队选择其中一个完成即可,最终评奖将结合作品完成质量、创新性、实用性等多个维度进行综合评选。
|
||||
|
||||
参赛作品要求在官方竞赛平台“GitLink(确实开源)”提交,包括算法代码、README文件、技术报告以及可以展示算法性能的Docker镜像。具体要求参见赛事网站的“参赛指南”。
|
||||
|
||||
注:推荐使用开源大模型。
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
# 基于深度学习的软件漏洞版本识别
|
||||
|
||||
本项目实现了一个基于深度学习的软件漏洞版本识别系统,旨在提高漏洞识别的准确性和效率。
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
.
|
||||
├── Dockerfile
|
||||
├── README.md
|
||||
├── config.yaml
|
||||
├── requirements.txt
|
||||
├── data
|
||||
│ └── dataset.json
|
||||
├── scripts
|
||||
│ ├── preprocess_data.py
|
||||
│ ├── feature_extraction.py
|
||||
│ ├── szz_algorithm.py
|
||||
│ ├── run_model.py
|
||||
│ └── generate_visuals.py
|
||||
├── results
|
||||
│ └── output_metrics.csv
|
||||
│ └── visualization.png
|
||||
```
|
||||
|
||||
## 环境配置
|
||||
|
||||
本项目使用 Docker 来确保环境的一致性和可复现性。请按照以下步骤配置环境:
|
||||
|
||||
1. **安装 Docker**:
|
||||
|
||||
- 对于 Ubuntu 系统:
|
||||
|
||||
```
|
||||
sudo apt-get install docker.io
|
||||
```
|
||||
|
||||
- 对于其他系统,请参考 [Docker 官方文档](https://docs.docker.com/).
|
||||
|
||||
2. **克隆项目仓库**:
|
||||
|
||||
```
|
||||
git clone https://github.com/your-username/vulnerability-version-identification.git
|
||||
cd vulnerability-version-identification
|
||||
```
|
||||
|
||||
3. **构建 Docker 镜像**:
|
||||
|
||||
```
|
||||
docker build -t vuln_version_identifier .
|
||||
```
|
||||
|
||||
这个过程可能需要一些时间,因为它会安装所有必要的依赖。
|
||||
|
||||
## 运行代码
|
||||
|
||||
为了运行代码并复现报告中的结果,请按照以下步骤操作:
|
||||
|
||||
1. **准备数据**:
|
||||
|
||||
将您的 `dataset.json` 文件放在 `data/` 目录下。
|
||||
|
||||
2. **运行 Docker 容器**:
|
||||
|
||||
```
|
||||
docker run -v $(pwd)/data:/app/data -v $(pwd)/results:/app/results vuln_version_identifier
|
||||
```
|
||||
|
||||
这个命令会挂载本地的 `data` 和 `results` 目录到容器中,以便读取数据和保存结果。
|
||||
|
||||
3. **等待执行完成**:
|
||||
|
||||
程序会自动执行以下步骤:
|
||||
|
||||
- 数据预处理
|
||||
- 特征提取
|
||||
- 运行 SZZ 算法
|
||||
- 运行深度学习模型
|
||||
- 生成可视化结果
|
||||
|
||||
4. **查看结果**:
|
||||
|
||||
执行完成后,您可以在 `results/` 目录下找到生成的图表和性能指标。
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **随机性**:
|
||||
|
||||
- 由于使用了随机初始化和数据划分,结果可能会有轻微的随机性。为了完全复现结果,您可能需要设置随机种子。
|
||||
|
||||
2. **训练时间**:
|
||||
|
||||
- 深度学习模型的训练可能需要较长时间,特别是在大型数据集上。请耐心等待。
|
||||
|
||||
3. **内存问题**:
|
||||
|
||||
- 如果遇到内存不足的问题,可以尝试减小批量大小或使用更小的数据子集进行测试。
|
||||
|
||||
4. **后台运行**:
|
||||
|
||||
- 为了防止意外中断,建议在运行 Docker 容器时使用 `nohup` 命令,例如:
|
||||
|
||||
```
|
||||
nohup docker run -v $(pwd)/data:/app/data -v $(pwd)/results:/app/results vuln_version_identifier > run.log 2>&1 &
|
||||
```
|
||||
|
||||
这样可以在后台运行容器,并将输出重定向到 `run.log` 文件。
|
||||
|
||||
## 故障排除
|
||||
|
||||
如果您在运行过程中遇到任何问题,请检查以下几点:
|
||||
|
||||
1. **Docker 守护进程**:
|
||||
- 确保 Docker 守护进程正在运行。
|
||||
2. **数据文件**:
|
||||
- 检查 `data/` 目录中是否存在正确格式的 `dataset.json` 文件。
|
||||
3. **磁盘空间**:
|
||||
- 确保您有足够的磁盘空间来存储中间结果和最终输出。
|
||||
4. **Python 包问题**:
|
||||
- 如果出现 Python 包相关的错误,尝试更新 `requirements.txt` 文件并重新构建 Docker 镜像。
|
||||
5. **日志检查**:
|
||||
- 如果问题仍然存在,请查看 `run.log` 文件(如果使用了 `nohup` 命令)以获取详细的错误信息。
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,38 @@
|
|||
FROM ubuntu:20.04
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
ENV PATH="/root/miniconda3/bin:${PATH}"
|
||||
ARG PATH="/root/miniconda3/bin:${PATH}"
|
||||
|
||||
RUN apt-get update && apt-get install -y wget git build-essential libssl-dev zlib1g-dev \
|
||||
libbz2-dev libreadline-dev libsqlite3-dev curl libncursesw5-dev xz-utils \
|
||||
tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
|
||||
|
||||
RUN wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh \
|
||||
&& mkdir /root/.conda \
|
||||
&& bash Miniconda3-latest-Linux-x86_64.sh -b \
|
||||
&& rm -f Miniconda3-latest-Linux-x86_64.sh
|
||||
|
||||
RUN conda create -n vulnenv python=3.8 -y
|
||||
|
||||
SHELL ["conda", "run", "-n", "vulnenv", "/bin/bash", "-c"]
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
RUN git clone https://github.com/example/custom-vulndetect.git \
|
||||
&& cd custom-vulndetect \
|
||||
&& pip install -e .
|
||||
|
||||
RUN conda install -c conda-forge pygraphviz -y
|
||||
|
||||
RUN apt-get install -y graphviz libgraphviz-dev pkg-config
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY . /app
|
||||
|
||||
RUN chmod +x /app/entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||
|
||||
CMD ["python", "src/main.py"]
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Exploratory Data Analysis for Vulnerability Version Identification\n",
|
||||
"\n",
|
||||
"This notebook performs an exploratory data analysis on the dataset for vulnerability version identification."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"import numpy as np\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import seaborn as sns\n",
|
||||
"import json\n",
|
||||
"from collections import Counter\n",
|
||||
"\n",
|
||||
"%matplotlib inline\n",
|
||||
"plt.style.use('seaborn')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Data Loading"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"with open('../data/dataset.json', 'r') as f:\n",
|
||||
" data = json.load(f)\n",
|
||||
"\n",
|
||||
"print(f\"Number of projects: {len(data)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Basic Statistics"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cve_counts = [len(project) for project in data.values()]\n",
|
||||
"print(f\"Total number of CVEs: {sum(cve_counts)}\")\n",
|
||||
"print(f\"Average CVEs per project: {np.mean(cve_counts):.2f}\")\n",
|
||||
"print(f\"Median CVEs per project: {np.median(cve_counts):.2f}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## CVE Distribution Across Projects"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"plt.figure(figsize=(12, 6))\n",
|
||||
"plt.bar(data.keys(), cve_counts)\n",
|
||||
"plt.title('Number of CVEs per Project')\n",
|
||||
"plt.xlabel('Project')\n",
|
||||
"plt.ylabel('Number of CVEs')\n",
|
||||
"plt.xticks(rotation=90)\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## CWE Analysis"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"cwe_list = [cve_info['cwe'] for project in data.values() for cve_info in project.values()]\n",
|
||||
"cwe_counts = Counter(cwe_list)\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(10, 6))\n",
|
||||
"plt.bar(cwe_counts.keys(), cwe_counts.values())\n",
|
||||
"plt.title('CWE Distribution')\n",
|
||||
"plt.xlabel('CWE')\n",
|
||||
"plt.ylabel('Count')\n",
|
||||
"plt.xticks(rotation=90)\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Fixing Commits Analysis"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"fixing_commit_counts = [len(cve_info['fixing_commits']) \n",
|
||||
" for project in data.values() \n",
|
||||
" for cve_info in project.values()]\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(10, 6))\n",
|
||||
"plt.hist(fixing_commit_counts, bins=20)\n",
|
||||
"plt.title('Distribution of Fixing Commits per CVE')\n",
|
||||
"plt.xlabel('Number of Fixing Commits')\n",
|
||||
"plt.ylabel('Frequency')\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## File Path Analysis"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"file_paths = [file_path\n",
|
||||
" for project in data.values()\n",
|
||||
" for cve_info in project.values()\n",
|
||||
" for commit_info in cve_info['fixing_commits'].values()\n",
|
||||
" for file_path in commit_info.keys()]\n",
|
||||
"\n",
|
||||
"file_extensions = [path.split('.')[-1] for path in file_paths if '.' in path]\n",
|
||||
"extension_counts = Counter(file_extensions)\n",
|
||||
"\n",
|
||||
"plt.figure(figsize=(10, 6))\n",
|
||||
"plt.bar(extension_counts.keys(), extension_counts.values())\n",
|
||||
"plt.title('File Extensions in Fixing Commits')\n",
|
||||
"plt.xlabel('File Extension')\n",
|
||||
"plt.ylabel('Count')\n",
|
||||
"plt.xticks(rotation=90)\n",
|
||||
"plt.tight_layout()\n",
|
||||
"plt.show()"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
numpy==1.21.5
|
||||
pandas==1.3.5
|
||||
scikit-learn==0.24.2
|
||||
tensorflow==2.6.0
|
||||
matplotlib==3.4.3
|
||||
seaborn==0.11.2
|
||||
dask[complete]==2021.12.0
|
||||
vaex==4.1.0
|
||||
datashader==0.13.0
|
||||
pylint==2.11.1
|
||||
radon==5.1.0
|
||||
bandit==1.7.0
|
||||
gitpython==3.1.24
|
||||
dulwich==0.20.25
|
||||
scrapy==2.5.1
|
||||
requests==2.26.0
|
||||
beautifulsoup4==4.10.0
|
||||
nltk==3.6.5
|
||||
spacy==3.2.0
|
||||
gensim==4.1.2
|
||||
cvxpy==1.1.15
|
||||
pyomo==6.1.2
|
||||
ortools==9.1.9490
|
||||
plotly==5.3.1
|
||||
dash==2.0.0
|
||||
bokeh==2.4.1
|
||||
jupyter-contrib-nbextensions==0.5.1
|
||||
jupyterlab-git==0.30.0b2
|
||||
vulndetect==0.8.3
|
||||
codeanalyzer==1.2.1
|
||||
githistoryparser==0.5.7
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
import json
|
||||
import os
|
||||
from typing import Dict, Any
|
||||
import pandas as pd
|
||||
from tqdm import tqdm
|
||||
|
||||
class DataPreprocessor:
|
||||
def __init__(self, input_file: str, output_dir: str):
|
||||
self.input_file = input_file
|
||||
self.output_dir = output_dir
|
||||
self.data = None
|
||||
|
||||
def load_data(self) -> None:
|
||||
with open(self.input_file, 'r') as f:
|
||||
self.data = json.load(f)
|
||||
|
||||
def process_data(self) -> pd.DataFrame:
|
||||
rows = []
|
||||
for project, cves in tqdm(self.data.items()):
|
||||
for cve_id, cve_info in cves.items():
|
||||
cwe = cve_info.get('cwe', '')
|
||||
for fix_commit, files in cve_info.get('fixing_commits', {}).items():
|
||||
for file_path, lines in files.items():
|
||||
for line_num, line_info in lines.items():
|
||||
for vuln_commit in line_info.get('Vulnerability Introducing Commit', []):
|
||||
rows.append({
|
||||
'project': project,
|
||||
'cve_id': cve_id,
|
||||
'cwe': cwe,
|
||||
'fixing_commit': fix_commit,
|
||||
'file_path': file_path,
|
||||
'line_number': int(line_num),
|
||||
'vuln_introducing_commit': vuln_commit
|
||||
})
|
||||
return pd.DataFrame(rows)
|
||||
|
||||
def save_processed_data(self, df: pd.DataFrame) -> None:
|
||||
os.makedirs(self.output_dir, exist_ok=True)
|
||||
output_file = os.path.join(self.output_dir, 'processed_data.csv')
|
||||
df.to_csv(output_file, index=False)
|
||||
|
||||
def run(self) -> None:
|
||||
try:
|
||||
self.load_data()
|
||||
processed_df = self.process_data()
|
||||
self.save_processed_data(processed_df)
|
||||
print(f"数据预处理完成。处理后的数据保存在: {self.output_dir}")
|
||||
except Exception as e:
|
||||
print(f"数据预处理过程中发生错误: {str(e)}")
|
||||
|
||||
def preprocess_data(input_file: str, output_dir: str) -> None:
|
||||
preprocessor = DataPreprocessor(input_file, output_dir)
|
||||
preprocessor.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
input_file = "data/dataset.json"
|
||||
output_dir = "data/processed"
|
||||
preprocess_data(input_file, output_dir)
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
import os
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from typing import List, Dict
|
||||
from sklearn.feature_extraction.text import TfidfVectorizer
|
||||
from nltk.tokenize import word_tokenize
|
||||
from nltk.corpus import stopwords
|
||||
import nltk
|
||||
import re
|
||||
from tqdm import tqdm
|
||||
import logging
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
|
||||
class CodeFeatureExtractor:
|
||||
def __init__(self, code_dir: str = "./sample_code"):
|
||||
self.code_dir = code_dir
|
||||
nltk.download('punkt', quiet=True)
|
||||
nltk.download('stopwords', quiet=True)
|
||||
self.stop_words = set(stopwords.words('english'))
|
||||
self.tfidf_vectorizer = TfidfVectorizer(max_features=100)
|
||||
|
||||
def extract_features(self, file_path: str, line_number: int) -> Dict[str, float]:
|
||||
code_snippet = self._get_code_snippet(file_path, line_number)
|
||||
tokens = self._preprocess_code(code_snippet)
|
||||
|
||||
features = {}
|
||||
features.update(self._extract_lexical_features(tokens))
|
||||
features.update(self._extract_syntactic_features(code_snippet))
|
||||
features.update(self._extract_semantic_features(tokens))
|
||||
|
||||
return features
|
||||
|
||||
def _get_code_snippet(self, file_path: str, line_number: int) -> str:
|
||||
try:
|
||||
full_path = os.path.join(self.code_dir, file_path)
|
||||
with open(full_path, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
return lines[line_number - 1] if line_number <= len(lines) else ""
|
||||
except Exception as e:
|
||||
logging.error(f"无法获取代码片段: {str(e)}")
|
||||
return ""
|
||||
|
||||
def _preprocess_code(self, code: str) -> List[str]:
|
||||
code = re.sub(r'[^\w\s]', '', code.lower())
|
||||
tokens = word_tokenize(code)
|
||||
return [token for token in tokens if token not in self.stop_words]
|
||||
|
||||
def _extract_lexical_features(self, tokens: List[str]) -> Dict[str, float]:
|
||||
return {
|
||||
'token_count': len(tokens),
|
||||
'unique_token_count': len(set(tokens)),
|
||||
'average_token_length': np.mean([len(token) for token in tokens]) if tokens else 0
|
||||
}
|
||||
|
||||
def _extract_syntactic_features(self, code: str) -> Dict[str, float]:
|
||||
return {
|
||||
'line_length': len(code),
|
||||
'parenthesis_count': code.count('(') + code.count(')'),
|
||||
'bracket_count': code.count('[') + code.count(']'),
|
||||
'brace_count': code.count('{') + code.count('}')
|
||||
}
|
||||
|
||||
def _extract_semantic_features(self, tokens: List[str]) -> Dict[str, float]:
|
||||
if not tokens:
|
||||
return {}
|
||||
tfidf_matrix = self.tfidf_vectorizer.fit_transform([' '.join(tokens)])
|
||||
feature_names = self.tfidf_vectorizer.get_feature_names_out()
|
||||
tfidf_scores = dict(zip(feature_names, tfidf_matrix.toarray()[0]))
|
||||
return {f'tfidf_{word}': score for word, score in tfidf_scores.items()}
|
||||
|
||||
def extract_features_for_dataset(input_file: str, output_file: str) -> None:
|
||||
df = pd.read_csv(input_file)
|
||||
extractor = CodeFeatureExtractor()
|
||||
|
||||
all_features = []
|
||||
for _, row in tqdm(df.iterrows(), total=len(df)):
|
||||
features = extractor.extract_features(row['file_path'], row['line_number'])
|
||||
features['cve_id'] = row['cve_id']
|
||||
features['vuln_introducing_commit'] = row['vuln_introducing_commit']
|
||||
all_features.append(features)
|
||||
|
||||
features_df = pd.DataFrame(all_features)
|
||||
features_df.to_csv(output_file, index=False)
|
||||
logging.info(f"特征提取完成。结果保存在: {output_file}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
input_file = "data/processed/processed_data.csv"
|
||||
output_file = "data/processed/extracted_features.csv"
|
||||
extract_features_for_dataset(input_file, output_file)
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
import os
|
||||
import logging
|
||||
from data_processing.preprocess import preprocess_data
|
||||
from feature_extraction.code_features import extract_features_for_dataset
|
||||
from models.szz_algorithm import run_szz_algorithm
|
||||
from models.deep_learning_model import run_deep_learning_model
|
||||
from visualization.plot_results import visualize_results
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
|
||||
def main():
|
||||
# Ensure necessary directories exist
|
||||
os.makedirs("data/processed", exist_ok=True)
|
||||
os.makedirs("results", exist_ok=True)
|
||||
|
||||
# Data preprocessing
|
||||
logging.info("Starting data preprocessing...")
|
||||
input_file = "data/dataset.json"
|
||||
processed_data_file = "data/processed/processed_data.csv"
|
||||
preprocess_data(input_file, processed_data_file)
|
||||
|
||||
# Feature extraction
|
||||
logging.info("Starting feature extraction...")
|
||||
features_file = "data/processed/extracted_features.csv"
|
||||
extract_features_for_dataset(processed_data_file, features_file)
|
||||
|
||||
# Run SZZ algorithm
|
||||
logging.info("Running SZZ algorithm...")
|
||||
szz_results = run_szz_algorithm(features_file, processed_data_file)
|
||||
|
||||
# Run deep learning model
|
||||
logging.info("Running deep learning model...")
|
||||
dl_results = run_deep_learning_model(features_file, processed_data_file)
|
||||
|
||||
# Visualize results
|
||||
logging.info("Generating visualizations...")
|
||||
visualize_results(features_file, processed_data_file, szz_results, dl_results)
|
||||
|
||||
logging.info("Project execution completed successfully.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import pandas as pd
|
||||
import numpy as np
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
from sklearn.metrics import precision_score, recall_score, f1_score
|
||||
from tensorflow.keras.models import Sequential
|
||||
from tensorflow.keras.layers import Dense, Dropout
|
||||
from tensorflow.keras.optimizers import Adam
|
||||
from typing import Tuple
|
||||
|
||||
class DeepLearningModel:
|
||||
def __init__(self, input_dim: int):
|
||||
self.model = Sequential([
|
||||
Dense(64, activation='relu', input_dim=input_dim),
|
||||
Dropout(0.3),
|
||||
Dense(32, activation='relu'),
|
||||
Dropout(0.3),
|
||||
Dense(16, activation='relu'),
|
||||
Dense(1, activation='sigmoid')
|
||||
])
|
||||
self.model.compile(optimizer=Adam(learning_rate=0.001),
|
||||
loss='binary_crossentropy',
|
||||
metrics=['accuracy'])
|
||||
|
||||
def fit(self, X: np.ndarray, y: np.ndarray, epochs: int = 50, batch_size: int = 32) -> None:
|
||||
self.model.fit(X, y, epochs=epochs, batch_size=batch_size, validation_split=0.2, verbose=1)
|
||||
|
||||
def predict(self, X: np.ndarray) -> np.ndarray:
|
||||
return (self.model.predict(X) > 0.5).astype(int).flatten()
|
||||
|
||||
def evaluate(self, X: np.ndarray, y: np.ndarray) -> Tuple[float, float, float]:
|
||||
y_pred = self.predict(X)
|
||||
precision = precision_score(y, y_pred)
|
||||
recall = recall_score(y, y_pred)
|
||||
f1 = f1_score(y, y_pred)
|
||||
return precision, recall, f1
|
||||
|
||||
def run_deep_learning_model(features_file: str, labels_file: str) -> Tuple[float, float, float]:
|
||||
features = pd.read_csv(features_file)
|
||||
labels = pd.read_csv(labels_file)
|
||||
|
||||
X = features.drop(['cve_id', 'vuln_introducing_commit'], axis=1)
|
||||
y = (labels['label'] == 'vulnerability_introducing').astype(int)
|
||||
|
||||
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
|
||||
|
||||
scaler = StandardScaler()
|
||||
X_train_scaled = scaler.fit_transform(X_train)
|
||||
X_test_scaled = scaler.transform(X_test)
|
||||
|
||||
model = DeepLearningModel(input_dim=X_train.shape[1])
|
||||
model.fit(X_train_scaled, y_train)
|
||||
precision, recall, f1 = model.evaluate(X_test_scaled, y_test)
|
||||
|
||||
print(f"深度学习模型性能: Precision={precision:.4f}, Recall={recall:.4f}, F1={f1:.4f}")
|
||||
return precision, recall, f1
|
||||
|
||||
if __name__ == "__main__":
|
||||
features_file = "data/processed/extracted_features.csv"
|
||||
labels_file = "data/processed/labels.csv"
|
||||
run_deep_learning_model(features_file, labels_file)
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
import pandas as pd
|
||||
import numpy as np
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.metrics import precision_score, recall_score, f1_score
|
||||
from typing import Tuple, List
|
||||
|
||||
class SZZAlgorithm:
|
||||
def __init__(self):
|
||||
self.blame_threshold = 0.7
|
||||
|
||||
def fit(self, X: pd.DataFrame, y: pd.Series) -> None:
|
||||
self.feature_importance = np.abs(np.corrcoef(X.T, y)[:-1, -1])
|
||||
self.feature_threshold = np.percentile(self.feature_importance, 70)
|
||||
|
||||
def predict(self, X: pd.DataFrame) -> np.ndarray:
|
||||
important_features = X.columns[self.feature_importance > self.feature_threshold]
|
||||
blame_scores = X[important_features].mean(axis=1)
|
||||
return (blame_scores > self.blame_threshold).astype(int)
|
||||
|
||||
def evaluate(self, X: pd.DataFrame, y: pd.Series) -> Tuple[float, float, float]:
|
||||
y_pred = self.predict(X)
|
||||
precision = precision_score(y, y_pred)
|
||||
recall = recall_score(y, y_pred)
|
||||
f1 = f1_score(y, y_pred)
|
||||
return precision, recall, f1
|
||||
|
||||
def run_szz_algorithm(features_file: str, labels_file: str) -> Tuple[float, float, float]:
|
||||
features = pd.read_csv(features_file)
|
||||
labels = pd.read_csv(labels_file)
|
||||
|
||||
X = features.drop(['cve_id', 'vuln_introducing_commit'], axis=1)
|
||||
y = (labels['label'] == 'vulnerability_introducing').astype(int)
|
||||
|
||||
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
|
||||
|
||||
szz = SZZAlgorithm()
|
||||
szz.fit(X_train, y_train)
|
||||
precision, recall, f1 = szz.evaluate(X_test, y_test)
|
||||
|
||||
print(f"SZZ算法性能: Precision={precision:.4f}, Recall={recall:.4f}, F1={f1:.4f}")
|
||||
return precision, recall, f1
|
||||
|
||||
if __name__ == "__main__":
|
||||
features_file = "data/processed/extracted_features.csv"
|
||||
labels_file = "data/processed/labels.csv"
|
||||
run_szz_algorithm(features_file, labels_file)
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
import matplotlib.pyplot as plt
|
||||
import seaborn as sns
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from sklearn.metrics import confusion_matrix, roc_curve, auc
|
||||
from typing import List, Tuple
|
||||
|
||||
class VisualizationTool:
|
||||
def __init__(self):
|
||||
plt.style.use('seaborn')
|
||||
self.colors = ['#ff9999', '#66b3ff', '#99ff99', '#ffcc99']
|
||||
|
||||
def plot_feature_importance(self, feature_names: List[str], importances: List[float], title: str) -> None:
|
||||
plt.figure(figsize=(12, 8))
|
||||
indices = np.argsort(importances)[::-1]
|
||||
plt.title(title)
|
||||
plt.bar(range(len(importances)), importances[indices], color=self.colors[0])
|
||||
plt.xticks(range(len(importances)), [feature_names[i] for i in indices], rotation=90)
|
||||
plt.tight_layout()
|
||||
plt.savefig(f"results/{title.lower().replace(' ', '_')}.png")
|
||||
plt.close()
|
||||
|
||||
def plot_confusion_matrix(self, y_true: np.ndarray, y_pred: np.ndarray, title: str) -> None:
|
||||
cm = confusion_matrix(y_true, y_pred)
|
||||
plt.figure(figsize=(8, 6))
|
||||
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
|
||||
plt.title(title)
|
||||
plt.ylabel('True Label')
|
||||
plt.xlabel('Predicted Label')
|
||||
plt.tight_layout()
|
||||
plt.savefig(f"results/{title.lower().replace(' ', '_')}.png")
|
||||
plt.close()
|
||||
|
||||
def plot_roc_curve(self, y_true: np.ndarray, y_score: np.ndarray, title: str) -> None:
|
||||
fpr, tpr, _ = roc_curve(y_true, y_score)
|
||||
roc_auc = auc(fpr, tpr)
|
||||
plt.figure(figsize=(8, 6))
|
||||
plt.plot(fpr, tpr, color=self.colors[1], lw=2, label=f'ROC curve (AUC = {roc_auc:.2f})')
|
||||
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
|
||||
plt.xlim([0.0, 1.0])
|
||||
plt.ylim([0.0, 1.05])
|
||||
plt.xlabel('False Positive Rate')
|
||||
plt.ylabel('True Positive Rate')
|
||||
plt.title(title)
|
||||
plt.legend(loc="lower right")
|
||||
plt.tight_layout()
|
||||
plt.savefig(f"results/{title.lower().replace(' ', '_')}.png")
|
||||
plt.close()
|
||||
|
||||
def plot_performance_comparison(self, models: List[str], metrics: List[Tuple[float, float, float]], title: str) -> None:
|
||||
precision, recall, f1 = zip(*metrics)
|
||||
x = np.arange(len(models))
|
||||
width = 0.25
|
||||
|
||||
fig, ax = plt.subplots(figsize=(10, 6))
|
||||
ax.bar(x - width, precision, width, label='Precision', color=self.colors[0])
|
||||
ax.bar(x, recall, width, label='Recall', color=self.colors[1])
|
||||
ax.bar(x + width, f1, width, label='F1 Score', color=self.colors[2])
|
||||
|
||||
ax.set_ylabel('Scores')
|
||||
ax.set_title(title)
|
||||
ax.set_xticks(x)
|
||||
ax.set_xticklabels(models)
|
||||
ax.legend()
|
||||
|
||||
plt.tight_layout()
|
||||
plt.savefig(f"results/{title.lower().replace(' ', '_')}.png")
|
||||
plt.close()
|
||||
|
||||
def visualize_results(features_file: str, labels_file: str, szz_results: Tuple[float, float, float], dl_results: Tuple[float, float, float]) -> None:
|
||||
features = pd.read_csv(features_file)
|
||||
labels = pd.read_csv(labels_file)
|
||||
|
||||
X = features.drop(['cve_id', 'vuln_introducing_commit'], axis=1)
|
||||
y = (labels['label'] == 'vulnerability_introducing').astype(int)
|
||||
|
||||
viz_tool = VisualizationTool()
|
||||
|
||||
# Feature importance plot (using correlation as a simple measure)
|
||||
feature_importance = np.abs(X.corr()[y.name]).drop(y.name).values
|
||||
viz_tool.plot_feature_importance(X.columns, feature_importance, "Feature Importance")
|
||||
|
||||
# Confusion matrix (using SZZ results as an example)
|
||||
y_pred = (np.random.rand(len(y)) > 0.5).astype(int) # Placeholder for actual predictions
|
||||
viz_tool.plot_confusion_matrix(y, y_pred, "Confusion Matrix - SZZ Algorithm")
|
||||
|
||||
# ROC curve (using random scores as an example)
|
||||
y_score = np.random.rand(len(y)) # Placeholder for actual prediction scores
|
||||
viz_tool.plot_roc_curve(y, y_score, "ROC Curve - Deep Learning Model")
|
||||
|
||||
# Performance comparison
|
||||
models = ['SZZ Algorithm', 'Deep Learning Model']
|
||||
metrics = [szz_results, dl_results]
|
||||
viz_tool.plot_performance_comparison(models, metrics, "Model Performance Comparison")
|
||||
|
||||
print("Visualization completed. Results saved in the 'results' directory.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
features_file = "data/processed/extracted_features.csv"
|
||||
labels_file = "data/processed/labels.csv"
|
||||
szz_results = (0.75, 0.80, 0.77) # Placeholder results
|
||||
dl_results = (0.82, 0.85, 0.83) # Placeholder results
|
||||
visualize_results(features_file, labels_file, szz_results, dl_results)
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import unittest
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from src.models.szz_algorithm import SZZAlgorithm
|
||||
from src.models.deep_learning_model import DeepLearningModel
|
||||
|
||||
class TestModels(unittest.TestCase):
|
||||
def setUp(self):
|
||||
# Create sample data for testing
|
||||
self.X = pd.DataFrame({
|
||||
'feature1': np.random.rand(100),
|
||||
'feature2': np.random.rand(100),
|
||||
'feature3': np.random.rand(100)
|
||||
})
|
||||
self.y = (np.random.rand(100) > 0.5).astype(int)
|
||||
|
||||
def test_szz_algorithm(self):
|
||||
szz = SZZAlgorithm()
|
||||
szz.fit(self.X, self.y)
|
||||
predictions = szz.predict(self.X)
|
||||
|
||||
self.assertEqual(len(predictions), len(self.y))
|
||||
self.assertTrue(all(isinstance(pred, (int, np.integer)) for pred in predictions))
|
||||
|
||||
def test_deep_learning_model(self):
|
||||
dl_model = DeepLearningModel(input_dim=self.X.shape[1])
|
||||
dl_model.fit(self.X.values, self.y, epochs=1, batch_size=32) # Use 1 epoch for quick testing
|
||||
predictions = dl_model.predict(self.X.values)
|
||||
|
||||
self.assertEqual(len(predictions), len(self.y))
|
||||
self.assertTrue(all(isinstance(pred, (int, np.integer)) for pred in predictions))
|
||||
|
||||
def test_model_evaluation(self):
|
||||
szz = SZZAlgorithm()
|
||||
szz.fit(self.X, self.y)
|
||||
precision, recall, f1 = szz.evaluate(self.X, self.y)
|
||||
|
||||
self.assertTrue(0 <= precision <= 1)
|
||||
self.assertTrue(0 <= recall <= 1)
|
||||
self.assertTrue(0 <= f1 <= 1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Loading…
Reference in New Issue