Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polyglot repair of configuration drifts in IaC scripts #49

Merged
merged 63 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
f773dd9
WIP: strace wrapper. start strace parser
Nfsaavedra Dec 15, 2023
99db191
WIP: strace parser
Nfsaavedra Dec 20, 2023
bf45ee9
refactor strace parser. extract strace model
Nfsaavedra Dec 20, 2023
5320b8d
support parsing function calls and dictionaries
Nfsaavedra Dec 20, 2023
68f8c1a
create package tracer. add support for more syscalls. get affected pa…
Nfsaavedra Jan 2, 2024
f3798d2
change paths to absolute paths
Nfsaavedra Jan 2, 2024
1892253
handle chdir
Nfsaavedra Jan 2, 2024
693fa2f
get file system state from affected files
Nfsaavedra Jan 2, 2024
1207526
delta P model
Nfsaavedra Jan 10, 2024
f436206
compile to delta P model prototype
Nfsaavedra Jan 11, 2024
84c2d4a
delta P to filesystem
Nfsaavedra Jan 11, 2024
ad6fd13
Labeler and use lets for handling attributes
Nfsaavedra Jan 21, 2024
b54232a
Implement first version of soft and hard constraints
Nfsaavedra Jan 21, 2024
ae0bb6f
refactor to allow branching
Nfsaavedra Jan 23, 2024
d7b93b5
WIP
Nfsaavedra Jan 23, 2024
e63f92a
prototype that generates the constraints correctly
Nfsaavedra Jan 23, 2024
5f3a430
small refactor
Nfsaavedra Jan 23, 2024
df35576
add sketched variables and black
Nfsaavedra Jan 30, 2024
3c6d0e2
fix sketched attribute
Nfsaavedra Jan 30, 2024
455f3c2
Implement let and if in to_filesystem
Nfsaavedra Jan 30, 2024
7ce3d1d
small fix
Nfsaavedra Jan 30, 2024
acf71a4
fix getting paths in name of atomic unit
Nfsaavedra Jan 30, 2024
0afa245
support variables as values in to_filesystem
Nfsaavedra Jan 30, 2024
578d9db
support file state
Nfsaavedra Jan 30, 2024
47a2582
apply patch
Nfsaavedra Jan 30, 2024
1c1ae17
fix hard constraints for mode and owner
Nfsaavedra Jan 30, 2024
4d5c22c
allow owner, mode and content to be sketched
Nfsaavedra Jan 30, 2024
8553d5e
remove attributes
Nfsaavedra Jan 31, 2024
c4eee4b
support repair in Ansible
Nfsaavedra Jan 31, 2024
958a4b7
support touch state
Nfsaavedra Jan 31, 2024
505a538
fix
Nfsaavedra Jan 31, 2024
159643a
add write statement, change way content is handling, generate multipl…
Nfsaavedra Feb 23, 2024
3b2c38c
minimize deltap
Nfsaavedra Feb 24, 2024
b0d5ea7
fix minimize deltap
Nfsaavedra Feb 24, 2024
8691714
fix with sketch attributes
Nfsaavedra Feb 24, 2024
ba1b514
fix way sketches are created
Nfsaavedra Feb 24, 2024
d086330
fix test
Nfsaavedra Feb 24, 2024
14d230b
fix non-unique sketch attributes
Nfsaavedra Feb 24, 2024
b955402
parse ifs in Puppet
Nfsaavedra Feb 26, 2024
8c12516
add if branching
Nfsaavedra Feb 27, 2024
5069b4d
small fix
Nfsaavedra Feb 27, 2024
1bce15c
transform deltap in multiple filesystems when if conditions have unkn…
Nfsaavedra Feb 27, 2024
41b7e5e
fix problem with atomic units without state defined
Nfsaavedra Feb 27, 2024
0d5dd06
fix problem with names not being translated back to their original te…
Nfsaavedra Feb 27, 2024
b4f1372
fix atomic units not being found
Nfsaavedra Feb 27, 2024
3e7a98d
allow to pass context to solver
Nfsaavedra Feb 27, 2024
b09e518
hack
Nfsaavedra Feb 28, 2024
42435dc
add timeout
Nfsaavedra Feb 28, 2024
d9501f1
allow to change timeout
Nfsaavedra Feb 28, 2024
a2d1139
small fix
Nfsaavedra Feb 28, 2024
d877c04
fix conditionals
Nfsaavedra Feb 28, 2024
b29bb35
fix timeout
Nfsaavedra Feb 28, 2024
5d5876f
fix missing conditions
Nfsaavedra Feb 28, 2024
3d34ced
test remove condition
Nfsaavedra Feb 28, 2024
5f8f454
remove conditions from if
Nfsaavedra Feb 28, 2024
3fddba5
small fix on reverse_attr_name
Nfsaavedra Feb 29, 2024
7f98b72
add alias to path in Ansible
Nfsaavedra Feb 29, 2024
60f1747
Merge branch 'main' into interactive_repair
Nfsaavedra Mar 18, 2024
1750b12
fix conditional statement name change
Nfsaavedra Mar 18, 2024
b9f677b
fix FIXMEs
Nfsaavedra Mar 18, 2024
faba613
add missing docstrings
Nfsaavedra Mar 18, 2024
8235ee8
add tests
Nfsaavedra Mar 19, 2024
cf97c52
remove test code
Nfsaavedra Mar 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions glitch/analysis/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ def check_comment(self, c: Comment, file: str) -> List[Error]:

