Skip to content

Conversation

@sechkova
Copy link
Contributor

Fixes #1137

Description of the changes being introduced by the pull request:

  • Added root metadata class to tuf.api.metadata module and implements serialization and update methods.
  • Added root and targets metadata tests

Please verify and check that the pull request fulfills the following
requirements
:

  • The code follows the Code Style Guidelines
  • Tests have been added for the bug fix or new feature
  • Docs have been added for the bug fix or new feature

Copy link
Member

@joshuagl joshuagl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch on the use of dictionaries in the test!

I think your proposed interface for Root.update() here might be inconsistent with the API in the other metadata classes. More details on that inline, what do you think?

Attributes:
consistent_snapshot: A boolean indicating whether the repository
supports consistent snapshots,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
supports consistent snapshots,
supports consistent snapshots.

Comment on lines 399 to 400
def update(self, keys: JsonDict, roles: JsonDict,
consistent_snapshot: bool) -> None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we might have an API granularity mismatch here.

Snapshot.update() takes information for a single targets metadata file, to update/add to the listed files in the snapshot metadata file.

Targets.update() takes information for a single target file, to update/add the fileinfo for a single target file.

Whereas Root.update() is overwriting all of the keys and roles defined in the root metadata.
Perhaps keys and roles parameters should be optional and singular (key and role), taking a single keydict to add/update and a single roleinfo to add/update? That probably gets easier with classes for complex metadata fields (#1139).

I'd appreciate hearing from some library users (@trishankatdatadog, @woodruffw, @jku) and co-maintainers (@lukpueh) on this topic of API granularity.

Copy link
Contributor Author

@sechkova sechkova Oct 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that you've said it, it seems you have a point. I think I like an api of the form:
Root.update('timestamp', key)
but what if you want to revoke a key and remove it, not only add/update one?
Should we then extend Root with Root.remove/delete(role, key) or implement this logic ... somewhere else?

How do you feel about consistent snapshot? Maybe we need a setter/getter pattern for toggling it independently? I am not sure ... a user of the class can access it anyway directly

Copy link
Member

@lukpueh lukpueh Nov 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good questions! I think the update methods on Targets/Snapshot/Timestamp are supposed to facilitate the chain of (currently manual) updates that are necessary when the target files in the repository are updated.

Root is not part of that chain, so it may not need to be consistent with the other update functions. Regardless, something like Root.update/delete(role_name, key) IMHO seems to add more value than mere (multi-)setter logic.

Generally, I think we should do in these methods whatever is convenient for updating an individual role either manually or from within methods like Repository.update_targets(...), Repository.create_snapshot(...), Repository.rotate_keys(...) etc., i.e. the methods that actually do TUF.

This discussion seems related to #1134.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, I think we should do in these methods whatever is convenient for updating an individual role either manually or from within methods like Repository.update_targets(...), Repository.create_snapshot(...), Repository.rotate_keys(...) etc., i.e. the methods that actually do TUF.

I think that sounds like a sensible approach.

I like the Root.update() and Root.remove() interfaces you've proposed here @sechkova. Do they fulfil the needs which led you to create this PR?

I think the best path forward for this PR would be to implement as much of Root functionality as you need to proceed. We can modify/extend the metadata API as we work on making use of it from higher-level pieces of the refactor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I worked on this PR in the context of the client meaning that I only need read access to 'signed' dictionaries.
Anyway I think we all agree on implementing a set of Root.update() and Root.remove() interfaces which won't cost me much and will be valuable for moving the metadata API forward.

Add root metadata class to tuf.api.metadata module and implement
(de)serialisation and modification methods.

Signed-off-by: Teodora Sechkova <tsechkova@vmware.com>
Use deepcopy to ensure that the dictionaries with expected data
are not referencing the same memory as the tested ones.

Add a check asserting that metadata is not equal prior to its
update.

Signed-off-by: Teodora Sechkova <tsechkova@vmware.com>
Add test cases for Root(Signed) and Targets(Signed) classes.

Signed-off-by: Teodora Sechkova <tsechkova@vmware.com>
@sechkova
Copy link
Contributor Author

sechkova commented Nov 9, 2020

Added two root methods that should be enough for a key revocation:

root.add_key(role, keyid, key_metadata) - root.update seemed ambiguous since a new keyid is appended to the role's list of keyids
root.remove_key(role, keyid)

I think this is what we can do for now, until we decide how to represent the internal metadata fields. For the same reason I haven't added any errors/warnings on missing/already existing keyids but I will if you don't like the idea of silently ignoring these cases.

@joshuagl
Copy link
Member

joshuagl commented Nov 13, 2020

root.add_key(role, keyid, key_metadata) - root.update seemed ambiguous since a new keyid is appended to the role's list of keyids

update() would be consistent with Targets.update(), which either replaces an existing entry in the targets dict, or adds a new one when the filename (key) is new.

@sechkova
Copy link
Contributor Author

sechkova commented Nov 13, 2020

root.add_key(role, keyid, key_metadata) - root.update seemed ambiguous since a new keyid is appended to the role's list of keyids

update() would be consistent with Targets.update(), which either replaces an existing entry in the targets dict, or adds a new one when the filename (key) is new.

I see your point about consistency but what would root.update('targets', keyid ...) mean with this metadata format:

 "targets": {
    "keyids": [
     "135c2f50e57ff11e744d234a62cebad8c38daf399604a7655661cc9199c69164"
    ],
    "threshold": 1
   },

We don't expect different keys with the same keyid, do we?

@joshuagl
Copy link
Member

root.add_key(role, keyid, key_metadata) - root.update seemed ambiguous since a new keyid is appended to the role's list of keyids

update() would be consistent with Targets.update(), which either replaces an existing entry in the targets dict, or adds a new one when the filename (key) is new.

I see your point about consistency but what would root.update('targets', keyid ...) mean with this metadata format:

 "targets": {
    "keyids": [
     "135c2f50e57ff11e744d234a62cebad8c38daf399604a7655661cc9199c69164"
    ],
    "threshold": 1
   },

You're right, update() doesn't make much sense with a list. 👍

We don't expect different keys with the same keyid, do we?

Not as I understand it. From TAP 12

keyids defined within a metadata file must be unique. For example, a root file that delegates trust to root, snapshot, timestamp, and top-level targets should provide unique keyids for each key trusted to sign metadata for these roles.

Copy link
Member

@joshuagl joshuagl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working through the details with me

@joshuagl
Copy link
Member

Trying a close/re-open to trigger CI.

@joshuagl joshuagl closed this Nov 13, 2020
@joshuagl joshuagl reopened this Nov 13, 2020
@joshuagl joshuagl merged commit 9d3ef85 into theupdateframework:develop Nov 23, 2020
@sechkova sechkova deleted the metadata-root branch November 27, 2020 11:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add root metadata class to new TUF metadata model

3 participants