Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28fa065ef9 | ||
|
|
b2cc65ef2c | ||
|
|
06b344dfac | ||
|
|
13d8399d4a | ||
|
|
adedc2277a |
5
.pypirc
Normal file
5
.pypirc
Normal file
@ -0,0 +1,5 @@
|
||||
[distutils]
|
||||
index_servers =
|
||||
private-gitea
|
||||
|
||||
[private-gitea]
|
||||
0
assets/.gitkeep
Normal file
0
assets/.gitkeep
Normal file
0
assets/compose-files/.gitkeep
Normal file
0
assets/compose-files/.gitkeep
Normal file
0
assets/dockerfiles/.gitkeep
Normal file
0
assets/dockerfiles/.gitkeep
Normal file
7
assets/dockerfiles/binary.dockerfile
Normal file
7
assets/dockerfiles/binary.dockerfile
Normal file
@ -0,0 +1,7 @@
|
||||
FROM fedora:41
|
||||
|
||||
RUN dnf install -y socat
|
||||
WORKDIR /service/
|
||||
ADD ./okay /service/okay
|
||||
RUN chmod +x ./okay
|
||||
ENTRYPOINT ["socat", "-d", "TCP-LISTEN:3000,reuseaddr,fork", "EXEC:timeout -k 5 30 ./okay"]
|
||||
9
assets/dockerfiles/crypto.dockerfile
Normal file
9
assets/dockerfiles/crypto.dockerfile
Normal file
@ -0,0 +1,9 @@
|
||||
FROM python:3.6-slim
|
||||
|
||||
RUN apt-get update && apt-get install -y socat gcc g++ make libffi-dev libssl-dev
|
||||
WORKDIR /service/
|
||||
COPY ./requirements.txt ./requirements.txt
|
||||
RUN pip install -r requirements.txt
|
||||
ADD ./main.py ./main.py
|
||||
RUN chmod +x main.py
|
||||
ENTRYPOINT socat -d TCP-LISTEN:3000,reuseaddr,fork EXEC:'timeout -k 5 30 python3 -u main.py'
|
||||
20
assets/dockerfiles/web.dockerfile
Normal file
20
assets/dockerfiles/web.dockerfile
Normal file
@ -0,0 +1,20 @@
|
||||
FROM docker.io/oven/bun AS frontend
|
||||
|
||||
WORKDIR /app
|
||||
COPY frontend/package*.json ./
|
||||
RUN bun i
|
||||
COPY frontend/ .
|
||||
RUN bun run build
|
||||
|
||||
|
||||
FROM python:3.12-slim
|
||||
|
||||
ENV DOCKER=1
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./backend/requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY ./backend/ .
|
||||
COPY --from=frontend /app/dist /app/frontend
|
||||
|
||||
CMD ["python3", "app.py"]
|
||||
25
assets/dockerfiles/with-chunks.dockerfile
Normal file
25
assets/dockerfiles/with-chunks.dockerfile
Normal file
@ -0,0 +1,25 @@
|
||||
FROM docker.io/oven/bun AS frontend
|
||||
|
||||
WORKDIR /app
|
||||
COPY frontend/package*.json ./
|
||||
RUN bun i
|
||||
COPY frontend/ .
|
||||
RUN bun run build
|
||||
|
||||
|
||||
FROM python:3.12-slim
|
||||
|
||||
ENV DOCKER=1
|
||||
WORKDIR /app
|
||||
|
||||
COPY ./backend/requirements.txt \
|
||||
.
|
||||
RUN pip install --no-cache-dir -r \
|
||||
requirements.txt
|
||||
COPY ./backend/ \
|
||||
\
|
||||
\
|
||||
.
|
||||
COPY --from=frontend /app/dist /app/frontend
|
||||
|
||||
CMD ["python3", "app.py"]
|
||||
0
src/docktoranalyzer/__init__.py
Normal file
0
src/docktoranalyzer/__init__.py
Normal file
6
src/docktoranalyzer/common/errors.py
Normal file
6
src/docktoranalyzer/common/errors.py
Normal file
@ -0,0 +1,6 @@
|
||||
class NotImplemented(Exception):
|
||||
|
||||
def __init__(self, *args):
|
||||
super().__init__(*args)
|
||||
|
||||
# TODO: Implement a way to print the method not impelemented
|
||||
29
src/docktoranalyzer/dockerfile/command_parser_utils.py
Normal file
29
src/docktoranalyzer/dockerfile/command_parser_utils.py
Normal file
@ -0,0 +1,29 @@
|
||||
import re
|
||||
import shlex
|
||||
from docktoranalyzer.dockerfile.docker_constants import DockerConstants
|
||||
|
||||
|
||||
def command_parser(command_line: str):
|
||||
|
||||
PARENTHESIS_OFFSET = 1
|
||||
|
||||
args: list[str] = []
|
||||
array_insides: str = ""
|
||||
|
||||
command_line = command_line.strip()
|
||||
|
||||
arr_regex = re.compile(DockerConstants.EXEC_FORM_REGEX)
|
||||
match = arr_regex.search(command_line)
|
||||
|
||||
if match is not None:
|
||||
array_insides = command_line[match.start(): -1]
|
||||
command_line = command_line[0:match.start() - PARENTHESIS_OFFSET]
|
||||
|
||||
args.extend(shlex.split(
|
||||
command_line
|
||||
))
|
||||
args.extend(shlex.split(
|
||||
array_insides
|
||||
))
|
||||
|
||||
return args
|
||||
8
src/docktoranalyzer/dockerfile/docker_constants.py
Normal file
8
src/docktoranalyzer/dockerfile/docker_constants.py
Normal file
@ -0,0 +1,8 @@
|
||||
from typing import Final
|
||||
|
||||
|
||||
class DockerConstants:
|
||||
|
||||
LINE_CONTINUATION_REGEX: Final[str] = r"(^[\s]*\\[\s]*$|[\s]+\\[\s]*$)"
|
||||
COMMENT_REGEX: Final[str] = r"[\s]*#"
|
||||
EXEC_FORM_REGEX: Final[str] = r"(?<!\\\[)(?<=\[).*[^\\](?=\])"
|
||||
38
src/docktoranalyzer/dockerfile/dockerfile_.py
Normal file
38
src/docktoranalyzer/dockerfile/dockerfile_.py
Normal file
@ -0,0 +1,38 @@
|
||||
from pathlib import Path
|
||||
from docktoranalyzer.dockerfile.dockerfile_instructions import (
|
||||
DockerInstruction,
|
||||
)
|
||||
|
||||
|
||||
# TODO: Make DockerStage have a DockerFS
|
||||
class DockerStage:
|
||||
"""_summary_
|
||||
Class that holds a Build Stage
|
||||
"""
|
||||
|
||||
def __init__(self, instructions: list[DockerInstruction]):
|
||||
self.commands: list[DockerInstruction] = []
|
||||
|
||||
self.commands = instructions
|
||||
|
||||
|
||||
class DockerFS:
|
||||
"""_summary_
|
||||
Class to take map file instructions
|
||||
"""
|
||||
|
||||
def __init__(self, last_build_stage: DockerStage):
|
||||
pass
|
||||
|
||||
|
||||
class Dockerfile:
|
||||
"""_summary_
|
||||
Class holding a representation of Dockerfile
|
||||
"""
|
||||
|
||||
def __init__(self, build_stages: list[DockerStage]):
|
||||
self.stages: list[DockerStage] = []
|
||||
self.fs: DockerFS
|
||||
|
||||
self.stages = build_stages
|
||||
self.fs = DockerFS(self.stages[-1])
|
||||
0
src/docktoranalyzer/dockerfile/dockerfile_errors.py
Normal file
0
src/docktoranalyzer/dockerfile/dockerfile_errors.py
Normal file
238
src/docktoranalyzer/dockerfile/dockerfile_instructions.py
Normal file
238
src/docktoranalyzer/dockerfile/dockerfile_instructions.py
Normal file
@ -0,0 +1,238 @@
|
||||
import re
|
||||
import shlex
|
||||
from docktoranalyzer.dockerfile.command_parser_utils import command_parser
|
||||
from docktoranalyzer.dockerfile.docker_constants import DockerConstants
|
||||
from docktoranalyzer.dockerfile.instruction_enums import DockerInstructionType
|
||||
|
||||
|
||||
# UGLY: refactor this
|
||||
def split_options_value(option: str) -> list[str]:
|
||||
return option.split("=")
|
||||
|
||||
|
||||
def split_args(command):
|
||||
pass
|
||||
|
||||
|
||||
# MARK: InstructionChunk
|
||||
class InstructionChunk:
|
||||
|
||||
def __init__(self, chunk_lines: list[str]):
|
||||
# UGLY: could preallocate space
|
||||
self.lines: list[str] = []
|
||||
|
||||
tmp = chunk_lines.copy()
|
||||
regex = re.compile(DockerConstants.LINE_CONTINUATION_REGEX)
|
||||
|
||||
for line in tmp:
|
||||
line = regex.sub("", line)
|
||||
self.lines.append(line)
|
||||
|
||||
def is_empty(self):
|
||||
|
||||
if len(self.lines[0]) == 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
def __len__(self):
|
||||
return len(self.lines)
|
||||
|
||||
def __str__(self):
|
||||
pass
|
||||
|
||||
|
||||
# MARK: DockerInstruction
|
||||
class DockerInstruction:
|
||||
"""_summary_
|
||||
Base Structure for all docker instructions
|
||||
"""
|
||||
|
||||
def __init__(self, chunk: list[str]):
|
||||
self.type: DockerInstructionType = DockerInstructionType.UNPARSED
|
||||
self.chunk: InstructionChunk = chunk
|
||||
self.command: str = ""
|
||||
self.args: str = ""
|
||||
|
||||
if self.chunk.is_empty():
|
||||
self.type = DockerInstructionType.EMPTY
|
||||
return
|
||||
|
||||
total_command = " ".join(self.chunk.lines)
|
||||
command_words = command_parser(total_command)
|
||||
self.command = command_words[0]
|
||||
self.args = command_words[1:]
|
||||
|
||||
|
||||
# MARK: COMMENT
|
||||
class DockerCOMMENT(DockerInstruction):
|
||||
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
self.type = DockerInstructionType.COMMENT
|
||||
|
||||
|
||||
# TODO: Work on ADD
|
||||
# MARK: ADD
|
||||
class DockerADD(DockerInstruction):
|
||||
|
||||
# --key=value
|
||||
__OPTIONS: set[str] = {
|
||||
"--keep-git-dir",
|
||||
"--checksum",
|
||||
"--chown",
|
||||
"--chmod",
|
||||
"--link",
|
||||
"--exclude",
|
||||
}
|
||||
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
self.options: list[str] = []
|
||||
self.type = DockerInstructionType.ADD
|
||||
self.remote: list[str] = []
|
||||
self.local: list[str] = []
|
||||
self.destination: str = ""
|
||||
|
||||
for arg in self.args:
|
||||
|
||||
if arg in DockerADD.__OPTIONS:
|
||||
self.options.append(
|
||||
arg
|
||||
)
|
||||
|
||||
if "]" in arg or "[" in arg:
|
||||
pass
|
||||
|
||||
|
||||
class DockerARG(DockerInstruction):
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
|
||||
# TODO: Work on CMD
|
||||
# MARK: CMD
|
||||
class DockerCMD(DockerInstruction):
|
||||
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
self.type = DockerInstructionType.CMD
|
||||
|
||||
|
||||
# TODO: Work on Copy
|
||||
# MARK: COPY
|
||||
class DockerCOPY(DockerInstruction):
|
||||
|
||||
# --key=value
|
||||
__OPTIONS: set[str] = {
|
||||
"--from",
|
||||
"--chown",
|
||||
"--chmod",
|
||||
"--link",
|
||||
"--parents",
|
||||
"--exclude",
|
||||
}
|
||||
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
self.type = DockerInstructionType.COPY
|
||||
|
||||
|
||||
# TODO: Work on ENTRYPOINT
|
||||
class DockerENTRYPOINT(DockerInstruction):
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
self.type = DockerInstructionType.ENTRYPOINT
|
||||
|
||||
|
||||
class DockerENV(DockerInstruction):
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
|
||||
class DockerEXPOSE(DockerInstruction):
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
|
||||
# TODO: Work on FROM
|
||||
# MARK: FROM
|
||||
class DockerFROM(DockerInstruction):
|
||||
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
self.type = DockerInstructionType.FROM
|
||||
|
||||
|
||||
class DockerHEALTHCHECK(DockerInstruction):
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
|
||||
class DockerLABEL(DockerInstruction):
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
|
||||
class DockerMAINTAINER(DockerInstruction):
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
|
||||
class DockerONBUILD(DockerInstruction):
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
|
||||
# TODO: Work on run
|
||||
# MARK: RUN
|
||||
class DockerRUN(DockerInstruction):
|
||||
|
||||
# This variable is only --key=value
|
||||
__OPTIONS: set[str] = {"--mount", "--netowrk", "--security"}
|
||||
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
self.type = DockerInstructionType.RUN
|
||||
|
||||
|
||||
class DockerSHELL(DockerInstruction):
|
||||
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
|
||||
class DockerSTOPSIGNAL(DockerInstruction):
|
||||
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
|
||||
class DockerUSER(DockerInstruction):
|
||||
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
|
||||
class DockerVOLUME(DockerInstruction):
|
||||
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
|
||||
# TODO: Work on workdir
|
||||
# MARK: WORKDIR
|
||||
class DockerWORKDIR(DockerInstruction):
|
||||
|
||||
def __init__(self, chunk: list[str]):
|
||||
super().__init__(chunk)
|
||||
|
||||
self.type = DockerInstructionType.WORKDIR
|
||||
|
||||
# TODO: Add workdirectory property
|
||||
194
src/docktoranalyzer/dockerfile/dockerfile_parser.py
Normal file
194
src/docktoranalyzer/dockerfile/dockerfile_parser.py
Normal file
@ -0,0 +1,194 @@
|
||||
from pathlib import Path
|
||||
import re
|
||||
import shlex
|
||||
from docktoranalyzer.dockerfile.docker_constants import DockerConstants
|
||||
from docktoranalyzer.dockerfile.instruction_enums import DockerInstructionType
|
||||
from docktoranalyzer.dockerfile.dockerfile_ import DockerStage, Dockerfile
|
||||
from docktoranalyzer.dockerfile.dockerfile_instructions import (
|
||||
DockerADD,
|
||||
DockerCMD,
|
||||
DockerCOMMENT,
|
||||
DockerCOPY,
|
||||
DockerENTRYPOINT,
|
||||
DockerFROM,
|
||||
DockerInstruction,
|
||||
DockerRUN,
|
||||
DockerWORKDIR,
|
||||
InstructionChunk,
|
||||
)
|
||||
|
||||
|
||||
class DockerFileParser:
|
||||
|
||||
DEFAULT_ESCAPE_STRING = "\\"
|
||||
DEFAULT_LINE_CONTINUATION = "\\"
|
||||
DIRECTIVE_REGEX = re.compile(
|
||||
"# +(?P<directive_name>[^\\s]*)=(?P<value>[^\\s]*)"
|
||||
)
|
||||
|
||||
def __new__(cls):
|
||||
raise TypeError("Static classes cannot be instantiated")
|
||||
|
||||
# MARK: dockerfile_factory()
|
||||
@staticmethod
|
||||
def dockerfile_factory(dockerfile_path: Path):
|
||||
|
||||
if not dockerfile_path.is_file():
|
||||
raise FileNotFoundError(f"{dockerfile_path} is not a valid path")
|
||||
|
||||
dockerfile = dockerfile_path.open()
|
||||
docker_instructions = dockerfile.readlines()
|
||||
dockerfile.close()
|
||||
|
||||
chunks = DockerFileParser.__parse_chunks(docker_instructions)
|
||||
instructions = DockerFileParser.__parse_instructions(chunks)
|
||||
stages = DockerFileParser.__parse_stages(instructions)
|
||||
|
||||
return Dockerfile(stages.copy())
|
||||
|
||||
# MARK: __parse_directives()
|
||||
@staticmethod
|
||||
def __parse_directives(docker_lines: list[str]):
|
||||
|
||||
found_directives: set[str] = set()
|
||||
|
||||
for line in docker_lines:
|
||||
|
||||
line_length = len(line)
|
||||
|
||||
# Line is too short to
|
||||
# make a directive
|
||||
if line_length < 4:
|
||||
continue
|
||||
|
||||
match = DockerFileParser.DIRECTIVE_REGEX.match(line)
|
||||
|
||||
# No match found
|
||||
if match is None:
|
||||
continue
|
||||
|
||||
directive_name = match.group("directive_name")
|
||||
value = match.group("value")
|
||||
|
||||
# Duplicate directive, ignore
|
||||
if directive_name in found_directives:
|
||||
continue
|
||||
|
||||
found_directives.add(directive_name)
|
||||
|
||||
if directive_name == "escape":
|
||||
DockerFileParser.ESCAPE_STRING = value
|
||||
|
||||
# MARK: __parse_chunks()
|
||||
@staticmethod
|
||||
def __parse_chunks(
|
||||
instruction_lines: list[str],
|
||||
line_continuation_regex: str = DockerConstants.LINE_CONTINUATION_REGEX,
|
||||
) -> list[InstructionChunk]:
|
||||
|
||||
continuation_check = re.compile(line_continuation_regex)
|
||||
comment_check = re.compile(DockerConstants.COMMENT_REGEX)
|
||||
chunks: list[InstructionChunk] = []
|
||||
accumulator: list[str] = []
|
||||
|
||||
for line in instruction_lines:
|
||||
line = line.rstrip()
|
||||
accumulator.append(line)
|
||||
|
||||
# If line is a comment, it can't continue
|
||||
if comment_check.search(line) is not None:
|
||||
|
||||
if len(accumulator) > 1:
|
||||
accumulator.pop()
|
||||
chunks.append(InstructionChunk(accumulator))
|
||||
|
||||
chunks.append(InstructionChunk([line]))
|
||||
accumulator = []
|
||||
|
||||
# If line doesn't continue, join everything found
|
||||
if continuation_check.search(line) is None:
|
||||
chunks.append(InstructionChunk(accumulator))
|
||||
accumulator = []
|
||||
|
||||
return chunks
|
||||
|
||||
# MARK: __parse_instruction()
|
||||
@staticmethod
|
||||
def __parse_instructions(
|
||||
instruction_chunks: list[InstructionChunk],
|
||||
) -> list[DockerInstruction]:
|
||||
|
||||
docker_instructions: list[DockerInstruction] = []
|
||||
|
||||
for chunk in instruction_chunks:
|
||||
docker_instructions.append(
|
||||
DockerFileParser.__instruction_mapper(chunk)
|
||||
)
|
||||
|
||||
return docker_instructions
|
||||
|
||||
# MARK: __instruction_mapper()
|
||||
@staticmethod
|
||||
def __instruction_mapper(
|
||||
chunk: InstructionChunk,
|
||||
) -> DockerInstruction:
|
||||
|
||||
if chunk.is_empty():
|
||||
return DockerInstruction(chunk)
|
||||
|
||||
command = shlex.split(chunk.lines[0])[0]
|
||||
|
||||
if command == "#":
|
||||
return DockerCOMMENT(chunk)
|
||||
|
||||
instruction_type: DockerInstructionType = DockerInstructionType[
|
||||
f"{command}"
|
||||
]
|
||||
|
||||
match instruction_type:
|
||||
|
||||
case DockerInstructionType.CMD:
|
||||
return DockerCMD(chunk)
|
||||
|
||||
case DockerInstructionType.COPY:
|
||||
return DockerCOPY(chunk)
|
||||
|
||||
case DockerInstructionType.ENTRYPOINT:
|
||||
return DockerENTRYPOINT(chunk)
|
||||
|
||||
case DockerInstructionType.FROM:
|
||||
return DockerFROM(chunk)
|
||||
|
||||
case DockerInstructionType.RUN:
|
||||
return DockerRUN(chunk)
|
||||
|
||||
case DockerInstructionType.ADD:
|
||||
return DockerADD(chunk)
|
||||
|
||||
case DockerInstructionType.WORKDIR:
|
||||
return DockerWORKDIR(chunk)
|
||||
|
||||
case _:
|
||||
return DockerInstruction(chunk)
|
||||
|
||||
# MARK: __parse_stages()
|
||||
@staticmethod
|
||||
def __parse_stages(
|
||||
instructions: list[DockerInstruction],
|
||||
) -> list[DockerStage]:
|
||||
|
||||
stages: list[DockerStage] = []
|
||||
accumulator: list[DockerInstruction] = []
|
||||
|
||||
for instruction in instructions:
|
||||
|
||||
if instruction.type is DockerInstructionType.FROM:
|
||||
|
||||
stages.append(DockerStage(accumulator.copy()))
|
||||
accumulator = []
|
||||
|
||||
accumulator.append(instruction)
|
||||
|
||||
stages.append(DockerStage(accumulator.copy()))
|
||||
|
||||
return stages
|
||||
30
src/docktoranalyzer/dockerfile/instruction_enums.py
Normal file
30
src/docktoranalyzer/dockerfile/instruction_enums.py
Normal file
@ -0,0 +1,30 @@
|
||||
from enum import Enum, auto
|
||||
|
||||
|
||||
class DockerInstructionType(Enum):
|
||||
|
||||
# Special values
|
||||
UNPARSED = auto()
|
||||
UNKOWN = auto()
|
||||
EMPTY = auto()
|
||||
COMMENT = auto()
|
||||
|
||||
# Docker Instructions
|
||||
ADD = auto()
|
||||
ARG = auto()
|
||||
CMD = auto()
|
||||
COPY = auto()
|
||||
ENTRYPOINT = auto()
|
||||
ENV = auto()
|
||||
EXPOSE = auto()
|
||||
FROM = auto()
|
||||
HEALTHCHECK = auto()
|
||||
LABEL = auto()
|
||||
MAINTAINER = auto()
|
||||
ONBUILD = auto()
|
||||
RUN = auto()
|
||||
SHELL = auto()
|
||||
STOPSIGNAL = auto()
|
||||
USER = auto()
|
||||
VOLUME = auto()
|
||||
WORKDIR = auto()
|
||||
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
0
tests/integration-tests/.gitkeep
Normal file
0
tests/integration-tests/.gitkeep
Normal file
36
tests/unit-tests/instruction_test.py
Normal file
36
tests/unit-tests/instruction_test.py
Normal file
@ -0,0 +1,36 @@
|
||||
# content of test_sample.py
|
||||
from pathlib import Path
|
||||
import re
|
||||
import pytest
|
||||
import docktoranalyzer
|
||||
import docktoranalyzer.dockerfile
|
||||
from docktoranalyzer.dockerfile.docker_constants import DockerConstants
|
||||
from docktoranalyzer.dockerfile.dockerfile_parser import DockerFileParser
|
||||
|
||||
# TODO: use a glob to take files and rege
|
||||
@pytest.fixture
|
||||
def docker_file_arrays():
|
||||
|
||||
# I need to count one stage over to account for instructions
|
||||
# the first FROM
|
||||
return [
|
||||
{"path": "./assets/dockerfiles/binary.dockerfile", "stages": 2},
|
||||
{"path": "./assets/dockerfiles/crypto.dockerfile", "stages": 2},
|
||||
{"path": "./assets/dockerfiles/web.dockerfile", "stages": 3},
|
||||
{"path": "./assets/dockerfiles/with-chunks.dockerfile", "stages": 3},
|
||||
]
|
||||
|
||||
|
||||
# TODO: Make tests for regex
|
||||
|
||||
|
||||
def test_dockerfile_parser(docker_file_arrays):
|
||||
|
||||
for docker_file_info in docker_file_arrays:
|
||||
|
||||
docker_path = docker_file_info["path"]
|
||||
actual_stages = docker_file_info["stages"]
|
||||
|
||||
docker = DockerFileParser.dockerfile_factory(Path(docker_path))
|
||||
|
||||
assert len(docker.stages) == actual_stages
|
||||
Loading…
x
Reference in New Issue
Block a user