def check_condition(self, c: ConditionalStatement, file: str) -> List[Error]:
errors = super().check_condition(c, file)
if c.type != ConditionalStatement.ConditionType.SWITCH:
return errors

condition = c
has_default = False
Expand Down
27 changes: 21 additions & 6 deletions glitch/parsers/cmof.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ def create_attribute(token, name, value) -> Attribute:
if (value in ["null", "~"]): value = ""
a = Attribute(name, value, has_variable)
a.line = token.start_mark.line + 1
a.column = token.start_mark.column + 1
if val == None:
a.code = AnsibleParser.__get_element_code(token, token, code)
else:
Expand Down Expand Up @@ -1283,14 +1284,28 @@ def process_hash_value(name: str, temp_value):
if lamb != "": return [res] + lamb
else: return res
elif (isinstance(codeelement, puppetmodel.If)):
# FIXME Conditionals are not yet supported
res = list(map(lambda ce: PuppetParser.__process_codeelement(ce, path, code),
codeelement.block))
condition = PuppetParser.__process_codeelement(
codeelement.condition, path, code
)
condition = ConditionalStatement(
condition, ConditionalStatement.ConditionType.IF
)
body = list(
map(
lambda ce: PuppetParser.__process_codeelement(ce, path, code),
codeelement.block
)
)
for statement in body:
condition.add_statement(statement)

if (codeelement.elseblock is not None):
res += PuppetParser.__process_codeelement(codeelement.elseblock, path, code)
return res
condition.else_statement = PuppetParser.__process_codeelement(
codeelement.elseblock, path, code
)
return condition
elif (isinstance(codeelement, puppetmodel.Unless)):
# FIXME Conditionals are not yet supported
# FIXME Unless is not yet supported
res = list(map(lambda ce: PuppetParser.__process_codeelement(ce, path, code),
codeelement.block))
if (codeelement.elseblock is not None):
Expand Down
Empty file added glitch/repair/__init__.py
Empty file.
Empty file.
249 changes: 249 additions & 0 deletions glitch/repair/interactive/compiler/compiler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
from typing import Optional, Dict, Tuple

from glitch.tech import Tech
from glitch.repr.inter import *
from glitch.repair.interactive.delta_p import *
from glitch.repair.interactive.compiler.names_database import NamesDatabase
from glitch.repair.interactive.compiler.labeler import LabeledUnitBlock
from glitch.repair.interactive.values import DefaultValue


class DeltaPCompiler:
_sketched = -1
_condition = 0

class __Attributes:
def __init__(self, au_type: str, tech: Tech):
self.au_type = NamesDatabase.get_au_type(au_type, tech)
self.__tech = tech
self.__attributes: Dict[str, Tuple[PExpr, Attribute]] = {}

def add_attribute(self, attribute: Attribute):
attr_name = NamesDatabase.get_attr_name(
attribute.name, self.au_type, self.__tech
)
if attr_name is not None:
self.__attributes[attr_name] = (
DeltaPCompiler._compile_expr(
NamesDatabase.get_attr_value(
attribute.value,
attr_name,
self.au_type,
self.__tech,
),
self.__tech,
),
attribute,
)

def get_attribute(self, attr_name: str) -> Optional[Attribute]:
return self.__attributes.get(attr_name, (None, None))[1]

def get_attribute_value(self, attr_name: str) -> PExpr:
default = PEUndef()
if attr_name == "state":
default = DefaultValue.DEFAULT_STATE
elif attr_name == "mode":
default = DefaultValue.DEFAULT_MODE
elif attr_name == "owner":
default = DefaultValue.DEFAULT_OWNER
elif attr_name == "content":
default = DefaultValue.DEFAULT_CONTENT

return self.__attributes.get(attr_name, (default, None))[0]

def __getitem__(self, key: str) -> PExpr:
return self.get_attribute_value(key)

def create_label_var_pair(
self,
attr_name: str,
atomic_unit: AtomicUnit,
labeled_script: LabeledUnitBlock,
) -> Optional[Tuple[str, str]]:
attr = self.get_attribute(attr_name)

if attr is not None:
label = labeled_script.get_label(attr)
else:
# Creates sketched attribute
if attr_name == "state": # HACK
attr = Attribute(
attr_name,
DefaultValue.DEFAULT_STATE.const.value,
False
)
else:
attr = Attribute(attr_name, PEUndef(), False)

attr.line, attr.column = (
DeltaPCompiler._sketched,
DeltaPCompiler._sketched,
)
DeltaPCompiler._sketched -= 1
labeled_script.add_sketch_location(atomic_unit, attr)
self.add_attribute(attr)
label = labeled_script.add_label(attr_name, attr, sketched=True)

return label, labeled_script.get_var(label)

@staticmethod
def _compile_expr(expr: Optional[str], tech: Tech) -> PExpr:
# FIXME to fix this I need to extend GLITCH's IR
if expr is None:
return None
if isinstance(expr, PEUndef):
return expr

return PEConst(PStr(expr))

@staticmethod
def __handle_file(
atomic_unit: AtomicUnit,
attributes: __Attributes,
labeled_script: LabeledUnitBlock,
) -> PStatement:
path = attributes["path"]
# The path may be defined as the name of the atomic unit
if path == PEUndef():
path = PEConst(PStr(atomic_unit.name))

state_label, state_var = attributes.create_label_var_pair(
"state", atomic_unit, labeled_script
)
statement = PLet(
state_var,
attributes["state"],
state_label,
PIf(
PEBinOP(PEq(), PEVar(state_var), PEConst(PStr("present"))),
PCreate(path),
PIf(
PEBinOP(PEq(), PEVar(state_var), PEConst(PStr("absent"))),
PRm(path),
PIf(
PEBinOP(PEq(), PEVar(state_var), PEConst(PStr("directory"))),
PMkdir(path),
PSkip(),
),
),
),
)

content_label, content_var = attributes.create_label_var_pair(
"content", atomic_unit, labeled_script
)
statement = PSeq(
statement,
PLet(
content_var,
attributes["content"],
content_label,
PWrite(path, PEVar(content_var)),
),
)

owner_label, owner_var = attributes.create_label_var_pair(
"owner", atomic_unit, labeled_script
)
statement = PSeq(
statement,
PLet(
owner_var,
attributes["owner"],
owner_label,
PChown(path, PEVar(owner_var)),
),
)

mode_label, mode_var = attributes.create_label_var_pair(
"mode", atomic_unit, labeled_script
)
statement = PSeq(
statement,
PLet(
mode_var,
attributes["mode"],
mode_label,
PChmod(path, PEVar(mode_var)),
),
)

return statement

@staticmethod
def __handle_atomic_unit(
statement: PStatement,
atomic_unit: AtomicUnit,
tech: Tech,
labeled_script: LabeledUnitBlock
) -> PStatement:
attributes: DeltaPCompiler.__Attributes = DeltaPCompiler.__Attributes(
atomic_unit.type, tech
)
if attributes.au_type == "file":
for attribute in atomic_unit.attributes:
attributes.add_attribute(attribute)
statement = PSeq(
statement,
DeltaPCompiler.__handle_file(atomic_unit, attributes, labeled_script),
)
return statement

@staticmethod
def __handle_conditional(
conditional: ConditionalStatement,
tech: Tech,
labeled_script: LabeledUnitBlock
) -> PStatement:
body = PSkip()
for stat in conditional.statements:
if isinstance(stat, AtomicUnit):
body = DeltaPCompiler.__handle_atomic_unit(
body, stat, tech, labeled_script
)
elif isinstance(stat, ConditionalStatement):
body = PSeq(
body,
DeltaPCompiler.__handle_conditional(
stat, tech, labeled_script
)
)

else_statement = PSkip()
if conditional.else_statement is not None:
else_statement = DeltaPCompiler.__handle_conditional(
conditional.else_statement, tech, labeled_script
)

DeltaPCompiler._condition += 1
return PIf(
# FIXME: This creates a placeholder since we will branch every time
# There are cases that we can infer the value of the condition
# The creation of these variables should be done in the solver
PEVar(f"dejavu-condition-{DeltaPCompiler._condition}"),
body,
else_statement
)

@staticmethod
def compile(labeled_script: LabeledUnitBlock, tech: Tech) -> PStatement:
statement = PSkip()
script = labeled_script.script

# TODO: Handle variables
# TODO: Handle scopes
# TODO: The statements will not be in the correct order

for stat in script.statements:
if isinstance(stat, ConditionalStatement):
statement = PSeq(statement, DeltaPCompiler.__handle_conditional(
stat, tech, labeled_script
))

for atomic_unit in script.atomic_units:
statement = DeltaPCompiler.__handle_atomic_unit(
statement, atomic_unit, tech, labeled_script
)

return statement
Loading
Loading