Skip to content

Commit

Permalink
feat: audit shared actions repositories codebase (#520)
Browse files Browse the repository at this point in the history
secureli-455 & secureli-456

<!-- Include general description here -->
Audit codebase for code bloat and quality(Shared, Actions, Repositories)

## Changes
<!-- A detailed list of changes -->
* Audit and updated shared module, actions and repository codebase
according to AC's described in #455 and #456.
* Updated pre-commit config revisions.

## Testing
<!--
Mention updated tests and any manual testing performed.
Are aspects not yet tested or not easily testable?
Feel free to include screenshots if appropriate.
 -->
* All existing tests are passing

## Clean Code Checklist
<!-- This is here to support you. Some/most checkboxes may not apply to
your change -->
- [x] Meets acceptance criteria for issue
- [ ] New logic is covered with automated tests
- [ ] Appropriate exception handling added
- [ ] Thoughtful logging included
- [ ] Documentation is updated
- [ ] Follow-up work is documented in TODOs
- [ ] TODOs have a ticket associated with them
- [x] No commented-out code included


<!--
Github-flavored markdown reference:
https://docs.github.com/en/get-started/writing-on-github
-->
  • Loading branch information
isaac-heist-slalom authored Apr 19, 2024
1 parent 6db8ed9 commit a662a88
Show file tree
Hide file tree
Showing 22 changed files with 431 additions and 399 deletions.
18 changes: 10 additions & 8 deletions secureli/actions/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
from secureli.modules.shared.models.install import VerifyOutcome, VerifyResult
from secureli.modules.shared.models import language
from secureli.modules.shared.models.scan import ScanMode
from secureli.repositories import secureli_config
from secureli.repositories.repo_settings import SecureliRepository, TelemetrySettings
from secureli.modules.language_analyzer import language_analyzer, language_support
from secureli.modules.core.core_services.scanner import HooksScannerService
from secureli.modules.core.core_services.updater import UpdaterService

from secureli.modules.shared.utilities import format_sentence_list
from secureli.repositories.repo_settings import SecureliRepository
import secureli.repositories.secureli_config as secureli_config
import secureli.modules.shared.models.repository as RepositoryModels
import secureli.modules.shared.models.config as ConfigModels


class ActionDependencies:
Expand Down Expand Up @@ -47,9 +49,9 @@ class Action(ABC):
def __init__(self, action_deps: ActionDependencies):
self.action_deps = action_deps

def get_secureli_config(self, reset: bool) -> secureli_config.SecureliConfig:
def get_secureli_config(self, reset: bool) -> ConfigModels.SecureliConfig:
return (
secureli_config.SecureliConfig()
ConfigModels.SecureliConfig()
if reset
else self.action_deps.secureli_config.load()
)
Expand All @@ -71,7 +73,7 @@ def verify_install(
"""
if (
self.action_deps.secureli_config.verify()
== secureli_config.VerifyConfigOutcome.OUT_OF_DATE
== ConfigModels.VerifyConfigOutcome.OUT_OF_DATE
):
update_config = self._update_secureli_config_only(always_yes)
if update_config.outcome != VerifyOutcome.UPDATE_SUCCEEDED:
Expand Down Expand Up @@ -206,13 +208,13 @@ def _install_secureli(
for error_msg in metadata.linter_config_write_errors:
self.action_deps.echo.warning(error_msg)

config = secureli_config.SecureliConfig(
config = ConfigModels.SecureliConfig(
languages=detected_languages,
version_installed=metadata.version,
)
self.action_deps.secureli_config.save(config)

settings.telemetry = TelemetrySettings(
settings.telemetry = RepositoryModels.TelemetrySettings(
api_url=self._prompt_get_telemetry_api_url(always_yes)
)
self.action_deps.settings.save(settings)
Expand Down Expand Up @@ -267,7 +269,7 @@ def _prompt_get_telemetry_api_url(self, always_yes: bool) -> str:
def _run_post_install_scan(
self,
folder_path: Path,
config: secureli_config.SecureliConfig,
config: ConfigModels.SecureliConfig,
metadata: language.LanguageMetadata,
new_install: bool,
):
Expand Down
99 changes: 49 additions & 50 deletions secureli/actions/scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from pathlib import Path
from time import time
from typing import Optional
from git import Repo

from secureli.modules.shared.abstractions.echo import EchoAbstraction
from secureli.actions import action
Expand Down Expand Up @@ -50,36 +49,6 @@ def __init__(
self.logging = logging
self.git_repo = git_repo

def _check_secureli_hook_updates(self, folder_path: Path) -> VerifyResult:
"""
Queries repositories referenced by pre-commit hooks to check
if we have the latest revisions listed in the .pre-commit-config.yaml file
:param folder_path: The folder path containing the .secureli/ folder
"""

self.action_deps.echo.info("Checking for pre-commit hook updates...")
pre_commit_config = self.hooks_scanner.pre_commit.get_pre_commit_config(
folder_path
)

repos_to_update = self.hooks_scanner.pre_commit.check_for_hook_updates(
pre_commit_config
)

if not repos_to_update:
self.action_deps.echo.print("No hooks to update")
return VerifyResult(outcome=VerifyOutcome.UP_TO_DATE)

for repo, revs in repos_to_update.items():
self.action_deps.echo.debug(
f"Found update for {repo}: {revs.oldRev} -> {revs.newRev}"
)
self.action_deps.echo.warning(
"You have out-of-date pre-commit hooks. Run `secureli update` to update them."
)
# Since we don't actually perform the updates here, return an outcome of UPDATE_CANCELLED
return VerifyResult(outcome=VerifyOutcome.UPDATE_CANCELED)

def publish_results(
self,
publish_results_condition: PublishResultsOption,
Expand All @@ -104,24 +73,6 @@ def publish_results(
else:
self.logging.failure(LogAction.publish, result.result_message)

def get_commited_files(self, scan_mode: ScanMode) -> list[Path]:
"""
Attempts to build a list of commited files for use in language detection if
the user is scanning staged files for an existing installation
:param scan_mode: Determines which files are scanned in the repo (i.e. staged only or all)
:returns: a list of Path objects for the commited files
"""
config = self.get_secureli_config(reset=False)
installed = bool(config.languages and config.version_installed)

if not installed or scan_mode != ScanMode.STAGED_ONLY:
return None
try:
committed_files = self.git_repo.get_commit_diff()
return [Path(file) for file in committed_files]
except:
return None

def scan_repo(
self,
folder_path: Path,
Expand All @@ -142,7 +93,7 @@ def scan_repo(
Otherwise, scans with all hooks.
"""

scan_files = [Path(file) for file in files or []] or self.get_commited_files(
scan_files = [Path(file) for file in files or []] or self._get_commited_files(
scan_mode
)
verify_result = self.verify_install(
Expand Down Expand Up @@ -208,3 +159,51 @@ def scan_repo(
self.echo.print("Scan executed successfully and detected no issues!")
else:
sys.exit(ExitCode.SCAN_ISSUES_DETECTED.value)

def _check_secureli_hook_updates(self, folder_path: Path) -> VerifyResult:
"""
Queries repositories referenced by pre-commit hooks to check
if we have the latest revisions listed in the .pre-commit-config.yaml file
:param folder_path: The folder path containing the .secureli/ folder
"""

self.action_deps.echo.info("Checking for pre-commit hook updates...")
pre_commit_config = self.hooks_scanner.pre_commit.get_pre_commit_config(
folder_path
)

repos_to_update = self.hooks_scanner.pre_commit.check_for_hook_updates(
pre_commit_config
)

if not repos_to_update:
self.action_deps.echo.print("No hooks to update")
return VerifyResult(outcome=VerifyOutcome.UP_TO_DATE)

for repo, revs in repos_to_update.items():
self.action_deps.echo.debug(
f"Found update for {repo}: {revs.oldRev} -> {revs.newRev}"
)
self.action_deps.echo.warning(
"You have out-of-date pre-commit hooks. Run `secureli update` to update them."
)
# Since we don't actually perform the updates here, return an outcome of UPDATE_CANCELLED
return VerifyResult(outcome=VerifyOutcome.UPDATE_CANCELED)

def _get_commited_files(self, scan_mode: ScanMode) -> list[Path]:
"""
Attempts to build a list of commited files for use in language detection if
the user is scanning staged files for an existing installation
:param scan_mode: Determines which files are scanned in the repo (i.e. staged only or all)
:returns: a list of Path objects for the commited files
"""
config = self.get_secureli_config(reset=False)
installed = bool(config.languages and config.version_installed)

if not installed or scan_mode != ScanMode.STAGED_ONLY:
return None
try:
committed_files = self.git_repo.get_commit_diff()
return [Path(file) for file in committed_files]
except:
return None
2 changes: 1 addition & 1 deletion secureli/modules/core/core_services/scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

import re

from secureli.modules.shared.models.repository import PreCommitSettings
import secureli.modules.shared.models.scan as scan
from secureli.modules.shared.abstractions.pre_commit import PreCommitAbstraction
from secureli.repositories.repo_settings import PreCommitSettings


class HooksScannerService:
Expand Down
2 changes: 1 addition & 1 deletion secureli/modules/shared/abstractions/pre_commit.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
import subprocess
import yaml

from secureli.repositories.repo_settings import PreCommitSettings
from secureli.modules.shared.abstractions.echo import EchoAbstraction
from secureli.modules.shared.models.repository import PreCommitSettings


class InstallFailedError(Exception):
Expand Down
51 changes: 51 additions & 0 deletions secureli/modules/shared/consts/repository.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
default_ignored_extensions = [
# Images
".png",
".jpg",
".jpeg",
".gif",
".bmp",
".tiff",
"psd",
# Videos
".mp4",
".mkv",
".avi",
".mov",
".mpg",
".vob",
# Audio
".mp3",
".aac",
".wav",
".flac",
".ogg",
".mka",
".wma",
# Documents
".pdf",
".doc",
".xls",
".ppt",
".docx",
".odt",
".drawio",
# Archives
".zip",
".rar",
".7z",
".tar",
".iso",
# Databases
".mdb",
".accde",
".frm",
".sqlite",
# Executable
".exe",
".dll",
".so",
".class",
# Other
".pyc",
]
24 changes: 23 additions & 1 deletion secureli/modules/shared/models/config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Any
from enum import Enum
from typing import Any, Optional
import pydantic


Expand Down Expand Up @@ -28,3 +29,24 @@ class LinterConfigData(pydantic.BaseModel):
class LinterConfig(pydantic.BaseModel):
language: str
linter_data: list[LinterConfigData]


class SecureliConfig(pydantic.BaseModel):
languages: Optional[list[str]] = None
version_installed: Optional[str] = None
last_hook_update_check: Optional[int] = 0


class DeprecatedSecureliConfig(pydantic.BaseModel):
"""
Represents a model containing all current and past options for repo-config.yaml
"""

overall_language: Optional[str]
version_installed: Optional[str]


class VerifyConfigOutcome(str, Enum):
UP_TO_DATE = ("up-to-date",)
OUT_OF_DATE = ("out-of-date",)
MISSING = "missing"
3 changes: 1 addition & 2 deletions secureli/modules/shared/models/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

import pydantic
from secureli.modules.shared.models.language import AnalyzeResult

from secureli.repositories.secureli_config import SecureliConfig
from secureli.modules.shared.models.config import SecureliConfig


class VerifyOutcome(str, Enum):
Expand Down
8 changes: 8 additions & 0 deletions secureli/modules/shared/models/language.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,11 @@ class LinterConfigWriteResult(pydantic.BaseModel):

successful_languages: list[str]
error_messages: list[str]


class LanguageSupportSettings(pydantic.BaseSettings):
"""
Settings that affect how seCureLI performs language analysis and support.
"""

command_timeout_seconds: int = pydantic.Field(default=300)
Loading

0 comments on commit a662a88

Please sign in to comment.