Skip to content

Commit 60a4da0

Browse files
authored
Merge pull request #1008 from sechkova/rework_path_checks
Adopt a consistent behavior when adding targets and paths
2 parents efd901f + 882df8e commit 60a4da0

8 files changed

+300
-222
lines changed

docs/TUTORIAL.md

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -352,15 +352,8 @@ the target filepaths to metadata.
352352
# in targets metadata.
353353
>>> repository = load_repository('repository')
354354

355-
# get_filepaths_in_directory() returns a list of file paths in a directory. It
356-
# can also return files in sub-directories if 'recursive_walk' is True.
357-
>>> list_of_targets = repository.get_filepaths_in_directory(
358-
... "repository/targets/", recursive_walk=False, followlinks=True)
359-
360-
# Note: Since we set the 'recursive_walk' argument to false, the 'myproject'
361-
# sub-directory is excluded from 'list_of_targets'.
362-
>>> list_of_targets
363-
['/path/to/repository/targets/file2.txt', '/path/to/repository/targets/file1.txt', '/path/to/repository/targets/file3.txt']
355+
# Create a list of all targets in the directory.
356+
>>> list_of_targets = ['file1.txt', 'file2.txt', 'file3.txt']
364357

365358
# Add the list of target paths to the metadata of the top-level Targets role.
366359
# Any target file paths that might already exist are NOT replaced, and
@@ -376,8 +369,11 @@ the target filepaths to metadata.
376369
# (octal number specifying file access for owner, group, others e.g., 0755) is
377370
# added alongside the default fileinfo. All target objects in metadata include
378371
# the target's filepath, hash, and length.
379-
>>> target4_filepath = os.path.abspath("repository/targets/myproject/file4.txt")
380-
>>> octal_file_permissions = oct(os.stat(target4_filepath).st_mode)[4:]
372+
# Note: target path passed to add_target() method has to be relative
373+
# to the targets directory or an exception is raised.
374+
>>> target4_filepath = 'myproject/file4.txt'
375+
>>> target4_abspath = os.path.abspath(os.path.join('repository', 'targets', target4_filepath))
376+
>>> octal_file_permissions = oct(os.stat(target4_abspath).st_mode)[4:]
381377
>>> custom_file_permissions = {'file_permissions': octal_file_permissions}
382378
>>> repository.targets.add_target(target4_filepath, custom_file_permissions)
383379
```
@@ -498,7 +494,6 @@ targets and generate signed metadata.
498494

499495
# Make a delegation (delegate trust of 'myproject/*.txt' files) from "targets"
500496
# to "unclaimed", where "unclaimed" initially contains zero targets.
501-
# NOTE: Please ignore the warning about the path pattern's location (see #963)
502497
>>> repository.targets.delegate('unclaimed', [public_unclaimed_key], ['myproject/*.txt'])
503498

504499
# Thereafter, we can access the delegated role by its name to e.g. add target
@@ -635,8 +630,7 @@ to some role.
635630
>>> repository.targets('unclaimed').remove_target("myproject/file4.txt")
636631

637632
# Get a list of target paths for the hashed bins.
638-
>>> targets = repository.get_filepaths_in_directory(
639-
... 'repository/targets/myproject', recursive_walk=True)
633+
>>> targets = ['myproject/file4.txt']
640634

641635
# Delegate trust to 32 hashed bin roles. Each role is responsible for the set
642636
# of target files, determined by the path hash prefix. TUF evenly distributes

tests/test_mix_and_match_attack.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def test_with_tuf(self):
218218
# new version is generated.
219219
with open(file3_path, 'wt') as file_object:
220220
file_object.write('This is role2\'s target file.')
221-
repository.targets('role1').add_target(file3_path)
221+
repository.targets('role1').add_target(os.path.basename(file3_path))
222222

223223
repository.writeall()
224224

tests/test_repository_tool.py

Lines changed: 150 additions & 93 deletions
Large diffs are not rendered by default.

tests/test_root_versioning_integration.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,15 @@ def test_root_role_versioning(self):
165165
repository.timestamp.load_signing_key(timestamp_privkey)
166166

167167
# (4) Add target files.
168-
target1 = os.path.join(targets_directory, 'file1.txt')
169-
target2 = os.path.join(targets_directory, 'file2.txt')
170-
target3 = os.path.join(targets_directory, 'file3.txt')
168+
target1 = 'file1.txt'
169+
target2 = 'file2.txt'
170+
target3 = 'file3.txt'
171171
repository.targets.add_target(target1)
172172
repository.targets.add_target(target2)
173173

174174

175175
# (5) Perform delegation.
176-
repository.targets.delegate('role1', [role1_pubkey], [os.path.basename(target3)])
176+
repository.targets.delegate('role1', [role1_pubkey], [target3])
177177
repository.targets('role1').load_signing_key(role1_privkey)
178178

179179
# (6) Write repository.

tests/test_tutorial.py

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -223,31 +223,27 @@ def test_tutorial(self):
223223

224224

225225
repository = load_repository('repository')
226-
list_of_targets = repository.get_filepaths_in_directory(
227-
os.path.join('repository', 'targets'), recursive_walk=False, followlinks=True)
228-
229-
self.assertListEqual(sorted(list_of_targets), [
230-
os.path.abspath(os.path.join('repository', 'targets', 'file1.txt')),
231-
os.path.abspath(os.path.join('repository', 'targets', 'file2.txt')),
232-
os.path.abspath(os.path.join('repository', 'targets', 'file3.txt'))])
233226

227+
# TODO: replace the hard-coded list of targets with a helper
228+
# method that returns a list of normalized relative target paths
229+
list_of_targets = ['file1.txt', 'file2.txt', 'file3.txt']
234230

235231
repository.targets.add_targets(list_of_targets)
236232

237233
self.assertTrue('file1.txt' in repository.targets.target_files)
238234
self.assertTrue('file2.txt' in repository.targets.target_files)
239235
self.assertTrue('file3.txt' in repository.targets.target_files)
240236

241-
242-
target4_filepath = os.path.abspath(os.path.join(
243-
'repository', 'targets', 'myproject', 'file4.txt'))
244-
octal_file_permissions = oct(os.stat(target4_filepath).st_mode)[4:]
237+
target4_filepath = 'myproject/file4.txt'
238+
target4_abspath = os.path.abspath(os.path.join(
239+
'repository', 'targets', target4_filepath))
240+
octal_file_permissions = oct(os.stat(target4_abspath).st_mode)[4:]
245241
custom_file_permissions = {'file_permissions': octal_file_permissions}
246242
repository.targets.add_target(target4_filepath, custom_file_permissions)
247243
# Note that target filepaths specified in the repo use '/' even on Windows.
248244
# (This is important to make metadata platform-independent.)
249245
self.assertTrue(
250-
os.path.join('myproject/file4.txt') in repository.targets.target_files)
246+
os.path.join(target4_filepath) in repository.targets.target_files)
251247

252248

253249
# Skipping user entry of password
@@ -346,8 +342,7 @@ def test_tutorial(self):
346342
# ----- Tutorial Section: Delegate to Hashed Bins
347343
repository.targets('unclaimed').remove_target("myproject/file4.txt")
348344

349-
targets = repository.get_filepaths_in_directory(
350-
os.path.join('repository', 'targets', 'myproject'), recursive_walk=True)
345+
targets = ['myproject/file4.txt']
351346

352347
# Patch logger to assert that it accurately logs the output of hashed bin
353348
# delegation. The logger is called multiple times, first with info level

tests/test_updater.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -863,7 +863,7 @@ def test_3__update_metadata_if_changed(self):
863863

864864
# Modify one target file on the remote repository.
865865
repository = repo_tool.load_repository(self.repository_directory)
866-
target3 = os.path.join(self.repository_directory, 'targets', 'file3.txt')
866+
target3 = 'file3.txt'
867867

868868
repository.targets.add_target(target3)
869869
repository.root.version = repository.root.version + 1
@@ -936,7 +936,7 @@ def test_4_refresh(self):
936936
unsafely_update_root_if_necessary=False)
937937

938938
repository = repo_tool.load_repository(self.repository_directory)
939-
target3 = os.path.join(self.repository_directory, 'targets', 'file3.txt')
939+
target3 = 'file3.txt'
940940

941941
repository.targets.add_target(target3)
942942
repository.targets.load_signing_key(self.role_keys['targets']['private'])
@@ -969,8 +969,6 @@ def test_4_refresh(self):
969969

970970
# Verify that the client's metadata was updated.
971971
targets_metadata = self.repository_updater.metadata['current']['targets']
972-
targets_directory = os.path.join(self.repository_directory, 'targets')
973-
target3 = target3[len(targets_directory) + 1:]
974972
self.assertTrue(target3 in targets_metadata['targets'])
975973

976974
# Verify the expected version numbers of the updated roles.
@@ -1142,12 +1140,13 @@ def test_6_get_one_valid_targetinfo(self):
11421140
# Test updater.get_one_valid_targetinfo() backtracking behavior (enabled by
11431141
# default.)
11441142
targets_directory = os.path.join(self.repository_directory, 'targets')
1145-
foo_directory = os.path.join(targets_directory, 'foo')
1143+
os.makedirs(os.path.join(targets_directory, 'foo'))
1144+
1145+
foo_package = 'foo/foo1.1.tar.gz'
11461146
foo_pattern = 'foo/foo*.tar.gz'
1147-
os.makedirs(foo_directory)
11481147

1149-
foo_package = os.path.join(foo_directory, 'foo1.1.tar.gz')
1150-
with open(foo_package, 'wb') as file_object:
1148+
foo_fullpath = os.path.join(targets_directory, foo_package)
1149+
with open(foo_fullpath, 'wb') as file_object:
11511150
file_object.write(b'new release')
11521151

11531152
# Modify delegations on the remote repository to test backtracking behavior.
@@ -1452,7 +1451,7 @@ def test_7_updated_targets(self):
14521451

14531452
length, hashes = securesystemslib.util.get_file_details(target1)
14541453

1455-
repository.targets.add_target(target1)
1454+
repository.targets.add_target(os.path.basename(target1))
14561455
repository.targets.load_signing_key(self.role_keys['targets']['private'])
14571456
repository.snapshot.load_signing_key(self.role_keys['snapshot']['private'])
14581457

@@ -1461,7 +1460,7 @@ def test_7_updated_targets(self):
14611460

14621461
length, hashes = securesystemslib.util.get_file_details(target1)
14631462

1464-
repository.targets.add_target(target1)
1463+
repository.targets.add_target(os.path.basename(target1))
14651464
repository.targets.load_signing_key(self.role_keys['targets']['private'])
14661465
repository.snapshot.load_signing_key(self.role_keys['snapshot']['private'])
14671466
repository.timestamp.load_signing_key(self.role_keys['timestamp']['private'])
@@ -2065,7 +2064,7 @@ def test_get_valid_targetinfo(self):
20652064
repository.targets.remove_target(os.path.basename(target1))
20662065

20672066
custom_field = {"custom": "my_custom_data"}
2068-
repository.targets.add_target(target1, custom_field)
2067+
repository.targets.add_target(os.path.basename(target1), custom_field)
20692068
repository.targets.load_signing_key(self.role_keys['targets']['private'])
20702069
repository.snapshot.load_signing_key(self.role_keys['snapshot']['private'])
20712070
repository.timestamp.load_signing_key(self.role_keys['timestamp']['private'])
@@ -2091,7 +2090,7 @@ def test_get_valid_targetinfo(self):
20912090

20922091
repository.targets.remove_target(os.path.basename(target1))
20932092

2094-
repository.targets.add_target(target1)
2093+
repository.targets.add_target(os.path.basename(target1))
20952094
repository.targets.load_signing_key(self.role_keys['targets']['private'])
20962095
repository.snapshot.load_signing_key(self.role_keys['snapshot']['private'])
20972096
repository.timestamp.load_signing_key(self.role_keys['timestamp']['private'])

tuf/repository_lib.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,7 +1319,7 @@ def generate_targets_metadata(targets_directory, target_files, version,
13191319
raise securesystemslib.exceptions.Error('use_existing_hashes option set'
13201320
' but fileinfo\'s length is not set')
13211321

1322-
filedict[target.replace('\\', '/').lstrip('/')] = fileinfo
1322+
filedict[target] = fileinfo
13231323

13241324
else:
13251325
filedict = _generate_targets_fileinfo(target_files, targets_directory,
@@ -1393,7 +1393,7 @@ def _generate_targets_fileinfo(target_files, targets_directory,
13931393
# the target's fileinfo dictionary) if specified here.
13941394
custom_data = fileinfo.get('custom', None)
13951395

1396-
filedict[relative_targetpath.replace('\\', '/').lstrip('/')] = \
1396+
filedict[relative_targetpath] = \
13971397
get_metadata_fileinfo(target_path, custom_data)
13981398

13991399
# Copy 'target_path' to 'digest_target' if consistent hashing is enabled.

0 commit comments

Comments
 (0)