Skip to content

Commit

Permalink
Merge pull request #6 from syn-4ck/dev
Browse files Browse the repository at this point in the history
Send refactors to main
  • Loading branch information
syn-4ck committed Nov 20, 2023
2 parents 68620fe + 5c3f6bd commit 6ff4839
Show file tree
Hide file tree
Showing 20 changed files with 1,138 additions and 260 deletions.
6 changes: 6 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "daily"
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ To check the options available in the CLI, you can run the following command:

* **--disable-apis**: Disable API requests to get external information

* **--verbose**: Verbose mode

### Recommendations

* Previous project build/compilation
Expand All @@ -83,7 +85,7 @@ To check the options available in the CLI, you can run the following command:

## Configuration

TO DO
The Fafnir configuration file, defined with the `--configuration` flag, may be defined with a YAML structure. You can see a full example of this file in [this repository](configuration_file/fafnir_config.yml). You can download it, fill it and then use it in your future scans.

## Security tools

Expand Down Expand Up @@ -120,6 +122,28 @@ To know the supported languages and technologies, review the integrated tools.

## Supported languages and technologies

|Language|Supported SAST|Supported extensions (SAST)|Supported SCA|Supported SCA files|
|----|--------|------|---------|-----------|
|Python|:white_check_mark:|.py / .pyc|:white_check_mark:|Pipfile.lock / poetry.lock / requirements.txt / .egg / .dist-info/META-DATA / envs/*/conda-meta/*.json|
|Java|:white_check_mark:|.java / .jar / .war / .ear|:white_check_mark:||
|JS & TS|:white_check_mark:|.js / .ts|:white_check_mark:||
|Go|:white_check_mark:|.go|:white_check_mark:||
|C / C++ / C#|:white_check_mark:|.c / .cpp / .cs|:white_check_mark:||
|Kotlin|:white_check_mark:|.kt|:white_check_mark:||
|PHP|:white_check_mark:|.php|:white_check_mark:||
|Ruby on rails|:x:||:x:||
|Lua|:x:||:x:||
|Batch file|:x:||:x:||
|Powershell script|:x:||:x:||

|Technologies|Supported|Supported extensions|
|--------|-------|------|
|Secrets|:white_check_mark:|All files|
|IaC|:white_check_mark:|.tf|
|Containers|:white_check_mark:|Dockerfile / Local builded images|
|SBOM generator|:white_check_mark:|Python / Java / JS / Go / C / C++ / C# / Kotlin / PHP|
|DAST|:x:|URL|

## FAQ

### PermissionError due to Docker container run
Expand Down
2 changes: 1 addition & 1 deletion configuration_file/fafnir_config.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
exclude-tools: # Uncomment the tools you want to exclude from analysis
#exclude-tools: # Uncomment the tools you want to exclude from analysis
#- semgrep
#- bandit
#- find-sec-bugs
Expand Down
2 changes: 1 addition & 1 deletion src/config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ technologies:
extensions: ['.js']
tools: ['trivy-sca','osv-scanner','syft','semgrep','gitleaks']
typescript:
extensions: ['.js']
extensions: ['.ts']
tools: ['trivy-sca','osv-scanner','syft','semgrep','gitleaks']
go:
extensions: ['.go']
Expand Down
77 changes: 47 additions & 30 deletions src/core/technology_detection/detect_technologies.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,58 @@
import os

#from guesslang import Guess

def _detect_technologies (code_path):
technologies = []
for root,_,f_names in os.walk(code_path):
for f in f_names:
tech = _guess_programming_language_from_extension(os.path.join(root, f))
if tech is not None:
technologies.append(tech)
return list(dict.fromkeys(technologies))

def _guess_programming_language_from_extension (filepath):
from typing import List, Dict

def _detect_technologies(code_path: str) -> List[str]:
"""
Detects the programming technologies used in the given code path.
Args:
code_path: The path to the directory containing the code.
Returns:
A list of programming technologies used in the code.
"""
return list(set(_guess_programming_language_from_extension(os.path.join(root, f))
for root, _, f_names in os.walk(code_path)
for f in f_names
if _guess_programming_language_from_extension(os.path.join(root, f))))

def _guess_programming_language_from_extension(filepath: str) -> str:
"""
Guesses the programming language based on the file extension of the given file path.
Parameters:
filepath (str): The path of the file.
Returns:
str: The file extension indicating the programming language.
"""
_, file_extension = os.path.splitext(filepath)
return file_extension

def select_tools(scan_fullpath, config, fafnir_configuration):
def select_tools(scan_fullpath: str, config: Dict[str, dict], fafnir_configuration: Dict[str, list]) -> List[str]:
"""
Generates a list of tools based on the detected technologies in the given scan_fullpath.
list_tools = []
Parameters:
- scan_fullpath (str): The full path of the scan.
- config (Dict[str, dict]): The configuration dictionary.
- fafnir_configuration (Dict[str, list]): The fafnir configuration dictionary.
technologies = _detect_technologies(scan_fullpath)
Returns:
- list[str]: A list of tools based on the detected technologies, excluding any tools specified in the fafnir configuration.
exclude_tools = []
if fafnir_configuration.get('exclude-tools') is not None:
exclude_tools = fafnir_configuration.get('exclude-tools')
"""
technologies = _detect_technologies(scan_fullpath)
exclude_tools = fafnir_configuration.get('exclude-tools', [])

for tech in list(config.get('technologies').keys()):
supported_technologies = config.get('technologies').get(tech).get('extensions')
for code_technology in technologies:
if code_technology in supported_technologies:
list_tools.extend(x for x in config.get('technologies').get(tech).get('tools') if x not in list_tools and x not in exclude_tools)
list_tools = [
tool
for tech in config.get('technologies').keys()
for code_technology in technologies
if code_technology in config.get('technologies').get(tech).get('extensions')
for tool in config.get('technologies').get(tech).get('tools')
if tool not in exclude_tools
]

return list_tools

# Deprecated: Not so eficient
#def _guess_programming_language_from_file (filepath):
# with open(filepath, 'r') as file:
# file_content = file.read()
# guess = Guess()
# return guess.language_name(file_content)
30 changes: 21 additions & 9 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import yaml
import docker
import click
import os
from typing import Optional

from core.run_containers import run_tools
from config.banner.banner import print_banner
Expand All @@ -10,27 +12,37 @@

VERSION = '1.0.0'

#volume = "/home/julian/workspace/fafnir/src"

@click.command()
@click.argument('scan_fullpath')
@click.option("--verbose", is_flag=True, show_default=True, default=False, help="Verbose mode")
@click.option("--configuration", help="Fafnir configuration file")
@click.option("--asynchronous", is_flag=True, show_default=True, default=False, help="Asynchronous mode (run multiple containers at same time)")
@click.option("--output-path", default=".", help="Path to store the tools/Fafnir report")
@click.option("--asynchronous", is_flag=True, show_default=True, default=False, help="Asynchronous mode")
@click.option("--output-path", default=os.path.join(os.path.abspath("."),"reports"), help="Path to store the tools/Fafnir report")
@click.option("--disable-apis", is_flag=True, show_default=True, default=True, help="Disable API requests")
def main(scan_fullpath, verbose, configuration, asynchronous, output_path, disable_apis):
def main(scan_fullpath: str, verbose: bool, configuration: Optional[str],
asynchronous: bool, output_path: str, disable_apis: bool) -> None:
"""
Run the main function of the program.
Args:
scan_fullpath (str): The full path of the scan.
verbose (bool): Flag indicating whether to run in verbose mode.
configuration (str): The file path of the Fafnir configuration file.
asynchronous (bool): Flag indicating whether to run in asynchronous mode.
output_path (str): The path to store the Fafnir report.
disable_apis (bool): Flag indicating whether to disable API requests.
Returns:
None
"""

print_banner(VERSION)

client = docker.from_env()

config = yaml.safe_load(open("src/config/config.yml"))

if configuration:
fafnir_config = yaml.safe_load(open(configuration))
else:
fafnir_config = None
fafnir_config = yaml.safe_load(open(configuration)) if configuration else None

tools = select_tools(scan_fullpath, config, fafnir_config)

Expand Down
154 changes: 153 additions & 1 deletion src/report/data_schema/dependency.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,163 @@

class Dependency:

def __init__(self, name, version, location, package_manager, language, licenses, purl):
def __init__(self) -> None:
pass

'''
def __init__(self, name:str, version:str, location:str, package_manager:str, language, licenses, purl):
self.name = name
self.version = version
self.location = location
self.package_manager = package_manager
self.language = language
self.licenses = licenses
self.purl = purl
'''

def get_name(self):
"""
Get the name attribute.
Returns:
str: The name attribute.
"""
return self.name

def set_name(self, name):
"""
Set the name attribute.
Parameters:
name (str): The new name attribute.
Returns:
None
"""
self.name = name

def get_version(self):
"""
Get the version attribute.
Returns:
str: The version attribute.
"""
return self.version

def set_version(self, version):
"""
Set the version attribute.
Parameters:
version (str): The new version attribute.
Returns:
None
"""
self.version = version

def get_location(self):
"""
Get the location attribute.
Returns:
str: The location attribute.
"""
return self.location

def set_location(self, location):
"""
Set the location attribute.
Parameters:
location (str): The new location attribute.
Returns:
None
"""
self.location = location

def get_package_manager(self):
"""
Get the package_manager attribute.
Returns:
str: The package_manager attribute.
"""
return self.package_manager

def set_package_manager(self, package_manager):
"""
Set the package_manager attribute.
Parameters:
package_manager (str): The new package_manager attribute.
Returns:
None
"""
self.package_manager = package_manager

def get_language(self):
"""
Get the language attribute.
Returns:
str: The language attribute.
"""
return self.language

def set_language(self, language):
"""
Set the language attribute.
Parameters:
language (str): The new language attribute.
Returns:
None
"""
self.language = language

def get_licenses(self):
"""
Get the licenses attribute.
Returns:
list: The licenses attribute.
"""
return self.licenses

def set_licenses(self, licenses):
"""
Set the licenses attribute.
Parameters:
licenses (list): The new licenses attribute.
Returns:
None
"""
self.licenses = licenses

def get_purl(self):
"""
Get the purl attribute.
Returns:
str: The purl attribute.
"""
return self.purl

def set_purl(self, purl):
"""
Set the purl attribute.
Parameters:
purl (str): The new purl attribute.
Returns:
None
"""
self.purl = purl
Loading

0 comments on commit 6ff4839

Please sign in to comment.