From 845f3070d0f41ea297ff260496046e8a3da53166 Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Wed, 24 Nov 2021 10:48:07 +0200 Subject: [PATCH 1/3] ADR: Add New repository library design Document the decision to build a repository library on top of Metadata API. Signed-off-by: Jussi Kukkonen --- docs/adr/0010-repository-library-design.md | 128 +++++++++++++++++++++ docs/adr/index.md | 1 + 2 files changed, 129 insertions(+) create mode 100644 docs/adr/0010-repository-library-design.md diff --git a/docs/adr/0010-repository-library-design.md b/docs/adr/0010-repository-library-design.md new file mode 100644 index 0000000000..35ce3b2173 --- /dev/null +++ b/docs/adr/0010-repository-library-design.md @@ -0,0 +1,128 @@ +# Repository library design built on top of Metadata API + + +## Context and Problem Statement + +The Metadata API provides a modern Python API for accessing individual pieces +of metadata. It does not provide any wider context help to someone looking to +implement a TUF repository. + +The legacy python-tuf implementation offers tools for this but suffers from +some issues (as do many other implementations): +* There is a _very_ large amount of code to maintain: repo.py, + repository_tool.py and repository_lib.py alone are almost 7000 lines of code. +* The "library like" parts of the implementation do not form a good coherent + API: methods routinely have a large number of arguments, code still depends + on globals in a major way and application (repo.py) still implements a lot of + "repository code" itself +* The "library like" parts of the implementation make decisions that look like + application decisions. As an example, repository_tool loads _every_ metadata + file in the repository: this is fine for CLI that operates on a small + repository but is unlikely to be a good choice for PyPI. + + +## Decision Drivers + +* There is a consensus on removing the legacy code from python-tuf due to + maintainability issues +* Metadata API makes modifying metadata far easier than legacy code base: this + makes significantly different designs possible +* Not providing a "repository library" (and leaving implementers on their own) + may be a short term solution because of the previous point, but it does seem + like the project would benefit from some shared repository code and shared + repository design +* Maintainability of new library code must be a top concern +* Allowing a wide range of repository implementations (from CLI tools to + minimal in-memory implementations to large scale applications like Warehouse) + would be good: unfortunately these can have wildly differing requirements + + +## Considered Options + +1. No repository packages +2. repository_tool -like API +3. Minimal repository abstraction + + +## Decision Outcome + +Option 3: Minimal repository abstraction + +While option 1 might be used temporarily, the goal should be to implement a +minimal repository abstraction as soon as possible: this should give the +project a path forward where the maintenance burden is reasonable and results +should be usable very soon. The python-tuf repository functionality can be +later extended as ideas are experimented with in upstream projects and in +python-tuf example code. + +The concept is still unproven but validating the design should be straight +forward: decision could be re-evaluated in a few months if not in weeks. + + +## Pros and Cons of the Options + +### No repository packages + +Metadata API makes editing the repository content vastly simpler. There are +already repository implementations built with it (RepositorySimulator in +python-tuf tests is an in-memory implementation, while +repository-editor-for-tuf is an external CLI tool) so clearly a repository +library is not an absolute requirement. + +Not providing repository packages in python-tuf does mean that external +projects could experiment and create implementations without adding to the +maintenance burden of python-tuf. This would be the easiest way to iterate many +different designs and hopefully find good ones in the end. + +That said, there are some tricky parts of repository maintenance (e.g. +initialization, snapshot update, hashed bin management) that would benefit from +having a canonical implementation. Likewise, a well designed library could make +some repeated actions (e.g. version bumps, expiry updates, signing) much easier +to manage. + +### repository_tool -like API + +It won't be possible to support the repository_tool API as it is but a similar +one would certainly be an option. + +This would likely be the easiest upgrade path for any repository_tool users out +there. The implementation would not be a huge amount of work as Metadata API +makes many things easier. + +However, repository_tool (and parts of repo.py) are not a great API. It is +likely that a similar API suffers from some of the same issues: it might end up +being a substantial amount of code that is only a good fit for one application. + +### Minimal repository abstraction + +python-tuf could define a tiny repository API that +* provides carefully selected core functionality (like core snapshot update) + but... +* does not implement all repository actions itself, instead i makes it easy + for the application code to do them +* leaves application details to specific implementations (examples of decisions + a library should not always decide: "are targets stored with the repo?", + "which versions of metadata are stored?", "when to load metadata?", "when to + unload metadata?", "when to bump metadata version?", "what is the new expiry + date?", "which targets versions should be part of new snapshot?") + +python-tuf could also provide one or more implementations of this abstraction +as examples -- this could include a repo.py- or repository_tool-like +implementation. + +This could be a compromise that allows: +* low maintenance burden on python-tuf: initial library could be tiny +* sharing the important, canonical parts of a TUF repository implementation +* ergonomic repository modification, meaning most actions do not have to be in + the core code +* very different repository implementations using the same core code and the + same abstract API + +The approach does have some downsides: +* it's not a drop in replacement for repository_tool or repo.py +* A prototype has been implemented (see Links below) but the concept is still + unproven + +## Links +[Design document for minimal repository abstraction](https://docs.google.com/document/d/1YY83J4ihztsi1Qv0dJ22EcqND8dT80AGTduwgh0trpY) +[Prototype implementation of minimal repository abstraction](https://github.com/vmware-labs/repository-editor-for-tuf/) diff --git a/docs/adr/index.md b/docs/adr/index.md index 54a9be0861..46d9d84b5d 100644 --- a/docs/adr/index.md +++ b/docs/adr/index.md @@ -14,6 +14,7 @@ This log lists the architectural decisions for tuf. - [ADR-0008](0008-accept-unrecognised-fields.md) - Accept metadata that includes unrecognized fields - [ADR-0009](0009-what-is-a-reference-implementation.md) - Primary purpose of the reference implementation +- [ADR-0010](0010-repository-library-design.md) - Repository library design built on top of Metadata API From bcab2e96b03abd28aa180c7ad51b90e000fbc1dd Mon Sep 17 00:00:00 2001 From: Jussi Kukkonen Date: Tue, 30 Nov 2021 16:05:49 +0200 Subject: [PATCH 2/3] Include the design doc in repo * Also add some new diagrams in the design doc * Fix some issues in ADR Signed-off-by: Jussi Kukkonen --- docs/adr/0010-repository-library-design.md | 40 ++-- docs/repository-library-design-ownership.jpg | Bin 0 -> 50177 bytes docs/repository-library-design-usage.jpg | Bin 0 -> 42997 bytes docs/repository-library-design.md | 194 +++++++++++++++++++ 4 files changed, 218 insertions(+), 16 deletions(-) create mode 100644 docs/repository-library-design-ownership.jpg create mode 100644 docs/repository-library-design-usage.jpg create mode 100644 docs/repository-library-design.md diff --git a/docs/adr/0010-repository-library-design.md b/docs/adr/0010-repository-library-design.md index 35ce3b2173..0673063e89 100644 --- a/docs/adr/0010-repository-library-design.md +++ b/docs/adr/0010-repository-library-design.md @@ -18,7 +18,7 @@ some issues (as do many other implementations): * The "library like" parts of the implementation make decisions that look like application decisions. As an example, repository_tool loads _every_ metadata file in the repository: this is fine for CLI that operates on a small - repository but is unlikely to be a good choice for PyPI. + repository but is unlikely to be a good choice for a large scale server. ## Decision Drivers @@ -28,12 +28,12 @@ some issues (as do many other implementations): * Metadata API makes modifying metadata far easier than legacy code base: this makes significantly different designs possible * Not providing a "repository library" (and leaving implementers on their own) - may be a short term solution because of the previous point, but it does seem - like the project would benefit from some shared repository code and shared - repository design + may be a short term solution because of the previous point, but to make + adoption easier and to help adopters create safe implementations the project + would benefit from some shared repository code and a shared repository design * Maintainability of new library code must be a top concern * Allowing a wide range of repository implementations (from CLI tools to - minimal in-memory implementations to large scale applications like Warehouse) + minimal in-memory implementations to large scale application servers) would be good: unfortunately these can have wildly differing requirements @@ -64,9 +64,7 @@ forward: decision could be re-evaluated in a few months if not in weeks. ### No repository packages Metadata API makes editing the repository content vastly simpler. There are -already repository implementations built with it (RepositorySimulator in -python-tuf tests is an in-memory implementation, while -repository-editor-for-tuf is an external CLI tool) so clearly a repository +already repository implementations built with it[^1] so clearly a repository library is not an absolute requirement. Not providing repository packages in python-tuf does mean that external @@ -76,9 +74,10 @@ different designs and hopefully find good ones in the end. That said, there are some tricky parts of repository maintenance (e.g. initialization, snapshot update, hashed bin management) that would benefit from -having a canonical implementation. Likewise, a well designed library could make -some repeated actions (e.g. version bumps, expiry updates, signing) much easier -to manage. +having a canonical implementation, both for easier adoption of python-tuf and +as a reference for other implementations. Likewise, a well designed library +could make some repeated actions (e.g. version bumps, expiry updates, signing) +much easier to manage. ### repository_tool -like API @@ -97,8 +96,7 @@ being a substantial amount of code that is only a good fit for one application. python-tuf could define a tiny repository API that * provides carefully selected core functionality (like core snapshot update) - but... -* does not implement all repository actions itself, instead i makes it easy +* does not implement all repository actions itself, instead it makes it easy for the application code to do them * leaves application details to specific implementations (examples of decisions a library should not always decide: "are targets stored with the repo?", @@ -107,7 +105,7 @@ python-tuf could define a tiny repository API that date?", "which targets versions should be part of new snapshot?") python-tuf could also provide one or more implementations of this abstraction -as examples -- this could include a repo.py- or repository_tool-like +as examples -- this could include a _repo.py_- or _repository_tool_-like implementation. This could be a compromise that allows: @@ -123,6 +121,16 @@ The approach does have some downsides: * A prototype has been implemented (see Links below) but the concept is still unproven +More details in [Design document](../repository-library-design.md). + ## Links -[Design document for minimal repository abstraction](https://docs.google.com/document/d/1YY83J4ihztsi1Qv0dJ22EcqND8dT80AGTduwgh0trpY) -[Prototype implementation of minimal repository abstraction](https://github.com/vmware-labs/repository-editor-for-tuf/) +* [Design document for minimal repository abstraction](../repository-library-design.md) +* [Prototype implementation of minimal repository abstraction](https://github.com/vmware-labs/repository-editor-for-tuf/) + + +[^1]: + [RepositorySimulator](https://github.com/theupdateframework/python-tuf/blob/develop/tests/repository_simulator.py) + in python-tuf tests is an in-memory implementation, while + [repository-editor-for-tuf](https://github.com/vmware-labs/repository-editor-for-tuf) + is an external Command line repository maintenance tool. + diff --git a/docs/repository-library-design-ownership.jpg b/docs/repository-library-design-ownership.jpg new file mode 100644 index 0000000000000000000000000000000000000000..68eaafc8e43c7fc7a3e2b0da771bf58150db4b24 GIT binary patch literal 50177 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
&flUvqaMabF{Aa$q6G4U49LV?z>M# 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 Dk&cox literal 0 HcmV?d00001 diff --git a/docs/repository-library-design-usage.jpg b/docs/repository-library-design-usage.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9eb7ca711bf1ff652b1ded3095a7afdfe71c2de8 GIT binary patch literal 42997 zcmeFZ1yo#JmOom!OK|r9L4!+hf`?$iEy0Vz-60SNt^tBWaCe8`?haMBOK|sB-}iOT z>+YH9?wR#}^ZqkyZmn}xt#!^i`|f?tz1x2KKF>d|0b1fqMb- z+zp_F-X{Xg?-$@t7Yr;MJOUyTG72ghbV4mQ02T%g4i+8`0RbK!I@=pM4uF4wfJ4n8 zj)<%B35muYkMna(7Ba0wWe2|M#0edjk%K=9Dghx8G097M2F6!R+&sK|`~rfKZ>6MV zWaZ@5KB#MGYH8~jo0yuJTL3K`ot#}<-P}C_z61t+4Gsy7jr$g#koY|*`A2q6ZeD&t zVNq3eO>JF$Lt|5CS9ecuU;n`1L>iXvP?l-<* z0C0b>1?~S}>~Hvb0p$x89v%)J={LS$U|pdN?gcyoH3uS&xC+uIdt4gM&&YTZFKPE5So7mv@rhn zoey8&@jCx96Xg#s|L7w_0darH+!F>c6x}{&8e= zo1Ot0BDHZvwflQ~=8A7Uk6->AEt^-P7tzajx9%rYuhZI`(oGT-dAKZHee!sr@rooa zgmsSD$$tD{($04;&1ISTRB<+`a5vc}F)uG$q~zt9*4Wk$D|PGc)rSTn2Z0SgM{Pl+ zPG7XHOfY2ML$P({84!ywGK8bONxN;eGo7j_!s?}vX(<9fwT$N3D$#d%B3;TmVGsM` z@V3IGZrJ&#$w z(tTtB>9Am^-|Lo zuQJhv>G#1Hf>VbsLAyg60_$IHhtt&(6S4Z1+u^N+91r!;)7fW_DODTBYmm!p9(i5; zWjuexE(&^|qQX|Ol(R08BN~+!R7R}5YAqXZ+yau28PV0tZ8gp?fJ_h? z&)Si@D~`wE^y;cNFm!cJo&iD5)lk=j0>%lqopIOuQ*NhZgKXiZT7AG$$E5mep&NnpE9#CGx2bU?UeH!`R8{MYbv$ z26W%`M3(1kyM@WrRY$2hlGj|-n|+KuWTA~?YM_Jj=j3E&Ryi>%E*@F;4A=xK`LagL z#F#G^vmiHOMM8qO_D1w#ySfeNXPtmN-kd86Rg*_P^J_L=#)LZL3-n-WrPt+z()lw{ z8P+lD>A!lGL2hgaCNFMH6%srbWe-T>%_3Yr`XRd0rhcAc7^g~NvtCcVLP*&YWDDaN@akNDaPw*{&_&P*%Q{a-oSv@-mG@-QN%@mWesLtpo(&hC_V#_83LXGyC24%0Vn!c&j4I~1U#6rXFw;) z>NDUDpIh{SQ1ThjJ@LO2|34K^2CSP5C41n7iRf}_uoHq68w1-3-5 z@Y!_7L<>4Sf-w8dLL`SBI_poVM$LkoEjBJoH~L=<4~;~zsuqrPvH z>W=9(^lChVNRjHKw0`(ewN%$lvuxG0_zN6v=~qe7Y-xGCPy^sgeD*^GlrYq5DGXv7%QiW>utm4(Z@MD+9$_-8-&FR z2Ac&hDKaIJF34IJWqM^sz6XtiLS~%OTqRGv=R&;Rm=fetWTD$zl6VeNyI7pz$S(cV z3#7xge*)k;fymLMPrYk=$W9fDbopaRM<^6!4iOfy;k>RRLK@m?GmRRy=$$n@drw7Mq~CNK%>OhZD@g zLW{deIaBzmDBLsy@GMYFq2Y^V3L5(1B44BjHX~d~#i{A;Y@FO$)gnoNc(0&qna**aqgz0`tKi6S5ZmF!E84(~BxeMaIGM2L%>9%|tTd zXPs*TN(K+l&Bm3H(eqO`xcEK@J7Jw|sc)@z%pk(p(wbqRIGUhKo|V9Jyz zZ3!=I7a;Bv(p1UJD@uM@F-I4qC|d{|hC@c73#4cuB0dfuN8&1S+t8}0ndXswcxiVh z9MF*9e)I)bkoq=_#&pY#&ct6z$#(-3vrei{C_O=`($F+DryMEWfZbb}zw_5I!zQnl>r(Vd$cj)$s5!oU0cMu)xu?N?*n!g`6 znJp{L4AYtsQZRKUPfB!Ff%WO!-&V8CR7vKBH|muf0=7cSH;hAwEglr4wTK>=zJW zRmSYrdhOU(v2I=FTQQjGZEza9f1?LCy`VclDMI)RsDK_zsGd70jyf#~qc2@ckrMcB zDCea4lvIL4EqXm&0KJRFut%N8R~P-yfSK~ijDKhd5Pp0HsJ2C&7c%jSPM2>y?92b% zZTv^u{GS;QI(XE&n~|^oQ$*ySacl8o%7Gk~vpA5!&lA)B7@!F;GR68}A?>VgR+HM= znT_|f3GT@#_D@src6}>wD-6jgPq2k$4IQ(ZBZtXKBR|p%6Ndo%3m)D zHOBvjrn9JVz>|B_U{qztGeD?sON^}kZ&$te8?yRJ^H2*v-S{l~&#cfAcC){DXM(o& zM!YgK4V)9e0C}X$RrpuLoHP?`ShjgpBy3zL85Po+o6X6KWJ{(7m3X<&c_Sbm=0AlC z;F6vJU(UNTE|{PJomHqGeoGN`qa-Bv43H>|dcrV-J{|{!f0BszAKU`A+SY_l86HvV zL~nR}pJcNCmFRu`kO$=-y!r{){>_TJ|B7Z)#-9Wt^CxCAF?IiTS<%0uT9*HZI8^?$ zYj6qBMOV7dVPkG=l>(z=tfe;Lp5Qjid^waRxKkEtiFvGbd}~$)VXF_p1=&Ano&l)g z>6_^}ar&=ozL0&v=PXe1;}8Q75#|0H5BcAo`u~e5hkHg8OHjQgt7qq_4>`0fQ@GTr;5}Ti5C*1LU zU3`9RsAk}rt5`2z?KOx5d(PI5g+(lDiQ|?wD-4H5Rul!bzg}j^6sWlg4{_ya&i3hzJCU|g^+nQxu}g0a~FkMd8VqdA$d zp^X2f4cX>*x3JjtclG;!MCBuZhR{IJSMnjUVSl_?6uLB-lhB8XMM*oNE+$$0P!4G% zbiv3s)A0%;Q#AwYbrk9?iLuo*MH|CjrcvZiH83v!K@p%;_!b)W-A>2 z4llXFB_P;Kx+hCF>FBUDCNI2+J%v+RtH6{2W}sI_-uFs0%y;+WMB9lH)WoBkbq)8O z+4H?3n0f|WlrbGyz$HHQo!UO4lkh#EK%MK&WYNk8-DiL#V#G7R-`)3?zA2RPf5eDSbw8Uy=33mhRL+mXRfy$_w_kXs0#}UT`h@nZ` zMM`;R0AAmG_OR(_yDYVX%w&cXK(n$XOt~ub2zy;XdTTlNy+}}rx@~R7A(#0T@G7`v zMb!4_Zo|g6bp_w-A8z7bCPLZ%WHx`W`{O8n`{OO3$W}C1($3{Qu0)^qhpC7Ex$GwX zVnkw2e(GY6hgD~fq`Lx&>U;kD`vkd3}8akgc~hPq*j+b)>qvQUMa}X>*7ta6^K(mxtU#X5%&cceNCP5t~Foe>op78@0;~U8xjPOfxkJ-=)Q}i5s zTB^t(KZ4MF#L~Pa{Q;nDfsUdhg=-ht;Aq38vIAq3#*|r;u2wCYOoN@ak@mMnxI#FA zU%pI$MkzIGT}6eQT5pL78}d*(X;aK$K|iio?_zo-yw}s0xe|k4klBr^67Iln3Poqy&k9`c*c^b>mSF4Jb?vbN9VuseUa@ng zX7fC})MO|r$3&6WRSJ)w_q8v^d~+c=hq#M$5)vIhmAg+PvguCvQ0E$FSXh$rT3T!C zVr?&h+=IDenFBi~nP}hC69ltr?u7jGoV;I_XC?Zq7pZZ zLnt$?>M4CjF37_m&XK8f^v5X8Pyt%4qM+mr0vti1Trz#LkpdY zfLE+IODnp%HGMBoazC(N3~Yz}Cb;t}$N|XeH^Jq@uTm(L0(5^AFB&d@b-c^AkC3f{ zkw#<13dfYbr>YsMRz`Lk3LiEtL=)+87t!{W{aS}gO1qw<#fTZDhQ zkv?Iw-dY#C@SQQ~rRtYBKR$Ef0oX8M`7RZ7t8(iy2|wL|cthg;9i;guX(-uuLC|az zjwF);F&&~bIwvL;?YRG|i+@kQ!(hzaRbCdw+x+1!{X;ix>%sV%yX_tg2#x=1;=A&6 zx%C|Z|MC^zUDImYrKSg>?Ka?>Ww}JY)NPnVz66fb8L473!G#-V_Bb1mpDI4ZulAeI z(6mjnu{jg7a(|15)mxUY9@Z)EEw2@e}@Yt{IRp;GCfzBAbB-BVWc6Z(#sHq zKxZVz9&swNi$0{#4QE62fxH`qp1U|V*LM@t))ZPaK}!z{DgMKw8vu5+K;pgBIdSWJ zx3ArCH?H?)y_2JT3eGL=Mvdnf(?59Mf}5p#ZU+Q*GOsgHl)7y%2xfZ&UA(xfehGe$ z=c;#E;Ts%1W*5HONL3G8A$y-(mv5fC%O{u&^pt{#3!-oiQeNA~H9n~dbGi|iP_Oyo z<@=|!hk?wmaPsCYdv|gxt)2lzkPI$cqEW6by=E@4}d$LW4a^w1CQY$;SW*1Dsgfog-8++K{p zMub)zGs@a2S?X8fq^0iyCvdeOmN_lFLvC~ubK=~b=%Y7CN%mCDz*5u0ra13sye9}m z4v}FQqT;ChC~LZb`XS&Ff3$0L$uzz9X;;^~$@WEAxjUYNDOIq<#1~buMKMU+=U7FV zQ$8ioqo!p2lr0YH`^U}6{0QA0kesGd>F2RQT!Fo@R)EVg#Vk@VH>t2TG^!YRDAd0Z zcWgy>$guy~mt?A7)t?#UR=Oq@^Y-%#Bq`2VRx+AAI|U(≥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 Date: Tue, 7 Dec 2021 12:52:51 +0200 Subject: [PATCH 3/3] Fix issues from review In addition to multiple smaller review fixes: * Explain how the proposed library is minimal: more specific functionality may be added as we get more experience * Explain what a concrete Repository implementation must implement (details are obviously subject to change but this is what the current prototype requires) Signed-off-by: Jussi Kukkonen --- docs/repository-library-design.md | 56 ++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/docs/repository-library-design.md b/docs/repository-library-design.md index 8ac71b00dc..5a9b0fde48 100644 --- a/docs/repository-library-design.md +++ b/docs/repository-library-design.md @@ -1,7 +1,7 @@ # Python-tuf repository API proposal: _minimal repository abstraction_ This is an attachment to ADR 10: _Repository library design built on top of -Metadata API_, and documents the design proposal in Dec 2020. +Metadata API_, and documents the design proposal in Dec 2021. ## Design principles @@ -31,22 +31,24 @@ other implementations? ## Design +### Application and library components + ![Design: Application and library components](repository-library-design-ownership.jpg) The design expects a fully functional repository application to contain code at three levels: * Repository library (abstract classes that are part of python-tuf) - * The Repository abstract class provides an ergonomic metadata editing API - for all code levels to use. It also implements some core edit actions like - snapshot update + * The Repository abstract class provides an ergonomic abstract metadata + editing API for all code levels to use. It also provides implementations + for some core edit actions like _snapshot update_. * A small amount of related functionality is also provided (private key - management API, maybe repository validation) - * is a very small library: possibly a few hundred lines of code + management API, maybe repository validation). + * is a very small library: possibly a few hundred lines of code. * Concrete Repository implementation (typically part of application code, implements interfaces provided by the repository API in python-tuf) * Contains the “application level” decisions that the Repository abstraction requires to operate: examples of application decisions include - * _when should “targets” metadata next expire when it is edited?_ + * _When should “targets” metadata next expire when it is edited?_ * _What is the current “targets” metadata version? Where do we load it from?_ * _Where to store current “targets” after editing? Should the previous @@ -55,7 +57,8 @@ three levels: * Uses the Repository API to do the repository actions it needs to do For context here’s a trivial example showing what “ergonomic editing” means -- -this key-adding code could be in the application or in the python-tuf library: +this key-adding code could be in the application (or later, if common patterns +are found, in the python-tuf library): ```python with repository.edit(“targets”) as targets: @@ -69,7 +72,8 @@ The reason for the context manager style is that it manages two things simultaneously: * Hides the complexity of loading and persisting metadata, and updating expiry and versions from the editing code (by putting it in the repository - implementation – which may still be provided by the application) + implementation that is defined in python-tuf but implemented by the + application) * Still allows completely arbitrary edits on the metadata in question: now the library does not need to anticipate what application wants to do and on the other hand library can still provide e.g. snapshot functionality without @@ -77,6 +81,8 @@ simultaneously: Other designs do not seem to manage both of these. +### How the components are used + ![Design: How components are used](repository-library-design-usage.jpg) The core idea here is that because editing is ergonomic enough, when new @@ -86,6 +92,12 @@ that adds a bunch of targets into the metadata, but one of the previous layers could offer that as a helper function as well: code in both cases would look similar as it would use the common editing interface. +The proposed design is purposefully spartan in that the library provides +very few high-level actions (the prototype only provided _sign_ and +_snapshot_): everything else is left to implementer at this point. As we gain +experience of common usage patterns we can start providing other features as +well. + There are a few additional items worth mentioning: * Private key management: the Repository API should come with a “keyring abstraction” -- a way for the application to provide roles’ private keys for @@ -132,8 +144,28 @@ proposal includes concrete implementations only for the following: Note that a concrete Repository implementation could provide an easier to use snapshot that does not require input (see example in git_repo.py) -More concrete implementations (see cli.py for examples) could be added to -Repository itself but none seem essential at this point. +More concrete method implementations (see cli.py for examples) could be added +to Repository itself but none seem essential at this point. + +The current prototype API defines five abstract methods that take care of +access to metadata storage, expiry updates, version updates and signing. These +must be implemented in the concrete implementation: + +* **keyring()**: A property that returns the private key mapping that should be + used for signing. + +* **_load()**: Loads metadata from storage or cache. Is used by edit() and + sign(). + +* **_save()**: Signs and persists metadata in cache/storage. Is used by edit() + and sign(). + +* **edit()**: The ContextManager that enables ergonomic metadata + editing by handling expiry and version number management. + +* **init_role()**: initializes new metadata handling expiry and version number. + (_init_role is in a way a special case of edit and should potentially be + integrated there_). The API requires a “Keyring” abstraction that the repository code can use to lookup a set of signers for a specific role. Specific implementations of @@ -144,7 +176,7 @@ and more could be implemented in applications. _Prototype status: Prototype Repository and Keyring abstractions exist in librepo/repo.py._ -### Example of Repository implementation +### Example concrete Repository implementation The design decisions that the included example `GitRepository` makes are not important but provide an example of what is possible: