Skip to content

Commit 8706cd7

Browse files
authored
Fix update process to only flag helpers as executable (#499)
**Why?** Multiple files were marked as executable without a specific reason to be executable. A permission change in our repository easily goes unnoticed when a pull request is opened. **What?** With this change, we keep track of the files that should be marked executable and only flag those as such. If a file would end up in the ADF repo with the wrong permissions, this will not get replicated to the bootstrap / pipelines repository as managed in ADF user environments. This change also updates the permissions of files that were marked executable without a good reason to be executable.
1 parent 16c9050 commit 8706cd7

File tree

14 files changed

+176
-29
lines changed

14 files changed

+176
-29
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ test:
55
# Run unit tests
66
pytest src/lambda_codebase/account -vvv -s -c src/lambda_codebase/account/pytest.ini
77
pytest src/lambda_codebase/account_processing -vvv -s -c src/lambda_codebase/account_processing/pytest.ini
8+
pytest src/lambda_codebase/initial_commit -vvv -s -c src/lambda_codebase/initial_commit/pytest.ini
89
pytest src/lambda_codebase/initial_commit/bootstrap_repository -vvv -s -c src/lambda_codebase/initial_commit/bootstrap_repository/pytest.ini
910
pytest src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/lambda_codebase -vvv -s -c src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/lambda_codebase/pytest.ini
11+
pytest src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/lambda_codebase/initial_commit -vvv -s -c src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/lambda_codebase/initial_commit/pytest.ini
1012
pytest src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/python -vvv -s -c src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/python/pytest.ini
1113
pytest src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk -vvv -s -c src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/pytest.ini
1214
pytest src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared -vvv -s -c src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/pytest.ini

src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/lambda_codebase/initial_commit/initial_commit.py

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
"""
2-
The Initial Commit main that is called when ADF is installed to commit the initial bootstrap repository content
2+
The Initial Commit main that is called when ADF is installed to commit the
3+
initial pipelines repository content.
34
"""
45

56
from typing import Mapping, Optional, Union, List, Dict, Any, Tuple
67
from dataclasses import dataclass
78
from enum import Enum
89
from pathlib import Path
9-
import os
1010
import re
1111
import boto3
1212
import jinja2
@@ -24,15 +24,25 @@
2424
NOT_YET_CREATED = "NOT_YET_CREATED"
2525
CC_CLIENT = boto3.client("codecommit")
2626
CONFIG_FILE_REGEX = re.compile(r"\A.*[.](yaml|yml|json)\Z", re.I)
27+
EXECUTABLE_FILES = []
2728

28-
PR_DESCRIPTION = """ADF Version {0} from https://github.com/awslabs/aws-deployment-framework
29+
PR_DESCRIPTION = """ADF Version {0}
2930
30-
This PR was automatically created when you deployed version {0} of the AWS Deployment Framework through the Serverless Application Repository.
31+
You can find the changelog at:
32+
https://github.com/awslabs/aws-deployment-framework/releases/tag/v{0}
3133
32-
Review this PR to understand what changes will be made to your bootstrapping repository. If you also made changes to the repository yourself, you might have to resolve merge conflicts before you can merge this PR.
34+
This PR was automatically created when you deployed version {0} of the
35+
AWS Deployment Framework through the Serverless Application Repository.
3336
34-
Merge this PR to complete the deployment of the version {0} of the AWS Deployment Framework.
37+
Review this PR to understand what changes will be made to your bootstrapping
38+
repository. If you also made changes to the repository yourself,
39+
you might have to resolve merge conflicts before you can merge this PR.
40+
41+
Merge this PR to complete the deployment of the version {0} of the
42+
AWS Deployment Framework.
3543
"""
44+
45+
3646
@dataclass
3747
class CustomResourceProperties:
3848
ServiceToken: str
@@ -69,7 +79,7 @@ class Event:
6979

7080
def __post_init__(self):
7181
self.ResourceProperties = CustomResourceProperties(
72-
**self.ResourceProperties # pylint: disable=not-a-mapping
82+
**self.ResourceProperties # pylint: disable=not-a-mapping
7383
)
7484

7585

@@ -101,10 +111,12 @@ def as_dict(self) -> Dict[str, Union[str, bytes]]:
101111
"filePath": self.filePath
102112
}
103113

114+
104115
@dataclass
105116
class CreateEvent(Event):
106117
pass
107118

119+
108120
@dataclass
109121
class UpdateEvent(Event):
110122
PhysicalResourceId: str
@@ -118,23 +130,27 @@ def __post_init__(self):
118130
**self.OldResourceProperties # pylint: disable=not-a-mapping
119131
)
120132

133+
121134
def generate_create_branch_input(event, repo_name, commit_id):
122135
return {
123136
"repositoryName": repo_name,
124137
"branchName": event.ResourceProperties.Version,
125138
"commitId": commit_id
126139
}
127140

141+
128142
def generate_delete_branch_input(event, repo_name):
129143
return {
130144
"repositoryName": repo_name,
131145
"branchName": event.ResourceProperties.Version
132146
}
133147

148+
134149
def chunks(list_to_chunk, number_to_chunk_into):
135150
number_of_chunks = max(1, number_to_chunk_into)
136151
return (list_to_chunk[item:item + number_of_chunks] for item in range(0, len(list_to_chunk), number_of_chunks))
137152

153+
138154
def generate_pull_request_input(event, repo_name):
139155
return {
140156
"title": f'ADF {event.ResourceProperties.Version} Automated Update PR',
@@ -148,6 +164,7 @@ def generate_pull_request_input(event, repo_name):
148164
]
149165
}
150166

167+
151168
def generate_commit_input(repo_name, index, branch="master", parent_commit_id=None, puts=None, deletes=None):
152169
commit_action = "Delete" if deletes else "Create"
153170
output = {
@@ -163,6 +180,7 @@ def generate_commit_input(repo_name, index, branch="master", parent_commit_id=No
163180
output["parentCommitId"] = parent_commit_id
164181
return output
165182

183+
166184
@create()
167185
def create_(event: Mapping[str, Any], _context: Any) -> Tuple[Union[None, PhysicalResourceId], Data]:
168186
create_event = CreateEvent(**event)
@@ -216,6 +234,7 @@ def create_(event: Mapping[str, Any], _context: Any) -> Tuple[Union[None, Physic
216234

217235
return commit_id, {}
218236

237+
219238
@update()
220239
def update_(event: Mapping[str, Any], _context: Any, create_pr=False) -> Tuple[PhysicalResourceId, Data]: #pylint: disable=R0912, R0915
221240
update_event = UpdateEvent(**event)
@@ -268,9 +287,11 @@ def update_(event: Mapping[str, Any], _context: Any, create_pr=False) -> Tuple[P
268287
def delete_(_event, _context):
269288
pass
270289

290+
271291
def repo_arn_to_name(repo_arn: str) -> str:
272292
return repo_arn.split(":")[-1]
273293

294+
274295
def get_files_to_delete(repo_name: str) -> List[FileToDelete]:
275296
differences = CC_CLIENT.get_differences(
276297
repositoryName=repo_name,
@@ -284,8 +305,12 @@ def get_files_to_delete(repo_name: str) -> List[FileToDelete]:
284305
if not CONFIG_FILE_REGEX.match(file['afterBlob']['path'])
285306
]
286307

287-
# 31: trimming off /var/task/pipelines_repository so we can compare correctly
288-
blobs = [str(filename)[31:] for filename in Path('/var/task/pipelines_repository/').rglob('*')]
308+
# 31: trimming off /var/task/pipelines_repository so
309+
# we can compare correctly
310+
blobs = [
311+
str(filename)[31:]
312+
for filename in Path('/var/task/pipelines_repository/').rglob('*')
313+
]
289314

290315
return [
291316
FileToDelete(
@@ -297,13 +322,23 @@ def get_files_to_delete(repo_name: str) -> List[FileToDelete]:
297322
]
298323

299324

325+
def determine_file_mode(entry, directoryName):
326+
if str(get_relative_name(entry, directoryName)) in EXECUTABLE_FILES:
327+
return FileMode.EXECUTABLE
328+
329+
return FileMode.NORMAL
330+
331+
300332
def get_files_to_commit(directoryName: str) -> List[FileToCommit]:
301333
path = HERE / directoryName
302334

303335
return [
304336
FileToCommit(
305337
str(get_relative_name(entry, directoryName)),
306-
FileMode.NORMAL if not os.access(entry, os.X_OK) else FileMode.EXECUTABLE,
338+
determine_file_mode(
339+
entry,
340+
directoryName,
341+
),
307342
entry.read_bytes(),
308343
)
309344
for entry in path.glob("**/*")
@@ -332,4 +367,5 @@ def create_adf_config_file(props: CustomResourceProperties) -> FileToCommit:
332367

333368
with open("/tmp/adfconfig.yml", mode="wb") as file:
334369
file.write(adf_config)
370+
335371
return FileToCommit("adfconfig.yml", FileMode.NORMAL, adf_config)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[pytest]
2+
testpaths = tests
3+
norecursedirs = pipelines_repository

src/lambda_codebase/initial_commit/bootstrap_repository/adf-bootstrap/deployment/lambda_codebase/initial_commit/tests/test_initial_commit.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@
33

44
# pylint: skip-file
55

6+
from pathlib import Path
7+
import pytest
68
from mock import Mock, patch
79
from initial_commit import (
10+
EXECUTABLE_FILES,
11+
FileMode,
812
FileToDelete,
13+
determine_file_mode,
914
get_files_to_delete,
1015
)
1116

@@ -34,6 +39,10 @@
3439
'pipeline_types/cc-cloudformation.yml.j2',
3540
'cc-cloudformation.yml.j2',
3641
]
42+
SHOULD_NOT_BE_EXECUTABLE = [
43+
"README.md",
44+
"deployment_map.yml",
45+
]
3746

3847

3948
class GenericPathMocked():
@@ -97,3 +106,23 @@ def test_get_files_to_delete(cc_client, path_cls):
97106
# Should delete all other
98107
assert all(x in result_paths for x in SHOULD_DELETE_PATHS)
99108
assert len(result_paths) == len(SHOULD_DELETE_PATHS)
109+
110+
111+
@pytest.mark.parametrize("entry", SHOULD_NOT_BE_EXECUTABLE)
112+
def test_determine_file_mode_normal(entry):
113+
base_path = "test"
114+
new_entry = f"/some/{base_path}/{entry}"
115+
assert determine_file_mode(
116+
Path(new_entry),
117+
base_path,
118+
) == FileMode.NORMAL
119+
120+
121+
@pytest.mark.parametrize("entry", EXECUTABLE_FILES)
122+
def test_determine_file_mode_executable(entry):
123+
base_path = "test"
124+
new_entry = f"/some/{base_path}/{entry}"
125+
assert determine_file_mode(
126+
Path(new_entry),
127+
base_path,
128+
) == FileMode.EXECUTABLE

src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/provisioner/src/__init__.py

100755100644
File mode changed.

src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/provisioner/src/account.py

100755100644
File mode changed.

src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/provisioner/src/configparser.py

100755100644
File mode changed.

src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/provisioner/src/vpc.py

100755100644
File mode changed.

src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/clean_pipelines.py

100755100644
File mode changed.

src/lambda_codebase/initial_commit/bootstrap_repository/adf-build/shared/cdk/execute_pipeline_stacks.py

100755100644
File mode changed.

0 commit comments

Comments
 (0)