Skip to content

Commit 578f7af

Browse files
Merge from aws/aws-sam-cli/develop
2 parents 668c8b7 + 1065683 commit 578f7af

File tree

11 files changed

+34
-118
lines changed

11 files changed

+34
-118
lines changed

.gitignore

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,6 @@ typings/
163163
# Output of 'npm pack'
164164
*.tgz
165165

166-
# Except test file
167-
!tests/functional/testdata/lib/utils/test.tgz
168-
!tests/functional/testdata/lib/utils/path_reversal_uxix.tgz
169-
!tests/functional/testdata/lib/utils/path_reversal_win.tgz
170-
171166
# Yarn Integrity file
172167
.yarn-integrity
173168

DEVELOPMENT_GUIDE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,27 @@ conventions are best practices that we have learnt over time.
328328
comments.
329329

330330

331+
### Dependency Updates
332+
333+
Please update all the required files if the changes involve a version update on a dependency or to include a new dependency. The requirements files are located inside the `requirements` folder.
334+
335+
#### base.txt for SAM CLI code dependencies
336+
For dependencies used in SAM CLI code, update `base.txt` in `requirements` folder. To update `base.txt` file, simply follow the current convention and input the dependency name plus version, together with any necessary comment. For more information on the operators to be used for restricting compatible versions, read on [python's enhancement proposals](https://peps.python.org/pep-0440/#compatible-release).
337+
338+
#### reproducible-linux.txt for SAM CLI code dependencies
339+
For dependencies used in SAM CLI code, also remember to update`reproducible-linux.txt` in `requirements` folder and `THIRD-PARTY-LICENSES` in `installer/assets` folder. To update the `reproducible-linux.txt`, run the following script to replace the file:
340+
```
341+
make update-reproducible-reqs
342+
```
343+
Note that this is a fully auto-generated file, any manual changes to reproducible-linux.txt will not last after the next update running the above script. As for updating the `THIRD-PARTY-LICENSES`, find the corresponding dependency entry in the license file (usually grouped by licensing organization) and update the versions. For adding a new dependency, look up for its licensing organization through PyPi and update the corresponding section. If the license is from GNU or another license type not included in the file, please contact the repository maintainers first. If you are not familiar with working with this file, please contact one of the repository maintainers or cut an issue to help with the update.
344+
345+
#### dev.txt for SAM CLI test dependencies
346+
For changing dependencies used for `make pr` checks and test related dependencies, update `dev.txt` in `requirements` folder only.
347+
348+
#### pyinstaller-build.txt for SAM CLI native installer build dependencies
349+
For changing Python dependencies needed for creating builds through Pyinstaller (to run `build-mac.sh` or `build-linux.sh` in `installer/pyinstaller` folder), modify `pyinstaller-build.txt`.
350+
351+
331352
### Our Testing Practices
332353

333354
We need thorough test coverage to ensure the code change works today,

samcli/lib/utils/tar.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
Tarball Archive utility
33
"""
44

5-
import os
65
import tarfile
7-
from typing import Union
86
from tempfile import TemporaryFile
97
from contextlib import contextmanager
108

@@ -41,26 +39,3 @@ def create_tarball(tar_paths, tar_filter=None, mode="w"):
4139
yield tarballfile
4240
finally:
4341
tarballfile.close()
44-
45-
46-
def _is_within_directory(directory: Union[str, os.PathLike], target: Union[str, os.PathLike]) -> bool:
47-
"""Checks if target is located under directory"""
48-
abs_directory = os.path.abspath(directory)
49-
abs_target = os.path.abspath(target)
50-
51-
prefix = os.path.commonprefix([abs_directory, abs_target])
52-
53-
return bool(prefix == abs_directory)
54-
55-
56-
def extract_tarfile(tarfile_path: Union[str, os.PathLike], unpack_dir: Union[str, os.PathLike]) -> None:
57-
"""Extracts a tarfile"""
58-
with tarfile.open(tarfile_path, "r:*") as tar:
59-
# Makes sure the tar file is sanitized and is free of directory traversal vulnerability
60-
# See: https://github.com/advisories/GHSA-gw9q-c7gh-j9vm
61-
for member in tar.getmembers():
62-
member_path = os.path.join(unpack_dir, member.name)
63-
if not _is_within_directory(unpack_dir, member_path):
64-
raise tarfile.ExtractError("Attempted Path Traversal in Tar File")
65-
66-
tar.extractall(unpack_dir)

samcli/local/docker/container.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44
import os
55
import logging
6+
import tarfile
67
import tempfile
78
import threading
89
import socket
@@ -13,7 +14,6 @@
1314

1415
from docker.errors import NotFound as DockerNetworkNotFound
1516
from samcli.lib.utils.retry import retry
16-
from samcli.lib.utils.tar import extract_tarfile
1717
from .exceptions import ContainerNotStartableException
1818

1919
from .utils import to_posix_path, find_free_port, NoFreePortsError
@@ -363,7 +363,6 @@ def _can_connect_to_socket(self) -> bool:
363363
return connection_succeeded
364364

365365
def copy(self, from_container_path, to_host_path):
366-
"""Copies a path from container into host path"""
367366

368367
if not self.is_created():
369368
raise RuntimeError("Container does not exist. Cannot get logs for this container")
@@ -379,7 +378,8 @@ def copy(self, from_container_path, to_host_path):
379378
# Seek the handle back to start of file for tarfile to use
380379
fp.seek(0)
381380

382-
extract_tarfile(tarfile_path=fp, unpack_dir=to_host_path)
381+
with tarfile.open(fileobj=fp, mode="r") as tar:
382+
tar.extractall(path=to_host_path)
383383

384384
@staticmethod
385385
def _write_container_output(output_itr, stdout=None, stderr=None):

tests/functional/lib/utils/__init__.py

Whitespace-only changes.

tests/functional/lib/utils/test_tar.py

Lines changed: 0 additions & 29 deletions
This file was deleted.
-800 Bytes
Binary file not shown.
-799 Bytes
Binary file not shown.
-769 Bytes
Binary file not shown.

tests/unit/lib/utils/test_tar.py

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
from unittest import TestCase
2-
import tarfile
32
from unittest.mock import Mock, patch, call
43

5-
from samcli.lib.utils.tar import extract_tarfile, create_tarball, _is_within_directory
4+
from samcli.lib.utils.tar import create_tarball
65

76

87
class TestTar(TestCase):
@@ -89,53 +88,3 @@ def tar_filter(tar_info):
8988
temp_file_mock.seek.assert_called_once_with(0)
9089
temp_file_mock.close.assert_called_once()
9190
tarfile_open_patch.assert_called_once_with(fileobj=temp_file_mock, mode="w")
92-
93-
@patch("samcli.lib.utils.tar.tarfile.open")
94-
@patch("samcli.lib.utils.tar._is_within_directory")
95-
def test_extract_tarfile(self, is_within_directory_patch, tarfile_open_patch):
96-
tarfile_path = "/test_tarfile_path/"
97-
unpack_dir = "/test_unpack_dir/"
98-
is_within_directory_patch.return_value = True
99-
100-
tarfile_file_mock = Mock()
101-
tar_file_obj_mock = Mock()
102-
tar_file_obj_mock.name = "obj_name"
103-
tarfile_file_mock.getmembers.return_value = [tar_file_obj_mock]
104-
tarfile_open_patch.return_value.__enter__.return_value = tarfile_file_mock
105-
106-
extract_tarfile(tarfile_path=tarfile_path, unpack_dir=unpack_dir)
107-
108-
is_within_directory_patch.assert_called_once()
109-
tarfile_file_mock.getmembers.assert_called_once()
110-
tarfile_file_mock.extractall.assert_called_once_with(unpack_dir)
111-
112-
@patch("samcli.lib.utils.tar.tarfile.open")
113-
@patch("samcli.lib.utils.tar._is_within_directory")
114-
def test_extract_tarfile_obj_not_within_dir(self, is_within_directory_patch, tarfile_open_patch):
115-
tarfile_path = "/test_tarfile_path/"
116-
unpack_dir = "/test_unpack_dir/"
117-
is_within_directory_patch.return_value = False
118-
119-
tarfile_file_mock = Mock()
120-
tar_file_obj_mock = Mock()
121-
tar_file_obj_mock.name = "obj_name"
122-
tarfile_file_mock.getmembers.return_value = [tar_file_obj_mock]
123-
tarfile_open_patch.return_value.__enter__.return_value = tarfile_file_mock
124-
125-
with self.assertRaises(tarfile.ExtractError):
126-
extract_tarfile(tarfile_path=tarfile_path, unpack_dir=unpack_dir)
127-
128-
is_within_directory_patch.assert_called_once()
129-
tarfile_file_mock.getmembers.assert_called_once()
130-
131-
def test_tarfile_obj_is_within_dir(self):
132-
directory = "/my/path"
133-
target = "/my/path/file"
134-
135-
self.assertTrue(_is_within_directory(directory, target))
136-
137-
def test_tarfile_obj_is_not_within_dir(self):
138-
directory = "/my/path"
139-
target = "/another/path/file"
140-
141-
self.assertFalse(_is_within_directory(directory, target))

0 commit comments

Comments
 (0)