issue 77 pt3 golangci
This commit is contained in:
parent
1316d31129
commit
7168174006
|
|
@ -87,9 +87,12 @@ jobs:
|
|||
type: biome
|
||||
path: TEMPLATES/fullstack-template/frontend
|
||||
# Go
|
||||
- name: simple-vulnerability-scanner
|
||||
type: go
|
||||
path: PROJECTS/beginner/simple-vulnerability-scanner
|
||||
- name: docker-security-audit
|
||||
type: go
|
||||
path: PROJECTS/beginner/docker-security-audit
|
||||
path: PROJECTS/intermediate/docker-security-audit
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
|
@ -142,9 +145,13 @@ jobs:
|
|||
if: matrix.type == 'go'
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version-file: ${{ matrix.path }}/go.mod
|
||||
cache-dependency-path: ${{ matrix.path }}/go.sum
|
||||
|
||||
- name: Install golangci-lint
|
||||
if: matrix.type == 'go'
|
||||
run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||
|
||||
# Ruff Linting
|
||||
- name: Run ruff
|
||||
if: matrix.type == 'ruff'
|
||||
|
|
@ -183,7 +190,7 @@ jobs:
|
|||
id: golangci
|
||||
run: |
|
||||
echo "Running golangci-lint..."
|
||||
if golangci-lint run --out-format=colored-line-number > golangci-output.txt 2>&1; then
|
||||
if golangci-lint run > golangci-output.txt 2>&1; then
|
||||
echo "GOLANGCI_PASSED=true" >> $GITHUB_ENV
|
||||
echo "No golangci-lint errors found!"
|
||||
else
|
||||
|
|
|
|||
|
|
@ -92,8 +92,24 @@ repos:
|
|||
exclude: (\.venv|__pycache__|\.pytest_cache)/
|
||||
|
||||
|
||||
# TODO: add golangci checks for GO projects
|
||||
# Go golangci-lint Checks
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: golangci-lint-simple-vulnerability-scanner
|
||||
name: golangci-lint (simple-vulnerability-scanner)
|
||||
entry: bash -c 'cd PROJECTS/beginner/simple-vulnerability-scanner && golangci-lint run --fix'
|
||||
language: system
|
||||
files: ^PROJECTS/beginner/simple-vulnerability-scanner/
|
||||
types: [go]
|
||||
pass_filenames: false
|
||||
|
||||
- id: golangci-lint-docker-security-audit
|
||||
name: golangci-lint (docker-security-audit)
|
||||
entry: bash -c 'cd PROJECTS/intermediate/docker-security-audit && golangci-lint run --fix'
|
||||
language: system
|
||||
files: ^PROJECTS/intermediate/docker-security-audit/
|
||||
types: [go]
|
||||
pass_filenames: false
|
||||
|
||||
# Biome Frontend Checks
|
||||
- repo: local
|
||||
|
|
|
|||
|
|
@ -37,14 +37,14 @@ from base64_tool.utils import (
|
|||
|
||||
|
||||
app = typer.Typer(
|
||||
name="b64tool",
|
||||
help=("Multi-format encoding/decoding CLI "
|
||||
"with recursive layer detection"),
|
||||
no_args_is_help=True,
|
||||
pretty_exceptions_show_locals=False,
|
||||
name = "b64tool",
|
||||
help = ("Multi-format encoding/decoding CLI "
|
||||
"with recursive layer detection"),
|
||||
no_args_is_help = True,
|
||||
pretty_exceptions_show_locals = False,
|
||||
)
|
||||
|
||||
_console = Console(stderr=True)
|
||||
_console = Console(stderr = True)
|
||||
|
||||
|
||||
def _version_callback(value: bool) -> None:
|
||||
|
|
@ -60,27 +60,27 @@ def main(
|
|||
typer.Option(
|
||||
"--version",
|
||||
"-v",
|
||||
help="Show version and exit.",
|
||||
callback=_version_callback,
|
||||
is_eager=True,
|
||||
help = "Show version and exit.",
|
||||
callback = _version_callback,
|
||||
is_eager = True,
|
||||
),
|
||||
] = False,
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
|
||||
@app.command(name="encode")
|
||||
@app.command(name = "encode")
|
||||
def encode_cmd(
|
||||
data: Annotated[
|
||||
str | None,
|
||||
typer.Argument(help="Data to encode."),
|
||||
typer.Argument(help = "Data to encode."),
|
||||
] = None,
|
||||
fmt: Annotated[
|
||||
EncodingFormat,
|
||||
typer.Option(
|
||||
"--format",
|
||||
"-f",
|
||||
help="Target encoding format.",
|
||||
help = "Target encoding format.",
|
||||
),
|
||||
] = EncodingFormat.BASE64,
|
||||
file: Annotated[
|
||||
|
|
@ -88,21 +88,21 @@ def encode_cmd(
|
|||
typer.Option(
|
||||
"--file",
|
||||
"-i",
|
||||
help="Read input from file.",
|
||||
help = "Read input from file.",
|
||||
),
|
||||
] = None,
|
||||
form: Annotated[
|
||||
bool,
|
||||
typer.Option(
|
||||
"--form",
|
||||
help="Use form-encoding for URL (space becomes +).",
|
||||
help = "Use form-encoding for URL (space becomes +).",
|
||||
),
|
||||
] = False,
|
||||
) -> None:
|
||||
try:
|
||||
raw = resolve_input_bytes(data, file)
|
||||
if fmt == EncodingFormat.URL and form:
|
||||
result = encode_url(raw, form=True)
|
||||
result = encode_url(raw, form = True)
|
||||
else:
|
||||
result = encode(raw, fmt)
|
||||
print_encoded(result, fmt)
|
||||
|
|
@ -110,21 +110,21 @@ def encode_cmd(
|
|||
raise
|
||||
except Exception as exc:
|
||||
_console.print(f"[red]Error:[/red] {exc}")
|
||||
raise typer.Exit(code=ExitCode.ERROR) from None
|
||||
raise typer.Exit(code = ExitCode.ERROR) from None
|
||||
|
||||
|
||||
@app.command(name="decode")
|
||||
@app.command(name = "decode")
|
||||
def decode_cmd(
|
||||
data: Annotated[
|
||||
str | None,
|
||||
typer.Argument(help="Data to decode."),
|
||||
typer.Argument(help = "Data to decode."),
|
||||
] = None,
|
||||
fmt: Annotated[
|
||||
EncodingFormat,
|
||||
typer.Option(
|
||||
"--format",
|
||||
"-f",
|
||||
help="Source encoding format.",
|
||||
help = "Source encoding format.",
|
||||
),
|
||||
] = EncodingFormat.BASE64,
|
||||
file: Annotated[
|
||||
|
|
@ -132,21 +132,21 @@ def decode_cmd(
|
|||
typer.Option(
|
||||
"--file",
|
||||
"-i",
|
||||
help="Read input from file.",
|
||||
help = "Read input from file.",
|
||||
),
|
||||
] = None,
|
||||
form: Annotated[
|
||||
bool,
|
||||
typer.Option(
|
||||
"--form",
|
||||
help="Use form-decoding for URL (+ becomes space).",
|
||||
help = "Use form-decoding for URL (+ becomes space).",
|
||||
),
|
||||
] = False,
|
||||
) -> None:
|
||||
try:
|
||||
text = resolve_input_text(data, file)
|
||||
if fmt == EncodingFormat.URL and form:
|
||||
result = decode_url(text, form=True)
|
||||
result = decode_url(text, form = True)
|
||||
else:
|
||||
result = decode(text, fmt)
|
||||
print_decoded(result)
|
||||
|
|
@ -154,21 +154,21 @@ def decode_cmd(
|
|||
raise
|
||||
except Exception as exc:
|
||||
_console.print(f"[red]Error:[/red] {exc}")
|
||||
raise typer.Exit(code=ExitCode.ERROR) from None
|
||||
raise typer.Exit(code = ExitCode.ERROR) from None
|
||||
|
||||
|
||||
@app.command(name="detect")
|
||||
@app.command(name = "detect")
|
||||
def detect_cmd(
|
||||
data: Annotated[
|
||||
str | None,
|
||||
typer.Argument(help="Data to analyze."),
|
||||
typer.Argument(help = "Data to analyze."),
|
||||
] = None,
|
||||
file: Annotated[
|
||||
Path | None,
|
||||
typer.Option(
|
||||
"--file",
|
||||
"-i",
|
||||
help="Read input from file.",
|
||||
help = "Read input from file.",
|
||||
),
|
||||
] = None,
|
||||
verbose: Annotated[
|
||||
|
|
@ -176,7 +176,7 @@ def detect_cmd(
|
|||
typer.Option(
|
||||
"--verbose",
|
||||
"-V",
|
||||
help="Show per-format score breakdown.",
|
||||
help = "Show per-format score breakdown.",
|
||||
),
|
||||
] = False,
|
||||
) -> None:
|
||||
|
|
@ -184,26 +184,26 @@ def detect_cmd(
|
|||
text = resolve_input_text(data, file)
|
||||
results = detect_encoding(text)
|
||||
scores = score_all_formats(text) if verbose else None
|
||||
print_detection(results, verbose_scores=scores)
|
||||
print_detection(results, verbose_scores = scores)
|
||||
except typer.BadParameter:
|
||||
raise
|
||||
except Exception as exc:
|
||||
_console.print(f"[red]Error:[/red] {exc}")
|
||||
raise typer.Exit(code=ExitCode.ERROR) from None
|
||||
raise typer.Exit(code = ExitCode.ERROR) from None
|
||||
|
||||
|
||||
@app.command(name="peel")
|
||||
@app.command(name = "peel")
|
||||
def peel_cmd(
|
||||
data: Annotated[
|
||||
str | None,
|
||||
typer.Argument(help="Data to recursively decode."),
|
||||
typer.Argument(help = "Data to recursively decode."),
|
||||
] = None,
|
||||
file: Annotated[
|
||||
Path | None,
|
||||
typer.Option(
|
||||
"--file",
|
||||
"-i",
|
||||
help="Read input from file.",
|
||||
help = "Read input from file.",
|
||||
),
|
||||
] = None,
|
||||
max_depth: Annotated[
|
||||
|
|
@ -211,7 +211,7 @@ def peel_cmd(
|
|||
typer.Option(
|
||||
"--max-depth",
|
||||
"-d",
|
||||
help="Maximum decoding layers.",
|
||||
help = "Maximum decoding layers.",
|
||||
),
|
||||
] = PEEL_MAX_DEPTH,
|
||||
verbose: Annotated[
|
||||
|
|
@ -219,34 +219,34 @@ def peel_cmd(
|
|||
typer.Option(
|
||||
"--verbose",
|
||||
"-V",
|
||||
help="Show per-format score breakdown at each layer.",
|
||||
help = "Show per-format score breakdown at each layer.",
|
||||
),
|
||||
] = False,
|
||||
) -> None:
|
||||
try:
|
||||
text = resolve_input_text(data, file)
|
||||
result = peel(text, max_depth=max_depth, verbose=verbose)
|
||||
print_peel_result(result, verbose=verbose)
|
||||
result = peel(text, max_depth = max_depth, verbose = verbose)
|
||||
print_peel_result(result, verbose = verbose)
|
||||
except typer.BadParameter:
|
||||
raise
|
||||
except Exception as exc:
|
||||
_console.print(f"[red]Error:[/red] {exc}")
|
||||
raise typer.Exit(code=ExitCode.ERROR) from None
|
||||
raise typer.Exit(code = ExitCode.ERROR) from None
|
||||
|
||||
|
||||
@app.command(name="chain")
|
||||
@app.command(name = "chain")
|
||||
def chain_cmd(
|
||||
data: Annotated[
|
||||
str | None,
|
||||
typer.Argument(help="Data to encode through chain."),
|
||||
typer.Argument(help = "Data to encode through chain."),
|
||||
] = None,
|
||||
steps: Annotated[
|
||||
str,
|
||||
typer.Option(
|
||||
"--steps",
|
||||
"-s",
|
||||
help=("Comma-separated encoding formats "
|
||||
"(e.g. base64,hex,url)."),
|
||||
help = ("Comma-separated encoding formats "
|
||||
"(e.g. base64,hex,url)."),
|
||||
),
|
||||
] = "base64",
|
||||
file: Annotated[
|
||||
|
|
@ -254,7 +254,7 @@ def chain_cmd(
|
|||
typer.Option(
|
||||
"--file",
|
||||
"-i",
|
||||
help="Read input from file.",
|
||||
help = "Read input from file.",
|
||||
),
|
||||
] = None,
|
||||
) -> None:
|
||||
|
|
@ -275,7 +275,7 @@ def chain_cmd(
|
|||
raise
|
||||
except Exception as exc:
|
||||
_console.print(f"[red]Error:[/red] {exc}")
|
||||
raise typer.Exit(code=ExitCode.ERROR) from None
|
||||
raise typer.Exit(code = ExitCode.ERROR) from None
|
||||
|
||||
|
||||
def _parse_chain_steps(raw: str) -> list[EncodingFormat]:
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ class ScoreWeight:
|
|||
URL_RATIO_CAP: Final[float] = 0.35
|
||||
URL_DECODE_CHANGED: Final[float] = 0.15
|
||||
|
||||
|
||||
BASE64_CHARSET: Final[
|
||||
frozenset[str]
|
||||
] = frozenset("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=")
|
||||
|
|
@ -75,4 +76,3 @@ BASE32_CHARSET: Final[frozenset[str]] = frozenset("ABCDEFGHIJKLMNOPQRSTUVWXYZ234
|
|||
HEX_CHARSET: Final[frozenset[str]] = frozenset("0123456789abcdefABCDEF")
|
||||
|
||||
HEX_SEPARATORS: Final[frozenset[str]] = frozenset(" :.-")
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ from base64_tool.encoders import try_decode
|
|||
from base64_tool.utils import is_printable_text
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
@dataclass(frozen = True, slots = True)
|
||||
class DetectionResult:
|
||||
format: EncodingFormat
|
||||
confidence: float
|
||||
|
|
@ -152,9 +152,7 @@ def _score_hex(data: str) -> float:
|
|||
else:
|
||||
score -= W.HEX_NO_ALPHA_PENALTY
|
||||
|
||||
is_consistent_case = (
|
||||
hex_only == hex_only.lower() or hex_only == hex_only.upper()
|
||||
)
|
||||
is_consistent_case = (hex_only == hex_only.lower() or hex_only == hex_only.upper())
|
||||
if is_consistent_case:
|
||||
score += W.HEX_CONSISTENT_CASE
|
||||
|
||||
|
|
@ -188,20 +186,22 @@ def _score_url(data: str) -> float:
|
|||
|
||||
decoded = try_decode(data, EncodingFormat.URL)
|
||||
if decoded is not None:
|
||||
decoded_text = decoded.decode("utf-8", errors="replace")
|
||||
decoded_text = decoded.decode("utf-8", errors = "replace")
|
||||
if decoded_text != data:
|
||||
score += W.URL_DECODE_CHANGED
|
||||
|
||||
return min(score, 1.0)
|
||||
|
||||
|
||||
_SCORERS: dict[EncodingFormat, Callable[[str], float]] = {
|
||||
EncodingFormat.BASE64: _score_base64,
|
||||
EncodingFormat.BASE64URL: _score_base64url,
|
||||
EncodingFormat.BASE32: _score_base32,
|
||||
EncodingFormat.HEX: _score_hex,
|
||||
EncodingFormat.URL: _score_url,
|
||||
}
|
||||
_SCORERS: dict[EncodingFormat,
|
||||
Callable[[str],
|
||||
float]] = {
|
||||
EncodingFormat.BASE64: _score_base64,
|
||||
EncodingFormat.BASE64URL: _score_base64url,
|
||||
EncodingFormat.BASE32: _score_base32,
|
||||
EncodingFormat.HEX: _score_hex,
|
||||
EncodingFormat.URL: _score_url,
|
||||
}
|
||||
|
||||
|
||||
def score_all_formats(data: str) -> dict[EncodingFormat, float]:
|
||||
|
|
@ -216,13 +216,14 @@ def detect_encoding(data: str) -> list[DetectionResult]:
|
|||
decoded = try_decode(data, fmt)
|
||||
results.append(
|
||||
DetectionResult(
|
||||
format=fmt,
|
||||
confidence=round(confidence, 2),
|
||||
decoded=decoded,
|
||||
format = fmt,
|
||||
confidence = round(confidence,
|
||||
2),
|
||||
decoded = decoded,
|
||||
)
|
||||
)
|
||||
|
||||
results.sort(key=lambda r: r.confidence, reverse=True)
|
||||
results.sort(key = lambda r: r.confidence, reverse = True)
|
||||
return results
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ from base64_tool.peeler import PeelResult
|
|||
from base64_tool.utils import safe_bytes_preview
|
||||
|
||||
|
||||
console = Console(stderr=True)
|
||||
console = Console(stderr = True)
|
||||
|
||||
|
||||
def is_piped() -> bool:
|
||||
|
|
@ -37,44 +37,49 @@ def print_encoded(result: str, fmt: EncodingFormat) -> None:
|
|||
write_raw(result)
|
||||
return
|
||||
panel = Panel(
|
||||
Text(result, style="green"),
|
||||
title=f"[bold cyan]{fmt.value}[/bold cyan] encoded",
|
||||
border_style="cyan",
|
||||
Text(result,
|
||||
style = "green"),
|
||||
title = f"[bold cyan]{fmt.value}[/bold cyan] encoded",
|
||||
border_style = "cyan",
|
||||
)
|
||||
console.print(panel)
|
||||
|
||||
|
||||
def print_decoded(result: bytes) -> None:
|
||||
preview = safe_bytes_preview(result, length=4096)
|
||||
preview = safe_bytes_preview(result, length = 4096)
|
||||
if is_piped():
|
||||
write_raw(preview)
|
||||
return
|
||||
panel = Panel(
|
||||
Text(preview, style="green"),
|
||||
title="[bold cyan]Decoded[/bold cyan]",
|
||||
border_style="cyan",
|
||||
Text(preview,
|
||||
style = "green"),
|
||||
title = "[bold cyan]Decoded[/bold cyan]",
|
||||
border_style = "cyan",
|
||||
)
|
||||
console.print(panel)
|
||||
|
||||
|
||||
def print_score_breakdown(
|
||||
scores: dict[EncodingFormat, float],
|
||||
scores: dict[EncodingFormat,
|
||||
float],
|
||||
) -> None:
|
||||
table = Table(
|
||||
title="Score Breakdown",
|
||||
show_header=True,
|
||||
header_style="bold magenta",
|
||||
title = "Score Breakdown",
|
||||
show_header = True,
|
||||
header_style = "bold magenta",
|
||||
)
|
||||
table.add_column("Format", style="cyan", min_width=10)
|
||||
table.add_column("Format", style = "cyan", min_width = 10)
|
||||
table.add_column(
|
||||
"Score",
|
||||
justify="right",
|
||||
min_width=8,
|
||||
justify = "right",
|
||||
min_width = 8,
|
||||
)
|
||||
table.add_column("Status", min_width=10)
|
||||
table.add_column("Status", min_width = 10)
|
||||
|
||||
sorted_scores = sorted(
|
||||
scores.items(), key=lambda x: x[1], reverse=True,
|
||||
scores.items(),
|
||||
key = lambda x: x[1],
|
||||
reverse = True,
|
||||
)
|
||||
for fmt, score in sorted_scores:
|
||||
color = _confidence_color(score)
|
||||
|
|
@ -96,7 +101,8 @@ def print_score_breakdown(
|
|||
def print_detection(
|
||||
results: list[DetectionResult],
|
||||
*,
|
||||
verbose_scores: dict[EncodingFormat, float] | None = None,
|
||||
verbose_scores: dict[EncodingFormat,
|
||||
float] | None = None,
|
||||
) -> None:
|
||||
if verbose_scores is not None:
|
||||
print_score_breakdown(verbose_scores)
|
||||
|
|
@ -107,18 +113,18 @@ def print_detection(
|
|||
return
|
||||
|
||||
table = Table(
|
||||
title="Detection Results",
|
||||
show_header=True,
|
||||
header_style="bold magenta",
|
||||
title = "Detection Results",
|
||||
show_header = True,
|
||||
header_style = "bold magenta",
|
||||
)
|
||||
table.add_column("Format", style="cyan", min_width=10)
|
||||
table.add_column("Format", style = "cyan", min_width = 10)
|
||||
table.add_column(
|
||||
"Confidence",
|
||||
justify="right",
|
||||
style="green",
|
||||
min_width=12,
|
||||
justify = "right",
|
||||
style = "green",
|
||||
min_width = 12,
|
||||
)
|
||||
table.add_column("Decoded Preview", style="dim")
|
||||
table.add_column("Decoded Preview", style = "dim")
|
||||
|
||||
for result in results:
|
||||
confidence_str = f"{result.confidence:.0%}"
|
||||
|
|
@ -171,18 +177,20 @@ def print_peel_result(
|
|||
|
||||
console.print()
|
||||
|
||||
preview = safe_bytes_preview(result.final_output, length=4096)
|
||||
preview = safe_bytes_preview(result.final_output, length = 4096)
|
||||
panel = Panel(
|
||||
Text(preview, style="bold green"),
|
||||
title="[bold]Final Output[/bold]",
|
||||
border_style="green",
|
||||
subtitle=(f"[dim]{layer_count} layer{suffix} peeled[/dim]"),
|
||||
Text(preview,
|
||||
style = "bold green"),
|
||||
title = "[bold]Final Output[/bold]",
|
||||
border_style = "green",
|
||||
subtitle = (f"[dim]{layer_count} layer{suffix} peeled[/dim]"),
|
||||
)
|
||||
console.print(panel)
|
||||
|
||||
|
||||
def print_chain_result(
|
||||
steps: list[tuple[EncodingFormat, str]],
|
||||
steps: list[tuple[EncodingFormat,
|
||||
str]],
|
||||
final: str,
|
||||
) -> None:
|
||||
if is_piped():
|
||||
|
|
@ -196,7 +204,7 @@ def print_chain_result(
|
|||
for i, (fmt, intermediate) in enumerate(steps):
|
||||
marker = "start" if i == 0 else "step"
|
||||
arrow = f" [{marker}] " if i == 0 else " -> "
|
||||
truncated = intermediate[:PREVIEW_LENGTH]
|
||||
truncated = intermediate[: PREVIEW_LENGTH]
|
||||
ellipsis = "..." if len(intermediate) > PREVIEW_LENGTH else ""
|
||||
console.print(
|
||||
f"{arrow}[cyan]{fmt.value}[/cyan] "
|
||||
|
|
@ -205,10 +213,11 @@ def print_chain_result(
|
|||
|
||||
console.print()
|
||||
panel = Panel(
|
||||
Text(final, style="green"),
|
||||
title="[bold]Chain Result[/bold]",
|
||||
border_style="cyan",
|
||||
subtitle=f"[dim]{len(steps)} steps[/dim]",
|
||||
Text(final,
|
||||
style = "green"),
|
||||
title = "[bold]Chain Result[/bold]",
|
||||
border_style = "cyan",
|
||||
subtitle = f"[dim]{len(steps)} steps[/dim]",
|
||||
)
|
||||
console.print(panel)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ from base64_tool.detector import detect_best, score_all_formats
|
|||
from base64_tool.utils import safe_bytes_preview, truncate
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
@dataclass(frozen = True, slots = True)
|
||||
class PeelLayer:
|
||||
depth: int
|
||||
format: EncodingFormat
|
||||
|
|
@ -24,7 +24,7 @@ class PeelLayer:
|
|||
all_scores: tuple[tuple[EncodingFormat, float], ...] = ()
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
@dataclass(frozen = True, slots = True)
|
||||
class PeelResult:
|
||||
layers: tuple[PeelLayer, ...]
|
||||
final_output: bytes
|
||||
|
|
@ -52,20 +52,16 @@ def peel(
|
|||
if detection.decoded is None:
|
||||
break
|
||||
|
||||
scores = (
|
||||
tuple(score_all_formats(current_text).items())
|
||||
if verbose
|
||||
else ()
|
||||
)
|
||||
scores = (tuple(score_all_formats(current_text).items()) if verbose else ())
|
||||
|
||||
decoded_bytes = detection.decoded
|
||||
layer = PeelLayer(
|
||||
depth=depth + 1,
|
||||
format=detection.format,
|
||||
confidence=detection.confidence,
|
||||
encoded_preview=truncate(current_text),
|
||||
decoded_preview=safe_bytes_preview(decoded_bytes),
|
||||
all_scores=scores,
|
||||
depth = depth + 1,
|
||||
format = detection.format,
|
||||
confidence = detection.confidence,
|
||||
encoded_preview = truncate(current_text),
|
||||
decoded_preview = safe_bytes_preview(decoded_bytes),
|
||||
all_scores = scores,
|
||||
)
|
||||
layers.append(layer)
|
||||
current_bytes = decoded_bytes
|
||||
|
|
@ -76,7 +72,7 @@ def peel(
|
|||
break
|
||||
|
||||
return PeelResult(
|
||||
layers=tuple(layers),
|
||||
final_output=current_bytes,
|
||||
success=len(layers) > 0,
|
||||
layers = tuple(layers),
|
||||
final_output = current_bytes,
|
||||
success = len(layers) > 0,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -26,5 +26,6 @@
|
|||
from caesar_cipher.cipher import CaesarCipher
|
||||
from caesar_cipher.analyzer import FrequencyAnalyzer
|
||||
|
||||
|
||||
__version__ = "0.1.0"
|
||||
__all__ = ["CaesarCipher", "FrequencyAnalyzer"]
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ from dnslookup.resolver import (
|
|||
|
||||
console = Console()
|
||||
|
||||
|
||||
RECORD_COLORS: dict[RecordType,
|
||||
str] = {
|
||||
RecordType.A: "green",
|
||||
|
|
|
|||
|
|
@ -134,11 +134,11 @@ func runInit() error {
|
|||
name := filepath.Base(dir)
|
||||
content := fmt.Sprintf(pyprojectTemplate, name)
|
||||
|
||||
if err := os.WriteFile(
|
||||
if err := os.WriteFile( //nolint:gosec // pyproject.toml needs 0644 for uv/pip reads
|
||||
"pyproject.toml",
|
||||
[]byte(content),
|
||||
0o644,
|
||||
); err != nil { //nolint:gosec
|
||||
); err != nil {
|
||||
return fmt.Errorf("write pyproject.toml: %w", err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
AngelaMos | 2026
|
||||
© AngelaMos | 2026
|
||||
container.go
|
||||
*/
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
"github.com/CarterPerez-dev/docksec/internal/docker"
|
||||
"github.com/CarterPerez-dev/docksec/internal/finding"
|
||||
"github.com/CarterPerez-dev/docksec/internal/rules"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
)
|
||||
|
||||
type ContainerAnalyzer struct {
|
||||
|
|
@ -49,7 +49,7 @@ func (a *ContainerAnalyzer) Analyze(
|
|||
}
|
||||
|
||||
func (a *ContainerAnalyzer) analyzeContainer(
|
||||
info types.ContainerJSON,
|
||||
info container.InspectResponse,
|
||||
) finding.Collection {
|
||||
var findings finding.Collection
|
||||
target := finding.Target{
|
||||
|
|
@ -75,7 +75,7 @@ func (a *ContainerAnalyzer) analyzeContainer(
|
|||
|
||||
func (a *ContainerAnalyzer) checkPrivileged(
|
||||
target finding.Target,
|
||||
info types.ContainerJSON,
|
||||
info container.InspectResponse,
|
||||
) finding.Collection {
|
||||
var findings finding.Collection
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ func (a *ContainerAnalyzer) checkPrivileged(
|
|||
|
||||
func (a *ContainerAnalyzer) checkCapabilities(
|
||||
target finding.Target,
|
||||
info types.ContainerJSON,
|
||||
info container.InspectResponse,
|
||||
) finding.Collection {
|
||||
var findings finding.Collection
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ func (a *ContainerAnalyzer) checkCapabilities(
|
|||
|
||||
func (a *ContainerAnalyzer) checkMounts(
|
||||
target finding.Target,
|
||||
info types.ContainerJSON,
|
||||
info container.InspectResponse,
|
||||
) finding.Collection {
|
||||
var findings finding.Collection
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ func (a *ContainerAnalyzer) checkMounts(
|
|||
|
||||
func (a *ContainerAnalyzer) checkNamespaces(
|
||||
target finding.Target,
|
||||
info types.ContainerJSON,
|
||||
info container.InspectResponse,
|
||||
) finding.Collection {
|
||||
var findings finding.Collection
|
||||
|
||||
|
|
@ -225,7 +225,7 @@ func (a *ContainerAnalyzer) checkNamespaces(
|
|||
|
||||
func (a *ContainerAnalyzer) checkSecurityOptions(
|
||||
target finding.Target,
|
||||
info types.ContainerJSON,
|
||||
info container.InspectResponse,
|
||||
) finding.Collection {
|
||||
var findings finding.Collection
|
||||
|
||||
|
|
@ -298,7 +298,7 @@ func (a *ContainerAnalyzer) checkSecurityOptions(
|
|||
|
||||
func (a *ContainerAnalyzer) checkResourceLimits(
|
||||
target finding.Target,
|
||||
info types.ContainerJSON,
|
||||
info container.InspectResponse,
|
||||
) finding.Collection {
|
||||
var findings finding.Collection
|
||||
|
||||
|
|
@ -342,7 +342,7 @@ func (a *ContainerAnalyzer) checkResourceLimits(
|
|||
|
||||
func (a *ContainerAnalyzer) checkReadonlyRootfs(
|
||||
target finding.Target,
|
||||
info types.ContainerJSON,
|
||||
info container.InspectResponse,
|
||||
) finding.Collection {
|
||||
var findings finding.Collection
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
AngelaMos | 2026
|
||||
© AngelaMos | 2026
|
||||
container_test.go
|
||||
*/
|
||||
|
||||
|
|
@ -12,23 +12,33 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/CarterPerez-dev/docksec/internal/finding"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func loadContainerJSON(t *testing.T, filename string) types.ContainerJSON {
|
||||
func loadContainerJSON(
|
||||
t *testing.T,
|
||||
filename string,
|
||||
) container.InspectResponse {
|
||||
t.Helper()
|
||||
|
||||
path := filepath.Join("..", "..", "tests", "testdata", "containers", filename)
|
||||
path := filepath.Join(
|
||||
"..",
|
||||
"..",
|
||||
"tests",
|
||||
"testdata",
|
||||
"containers",
|
||||
filename,
|
||||
)
|
||||
data, err := os.ReadFile(path)
|
||||
require.NoError(t, err, "Failed to read container JSON file")
|
||||
|
||||
var container types.ContainerJSON
|
||||
err = json.Unmarshal(data, &container)
|
||||
var ctr container.InspectResponse
|
||||
err = json.Unmarshal(data, &ctr)
|
||||
require.NoError(t, err, "Failed to unmarshal container JSON")
|
||||
|
||||
return container
|
||||
return ctr
|
||||
}
|
||||
|
||||
func TestContainerAnalyzer_PrivilegedContainer(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
AngelaMos | 2026
|
||||
© AngelaMos | 2026
|
||||
image.go
|
||||
*/
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ import (
|
|||
"github.com/CarterPerez-dev/docksec/internal/benchmark"
|
||||
"github.com/CarterPerez-dev/docksec/internal/docker"
|
||||
"github.com/CarterPerez-dev/docksec/internal/finding"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/image"
|
||||
)
|
||||
|
||||
type ImageAnalyzer struct {
|
||||
|
|
@ -62,7 +62,7 @@ func (a *ImageAnalyzer) Analyze(
|
|||
|
||||
func (a *ImageAnalyzer) analyzeImage(
|
||||
target finding.Target,
|
||||
info types.ImageInspect,
|
||||
info image.InspectResponse,
|
||||
) finding.Collection {
|
||||
var findings finding.Collection
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ func (a *ImageAnalyzer) analyzeImage(
|
|||
|
||||
func (a *ImageAnalyzer) checkRootUser(
|
||||
target finding.Target,
|
||||
info types.ImageInspect,
|
||||
info image.InspectResponse,
|
||||
) finding.Collection {
|
||||
var findings finding.Collection
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ func (a *ImageAnalyzer) checkRootUser(
|
|||
|
||||
func (a *ImageAnalyzer) checkHealthcheck(
|
||||
target finding.Target,
|
||||
info types.ImageInspect,
|
||||
info image.InspectResponse,
|
||||
) finding.Collection {
|
||||
var findings finding.Collection
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ func (a *ImageAnalyzer) checkHealthcheck(
|
|||
|
||||
func (a *ImageAnalyzer) checkExposedPorts(
|
||||
target finding.Target,
|
||||
info types.ImageInspect,
|
||||
info image.InspectResponse,
|
||||
) finding.Collection {
|
||||
var findings finding.Collection
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
CarterPerez-dev | 2026
|
||||
© AngelaMos | 2026
|
||||
client.go
|
||||
*/
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ func (c *Client) ServerVersion(ctx context.Context) (types.Version, error) {
|
|||
func (c *Client) ListContainers(
|
||||
ctx context.Context,
|
||||
all bool,
|
||||
) ([]types.Container, error) {
|
||||
) ([]container.Summary, error) {
|
||||
listCtx, cancel := context.WithTimeout(ctx, config.DefaultTimeout)
|
||||
defer cancel()
|
||||
|
||||
|
|
@ -107,13 +107,13 @@ func (c *Client) ListContainers(
|
|||
func (c *Client) InspectContainer(
|
||||
ctx context.Context,
|
||||
containerID string,
|
||||
) (types.ContainerJSON, error) {
|
||||
) (container.InspectResponse, error) {
|
||||
inspectCtx, cancel := context.WithTimeout(ctx, config.InspectTimeout)
|
||||
defer cancel()
|
||||
|
||||
info, err := c.api.ContainerInspect(inspectCtx, containerID)
|
||||
if err != nil {
|
||||
return types.ContainerJSON{}, fmt.Errorf(
|
||||
return container.InspectResponse{}, fmt.Errorf(
|
||||
"inspecting container %s: %w",
|
||||
containerID,
|
||||
err,
|
||||
|
|
@ -136,13 +136,13 @@ func (c *Client) ListImages(ctx context.Context) ([]image.Summary, error) {
|
|||
func (c *Client) InspectImage(
|
||||
ctx context.Context,
|
||||
imageID string,
|
||||
) (types.ImageInspect, error) {
|
||||
) (image.InspectResponse, error) {
|
||||
inspectCtx, cancel := context.WithTimeout(ctx, config.InspectTimeout)
|
||||
defer cancel()
|
||||
|
||||
info, _, err := c.api.ImageInspectWithRaw(inspectCtx, imageID)
|
||||
info, err := c.api.ImageInspect(inspectCtx, imageID)
|
||||
if err != nil {
|
||||
return types.ImageInspect{}, fmt.Errorf(
|
||||
return image.InspectResponse{}, fmt.Errorf(
|
||||
"inspecting image %s: %w",
|
||||
imageID,
|
||||
err,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,12 @@ func TestE2E_DockerfileAnalysis(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
|
||||
t.Run("analyze bad-secrets.Dockerfile end-to-end", func(t *testing.T) {
|
||||
path := filepath.Join("..", "testdata", "dockerfiles", "bad-secrets.Dockerfile")
|
||||
path := filepath.Join(
|
||||
"..",
|
||||
"testdata",
|
||||
"dockerfiles",
|
||||
"bad-secrets.Dockerfile",
|
||||
)
|
||||
|
||||
require.FileExists(t, path, "Test file should exist")
|
||||
|
||||
|
|
@ -47,7 +52,12 @@ func TestE2E_DockerfileAnalysis(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("analyze good-security.Dockerfile end-to-end", func(t *testing.T) {
|
||||
path := filepath.Join("..", "testdata", "dockerfiles", "good-security.Dockerfile")
|
||||
path := filepath.Join(
|
||||
"..",
|
||||
"testdata",
|
||||
"dockerfiles",
|
||||
"good-security.Dockerfile",
|
||||
)
|
||||
|
||||
require.FileExists(t, path, "Test file should exist")
|
||||
|
||||
|
|
@ -73,7 +83,12 @@ func TestE2E_ComposeAnalysis(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
|
||||
t.Run("analyze bad-docker-socket.yml end-to-end", func(t *testing.T) {
|
||||
path := filepath.Join("..", "testdata", "compose", "bad-docker-socket.yml")
|
||||
path := filepath.Join(
|
||||
"..",
|
||||
"testdata",
|
||||
"compose",
|
||||
"bad-docker-socket.yml",
|
||||
)
|
||||
|
||||
require.FileExists(t, path, "Test file should exist")
|
||||
|
||||
|
|
@ -83,8 +98,11 @@ func TestE2E_ComposeAnalysis(t *testing.T) {
|
|||
require.NoError(t, err, "Analyze should not return error")
|
||||
require.NotEmpty(t, findings, "Should have findings")
|
||||
|
||||
assert.True(t, findings.HasSeverityAtOrAbove(finding.SeverityCritical),
|
||||
"Should detect CRITICAL issues")
|
||||
assert.True(
|
||||
t,
|
||||
findings.HasSeverityAtOrAbove(finding.SeverityCritical),
|
||||
"Should detect CRITICAL issues",
|
||||
)
|
||||
|
||||
counts := findings.CountBySeverity()
|
||||
t.Logf("Findings by severity: %+v", counts)
|
||||
|
|
@ -95,7 +113,12 @@ func TestE2E_ComposeAnalysis(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("analyze good-production.yml end-to-end", func(t *testing.T) {
|
||||
path := filepath.Join("..", "testdata", "compose", "good-production.yml")
|
||||
path := filepath.Join(
|
||||
"..",
|
||||
"testdata",
|
||||
"compose",
|
||||
"good-production.yml",
|
||||
)
|
||||
|
||||
require.FileExists(t, path, "Test file should exist")
|
||||
|
||||
|
|
@ -104,8 +127,11 @@ func TestE2E_ComposeAnalysis(t *testing.T) {
|
|||
findings, err := a.Analyze(ctx)
|
||||
require.NoError(t, err, "Analyze should not return error")
|
||||
|
||||
assert.False(t, findings.HasSeverityAtOrAbove(finding.SeverityCritical),
|
||||
"Production compose should have no CRITICAL findings")
|
||||
assert.False(
|
||||
t,
|
||||
findings.HasSeverityAtOrAbove(finding.SeverityCritical),
|
||||
"Production compose should have no CRITICAL findings",
|
||||
)
|
||||
|
||||
counts := findings.CountBySeverity()
|
||||
t.Logf("Findings by severity: %+v", counts)
|
||||
|
|
@ -126,22 +152,42 @@ func TestE2E_MultipleFiles(t *testing.T) {
|
|||
wantIssues bool
|
||||
}{
|
||||
{
|
||||
path: filepath.Join("..", "testdata", "dockerfiles", "bad-secrets.Dockerfile"),
|
||||
path: filepath.Join(
|
||||
"..",
|
||||
"testdata",
|
||||
"dockerfiles",
|
||||
"bad-secrets.Dockerfile",
|
||||
),
|
||||
analyzer: func(p string) analyzer.Analyzer { return analyzer.NewDockerfileAnalyzer(p) },
|
||||
wantIssues: true,
|
||||
},
|
||||
{
|
||||
path: filepath.Join("..", "testdata", "dockerfiles", "good-minimal.Dockerfile"),
|
||||
path: filepath.Join(
|
||||
"..",
|
||||
"testdata",
|
||||
"dockerfiles",
|
||||
"good-minimal.Dockerfile",
|
||||
),
|
||||
analyzer: func(p string) analyzer.Analyzer { return analyzer.NewDockerfileAnalyzer(p) },
|
||||
wantIssues: false,
|
||||
},
|
||||
{
|
||||
path: filepath.Join("..", "testdata", "compose", "bad-privileged.yml"),
|
||||
path: filepath.Join(
|
||||
"..",
|
||||
"testdata",
|
||||
"compose",
|
||||
"bad-privileged.yml",
|
||||
),
|
||||
analyzer: func(p string) analyzer.Analyzer { return analyzer.NewComposeAnalyzer(p) },
|
||||
wantIssues: true,
|
||||
},
|
||||
{
|
||||
path: filepath.Join("..", "testdata", "compose", "good-production.yml"),
|
||||
path: filepath.Join(
|
||||
"..",
|
||||
"testdata",
|
||||
"compose",
|
||||
"good-production.yml",
|
||||
),
|
||||
analyzer: func(p string) analyzer.Analyzer { return analyzer.NewComposeAnalyzer(p) },
|
||||
wantIssues: false,
|
||||
},
|
||||
|
|
@ -158,7 +204,12 @@ func TestE2E_MultipleFiles(t *testing.T) {
|
|||
require.NoError(t, err, "Analyze should not error for %s", f.path)
|
||||
|
||||
if f.wantIssues {
|
||||
assert.NotEmpty(t, findings, "File %s should have findings", f.path)
|
||||
assert.NotEmpty(
|
||||
t,
|
||||
findings,
|
||||
"File %s should have findings",
|
||||
f.path,
|
||||
)
|
||||
}
|
||||
|
||||
allFindings = append(allFindings, findings...)
|
||||
|
|
@ -166,7 +217,11 @@ func TestE2E_MultipleFiles(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Logf("Total findings across all files: %d", allFindings.Total())
|
||||
assert.NotEmpty(t, allFindings, "Should have findings across all files")
|
||||
assert.NotEmpty(
|
||||
t,
|
||||
allFindings,
|
||||
"Should have findings across all files",
|
||||
)
|
||||
|
||||
counts := allFindings.CountBySeverity()
|
||||
t.Logf("Overall severity distribution: %+v", counts)
|
||||
|
|
@ -191,12 +246,28 @@ func TestE2E_FindingProperties(t *testing.T) {
|
|||
assert.NotEmpty(t, f.ID, "Finding should have ID")
|
||||
assert.NotEmpty(t, f.RuleID, "Finding should have RuleID")
|
||||
assert.NotEmpty(t, f.Title, "Finding should have Title")
|
||||
assert.NotEmpty(t, f.Description, "Finding should have Description")
|
||||
assert.NotEmpty(
|
||||
t,
|
||||
f.Description,
|
||||
"Finding should have Description",
|
||||
)
|
||||
assert.NotEmpty(t, f.Category, "Finding should have Category")
|
||||
assert.NotEmpty(t, f.Remediation, "Finding should have Remediation")
|
||||
assert.NotEmpty(
|
||||
t,
|
||||
f.Remediation,
|
||||
"Finding should have Remediation",
|
||||
)
|
||||
assert.NotZero(t, f.Severity, "Finding should have Severity")
|
||||
assert.NotEmpty(t, f.Target.Type, "Finding should have Target.Type")
|
||||
assert.NotEmpty(t, f.Target.Name, "Finding should have Target.Name")
|
||||
assert.NotEmpty(
|
||||
t,
|
||||
f.Target.Type,
|
||||
"Finding should have Target.Type",
|
||||
)
|
||||
assert.NotEmpty(
|
||||
t,
|
||||
f.Target.Name,
|
||||
"Finding should have Target.Name",
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
@ -205,12 +276,25 @@ func TestE2E_FindingProperties(t *testing.T) {
|
|||
for _, f := range findings {
|
||||
if f.Location != nil {
|
||||
hasLocation = true
|
||||
assert.NotEmpty(t, f.Location.Path, "Location should have Path")
|
||||
assert.Greater(t, f.Location.Line, 0, "Location should have Line > 0")
|
||||
assert.NotEmpty(
|
||||
t,
|
||||
f.Location.Path,
|
||||
"Location should have Path",
|
||||
)
|
||||
assert.Greater(
|
||||
t,
|
||||
f.Location.Line,
|
||||
0,
|
||||
"Location should have Line > 0",
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
assert.True(t, hasLocation, "At least one finding should have location info")
|
||||
assert.True(
|
||||
t,
|
||||
hasLocation,
|
||||
"At least one finding should have location info",
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("CIS findings have CIS control info", func(t *testing.T) {
|
||||
|
|
@ -219,8 +303,16 @@ func TestE2E_FindingProperties(t *testing.T) {
|
|||
if len(f.RuleID) >= 4 && f.RuleID[:4] == "CIS-" {
|
||||
hasCIS = true
|
||||
if f.CISControl != nil {
|
||||
assert.NotEmpty(t, f.CISControl.ID, "CISControl should have ID")
|
||||
assert.NotEmpty(t, f.CISControl.Title, "CISControl should have Title")
|
||||
assert.NotEmpty(
|
||||
t,
|
||||
f.CISControl.ID,
|
||||
"CISControl should have ID",
|
||||
)
|
||||
assert.NotEmpty(
|
||||
t,
|
||||
f.CISControl.Title,
|
||||
"CISControl should have Title",
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
|
@ -235,7 +327,12 @@ func TestE2E_SeverityFiltering(t *testing.T) {
|
|||
}
|
||||
|
||||
ctx := context.Background()
|
||||
path := filepath.Join("..", "testdata", "compose", "bad-docker-socket.yml")
|
||||
path := filepath.Join(
|
||||
"..",
|
||||
"testdata",
|
||||
"compose",
|
||||
"bad-docker-socket.yml",
|
||||
)
|
||||
|
||||
a := analyzer.NewComposeAnalyzer(path)
|
||||
findings, err := a.Analyze(ctx)
|
||||
|
|
@ -247,7 +344,12 @@ func TestE2E_SeverityFiltering(t *testing.T) {
|
|||
high := findings.BySeverity(finding.SeverityHigh)
|
||||
medium := findings.BySeverity(finding.SeverityMedium)
|
||||
|
||||
t.Logf("CRITICAL: %d, HIGH: %d, MEDIUM: %d", len(critical), len(high), len(medium))
|
||||
t.Logf(
|
||||
"CRITICAL: %d, HIGH: %d, MEDIUM: %d",
|
||||
len(critical),
|
||||
len(high),
|
||||
len(medium),
|
||||
)
|
||||
|
||||
assert.NotEmpty(t, critical, "Should have CRITICAL findings")
|
||||
|
||||
|
|
@ -278,7 +380,12 @@ func TestE2E_FileNotFound(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
|
||||
t.Run("nonexistent Dockerfile", func(t *testing.T) {
|
||||
path := filepath.Join("..", "testdata", "dockerfiles", "does-not-exist.Dockerfile")
|
||||
path := filepath.Join(
|
||||
"..",
|
||||
"testdata",
|
||||
"dockerfiles",
|
||||
"does-not-exist.Dockerfile",
|
||||
)
|
||||
|
||||
a := analyzer.NewDockerfileAnalyzer(path)
|
||||
_, err := a.Analyze(ctx)
|
||||
|
|
@ -288,7 +395,12 @@ func TestE2E_FileNotFound(t *testing.T) {
|
|||
})
|
||||
|
||||
t.Run("nonexistent compose file", func(t *testing.T) {
|
||||
path := filepath.Join("..", "testdata", "compose", "does-not-exist.yml")
|
||||
path := filepath.Join(
|
||||
"..",
|
||||
"testdata",
|
||||
"compose",
|
||||
"does-not-exist.yml",
|
||||
)
|
||||
|
||||
a := analyzer.NewComposeAnalyzer(path)
|
||||
_, err := a.Analyze(ctx)
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import (
|
|||
"context"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"github.com/CarterPerez-dev/docksec/internal/analyzer"
|
||||
|
||||
"github.com/CarterPerez-dev/docksec/internal/analyzer"
|
||||
"github.com/CarterPerez-dev/docksec/internal/finding"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 0eec274fba59ddd373080ae961dd4497eaf2e454
|
||||
Subproject commit ecbb534e85e8e381e6e89aece4b786db8f7ad172
|
||||
Loading…
Reference in New Issue