spec.bs 170 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866
  1. <pre class='metadata'>
  2. Status: LS-BRANCH
  3. Group: ForgeFed Working Group
  4. Editor: Alice Doe, MyCoolCompany https://mycoolcompany.com/home, https://alicedoe.me/about
  5. Editor: Bob Doe, SomeOrg https://some.org, https://home.net/bob
  6. Favicon: /img/favicon.png
  7. Logo: /img/logo.svg
  8. Status Text: Work in progress
  9. Issue Tracking: Codeberg https://codeberg.org/forgefed/forgefed/issues
  10. Issue Tracker Template: https://codeberg.org/forgefed/forgefed/issues/{0}
  11. Indent: 4
  12. Work Status: exploring
  13. Repository: https://codeberg.org/forgefed/forgefed forgefed
  14. Line Numbers: yes
  15. Markup Shorthands: markdown yes, css no, http no, idl no, markup no
  16. Title: ForgeFed
  17. Shortname: forgefed
  18. URL: https://forgefed.org/spec
  19. Revision: 1
  20. Abstract:
  21. This document describes the ForgeFed vocabulary. It's intended to be an
  22. extension of [[ActivityStreams-Vocabulary]] and provides additional
  23. vocabulary for federation of project management and version control system
  24. hosting and collaboration platforms.
  25. This document describes the rules and guidelines for representing version
  26. control and project management related objects as linked data, using the
  27. ForgeFed vocabulary, ActivityStreams 2, and other related vocabularies.
  28. This document provides instructions for using ActivityPub activities and
  29. properties to represent forge events, and describes the side-effects these
  30. activities should have.
  31. </pre>
  32. Issue: (fr33) In the abstract I just pasted the 3 abstracts of the separate
  33. specs. Write something new, probably with inspiration from existing specs such
  34. as ActivityPub.
  35. This draft is generated from branch <code>[GITBRANCH]</code>, commit
  36. <a href="https://codeberg.org/ForgeFed/ForgeFed/commit/[GITCOMMIT]">[GITSHORT]</a>.
  37. # Introduction # {#intro}
  38. Note: The spec is still under construction. Want to start implementing? Check
  39. out the ActivityPub implementation guide, and then the [[#s2s]] section here.
  40. Issue: Below are the 3 intro texts from the 3 specs. We probably want to
  41. replace them with a human-friendly tutorial-like example, like in the
  42. ActivityPub spec.
  43. The ForgeFed Vocabulary describes a set of types and properties to be used by
  44. platforms that support the ForgeFed protocol. This specification describes only
  45. the new vocabulary called ForgeFed. The ForgeFed behavior specification
  46. describes how to use this vocabulary, along with standard ActivityPub
  47. vocabulary, to support the ForgeFed protocol.
  48. **The ForgeFed modeling specification** is a set of rules and guidelines which
  49. describe version control repository and project management related objects and
  50. properties, and specify how to represent them as JSON-LD objects (and linked
  51. data in general) using the ForgeFed vocabulary and related vocabularies and
  52. ontologies. Using these modeling rules consistently across implementations and
  53. instances allows to have a common language spoken across networks of software
  54. forges, project management apps and more.
  55. The ForgeFed vocabulary specification defines a dedicated vocabulary of
  56. forge-related terms, and the **modeling specification** uses these terms, along
  57. with terms that already exist in ActivityPub or elsewhere and can be reused for
  58. forge federation.
  59. The ForgeFed behavior specification provides instructions for using Activities,
  60. and which Activities and properties to use, to represent forge events, and
  61. describes the side-effects these Activities should have. The objects used as
  62. inputs and outputs of behavior descriptions there are defined here in the
  63. **modeling specification**.
  64. **The ForgeFed behavior specification** is a set of instructions for
  65. representing version control systems and project management related transactions
  66. using ActivityPub activity objects, and it describes the side effects and
  67. expected results of sending and receiving these activities. The vocabulary for
  68. these activities includes standard ActivityPub terms, new terms defined by
  69. ForgeFed, and terms borrowed from other external vocabularies.
  70. The ForgeFed vocabulary specification defines a dedicated vocabulary of
  71. forge-related terms, and the **behavior specification** uses these terms, along
  72. with terms that already exist in ActivityPub or elsewhere and can be reused for
  73. forge federation.
  74. The ForgeFed modeling specification defines rules for representing forge
  75. related objects as ActivityPub JSON-LD objects, and these objects are used in
  76. the **behavior specification**, included in activities, mentioned in
  77. activities, or modified as a result of activity side-effects.
  78. # Objects
  79. ## Kinds of Objects
  80. Objects are the core concept around which both ActivityPub and ForgeFed are
  81. built. Examples of Objects are [=Note=], [=Ticket=], [=Image=],
  82. [=Create=], [=Push=]. Some objects are resources, which are objects that
  83. contain or represent information and user made or program made content, and
  84. some objects are helpers that exist as implementation detail aren't necessarily
  85. exposed to humans or are useful to humans. But everything is an [=Object=],
  86. represented as compacted JSON-LD.
  87. ForgeFed is an ActivityPub extension, and communication between ForgeFed
  88. implementations occurs using activity objects sent to actor inboxes and
  89. outboxes.
  90. There are 4 kinds of objects in ForgeFed:
  91. : Activities
  92. :: These are objects that describe actions, such as actions that
  93. happened, actions that are happening, or a request to perform an action.
  94. Their primary use is for server-to-server interaction between actors by
  95. being sent to an actor's inbox, and client-to-server interaction between a
  96. person or program and an actor they control by being sent to the actor's
  97. outbox. Activities can also appear or be linked inside other objects and
  98. activities and be listed in Collections.
  99. : Actors
  100. :: These are static persistent objects that have an [=inbox=] and can be
  101. directly interacted with by POSTing activities to it. Their primary use is
  102. to contain or represent information and output of user actions or program
  103. actions, and to manage access to this information and modifications of it.
  104. : Child objects
  105. :: These are persistent objects that, like actors, contain or
  106. represent information and output of user actions or program actions, but
  107. they do not have their own [=inbox=] and are not directly interacted with.
  108. A managed static object always has a parent object, which is an actor, and
  109. that actor's inbox is the way to interact with the child object. The parent
  110. actor manages access and modification of the child object.
  111. : Global helper objects
  112. :: These are objects that do not belong to any actor and do not need any
  113. interaction through activities. As such, they do not exactly fit into the
  114. actor model, but may be involved in implementation details and practical
  115. considerations.
  116. Actors, children, and globals are referred to in ForgeFed as *static* objects,
  117. while activities are *dynamic* objects. The terms *constant* and *variable*
  118. are used to indicate whether an object changes during its lifetime or not.
  119. *Static* objects, in addition to being an actor or child or global, also have a
  120. resource/helper distinction:
  121. : Resource
  122. :: Contains or represents information and user made or program made
  123. content, usually belongs to the domain model of version control systems and
  124. project management.
  125. : Helper
  126. :: Used for running things behind the scenes, not exposed directly as
  127. user content, may be transient or auto generated, usually related to
  128. implementation detail and not to concepts of version control and project
  129. management.
  130. ## Object Publishing and Hosting ## {#publishing}
  131. In ForgeFed, actors host their child objects locally, meaning the actor and the
  132. child object are hosted on the same instance. Actors may create remote objects by
  133. *offering* them to the relevant actor, which then may create the object on their
  134. side and assign it a URI.
  135. The process begins with an [=Offer=] activity, in which:
  136. - [=object=] MUST be the object being offered for publishing, and that object
  137. MUST NOT have an [=id=]
  138. - [=target=] MUST indicate under which list/collection/context the sender would
  139. like the object to be published (it may also be the URI of the target actor
  140. itself)
  141. Among the recipients listed in the [=Offer=]'s recipient fields, exactly one
  142. recipient is the actor who is responsible for inspecting and possibly publishing
  143. the newly created object, and possibly sending back an [=Accept=] or a [=Reject=].
  144. We'll refer to this actor as the *target actor*. Specific object types described
  145. throughout this specification have a specific meaning for the *target actor*,
  146. which processing and inspection it is expected to do, and where it is expected
  147. to list the URI of the object once it publishes it.
  148. The sender is essentially asking that the target actor hosts the object as a
  149. child object and assigns is a URI, allowing to observe and interact with the
  150. object. The target actor will be responsible for hosting and controlling the
  151. object, and the sender will just be mentioned as the author.
  152. When an actor *A* receives the [=Offer=] activity, they can determine whether
  153. they're the *target actor* as follows: If the [=target=] is *A* or a child
  154. object of *A*, then *A* is the *target actor*. Otherwise, *A* isn't the target
  155. actor.
  156. In the following example, Luke wants to open a ticket under Aviva's Game Of
  157. Life simulation app:
  158. <div class=example>
  159. <xmp highlight=json-ld>
  160. {
  161. "@context": [
  162. "https://www.w3.org/ns/activitystreams",
  163. "https://forgefed.org/ns"
  164. ],
  165. "id": "https://forge.example/luke/outbox/02Ljp",
  166. "type": "Offer",
  167. "actor": "https://forge.example/luke",
  168. "to": [
  169. "https://dev.example/aviva/game-of-life",
  170. "https://dev.example/aviva/game-of-life/team",
  171. "https://dev.example/aviva/game-of-life/followers"
  172. ],
  173. "object": {
  174. "type": "Ticket",
  175. "attributedTo": "https://forge.example/luke",
  176. "summary": "Test test test",
  177. "content": "<p>Just testing</p>",
  178. "mediaType": "text/html",
  179. "source": {
  180. "mediaType": "text/markdown; variant=Commonmark",
  181. "content": "Just testing"
  182. }
  183. },
  184. "target": "https://dev.example/aviva/game-of-life"
  185. }
  186. </xmp>
  187. </div>
  188. The *target actor* SHOULD send an [=Accept=] or a [=Reject=] activity to the
  189. Offer's author in response. If the *target actor* sends an Accept, it MUST
  190. host its own copy, assigning an [=id=] to the newly published object and adding
  191. it to the expected list specified by the [=Offer=]'s [=target=].
  192. If the *target actor* sends a [=Reject=], it MUST NOT add the object's [=id=]
  193. to that list. However if the *target actor* doesn't make any use of the
  194. object, it MAY choose not to send a Reject, e.g. to protect user privacy. The
  195. `Accept` or `Reject` may also be delayed, e.g. until review by a human user;
  196. that is implementation dependent, and implementations should not rely on an
  197. instant response.
  198. In the [=Accept=] activity:
  199. - [=object=] MUST be the Offer activity or its [=id=]
  200. - [=result=] MUST be specified and be the [=id=] of the new child object now
  201. hosted by the *target actor*, which is extracted from the [=Offer=]'s
  202. [=object=]
  203. In the following example, Luke's ticket is opened automatically and Aviva's
  204. Game Of Life repository, which is an actor, automatically sends Luke an Accept
  205. activity:
  206. <div class=example>
  207. <xmp highlight=json-ld>
  208. {
  209. "@context": [
  210. "https://www.w3.org/ns/activitystreams",
  211. "https://forgefed.org/ns"
  212. ],
  213. "id": "https://dev.example/aviva/game-of-life/outbox/096al",
  214. "type": "Accept",
  215. "actor": "https://dev.example/aviva/game-of-life",
  216. "to": [
  217. "https://forge.example/luke",
  218. "https://dev.example/aviva/game-of-life/team",
  219. "https://dev.example/aviva/game-of-life/followers"
  220. ],
  221. "object": "https://forge.example/luke/outbox/02Ljp",
  222. "result": "https://dev.example/aviva/game-of-life/issues/113"
  223. }
  224. </xmp>
  225. </div>
  226. # Server to Server Interactions # {#s2s}
  227. Issue: This section describes the whole flow of actor interactions, that allows
  228. the federated implementation of the various features of forges and related
  229. software. It provides a complete picture of interaction flows, which the actor
  230. API section can't, because it focuses on a single actor type at a time.
  231. ## Reporting Pushed Commits ## {#pushing}
  232. - Role required for pushing: [=write=]
  233. - Role required for reporting a Push: None (because the [=Repository=] itself
  234. is publishing the Push)
  235. The ForgeFed [=Push=] activity can be used for representing an action
  236. of pushing commits into a [=Repository=]. Two actors are
  237. involved in the process, the *pusher* (usually a person) and the *repository*,
  238. and they may be hosted on different instances.
  239. [=Push=] activities MUST be authored and published by the [=Repository=], not
  240. by the actor that pushed. That actor is specified in the Push's
  241. [=attributedTo=] property.
  242. Upon a successful push, a ForgeFed implementation that publishes a Push
  243. activity MUST provide the [=type=], [=actor=], [=attributedTo=] and [=target=]
  244. properties as described in [[#Push]].
  245. See example in [[#Push]].
  246. ## Opening an issue ## {#opening-issue}
  247. Minimal required role: [=report=]
  248. The first step for opening a ticket is to determine to which actor to send the
  249. ticket. We'll refer to this actor as the *ticket tracker*. Given an object
  250. *obj* against which you'd like to open a ticket (e.g. some application's source
  251. code repository), look at the [=ticketsTrackedBy=]
  252. property of *obj*.
  253. - If `ticketsTrackedBy` isn't specified, then *obj* does't declare a way to
  254. open tickets via ForgeFed.
  255. - If `ticketsTrackedBy` is specified and is set to the [=id=] of *obj*
  256. itself, that means *obj* manages its own tickets, i.e. it is the *ticket
  257. tracker* to which you'll send the ticket.
  258. - If `ticketsTrackedBy` is specified and is set to some other object, look at
  259. the [=tracksTicketsFor=] property of that other object. If the [=id=] of
  260. *obj* is listed there under `tracksTicketsFor`, then that other object is
  261. the *ticket tracker* to which you'll send the ticket. Implementations
  262. SHOULD verify this bidirectional reference between the object and the
  263. tracker, and SHOULD NOT send a ticket if the bidirectional reference isn't
  264. found.
  265. Now that we've determined the *ticket tracker*, i.e. the actor to whom we'll
  266. send the [=Ticket=], the ticket may be opened using an [=Offer=]
  267. activity in which:
  268. - [=object=] is the ticket to be opened, it's a [=Ticket=] object with fields
  269. as described in [[#Ticket]]. It MUST specify at least [=attributedTo=],
  270. [=summary=] and [=content=], and MUST NOT specify [=id=]. If it specifies a
  271. [=context=], then it MUST be identical the Offer's [=target=] described
  272. below.
  273. - [=target=] is the ticket tracker to which the actor is offering the Ticket
  274. (e.g. a repository or project etc. under which the ticket will be opened if
  275. accepted). It MUST be either an actor or a child object. If it's a child
  276. object, the actor to whom the child object belongs MUST be listed as a
  277. recipient in the Offer's [=to=] field. If it's an actor, then that actor
  278. MUST be listed in the `to` field.
  279. The *target actor* MAY then send back an Accept or Reject. The action that has
  280. been taken by the *target actor* is indicated to the ticket author as follows:
  281. - If a [=Reject=] was sent, it means the ticket hasn't been assigned an
  282. [=id=] URI by the tracker and isn't being tracked by the tracker
  283. - If an [=Accept=] was sent, it means the ticket is now tracked and hosted on
  284. the target's side
  285. In the following example, Luke wants to open a ticket under Aviva's Game Of
  286. Life simulation app:
  287. <div class=example>
  288. <xmp highlight=json-ld>
  289. {
  290. "@context": [
  291. "https://www.w3.org/ns/activitystreams",
  292. "https://forgefed.org/ns"
  293. ],
  294. "id": "https://forge.example/luke/outbox/02Ljp",
  295. "type": "Offer",
  296. "actor": "https://forge.example/luke",
  297. "to": [
  298. "https://dev.example/aviva/game-of-life",
  299. "https://dev.example/aviva/game-of-life/team",
  300. "https://dev.example/aviva/game-of-life/followers"
  301. ],
  302. "object": {
  303. "type": "Ticket",
  304. "attributedTo": "https://forge.example/luke",
  305. "summary": "Test test test",
  306. "content": "<p>Just testing</p>",
  307. "mediaType": "text/html",
  308. "source": {
  309. "mediaType": "text/markdown; variant=Commonmark",
  310. "content": "Just testing"
  311. }
  312. },
  313. "target": "https://dev.example/aviva/game-of-life"
  314. }
  315. </xmp>
  316. </div>
  317. Luke's ticket is opened automatically and Aviva's Game Of Life repository,
  318. which is an actor, automatically sends Luke an Accept activity:
  319. <div class=example>
  320. <xmp highlight=json-ld>
  321. {
  322. "@context": [
  323. "https://www.w3.org/ns/activitystreams",
  324. "https://forgefed.org/ns"
  325. ],
  326. "id": "https://dev.example/aviva/game-of-life/outbox/096al",
  327. "type": "Accept",
  328. "actor": "https://dev.example/aviva/game-of-life",
  329. "to": [
  330. "https://forge.example/luke",
  331. "https://dev.example/aviva/game-of-life/team",
  332. "https://dev.example/aviva/game-of-life/followers"
  333. ],
  334. "object": "https://forge.example/luke/outbox/02Ljp",
  335. "result": "https://dev.example/aviva/game-of-life/issues/113"
  336. }
  337. </xmp>
  338. </div>
  339. ## Opening a merge request ## {#opening-mr}
  340. Minimal required role: [=report=]
  341. If actor *A* wishes to submit a Merge Request (MR)/Pull Request (PR)/patch
  342. against a [=Repository=] *R*, it may do so by following these
  343. steps:
  344. 1. Look at *R*'s [=sendPatchesTo=] property: That is the [=PatchTracker=] to
  345. which the MR needs to be submitted; let's call it *P*
  346. 2. Verify that *P* consents to handling MRs for repository *R* by verifying
  347. that *R* is listed in *P*'s [=tracksPatchesFor=] property
  348. 3. Publish and deliver, at least to *P*, an [=Offer=] activity in which:
  349. - [=actor=] is *A*
  350. - [=target=] is *P*
  351. - [=object=] is a [=Ticket=] in which:
  352. * [=id=] isn't specified
  353. * [=type=] is [=Ticket=]
  354. * [=attributedTo=] is *A*
  355. * [=summary=] is a one-line HTML-escaped plain-text title of the MR
  356. * [=source=] is the MR's description
  357. * [=content=] is an HTML rendering of the MR's description
  358. * [=context=], if specified, is *P*
  359. * Among the [=attachment=]s there's exactly one of type [=Offer=], in
  360. which:
  361. + [=type=] is [=Offer=]
  362. + [=origin=] is the [=Repository=] or [=Branch=] from which the
  363. proposed changes are proposed to be merged into the target
  364. repository/branch
  365. + [=target=] is the [=Repository=] or [=Branch=] into which the
  366. changes are proposed to be merged
  367. + [=object=] is an [=OrderedCollection=] of [=Patch=] objects in
  368. reverse chronological order, all of them with:
  369. - the same [=mediaType=]
  370. - that [=mediaType=] MUST match the Version Control System of
  371. the target [=Repository=]
  372. - [=attributedTo=] MUST be *A*
  373. + At least [=origin=] or [=object=] MUST be provided, both MAY be
  374. provided
  375. Actor *P* MAY send back an [=Accept=] or [=Reject=]. The action that has been
  376. taken by *P* is indicated to actor *A* as follows:
  377. - If a [=Reject=] was sent, it mean the MR has been rejected, and isn't being
  378. tracked by *P*
  379. - If an [=Accept=] was sent, it means the MR is now tracked by *P*, and its
  380. [=id=] is indicated by the [=Accept=]'s [=result=]
  381. In the following example, Luke wants to open a Merge Request against a Game Of
  382. Life simulation app:
  383. <div class=example>
  384. <xmp highlight=json-ld>
  385. {
  386. "@context": [
  387. "https://www.w3.org/ns/activitystreams",
  388. "https://forgefed.org/ns"
  389. ],
  390. "id": "https://forge.example/luke/outbox/uCSW6urN",
  391. "type": "Offer",
  392. "actor": "https://forge.example/luke",
  393. "to": [
  394. "https://dev.example/projects/game-of-life/pr-tracker"
  395. ],
  396. "cc": [
  397. "https://dev.example/projects/game-of-life",
  398. "https://dev.example/projects/game-of-life/followers",
  399. "https://dev.example/projects/game-of-life/repo",
  400. "https://dev.example/projects/game-of-life/repo/followers",
  401. "https://dev.example/projects/game-of-life/pr-tracker/followers"
  402. ],
  403. "object": {
  404. "type": "Ticket",
  405. "attributedTo": "https://forge.example/luke",
  406. "summary": "Fix the animation bug",
  407. "content": "<p>Please review, thanks!</p>",
  408. "mediaType": "text/html",
  409. "source": {
  410. "mediaType": "text/markdown; variant=Commonmark",
  411. "content": "Please review, thanks!"
  412. },
  413. "attachment": {
  414. "type": "Offer",
  415. "origin": {
  416. "type": "Branch",
  417. "context": "https://forge.example/luke/game-of-life",
  418. "ref": "refs/heads/fix-animation-bug"
  419. },
  420. "target": {
  421. "type": "Branch",
  422. "context": "https://dev.example/projects/game-of-life/repo",
  423. "ref": "refs/heads/main"
  424. },
  425. "object": {
  426. "type": "OrderedCollection",
  427. "totalItems": 1,
  428. "items": [
  429. {
  430. "type": "Patch",
  431. "attributedTo": "https://forge.example/luke",
  432. "mediaType": "application/x-git-patch",
  433. "content": "From c9ae5f4ff4a330b6e1196ceb7db1665bd4c1..."
  434. }
  435. ]
  436. }
  437. }
  438. },
  439. "target": "https://dev.example/projects/game-of-life/pr-tracker"
  440. }
  441. </xmp>
  442. </div>
  443. Luke's MR is opened automatically and the [=PatchTracker=]
  444. sends Luke an Accept activity:
  445. <div class=example>
  446. <xmp highlight=json-ld>
  447. {
  448. "@context": [
  449. "https://www.w3.org/ns/activitystreams",
  450. "https://forgefed.org/ns"
  451. ],
  452. "id": "https://dev.example/projects/game-of-life/pr-tracker/outbox/qQfFKwJ8",
  453. "type": "Accept",
  454. "actor": "https://dev.example/projects/game-of-life/pr-tracker",
  455. "to": [
  456. "https://forge.example/luke"
  457. ],
  458. "cc": [
  459. "https://dev.example/projects/game-of-life",
  460. "https://dev.example/projects/game-of-life/followers",
  461. "https://dev.example/projects/game-of-life/repo",
  462. "https://dev.example/projects/game-of-life/repo/followers",
  463. "https://dev.example/projects/game-of-life/pr-tracker/followers"
  464. ],
  465. "object": "https://forge.example/luke/outbox/uCSW6urN",
  466. "result": "https://dev.example/projects/game-of-life/pr-tracker/pulls/1219"
  467. }
  468. </xmp>
  469. </div>
  470. ## Commenting ## {#commenting}
  471. Minimal required role: [=report=]
  472. A comment on a ForgeFed resource object (such as tickets, merge requests) MUST
  473. be published as a [=Create=] activity, in which [=object=] is a [=Note=] with
  474. fields as described in [[#Comment]].
  475. In the following example, Luke replies to Aviva's comment under a merge request
  476. he submitted earlier against her Game Of Life simulation app repository:
  477. <div class=example>
  478. <xmp highlight=json-ld>
  479. {
  480. "@context": "https://www.w3.org/ns/activitystreams",
  481. "id": "https://forge.example/luke/outbox/rLaYo",
  482. "type": "Create",
  483. "actor": "https://forge.example/luke",
  484. "to": [
  485. "https://forge.example/luke/followers",
  486. "https://dev.example/aviva/game-of-life",
  487. "https://dev.example/aviva/game-of-life/followers",
  488. "https://dev.example/aviva/game-of-life/team",
  489. "https://dev.example/aviva/game-of-life/merge-requests/19/followers",
  490. "https://dev.example/aviva/game-of-life/merge-requests/19/team"
  491. ],
  492. "object": {
  493. "id": "https://forge.example/luke/comments/rD05r",
  494. "type": "Note",
  495. "attributedTo": "https://forge.example/luke",
  496. "to": [
  497. "https://forge.example/luke/followers",
  498. "https://dev.example/aviva/game-of-life",
  499. "https://dev.example/aviva/game-of-life/followers",
  500. "https://dev.example/aviva/game-of-life/team",
  501. "https://dev.example/aviva/game-of-life/merge-requests/19/followers",
  502. "https://dev.example/aviva/game-of-life/merge-requests/19/team"
  503. ],
  504. "context": "https://dev.example/aviva/game-of-life/merge-requests/19",
  505. "inReplyTo": "https://dev.example/aviva/comments/E9AGE",
  506. "mediaType": "text/html",
  507. "content": "<p>Thank you for the review! I'll submit a correction ASAP</p>",
  508. "source": {
  509. "mediaType": "text/markdown; variant=Commonmark",
  510. "content": "Thank you for the review! I'll submit a correction ASAP"
  511. },
  512. "published": "2019-11-06T20:49:05.604488Z"
  513. }
  514. }
  515. </xmp>
  516. </div>
  517. ## Granting access to shared resources ## {#managing-access}
  518. Minimal required role: [=admin=]
  519. An actor that wishes to give other specific actors access to view or modify it
  520. (or a child object of it), SHOULD do so according to the following
  521. instructions.
  522. ### Object capabilities
  523. #### Introduction #### {#s2s-grant-simple}
  524. An Object Capability (or in short OCap or OCAP) is a token providing access to
  525. certain operations on a certain resource. An actor wishing to act on a resource
  526. provides the token to the resource, alongside the Activity they wish to
  527. perform. The resource verifies the token, and if and only if it finds the token
  528. valid, and access to the requested Activity is allowed by the token, *then* the
  529. resource allows the Activity to be performed.
  530. The token provided by the actor to the resource, i.e. the OCAP, is the ID URI
  531. of a previously published [=Grant=] activity.
  532. The fundamental steps for accessing shared resources using OCAPs are:
  533. 1. The actor managing the resource (which may be the resource itself) sends a
  534. `Grant` activity to the actor to whom it wishes to grant access
  535. 2. When the actor who received the access wishes to operate on the resource,
  536. it sends the activity to the actor managing the resource, along with the ID
  537. URI of the `Grant` sent in step 1
  538. 3. The actor managing the resource verifies the access provided by the `Grant`
  539. whose ID URI is provided, and allows the activity to be performed only if
  540. the verification passes
  541. Providing the `Grant` ID URI like that when requesting to interact with a
  542. resource is called an *invocation* of the `Grant`. There is another operation
  543. possible with a `Grant` though: An actor can *delegate* a `Grant` it has
  544. received, i.e. pass on the access, giving it to more actors. Delegation is
  545. covered in a [later section](#s2s-grant-flow); for now let's assume `Grant`s
  546. are used only for invocation. We therefore get the following simplified
  547. validation process.
  548. When an actor *R* receives from actor *A* a request to access/modify a resource
  549. *r*, where the request is expressed as an activity *a* whose
  550. [=capability=] field specifies some other activity *g*, then *R*
  551. can validate *a* (i.e. decide whether or not to perform the requested action)
  552. using the following steps:
  553. 1. Resource *r* MUST be a resource that *R* manages (it may be *R* itself)
  554. 2. *g*'s [=type=] MUST be [=Grant=]
  555. 3. *g*'s [=context=] MUST be *r*
  556. 4. *g*'s [=target=] MUST be *A*
  557. 5. Verify that *g*'s [=startTime=] <= now < *g*'s [=endTime=]
  558. 6. Verify that *g* doesn't specify [=delegates=]
  559. 7. *g*'s [=actor=] MUST be *R*
  560. 8. Verify that *R* indeed published *g* and considers it an active grant
  561. (i.e. *R* hasn't disabled/revoked it)
  562. 9. *checkLeaf(g):*
  563. 1. *g*'s [=allows=] MUST be [=invoke=]
  564. 2. Actor *A* SHOULD be of a [=type=] to which *R* allows to perform
  565. activity *a* on resource *r*, i.e. *A* should probably be a [=Person=],
  566. or some automated service/bot
  567. 10. Verify that the action being requested by activity *a* to perform on
  568. resource *r* is within what *R* permits for the [=Role=] specified by *g*'s
  569. [=object=]
  570. At this point, activity *a* is considered authorized, and the requested action
  571. may be performed.
  572. #### Direct Granting
  573. When an actor *R*, managing some resource *r*, wishes to allow some other actor
  574. *A* to interact with *r*, under the conditions and permissions specified by
  575. [=Role=] *p*, then actor *R* can send to actor *A* a [=Grant=] activity
  576. with the following properties:
  577. - [=actor=]: Specifies actor *R*
  578. - [=context=]: Specifies resource *r*
  579. - [=target=]: Specifies actor *A*
  580. - [=object=]: Specifies role *p*
  581. - [=startTime=]: (optional) The time at which the Grant becomes valid
  582. - [=endTime=]: (recommended) The time at which the Grant expires
  583. - [=allows=]: Specifies [=invoke=]
  584. - [=delegates=]: Not used
  585. #### Granting the delegate role #### {#grant-delegate}
  586. A special case of direct granting is *granting permission to delegate*: If role
  587. *p* is [=delegate=], then the `Grant` [=actor=] is allowing the
  588. [=target=] to delegate `Grant`s to the [=actor=], i.e. to send `Grant`s meant
  589. for delegation or `Grants` that are themselves delegations of other `Grant`s
  590. (either start a chain, or extend a chain that some other actor started). More
  591. on delegation in the next sections.
  592. When an actor *A* wishes to allow some other actor *R* to delegate `Grant`s to
  593. actor *A*, then actor *A* can send to actor *R* a [=Grant=] activity
  594. with the following properties:
  595. - [=actor=]: Specifies actor *A*
  596. - [=context=]: Specifies actor *A*
  597. - [=target=]: Specifies actor *R*
  598. - [=object=]: Specifies [=delegate=]
  599. - [=startTime=]: (optional) The time at which the Grant becomes valid
  600. - [=endTime=]: (recommended) The time at which the Grant expires
  601. - [=allows=]: Specifies [=invoke=]
  602. - [=delegates=]: Not used
  603. #### Starting a delegation chain #### {#start-grant-chain}
  604. When an actor *R*, managing some resource *r*, wishes to allow or request some
  605. other actor *A* to delegate some access-to-*r*-under-role-*p* to certain (or
  606. any) other actors that *A* knows, then actor *R* can send to actor *A* a
  607. [=Grant=] activity with the following properties:
  608. - [=actor=]: Specifies actor *R*
  609. - [=context=]: Specifies resource *r*
  610. - [=target=]: Specifies actor *A*
  611. - [=object=]: Specifies role *p*
  612. - [=startTime=]: (optional) The time at which the Grant becomes valid
  613. - [=endTime=]: (recommended) The time at which the Grant expires
  614. - [=allows=]: Specifies the conditions under which actor *A* may
  615. delegate this `Grant` (i.e. conditions under which actor *R* will consider
  616. the delegation valid when verifying the chain), and what the recipients of
  617. the delegtaions that *A* will send (which are themselves `Grant` activites)
  618. are allowed to do with these `Grants` (invoke? further delegate to certain
  619. other actors?)
  620. - [=delegates=]: Not used
  621. - [=capability=]: *(optional)* Specifies a
  622. [[#grant-delegate|delegate Grant]] previously given by *A* to *R*
  623. The following cases are supported in ForgeFed for starting a delegation chain.
  624. The term 'component' used below refers to a forge related service actor. This
  625. may be a service of a [=type=] defined in ForgeFed (such as
  626. [=Repository=], [=TicketTracker=],
  627. [=PatchTracker=]), or a service defined in some extension.
  628. 1. [=actor=] is a component, [=target=] is a [=Project=]
  629. - Scenario: A component delegates access-to-a-resource-it-manages (which is
  630. often simply itself) to a project to which the component belongs
  631. - [=allows=] value to use: [=gatherAndConvey=]
  632. - Conditions for the target project:
  633. * It SHOULD delegate the `Grant`, allowing only `gatherAndConvey`, to
  634. its own parent projects
  635. * It SHOULD delegate the `Grant`, allowing only `distribute`, to teams
  636. to which it allows to access it
  637. * It SHOULD delegate the `Grant`, allowing only `invoke`, to people and
  638. bots to which it allows to access it
  639. * It SHOULD NOT make any other delegation of this `Grant`, and SHOULD
  640. NOT invoke it
  641. 2. [=actor=] is a [=Project=], [=target=] is a parent [=Project=] of it
  642. - Scenario: A project delegates access-to-a-resource-itself to its parent
  643. project
  644. - [=allows=] value to use: Same as 1
  645. - Conditions for the target project: Same as 1
  646. 3. [=actor=] is a component, [=target=] is a [=Team=]
  647. - Scenario: A component delegates access-to-a-resource-it-manages to a team
  648. that has been approved to access the component
  649. - [=allows=] value to use: [=distribute=]
  650. - Conditions for the target team:
  651. * It SHOULD delegate the `Grant`, allowing `distribute` only, to its
  652. subteams
  653. * It SHOULD delegate the `Grant`, allowing `invoke` only, to its
  654. members
  655. * It SHOULD NOT make any other delegation of this `Grant`, and SHOULD
  656. NOT invoke it
  657. 4. [=actor=] is a [=Project=], [=target=] is a [=Team=]
  658. - Scenario: A project delegates access-to-itself to a team that has been
  659. approved to access the project
  660. - [=allows=] value to use: Same as 3
  661. - Conditions for the target project: Same as 3
  662. #### Extending a delegation chain
  663. When an actor *A* receives a [=Grant=] activity *g* where the
  664. [=target=] is *A*, and wishes to pass on the granted access to some other actor
  665. *B* (who isn't the [=actor=] of that `Grant`), then actor *A* can do so by
  666. sending to actor *B* a new `Grant` activity *h* in which:
  667. - [=actor=] is actor *A*
  668. - [=context=] (i.e. the resource) is same as *g*'s [=context=]
  669. - [=target=] is actor *B*
  670. - [=object=] (i.e. the granted role) is either *g*'s [=object=] or a
  671. lower-access role than *g*'s [=object=], i.e. provides a subset of the
  672. permissions that *g*'s [=object=] provides (the latter case is called
  673. *attenuation*)
  674. - [=startTime=]: *(optional)* The time at which this Grant becomes valid
  675. - [=endTime=]: *(recommended)* The time at which this Grant expires
  676. - [=allows=]: Specifies the conditions under which actor *B* may
  677. delegate this `Grant` (i.e. conditions under which the delegation will be
  678. considered valid when verifying the chain), and what the recipients of
  679. the delegtaions that *B* will send (which are themselves `Grant` activites)
  680. are allowed to do with these `Grants` (invoke? further delegate to certain
  681. other actors?)
  682. - [=delegates=] is activity *g*
  683. - [=capability=]: *(optional)* Specifies a
  684. [delegate Grant](#grant-delegate) previously given by *B* to *A*
  685. - [=result=]: a URI that will be used later to verify that *h* is still active
  686. and hasn't been revoked. Alternatively, an object with [=id=] and
  687. [=duration=] as described below.
  688. The [=result=] URI MUST be provided whenever extending a delegation chain. It
  689. MUST be a URI that actor *A* controls, i.e. decides what will be returned by
  690. HTTP requests to that URI. Requirements:
  691. - From the moment that actor *A* publishes activity *h*, as long as actor *A*
  692. considers *h* an active `Grant` and hasn't revoked it, any HTTP HEAD or HTTP
  693. GET request the [=result=] URI MUST return an HTTP response status 204 or 200.
  694. - If later activity *h* is revoked, or actor *A* is deleted, then from the
  695. moment that actor *A* considers *h* deactivated, any HTTP HEAD or HTTP GET
  696. request to the [=result=] URI MUST NOT return an HTTP response status in the
  697. 200-299 range. The response status SHOULD be 410 or 404.
  698. [=result=] MAY instead specify a JSON object in which:
  699. - [=id=] is the URI as described above
  700. - *(optional)* [=duration=] specifies a duration that allows the recovation URI
  701. check to be skipped, if the duration hasn't yet passed since the last check
  702. of the URI. If [=duration=] is specified, it MUST be positive and include
  703. only an integral number of seconds that is less than `2^63`, and no other
  704. component. In other words, its format is: The string "PT", then the
  705. integer, then the string "S".
  706. In the following cases, *g* is a *request* for actor *A* to extend the
  707. delegation chain, and actor *A* SHOULD extend the chain by sending `Grant`
  708. activities, as described for each case.
  709. The term 'component' used below refers to a forge related service actor. This
  710. may be a service of a [=type=] defined in ForgeFed (such as
  711. [=Repository=], [=TicketTracker=],
  712. [=PatchTracker=]), or a service defined in some extension.
  713. 1. Actor *A* is a [=Project=], AND *g*'s [=actor=] is either a
  714. [=component=] of *A* or a [=subproject=] of
  715. *A*, AND *g*'s [=allows=] is a single value
  716. [=gatherAndConvey=]
  717. - Scenario: Project *A* received some access from a component/subproject of
  718. it, and is requested to pass it on its member people, to its member
  719. teams, and to its parent projects
  720. - Requirements for extending the delegation chain:
  721. 1. For each parent project *P* of project *A*, project *A* SHOULD
  722. publish and deliver to *P* a `Grant` activity in which:
  723. - [=actor=] is project *A*
  724. - [=context=] (i.e. the resource) is same as *g*'s [=context=]
  725. - [=target=] is project *P*
  726. - [=object=] (i.e. the granted role) is either *g*'s [=object=] or
  727. a lower-access role than *g*'s [=object=]
  728. - [=allows=] is a single value [=gatherAndConvey=]
  729. - [=delegates=] is activity *g*
  730. - [=capability=]: *(optional)* Specifies a
  731. [delegate Grant](#grant-delegate) previously given by *P* to *A*
  732. - [=result=]: a URI that will be used later to verify that *h* is
  733. still active and hasn't been revoked, or a JSON object as
  734. describes above
  735. 2. For each team *T* that project *A* considers a member team with role
  736. *p*, project *A* SHOULD publish and deliver to *T* a `Grant`
  737. activity in which:
  738. - [=actor=] is project *A*
  739. - [=context=] (i.e. the resource) is same as *g*'s [=context=]
  740. - [=target=] is team *T*
  741. - [=object=] (i.e. the granted role) is the lower-access role
  742. among *g*'s [=object=] and *p*
  743. - [=allows=] is a single value [=distribute=]
  744. - [=delegates=] is activity *g*
  745. - [=capability=]: *(optional)* Specifies a
  746. [delegate Grant](#grant-delegate) previously given by *T* to *A*
  747. - [=result=]: a URI that will be used later to verify that *h* is
  748. still active and hasn't been revoked, or a JSON object as
  749. describes above
  750. 3. For each [=Person=] or automated service bot *M* (that isn't a team)
  751. that project *A* considers a member with role *p*, project *A*
  752. SHOULD publish and deliver to *M* a `Grant` activity in which:
  753. - [=actor=] is project *A*
  754. - [=context=] (i.e. the resource) is same as *g*'s [=context=]
  755. - [=target=] is actor *M*
  756. - [=object=] (i.e. the granted role) is the lower-access role
  757. among *g*'s [=object=] and *p*
  758. - [=allows=] is a single value [=invoke=]
  759. - [=delegates=] is activity *g*
  760. - [=capability=]: *(optional)* Specifies a
  761. [delegate Grant](#grant-delegate) previously given by *M* to *A*
  762. - [=result=]: a URI that will be used later to verify that *h* is
  763. still active and hasn't been revoked, or a JSON object as
  764. describes above
  765. 4. Project *A* MUST NOT make any other delegations of *g*, and SHOULD
  766. NOT try to invoke it
  767. 2. Actor *A* is a [=Team=], AND *g*'s [=actor=] is either a
  768. component/[=Project=] in which *A* is a member or a
  769. parent team (see [=subteams=]) of *A*, AND *g*'s [=allows=] is a
  770. single value [=distribute=]
  771. - Scenario: Team *A* received some access from a component/project that
  772. considers *A* a member team, or from a parent team of *A*, and *A* is
  773. requested to pass it on its member people and to its subteams
  774. - Requirements for extending the delegation chain:
  775. 1. For each team *T* that team *A* considers a
  776. [=subteam=], team *A* SHOULD publish and deliver to *T*
  777. a `Grant` activity in which:
  778. - [=actor=] is team *A*
  779. - [=context=] (i.e. the resource) is same as *g*'s [=context=]
  780. - [=target=] is team *T*
  781. - [=object=] (i.e. the granted role) is the same as
  782. *g*'s [=object=]
  783. - [=allows=] is a single value [=distribute=]
  784. - [=delegates=] is activity *g*
  785. - [=capability=]: *(optional)* Specifies a
  786. [delegate Grant](#grant-delegate) previously given by *T* to *A*
  787. 2. For each [=Person=] or automated service bot *M* (that isn't a team)
  788. that team *A* considers a member with role *p*, team *A*
  789. SHOULD publish and deliver to *M* a `Grant` activity in which:
  790. - [=actor=] is team *A*
  791. - [=context=] (i.e. the resource) is same as *g*'s [=context=]
  792. - [=target=] is actor *M*
  793. - [=object=] (i.e. the granted role) is the lower-access role
  794. among *g*'s [=object=] and *p*
  795. - [=allows=] is a single value [=invoke=]
  796. - [=delegates=] is activity *g*
  797. - [=capability=]: *(optional)* Specifies a
  798. [delegate Grant](#grant-delegate) previously given by *M* to *A*
  799. 3. Team *A* MUST NOT make any other delegations of *g*, and SHOULD NOT
  800. try to invoke it
  801. #### Revoking a Grant #### {#s2s-revoke}
  802. At any point after an actor *A* publishes a [[#Grant]] in which it
  803. grants some actor *B* access to a resource that actor *A* manages, actor *A*
  804. MAY cancel that `Grant`, deciding it's no longer a valid OCAP to use via the
  805. [=capability=] property of activies that actor *B* sends.
  806. If actor *A* cancels such a `Grant`, it SHOULD publish and deliver, at least to
  807. actor *B*, a [=Revoke=] activity notifying about the canceled
  808. `Grant`. In the `Revoke` activity, actor *A* MUST specify the Grants being
  809. revoked, via the [=object=] property, where each Grant is specified in one of
  810. the following ways:
  811. 1. The Grant is specified by its `id` URI
  812. 2. The whole Grant activity object is provided, and MUST contain an
  813. [[fep-8b32|integrity proof]]
  814. Additional requirements:
  815. - Implementations displaying a `Revoke` activity or an interpretation of it in
  816. a human interface MUST examine the `Revoke`'s [=object=] property if it is
  817. present, check if any of the `Grant`s listed are delegations, and communicate
  818. that detail in the human interface
  819. Once actor *A* publishes the `Revoke`, it MUST from now on refuse to execute
  820. requests from actor *B* to access resources that actor *A* manages, coming as
  821. activities that specify any of the canceled `Grant`s in the `capability`
  822. property. If actor *A* receives such an activity from actor *B*, it SHOULD
  823. publish and send back a [=Reject=] activity, whose [=object=] specifies the
  824. activity that actor *B* sent.
  825. If the `Grant` that actor *A* is revoking specifies a [=result=], then from now
  826. on any HTTP HEAD request to the URI specified by [=result=] MUST NOT return an
  827. HTTP response status in the 200-299 range. The returned status SHOULD be 410
  828. or 404. See [Extending a delegation chain](#extending-a-delegation-chain) for
  829. more information.
  830. #### Verifying an invocation #### {#s2s-grant-flow}
  831. A [previous section](#s2s-grant-simple) described *direct* usage of
  832. [=Grant=]s, where the *resource actor* gives some access to a *target
  833. actor*, and the *target actor* then uses it to interact with the resource.
  834. Another way to give authorization is via delegation chains:
  835. - The *resource actor* passes access to a *target actor*, allowing (or
  836. requesting) the *target actor* to pass this access (or reduced access) on to
  837. more actors
  838. - If authorized by the delegation, those actors may further pass on the access
  839. (possibly reduced)
  840. - Eventually, an actor that received such a delegation may use it to access the
  841. resource
  842. Access is delegated using [=Grant=] activities as well, using the
  843. [=delegates=] property to point from each `Grant` in the chain to
  844. the previous one. The "direct" `Grant` discussed earlier is simply a delegation
  845. chain of length 1.
  846. When an actor *R* receives from actor *A* a request to access/modify a resource
  847. *r*, where the request is expressed as an activity *a* whose
  848. [=capability=] field specifies some other activity *g*, then *R*
  849. can validate *a* (i.e. decide whether or not to perform the requested action)
  850. using the following steps.
  851. *R* begins by verifying that resource *r* is indeed a resource that *R* manages
  852. (it may be *R* itself). Otherwise, verification has failed.
  853. *R* proceeds by collecting the delegation chain in a list, by traversing the
  854. chain backwards from the leaf all the way to the beginning of the chain. The
  855. traversal starts with the list *L* being empty, and *R* examines activity *g*:
  856. 1. *g*'s [=type=] MUST be [=Grant=]
  857. 2. *g*'s [=context=] MUST be *r*
  858. 3. *g*'s [=target=] MUST be *A*
  859. 4. *g* MUST NOT already be listed in *L*
  860. 5. Verify that *g*'s [=startTime=] <= now < *g*'s [=endTime=]
  861. 6. Look at *g*'s [=delegates=]:
  862. - If *g* doesn't specify [=delegates=]:
  863. 1. *g*'s [=actor=] MUST be *R*
  864. 2. Verify that *R* indeed published *g* and considers it an active
  865. grant (i.e. *R* hasn't disabled/revoked it)
  866. 3. Prepend *g* to the beginning of *L*, resulting with new list *M*
  867. 4. We're done with the traversal step, the output is *M*
  868. - If *g*'s [=delegates=] is some activity *h*:
  869. 1. *g*'s [=actor=] MUST NOT be *R*
  870. 2. *g* MUST specify exactly one [=result=] URI
  871. 3. Verify the [=result=]:
  872. - If it's an object with [=duration=] specified, and this duration
  873. of time hasn't yet passed since the last check, proceed without
  874. checking the URI
  875. - Otherwise, send an HTTP HEAD request to the URI, The HTTP
  876. response status MUST be 200 or 204
  877. 4. Prepend *g* to the beginning of *L*, resulting with new list *M*
  878. 5. Continue traversal by going back to step 1, but with *M* being the
  879. list, and with *g*'s [=actor=] instead of *A*, and now examining
  880. activity *h*
  881. Issue: "Going back to step 1" refers to the top-level list item; should
  882. probably tweak the CSS to display nested lists differently.
  883. *R* proceeds by traversing the resulting list *L* from the beginning forward,
  884. all the way to the leaf, validating and tracking attenuation in each step. *R*
  885. starts this by examining the first item in *L*, let's call this item *g*:
  886. 1. Let *p* be *g*'s [=object=]
  887. 2. Examine *g*'s position in *L*:
  888. - If *g* is the last item in *L*:
  889. 1. Perform *checkLeaf* on *g* (see below)
  890. 2. Verify that the action being requested by activity *a* to perform on
  891. resource *r* is within what *R* permits for [=Role=] *p*.
  892. 3. We're done with the traversal!
  893. - Otherwise:
  894. 1. Let *h* be the next item after *g* in *L*
  895. 2. Let *q* be *h*'s [=object=]
  896. 3. The permissions that role *q* allows on resource *r* MUST be
  897. identical to or a subset of the permissios that role *p* allows on
  898. *r*
  899. 4. Perform *checkItem* on *(g, h)* (see below)
  900. 5. Continue traversal by going back to step 2, but with *h* instead of
  901. *g* and *q* instead of *p*
  902. Issue: "Step 2" refers to the top-level one, need to tweak CSS for lists
  903. The steps *checkLeaf* and *checkItem* mentioned above MAY be extended by
  904. implementations, by using custom values in the [=allows=] property.
  905. But here are the standard definitions, using the values defined in ForgeFed:
  906. *checkLeaf (g):*
  907. 1. *g*'s [=allows=] MUST be [=invoke=]
  908. 2. *g*'s [=target=] (which is actor *A*, the sender of activity *a*) SHOULD be
  909. an actor of a [=type=] to which *R* allows to perform activity *a* on
  910. resource *r*, i.e. *A* should probably be a [=Person=], or some automated
  911. service/bot
  912. *checkItem (g, h):*
  913. 1. *g* MUST specify exactly one value for [=allows=]
  914. 2. That value MUST be either [=gatherAndConvey=] or [=distribute=]
  915. - If it's [=gatherAndConvey=]:
  916. 1. *g*'s [=target=] MUST be a [=Project=]
  917. - If it's [=distribute=]:
  918. 1. *g*'s [=target=] MUST be a [=Team=]
  919. 2. *h*'s [=allows=] MUST be either [=distribute=]
  920. or [=invoke=]
  921. At this point, activity *a* is considered authorized, and the requested action
  922. may be performed.
  923. #### Identifying resources and their managing actors #### {#manager}
  924. Some shared resources are themselves actors. Some shared resources aren't
  925. actors, but they are child objects of actors. When some actor *A* wishes to
  926. access a resource *R* and perform a certain operation, it needs to determine
  927. which actor to contact in order to request that operation. Actor *A* then looks
  928. at resource *R*, and the following MUST hold:
  929. - Either the resource *R* isn't an actor (i.e. doesn't have an [=inbox=]) but
  930. does specify which actor manages it via the [=managedBy=] property;
  931. - Or the resource *R* is an actor, i.e. it has an [=inbox=] (it doesn't have to
  932. specify [=managedBy=], but if it does, then it MUST refer to itself)
  933. Therefore any object that wishes to be specified as the [=context=] of a
  934. [=Grant=] MUST either be an actor or be [=managedBy=] an
  935. actor.
  936. #### Invoking a Grant
  937. Invoking a [=Grant=] means using the `Grant` to authorize a request to
  938. access or modify some resource. If some actor *A* wishes to access or modify a
  939. resource *r*, using a `Grant` activity *g* for authorization, preconditions
  940. for a successful invocation include:
  941. - *g*'s [=target=] is actor *A*
  942. - *g*'s [=context=] is either the resource *r*, or a resource in which *r* is
  943. contained, or the actor that [=managedBy|manages=] *r*
  944. - *g*'s [=object=] is a [=Role=] that permits the kind of operation
  945. that actor *A* is requesting to do on resource *r*
  946. - *g*'s [=allows=] is [=invoke=]
  947. - *g*'s [=startTime=] <= now < *g*'s [=endTime=]
  948. When actor *A* sends the activity *a* that requests to access or modify
  949. resource *r*, it can use *g* for authorization by specifying its [=id=] URI in
  950. the [=capability=] property of activity *a*.
  951. To have a chance to access resource *r*, actor *A* needs to deliver activity
  952. *a* to the actor that manages *r*. [See above](#manager) instructions for
  953. determining who that actor is.
  954. #### Time Bounds
  955. A [=Grant=] activity MUST be considered valid for invocation (or as a valid
  956. link in a delegation chain) if and only if the current time, at the time of
  957. invocation, is within the time bounds defined by the [=Grant=]:
  958. 1. A [=Grant=] MAY specify a [=startTime=]: The time at which the Grant becomes
  959. valid. If specified, the [=Grant=] is valid only if the time of invocation
  960. is equal or greater than the [=startTime=]
  961. 2. A [=Grant=] SHOULD specify an [=endTime=]: The time at which the Grant
  962. expires. If specified, the [=Grant=] is valid only if the time of
  963. invocation is less than the [=endTime=]
  964. Suggested default for picking the [=endTime=]: 6 months after publishing the
  965. [=Grant=].
  966. ### Granting access
  967. #### Initial Grant upon resource creation
  968. When an actor *A* requests to create a new shared resource *R*, and the
  969. *resource actor* approves and creates it, then the *resource actor* SHOULD send
  970. a `Grant` to actor *A*, which provides actor *A* with access to resource *R*.
  971. The [=Role=] specified by the [=Grant=]'s [=object=] MUST be [=admin=], which
  972. means full access to *R*, including the ability to gives access-to-*R* to more
  973. actors (using an [=Invite=] activity, see below).
  974. If such a `Grant` is sent by the *resource actor* upon the creation of resource
  975. *R*, then the `Grant`'s [=fulfills=] property MUST be provided and
  976. specify the ID URI of the activity (published by actor *A*) that requested to
  977. create resource *R* (typically this would be a [=Create=] activity, see
  978. [Object Publishing and Hosting](#publishing)).
  979. If *R* is a [=Project=] or a [=Team=], additional steps occur:
  980. 1. *A*, seeing *R*'s Grant, publishes a [[#grant-delegate|delegate-Grant]]
  981. in which the [=target=] is *R* and [=capability=] is *R*'s Grant
  982. 2. From now on, whenever *R* wishes to
  983. [[#extending-a-delegation-chain|extend a Grant chain]] to *A*, it uses
  984. *A*'s delegate-Grant as the [=capability=]
  985. #### Offering access using Invite activities
  986. When an actor *A* wishes to offer actor *B* access to resource *R* (where the
  987. *resource actor* who manages *R* is neither *A* nor *B*), then actor *A* SHOULD
  988. use an [=Invite=] activity, and the following steps:
  989. 1. Actor *A* publishes and delivers an [=Invite=], at least to actor
  990. *B* and to the *resource actor* of *R*, with a relevant
  991. [=capability=] (see [[#Invite]] for details on the properties to use)
  992. 2. If actor *B* wishes to have the offered access, it publishes and delivers
  993. (at least to the *resource actor* of *R*) an [=Accept=] activity whose
  994. [=object=] specifies the `Invite` sent by actor *A*
  995. 3. The *resource actor* of *R* receives the `Invite` and the `Accept` and:
  996. 1. Verifies the `Invite` is authorized, as described above in
  997. [Verifying an invocation](#s2s-grant-flow)
  998. 2. Verifies that the `Accept`'s [=object=] specifies the `Invite` and the
  999. `Accept`'s [=actor=] is the `Invite`'s [=object=]
  1000. 3. Publishes and delivers a [=Grant=] activity (see
  1001. [[#Grant]] for more details on the properties) where:
  1002. - [=object=] is the `Invite`'s [=instrument=]
  1003. - [=context=] is the `Invite`'s [=target=], which is resource *R*
  1004. - [=target=] is the `Invite`'s [=object=], which is actor *B*
  1005. - [=fulfills=] is the `Invite`
  1006. - [=allows=] is [=invoke=]
  1007. - [=delegates=] isn't specified
  1008. 4. *B* is now considered a collaborator in *R*!
  1009. 5. If *R* is a [=Project=] or a [=Team=], additional steps occur:
  1010. 1. *B*, seeing *R*'s Grant, publishes a [[#grant-delegate|delegate-Grant]]
  1011. in which the [=target=] is *R* and [=capability=] is *R*'s Grant
  1012. 2. From now on, whenever *R* wishes to
  1013. [[#extending-a-delegation-chain|extend a Grant chain]] to *B*, it uses
  1014. *B*'s delegate-Grant as the [=capability=]
  1015. Actor *B* can now use the URI of that new `Grant` as the
  1016. [=capability=] when it sends activities that access or
  1017. manipulate resource *R*.
  1018. #### Requesting access using Join activities
  1019. When an actor *A* wishes to request access to resource *R* (where the *resource
  1020. actor* who manages *R* isn't *A*), then actor *A* SHOULD use a
  1021. [=Join=] activity, and the following steps. There are two options detailed
  1022. below, depending on whether actor *A* has been previously given a
  1023. [=Grant=] authorizing it to gain access to resource *R* without
  1024. needing someone else to approve. For example, perhaps actor *A* already has
  1025. some access to a resource collection to which *R* belongs, and that access
  1026. allows *A* to freely `Join` *R* without needing to wait for human approval.
  1027. **Option 1: Actor *A* already has a `Grant` allowing it to gain access to *R*
  1028. without external approval:**
  1029. 1. Actor *A* publishes and delivers a [=Join=], at least to the
  1030. *resource actor* of *R*, with the relevant [=capability=] it
  1031. has (see [[#Join]] for details on the properties
  1032. to use)
  1033. 2. The *resource actor* of *R* receives the `Join` and:
  1034. 1. Verifies the `Join` is authorized, as described above in
  1035. [Verifying an invocation](#s2s-grant-flow)
  1036. 2. Publishes and delivers a [=Grant=] activity (see
  1037. [[#Grant]] for more details on the
  1038. properties) where:
  1039. - [=object=] is the `Join`'s [=instrument=]
  1040. - [=context=] is the `Join`'s [=object=], which is resource *R*
  1041. - [=target=] is the `Join`'s [=actor=], which is actor *A*
  1042. - [=fulfills=] is the `Join`
  1043. 3. *A* is now considered a collaborator in *R*!
  1044. 4. If *R* is a [=Project=] or a [=Team=], additional steps occur:
  1045. 1. *A*, seeing *R*'s Grant, publishes a [[#grant-delegate|delegate-Grant]]
  1046. in which the [=target=] is *R* and [=capability=] is *R*'s Grant
  1047. 2. From now on, whenever *R* wishes to
  1048. [[#extending-a-delegation-chain|extend a Grant chain]] to *A*, it uses
  1049. *A*'s delegate-Grant as the [=capability=]
  1050. Actor *A* can now use the URI of that new `Grant` as the
  1051. [=capability=] when it sends activities that access or
  1052. manipulate resource *R*.
  1053. **Option 2: Actor *A* doesn't have (or chooses not to use) a `Grant` allowing
  1054. it to gain access to *R* without external approval:**
  1055. 1. Actor *A* publishes and delivers a [=Join=], at least to the
  1056. *resource actor* of *R* (see [[#Join]] for
  1057. details on the properties to use)
  1058. 2. If some actor *B*, that has previously received a `Grant` from the *resource
  1059. actor* of *R* authorizing it to approve joins, sees the `Join` sent by actor
  1060. *A* and decides to approve it, then actor *B* publishes and delivers (at
  1061. least to the *resource actor* of *R*) an [=Accept=] activity where:
  1062. - [=object=] specifies the `Join` sent by actor *A*
  1063. - [=capability=] is the `Grant` mentioned above,
  1064. authorizing to approve or deny Joins
  1065. 3. The *resource actor* of *R* receives the `Join` and the `Accept` and:
  1066. 1. Verifies the `Accept` is authorized, as described above in
  1067. [Verifying an invocation](#s2s-grant-flow)
  1068. 2. Verifies that the `Accept`'s [=object=] specifies the `Join`
  1069. 3. Publishes and delivers a [=Grant=] activity (see
  1070. [[#Grant]] for more details on the properties) where:
  1071. - [=object=] is the `Join`'s [=instrument=]
  1072. - [=context=] is the `Join`'s [=object=], which is resource *R*
  1073. - [=target=] is the `Join`'s [=actor=], which is actor *A*
  1074. - [=fulfills=] is the `Join`
  1075. 4. *A* is now considered a collaborator in *R*!
  1076. 5. If *R* is a [=Project=] or a [=Team=], additional steps occur:
  1077. 1. *A*, seeing *R*'s Grant, publishes a [[#grant-delegate|delegate-Grant]]
  1078. in which the [=target=] is *R* and [=capability=] is *R*'s Grant
  1079. 2. From now on, whenever *R* wishes to
  1080. [[#extending-a-delegation-chain|extend a Grant chain]] to *A*, it uses
  1081. *A*'s delegate-Grant as the [=capability=]
  1082. Actor *A* can now use the URI of that new `Grant` as the
  1083. [=capability=] when it sends activities that access or
  1084. manipulate resource *R*.
  1085. In step 2, actor *B* may choose to deny the request of actor *A*, by sending a
  1086. [=Reject=] activity (at least to the *resource actor* of *R*) where:
  1087. - [=object=] specifies the `Join` that actor *A* sent
  1088. - [=capability=] is the `Grant` mentioned in step 2, authorizing
  1089. actor *B* to approve or deny Joins
  1090. If the *resource actor* of *R* receives the `Reject`:
  1091. 1. It MUST verify the `Reject` is authorized, as described above in
  1092. [Verifying an invocation](#s2s-grant-flow)
  1093. 2. it MUST verify that the `Reject`'s [=object=] specifies the `Join`
  1094. 2. Consider this `Join` request canceled: If actor *B*, or some other actor
  1095. *C*, tries again to `Accept` the `Join`, then:
  1096. 1. The *resource actor* MUST NOT send a `Grant` to actor *A*, even if the
  1097. `Accept` is authorized
  1098. 2. The *resource actor* MAY publish and deliver a `Reject` activity, at
  1099. least to the actor that sent the `Accept`, where [=object=] specifies
  1100. the `Accept`
  1101. 4. It SHOULD publish and deliver a `Reject` activity, at least to actor *A*,
  1102. where [=object=] specifies the `Join` that actor *A* sent
  1103. So, once a `Join` is rejected (using an authorized `Reject`), it cannot be
  1104. accepted. But actor *A* MAY send a new `Join`, which could then possibly get
  1105. accepted.
  1106. ### Revoking access
  1107. #### Taking away access using Remove activities
  1108. When an actor *A* wishes to cancel the membership of another actor *B* (who
  1109. isn't *A*) in a shared resource *R*, invalidating any active
  1110. [[#Grant]]s that the *resource actor* of *R* has granted to actor
  1111. *B*, then actor *A* SHOULD use a [=Remove=] activity, and the following steps:
  1112. 1. Actor *A* publishes and delivers a [=Remove=], at least to actor
  1113. *B* and to the *resource actor* of *R*, with a relevant
  1114. [=capability=] (see [[#Remove]]
  1115. for details on the properties to use)
  1116. 2. The *resource actor* of *R* receives the `Remove` and:
  1117. 1. Verifies the `Remove` is authorized, as described above in
  1118. [Verifying an invocation](#s2s-grant-flow)
  1119. 2. Verifies that actor *B* indeed has active `Grant`s for accessing
  1120. resource *R*
  1121. 3. Marks those Grants as disabled in its internal state
  1122. 4. Publishes and delivers a [[#Revoke]] activity, as described
  1123. above in [Revoking a Grant](#s2s-revoke), where
  1124. [=fulfills=] specifies the `Remove`
  1125. Actor *B* SHOULD no longer use the URI of any `Grant` that has been disabled as
  1126. the [=capability=] when it sends activities that access or
  1127. manipulate resource *R*.
  1128. #### Waiving access using Leave activities
  1129. When an actor *A* wishes to cancel their membership in a shared resource *R*
  1130. (where the *resource actor* who manages *R* isn't *A*), invalidating any active
  1131. [[#Grant]]s that the *resource actor* of *R* has granted to actor
  1132. *A*, then actor *A* SHOULD use a [=Leave=] activity, and the following steps:
  1133. 1. Actor *A* publishes and delivers a [=Leave=], at least to the
  1134. *resource actor* of *R* (see [[#Leave]] for
  1135. details on the properties to use)
  1136. 2. The *resource actor* of *R* receives the `Leave` and:
  1137. 1. Verifies that actor *A* indeed has active `Grant`s for accessing
  1138. resource *R*
  1139. 2. Marks those Grants as disabled in its internal state
  1140. 3. Publishes and delivers a [[#Revoke]] activity, as described
  1141. above in [Revoking a Grant](#s2s-revoke), where
  1142. [=fulfills=] specifies the `Leave`
  1143. Actor *A* SHOULD no longer use the URI of any `Grant` that has been disabled as
  1144. the [=capability=] when it sends activities that access or
  1145. manipulate resource *R*.
  1146. #### Requesting to disable specific Grants using Undo
  1147. When an actor *A* wishes to deactivate a specific [[#Grant]] activity
  1148. (or multiple `Grant`s), providing access to view or manipulate some resource
  1149. *R* (where the *resource actor* of *R* isn't *A*), then actor *A* SHOULD use an
  1150. [=Undo=] activity, and the following steps. The actor *B* to whom
  1151. access-to-resource-*R* was given by the `Grant` may be actor *A* itself, or
  1152. some other actor, as long as actor *A* is authorized by the *resource actor* of
  1153. *R* to deactivate that `Grant`.
  1154. NOTE: Upon a successful `Undo`, if actor *B* doesn't have any active `Grants`
  1155. left, that allow access to resource *R*, then the *resource actor* of *R* MAY
  1156. remove actor *B*'s membership in *R*, or it MAY consider actor *B* a member
  1157. without access.
  1158. 1. Actor *A* publishes and delivers an [=Undo=], at least to the
  1159. *resource actor* of *R* (see [[#undo-grant]] for
  1160. details on the properties to use)
  1161. 2. The *resource actor* of *R* receives the `Undo` and:
  1162. 1. Verifies the `Undo` is authorized, as described above in
  1163. [Verifying an invocation](#s2s-grant-flow)
  1164. 2. Verifies that actor *B* indeed has all the active `Grant`s for accessing
  1165. resource *R*, that are listed as [=object=]s of the `Undo` (if more than
  1166. one `Grant` is listed, the [=target=] of all the `Grant`s MUST be
  1167. identical)
  1168. 3. Marks all of those Grants as disabled in its internal state
  1169. 4. Publishes and delivers a [[#Revoke]] activity, at least to
  1170. actors *A* and *B*, as described above in
  1171. [Revoking a Grant](#s2s-revoke), where:
  1172. - [=object=] MUST specify all the deactivated `Grant`s
  1173. - [=fulfills=] MUST specify the `Undo`
  1174. Actor *B* SHOULD no longer use the URI of any `Grant` that has been disabled as
  1175. the [=capability=] when it sends activities that access or
  1176. manipulate resource *R*.
  1177. ### Example
  1178. Aviva creates a new [=Repository=] for her 3D Tree Growth
  1179. Simulation software:
  1180. <div class=example>
  1181. <xmp highlight=json-ld>
  1182. {
  1183. "@context": [
  1184. "https://www.w3.org/ns/activitystreams",
  1185. "https://forgefed.org/ns"
  1186. ],
  1187. "id": "https://forge.community/users/aviva/outbox/oU6QGAqr-create-treesim",
  1188. "type": "Create",
  1189. "actor": "https://forge.community/users/aviva",
  1190. "to": [
  1191. "https://forge.community/users/aviva/followers"
  1192. ],
  1193. "object": {
  1194. "id": "https://forge.community/repos/treesim",
  1195. "type": "Repository",
  1196. "name": "Tree Growth 3D Simulation",
  1197. "summary": "A graphical simulation of trees growing"
  1198. }
  1199. }
  1200. </xmp>
  1201. </div>
  1202. The newly created *treesim* `Repository` automatically sends back a `Grant` to
  1203. Aviva, allowing her full access to the repo:
  1204. <div class=example>
  1205. <xmp highlight=json-ld>
  1206. {
  1207. "@context": [
  1208. "https://www.w3.org/ns/activitystreams",
  1209. "https://forgefed.org/ns"
  1210. ],
  1211. "id": "https://forge.community/repos/treesim/outbox/2NwyPWMX-grant-admin-to-aviva",
  1212. "type": "Grant",
  1213. "actor": "https://forge.community/repos/treesim",
  1214. "to": [
  1215. "https://forge.community/aviva",
  1216. "https://forge.community/aviva/followers"
  1217. ],
  1218. "object": "admin",
  1219. "context": "https://forge.community/repos/treesim",
  1220. "target": "https://forge.community/aviva",
  1221. "fulfills": "https://forge.community/users/aviva/outbox/oU6QGAqr-create-treesim",
  1222. "allows": "invoke",
  1223. "endTime": "2023-12-31T23:00:00-08:00"
  1224. }
  1225. </xmp>
  1226. </div>
  1227. Aviva can now use this `Grant`, e.g. to update the repo's description text:
  1228. <div class=example>
  1229. <xmp highlight=json-ld>
  1230. {
  1231. "@context": [
  1232. "https://www.w3.org/ns/activitystreams",
  1233. "https://forgefed.org/ns"
  1234. ],
  1235. "id": "https://forge.community/users/aviva/outbox/RmTygyuj",
  1236. "type": "Update",
  1237. "actor": "https://forge.community/users/aviva",
  1238. "to": [
  1239. "https://forge.community/users/aviva/followers",
  1240. "https://forge.community/repos/treesim",
  1241. "https://forge.community/repos/treesim/followers"
  1242. ],
  1243. "object": {
  1244. "id": "https://forge.community/repos/treesim",
  1245. "type": "Repository",
  1246. "name": "Tree Growth 3D Simulation",
  1247. "summary": "Tree growth 3D simulator for my nature exploration game"
  1248. },
  1249. "capability": "https://forge.community/repos/treesim/outbox/2NwyPWMX-grant-admin-to-aviva"
  1250. }
  1251. </xmp>
  1252. </div>
  1253. Aviva wants to keep track of events related to the *treesim* repo:
  1254. <div class=example>
  1255. <xmp highlight=json-ld>
  1256. {
  1257. "@context": "https://www.w3.org/ns/activitystreams",
  1258. "id": "https://forge.community/users/aviva/outbox/gqtpAhm2",
  1259. "type": "Follow",
  1260. "actor": "https://forge.community/users/aviva",
  1261. "to": "https://forge.community/repos/treesim",
  1262. "object": "https://forge.community/repos/treesim",
  1263. }
  1264. </xmp>
  1265. </div>
  1266. Aviva can invite Luke to have access to the *treesim* repo:
  1267. <div class=example>
  1268. <xmp highlight=json-ld>
  1269. {
  1270. "@context": [
  1271. "https://www.w3.org/ns/activitystreams",
  1272. "https://forgefed.org/ns"
  1273. ],
  1274. "id": "https://forge.community/users/aviva/outbox/qfrEGqnC-invite-luke",
  1275. "type": "Invite",
  1276. "actor": "https://forge.community/users/aviva",
  1277. "to": [
  1278. "https://forge.community/aviva/followers",
  1279. "https://forge.community/repos/treesim",
  1280. "https://forge.community/repos/treesim/followers",
  1281. "https://software.site/people/luke",
  1282. "https://software.site/people/luke/followers"
  1283. ],
  1284. "instrument": "maintain",
  1285. "target": "https://forge.community/repos/treesim",
  1286. "object": "https://software.site/people/luke",
  1287. "capability": "https://forge.community/repos/treesim/outbox/2NwyPWMX-grant-admin-to-aviva"
  1288. }
  1289. </xmp>
  1290. </div>
  1291. And it appears that Luke accepts the invitation:
  1292. <div class=example>
  1293. <xmp highlight=json-ld>
  1294. {
  1295. "@context": [
  1296. "https://www.w3.org/ns/activitystreams",
  1297. "https://forgefed.org/ns"
  1298. ],
  1299. "id": "https://software.site/people/luke/activities/mEYYmt8u",
  1300. "type": "Accept",
  1301. "actor": "https://software.site/people/luke",
  1302. "to": [
  1303. "https://forge.community/aviva",
  1304. "https://forge.community/aviva/followers",
  1305. "https://forge.community/repos/treesim",
  1306. "https://forge.community/repos/treesim/followers",
  1307. "https://software.site/people/luke/followers"
  1308. ],
  1309. "object": "https://forge.community/users/aviva/outbox/qfrEGqnC-invite-luke"
  1310. }
  1311. </xmp>
  1312. </div>
  1313. Seeing the `Invite` and the `Accept`, the *treesim* repo sends Luke a `Grant`
  1314. giving him the access that Aviva offered, and which he accepted:
  1315. <div class=example>
  1316. <xmp highlight=json-ld>
  1317. {
  1318. "@context": [
  1319. "https://www.w3.org/ns/activitystreams",
  1320. "https://forgefed.org/ns"
  1321. ],
  1322. "id": "https://forge.community/repos/treesim/outbox/D5uod3pz-grant-maintainer-to-luke",
  1323. "type": "Grant",
  1324. "actor": "https://forge.community/repos/treesim",
  1325. "to": [
  1326. "https://forge.community/aviva",
  1327. "https://forge.community/aviva/followers",
  1328. "https://forge.community/repos/treesim/followers",
  1329. "https://software.site/people/luke",
  1330. "https://software.site/people/luke/followers"
  1331. ],
  1332. "object": "maintain",
  1333. "context": "https://forge.community/repos/treesim",
  1334. "target": "https://software.site/people/luke",
  1335. "fulfills": "https://forge.community/users/aviva/outbox/qfrEGqnC-invite-luke",
  1336. "allows": "invoke",
  1337. "endTime": "2023-12-31T23:00:00-08:00"
  1338. }
  1339. </xmp>
  1340. </div>
  1341. Luke can now use this `Grant`, e.g. to delete some old obsolete branch of the
  1342. *treesim* repo:
  1343. <div class=example>
  1344. <xmp highlight=json-ld>
  1345. {
  1346. "@context": [
  1347. "https://www.w3.org/ns/activitystreams",
  1348. "https://forgefed.org/ns"
  1349. ],
  1350. "id": "https://software.site/people/luke/activities/vShj2aIe",
  1351. "type": "Delete",
  1352. "actor": "https://software.site/people/luke",
  1353. "to": [
  1354. "https://forge.community/repos/treesim",
  1355. "https://forge.community/repos/treesim/followers",
  1356. "https://software.site/people/luke/followers"
  1357. ],
  1358. "object": "https://forge.community/repos/treesim/branches/fixes-for-release-0.1.3",
  1359. "origin": "https://forge.community/repos/treesim",
  1360. "capability": "https://forge.community/repos/treesim/outbox/D5uod3pz-grant-maintainer-to-luke"
  1361. }
  1362. </xmp>
  1363. </div>
  1364. Celine requests to have developer access to the *treesim* repo:
  1365. <div class=example>
  1366. <xmp highlight=json-ld>
  1367. {
  1368. "@context": [
  1369. "https://www.w3.org/ns/activitystreams",
  1370. "https://forgefed.org/ns"
  1371. ],
  1372. "id": "https://dev.online/@celine/sent/v5Qvd6bB-celine-join",
  1373. "type": "Join",
  1374. "actor": "https://dev.online/@celine",
  1375. "to": [
  1376. "https://forge.community/repos/treesim",
  1377. "https://forge.community/repos/treesim/followers",
  1378. "https://dev.online/@celine/followers"
  1379. ],
  1380. "object": "https://forge.community/repos/treesim",
  1381. "instrument": "write"
  1382. }
  1383. </xmp>
  1384. </div>
  1385. Aviva sees the `Join` request, talks with Celine and decides to approve her
  1386. request:
  1387. <div class=example>
  1388. <xmp highlight=json-ld>
  1389. {
  1390. "@context": [
  1391. "https://www.w3.org/ns/activitystreams",
  1392. "https://forgefed.org/ns"
  1393. ],
  1394. "id": "https://forge.community/users/aviva/outbox/PzRtDydu",
  1395. "type": "Accept",
  1396. "actor": "https://forge.community/users/aviva",
  1397. "to": [
  1398. "https://forge.community/repos/treesim",
  1399. "https://forge.community/repos/treesim/followers",
  1400. "https://dev.online/@celine",
  1401. "https://dev.online/@celine/followers"
  1402. ],
  1403. "object": "https://dev.online/@celine/sent/v5Qvd6bB-celine-join",
  1404. "capability": "https://forge.community/repos/treesim/outbox/2NwyPWMX-grant-admin-to-aviva"
  1405. }
  1406. </xmp>
  1407. </div>
  1408. Seeing the `Join` and the `Accept`, the *treesim* repo sends Celine a `Grant`
  1409. giving her the access that she requested, and which Aviva approved:
  1410. <div class=example>
  1411. <xmp highlight=json-ld>
  1412. {
  1413. "@context": [
  1414. "https://www.w3.org/ns/activitystreams",
  1415. "https://forgefed.org/ns"
  1416. ],
  1417. "id": "https://forge.community/repos/treesim/outbox/D5uod3pz-grant-developer-to-celine",
  1418. "type": "Grant",
  1419. "actor": "https://forge.community/repos/treesim",
  1420. "to": [
  1421. "https://forge.community/aviva",
  1422. "https://forge.community/repos/treesim/followers",
  1423. "https://dev.online/@celine",
  1424. "https://dev.online/@celine/followers"
  1425. ],
  1426. "object": "write",
  1427. "context": "https://forge.community/repos/treesim",
  1428. "target": "https://dev.online/@celine",
  1429. "fulfills": "https://dev.online/@celine/sent/v5Qvd6bB-celine-join",
  1430. "allows": "invoke",
  1431. "endTime": "2023-12-31T23:00:00-08:00"
  1432. }
  1433. </xmp>
  1434. </div>
  1435. Celine can now use this `Grant` to access the *treesim* repo.
  1436. ## Associating Projects and Components
  1437. Minimal required role: [=admin=]
  1438. Adding and removing a component to/from a project each have 2 versions: The
  1439. "component side" version allows an actor to initiate the action using admin
  1440. access to the component, while the "project side" version allows to initiate
  1441. the action using admin access to the project.
  1442. Whenever authorization is mentioned below, it SHOULD be done using the
  1443. [[#s2s-grant-flow|invocation verification process]].
  1444. ### Adding a component to a project - component side
  1445. Assuming:
  1446. - A project *P*
  1447. - A component *C*
  1448. - A person with admin access to *C*, Alice
  1449. - A person with admin access to *P*, Bob
  1450. Alice wants to add component *C* to project *P*. The exchange of activities
  1451. SHOULD be as follows:
  1452. 1. Alice sends an [=Add=] activity in which:
  1453. - [=object=] is *C*
  1454. - [=target=] is the URI of *P*'s [=components=] collection
  1455. - [=instrument=] is the maximal [=Role=] that Alice would like to allow for
  1456. people (and bots) when authorizing their manipulation of *C* by their
  1457. access in *P* (normally it would be [=admin=], perhaps sometimes
  1458. [=maintain=])
  1459. - [=capability=] is the URI of a [=Grant=] that authorizes admin access to
  1460. *C*
  1461. 2. *C*, seeing and authorizing the Add, publishes an [=Accept=] where
  1462. [=object=] is the Add's URI
  1463. 3. Bob, seeing the Add and the Accept, sends an [=Accept=] where:
  1464. - [=object=] is the Add's URI
  1465. - [=capability=] is the URI of a [=Grant=] that authorizes admin access to
  1466. *P*
  1467. 4. *P*, seeing the previous 3 activities and authorizing Bob's Accept,
  1468. publishes a [[#grant-delegate|delegate-Grant]] in which the [=target=] is
  1469. *C*
  1470. 5. *C*, seeing *P*'s Grant, sends a [[#start-grant-chain|start-Grant]] where:
  1471. - [=actor=] and [=context=] specify *C*
  1472. - [=target=] specifies *P*
  1473. - [=object=] specifies the role specified in the Add's [=instrument=]
  1474. - [=allows=] is [=gatherAndConvey=]
  1475. - [=capability=] is the URI of the delegate-Grant
  1476. 6. *P*, seeing and authorizing *C*'s Grant, now
  1477. [[#extending-a-delegation-chain|extends the Grant chain]] as relevant, to
  1478. its members and parent projects
  1479. ### Removing a component from a project - component side
  1480. Assuming:
  1481. - A project *P* with a component *C*
  1482. - A person with admin access to *C*, Alice
  1483. Alice wants to ask component *C* to remove itself from project *P*. The
  1484. exchange of activities SHOULD be as follows:
  1485. 1. Alice sends a [=Remove=] activity where:
  1486. - [=object=] is *C*
  1487. - [=origin=] is the URI of *P*'s [=components=] collection
  1488. - [=tag=] is *C*
  1489. - [=capability=] is the URI of a [=Grant=] that authorizes admin access to
  1490. *C*
  1491. 2. *C*, seeing and authorizing the Remove, publishes a [=Revoke=] where
  1492. [=object=] specifies the active [[#start-grant-chain|start-Grant]] it had
  1493. sent to *P* (and *C* now considers that Grant revoked and no longer
  1494. considers itself as a component of *P*)
  1495. 3. *P*, seeing the Remove and the Revoke, publishes a [=Revoke=] where
  1496. [=object=] specifies the active [[#grant-delegate|delegate-Grant]] it had
  1497. sent to *C* (and *P* now considers that Grant revoked and no longer
  1498. considers *C* a component of it)
  1499. ### Adding a component to a project - project side
  1500. Assuming:
  1501. - A project *P*
  1502. - A component *C*
  1503. - A person with admin access to *C*, Alice
  1504. - A person with admin access to *P*, Bob
  1505. Bob wants to add component *C* to project *P*. The exchange of activities
  1506. SHOULD be as follows:
  1507. 1. Bob sends an [=Invite=] activity in which:
  1508. - [=object=] is *C*
  1509. - [=target=] is the URI of *P*'s [=components=] collection
  1510. - [=instrument=] is the maximal [=Role=] that Bob would like to allow for
  1511. people (and bots) when authorizing their manipulation of *C* by their
  1512. access in *P* (normally it would be [=admin=], perhaps sometimes
  1513. [=maintain=])
  1514. - [=capability=] is the URI of a [=Grant=] that authorizes admin access to
  1515. *P*
  1516. 2. *P*, seeing and authorizing the Invite, publishes an [=Accept=] where
  1517. [=object=] is the Invite's URI
  1518. 3. Alice, seeing the Invite and the Accept, sends an [=Accept=] where:
  1519. - [=object=] is the Invite's URI
  1520. - [=capability=] is the URI of a [=Grant=] that authorizes admin access to
  1521. *C*
  1522. 4. *C*, seeing the previous 3 activities and authorizing Alice's Accept, sends
  1523. an [=Accept=] where [=object=] is the Invite's URI
  1524. 5. *P*, seeing *C*'s Accept, publishes a [[#grant-delegate|delegate-Grant]] in
  1525. which the [=target=] is *C*
  1526. 6. *C*, seeing *P*'s Grant, sends a [[#start-grant-chain|start-Grant]] where:
  1527. - [=actor=] and [=context=] specify *C*
  1528. - [=target=] specifies *P*
  1529. - [=object=] specifies the role specified in the Invite's [=instrument=]
  1530. - [=allows=] is [=gatherAndConvey=]
  1531. - [=capability=] is the URI of the delegate-Grant
  1532. 7. *P*, seeing and authorizing *C*'s Grant, now
  1533. [[#extending-a-delegation-chain|extends the Grant chain]] as relevant, to
  1534. its members and parent projects
  1535. ### Removing a component from a project - project side
  1536. Assuming:
  1537. - A project *P* with a component *C*
  1538. - A person with admin access to *P*, Bob
  1539. Bob wants to ask project *P* to remove component *C* from it. The exchange of
  1540. activities SHOULD be as follows:
  1541. 1. Bob sends a [=Remove=] activity where:
  1542. - [=object=] is *C*
  1543. - [=origin=] is the URI of *P*'s [=components=] collection
  1544. - [=tag=] is *P*
  1545. - [=capability=] is the URI of a [=Grant=] that authorizes admin access to
  1546. *P*
  1547. 3. *P*, seeing and authorizing the Remove, publishes a [=Revoke=] where
  1548. [=object=] specifies the active [[#grant-delegate|delegate-Grant]] it had
  1549. sent to *C* (and *P* now considers that Grant revoked and no longer
  1550. considers *C* a component of it)
  1551. 2. *C*, seeing the Remove and the Revoke, publishes a [=Revoke=] where
  1552. [=object=] specifies the active [[#start-grant-chain|start-Grant]] it had
  1553. sent to *P* (and *C* now considers that Grant revoked and no longer
  1554. considers itself as a component of *P*)
  1555. # Actor Interface
  1556. Issue: This section will provide, for each actor type, a summary of the various
  1557. (1) "methods" i.e. activities it can receive as requests for action; (2)
  1558. "events", i.e. activities it sends out; (3) perhaps representation of resources
  1559. that are specific to the actor type. Right now there's a grey zone between
  1560. methods and events, because some activities are methods for the target actor
  1561. but events for any other recipient, and some events are actually sent by other
  1562. actors, which cc the target actor's followers and the target actor delivers via
  1563. inbox-forwarding and not by `Announce`ing (or custom `Forward`ing) those
  1564. activities.
  1565. ## Person ## {#person-iface}
  1566. ## Team ## {#team-iface}
  1567. ## Project ## {#project-iface}
  1568. ## Repository ## {#repo-iface}
  1569. ## TicketTracker ## {#tt-iface}
  1570. ## PatchTracker ## {#pt-iface}
  1571. # Client to Server Interactions
  1572. Issue: This section is about how a human or bot can interact with the system by
  1573. POSTing activities into the outbox of a Person (or Application/Service?) actor,
  1574. and managing notifications. It's less urgent than Server-to-Server. fr33 is
  1575. using C2S in Vervis, and will be gradually working on this part.
  1576. ForgeFed uses Activities for client to server interactions, as described by
  1577. ActivityPub. A client will send objects (eg. a Ticket) wrapped in a Activity
  1578. (eg. Create) to an actor's outbox, and in turn the server will take care of
  1579. delivery.
  1580. ## Follow Activity
  1581. The Follow activity is used to subscribe to the activities of a Repository.
  1582. The client MUST send a Follow activity to the Person's outbox. The server
  1583. in turn delivers the message to the destination inbox.
  1584. ## Push Activity
  1585. The Push activity is used to notify followers when somebody has pushed changes
  1586. to a Repository.
  1587. The client MUST send a Push activity to the Repository's outbox. The server
  1588. in turn delivers the message to the Repository followers.
  1589. # Actor and Resource Representation
  1590. Issue: This section is about representation of objects. It's possible that
  1591. actor representation will move into a separate section, as well as objects
  1592. specific to one actor type. And then this section will describe only
  1593. objects/resources used by multiple actor types, such as comments (person, issue
  1594. tracker, PR tracker) and tickets (used for both issues and PRs).
  1595. ## Comment ## {#Comment}
  1596. To represent a comment, e.g. a comment on a ticket or a merge request, use the
  1597. ActivityPub [=Note=] type.
  1598. Properties:
  1599. <pre class=simpledef>
  1600. [=type=]:
  1601. [=Note=]
  1602. [=attributedTo=]:
  1603. The author of the comment
  1604. [=context=]:
  1605. The topic of the discussion, e.g. a ticket or a merge request. It MUST be
  1606. provided.
  1607. [=inReplyTo=]:
  1608. The entity on which this comment replies. MUST be provided. If the comment
  1609. is made directly on the discussion topic, then [=inReplyTo=] MUST be
  1610. identical to [=context=]. Otherwise, set [=inReplyTo=] to the comment to
  1611. which this comment replies. In that case both comments MUST have an
  1612. identical [=context=].
  1613. [=content=], [=mediaType=], [=source=]:
  1614. The comment text, in rendered form and in source form
  1615. </pre>
  1616. <div class=example>
  1617. <xmp highlight=json-ld>
  1618. {
  1619. "@context": "https://www.w3.org/ns/activitystreams",
  1620. "id": "https://forge.example/luke/comments/rD05r",
  1621. "type": "Note",
  1622. "attributedTo": "https://forge.example/luke",
  1623. "context": "https://dev.example/aviva/game-of-life/merge-requests/19",
  1624. "inReplyTo": "https://dev.example/aviva/comments/E9AGE",
  1625. "mediaType": "text/html",
  1626. "content": "<p>Thank you for the review! I'll submit a correction ASAP</p>",
  1627. "source": {
  1628. "mediaType": "text/markdown; variant=Commonmark",
  1629. "content": "Thank you for the review! I'll submit a correction ASAP"
  1630. },
  1631. "published": "2019-11-06T20:49:05.604488Z"
  1632. }
  1633. </xmp>
  1634. </div>
  1635. ## Team Membership
  1636. Properties:
  1637. <pre class=simpledef>
  1638. [=type=]:
  1639. [=Relationship=]
  1640. [=subject=]:
  1641. A [=Team=]
  1642. [=relationship=]:
  1643. [=hasMember=]
  1644. [=object=]:
  1645. A [=Person=] who is a member of the `Team`
  1646. [=tag=]:
  1647. The role that the member has in the team
  1648. </pre>
  1649. <div class=example>
  1650. <xmp highlight=json-ld>
  1651. {
  1652. "@context": [
  1653. "https://www.w3.org/ns/activitystreams",
  1654. "https://forgefed.org/ns"
  1655. ],
  1656. "id": "https://dev.example/teams/mobilizon-dev-team/members/ThmsicTj",
  1657. "type": "Relationship",
  1658. "subject": "https://dev.example/teams/mobilizon-dev-team",
  1659. "relationship": "hasMember",
  1660. "object": "https://dev.example/people/celine",
  1661. "tag": "develop"
  1662. }
  1663. </xmp>
  1664. </div>
  1665. ## Team
  1666. Properties:
  1667. <pre class=simpledef>
  1668. [=type=]:
  1669. [=Team=]
  1670. [=name=]:
  1671. The user-given name of the team, e.g. "Gitea Development Team"
  1672. [=published=]:
  1673. The time the team was created on the server
  1674. [=summary=]:
  1675. A one-line user provided description of the project, as HTML, e.g.
  1676. `"We are creating a code hosting platform"`
  1677. [=members=]:
  1678. [=Collection=] of the members of this team
  1679. [=subteams=]:
  1680. Subteams of this team, i.e. teams whose members (and subteams) inherit the
  1681. access that this team has been granted (to projects, repositories, etc.)
  1682. [=context=]:
  1683. Parent [=Team=]s of this team, i.e. teams from which this team inherits
  1684. access to projects, components and resources, e.g. repositories, ticket
  1685. trackers (and passes them to its [=members=] and inherits them to its own
  1686. [=subteams=])
  1687. </pre>
  1688. <div class=example>
  1689. <xmp highlight=json-ld>
  1690. {
  1691. "@context": [
  1692. "https://www.w3.org/ns/activitystreams",
  1693. "https://w3id.org/security/v2",
  1694. "https://forgefed.org/ns"
  1695. ],
  1696. "id": "https://dev.example/teams/mobilizon-dev-team",
  1697. "type": "Team",
  1698. "name": "Mobilizon Development Team",
  1699. "summary": "We're creating a federated tool for organizing events!",
  1700. "members": {
  1701. "type": "Collection",
  1702. "totalItems": 3,
  1703. "items": [
  1704. { "type": "Relationship",
  1705. "subject": "https://dev.example/teams/mobilizon-dev-team",
  1706. "relationship": "hasMember",
  1707. "object": "https://dev.example/people/alice",
  1708. "tag": "admin"
  1709. },
  1710. { "type": "Relationship",
  1711. "subject": "https://dev.example/teams/mobilizon-dev-team",
  1712. "relationship": "hasMember",
  1713. "object": "https://dev.example/people/bob",
  1714. "tag": "maintain"
  1715. },
  1716. { "type": "Relationship",
  1717. "subject": "https://dev.example/teams/mobilizon-dev-team",
  1718. "relationship": "hasMember",
  1719. "object": "https://dev.example/people/celine",
  1720. "tag": "develop"
  1721. }
  1722. ]
  1723. },
  1724. "subteams": {
  1725. "type": "Collection",
  1726. "totalItems": 2,
  1727. "items": [
  1728. "https://dev.example/teams/mobilizon-backend-team",
  1729. "https://dev.example/teams/mobilizon-frontend-team"
  1730. ]
  1731. },
  1732. "context": "https://dev.example/teams/framasoft-developers",
  1733. "publicKey": {
  1734. "id": "https://dev.example/teams/mobilizon-dev-team#main-key",
  1735. "owner": "https://dev.example/teams/mobilizon-dev-team",
  1736. "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....."
  1737. },
  1738. "inbox": "https://dev.example/teams/mobilizon-dev-team/inbox",
  1739. "outbox": "https://dev.example/teams/mobilizon-dev-team/outbox",
  1740. "followers": "https://dev.example/teams/mobilizon-dev-team/followers"
  1741. }
  1742. </xmp>
  1743. </div>
  1744. ## Project ## {#Project}
  1745. Properties:
  1746. <pre class=simpledef>
  1747. [=type=]:
  1748. [=Project=]
  1749. [=name=]:
  1750. The user-given name of the project, e.g. "My cool project"
  1751. [=published=]:
  1752. The time the project was created on the server
  1753. [=summary=]:
  1754. A one-line user provided description of the project, as HTML, e.g.
  1755. "`<p>A command-line tool that does cool things</p>`"
  1756. [=ticketsTrackedBy=]:
  1757. The default ticket tracker to use when submitting a ticket to this project
  1758. (this tracker MUST be listed under the project's [=components=])
  1759. [=subprojects=]:
  1760. A [=Collection=] of the subprojects of this project
  1761. [=context=]:
  1762. The parent [=Project=](s) to which this project belongs
  1763. </pre>
  1764. <div class=example>
  1765. <xmp highlight=json-ld>
  1766. {
  1767. "@context": [
  1768. "https://www.w3.org/ns/activitystreams",
  1769. "https://forgefed.org/ns"
  1770. ],
  1771. "id": "https://dev.example/projects/wanderer",
  1772. "type": "Project",
  1773. "name": "Wanderer",
  1774. "summary": "3D nature exploration game",
  1775. "components": {
  1776. "type": "Collection",
  1777. "totalItems": 7,
  1778. "items": [
  1779. "https://dev.example/repos/opengl-vegetation",
  1780. "https://dev.example/repos/opengl-vegetation/patch-tracker",
  1781. "https://dev.example/repos/treesim",
  1782. "https://dev.example/repos/treesim/patch-tracker",
  1783. "https://dev.example/repos/wanderer",
  1784. "https://dev.example/repos/wanderer/patch-tracker",
  1785. "https://dev.example/issue-trackers/wanderer"
  1786. ]
  1787. },
  1788. "subprojects": {
  1789. "type": "Collection",
  1790. "totalItems": 2,
  1791. "items": [
  1792. "https://dev.example/projects/nature-3d-models",
  1793. "https://dev.example/projects/wanderer-fundraising"
  1794. ]
  1795. },
  1796. "ticketsTrackedBy": "https://dev.example/issue-trackers/wanderer",
  1797. "inbox": "https://dev.example/projects/wanderer/inbox",
  1798. "outbox": "https://dev.example/projects/wanderer/outbox",
  1799. "followers": "https://dev.example/projects/wanderer/followers"
  1800. }
  1801. </xmp>
  1802. </div>
  1803. ## Commit
  1804. To represent a named set of changes committed into a repository's history, use
  1805. the ForgeFed [=Commit=] type. Such a committed change set is called
  1806. e.g. a *commit* in Git, and a *patch* in Darcs.
  1807. Properties:
  1808. <pre class=simpledef>
  1809. [=type=]:
  1810. [=Commit=]
  1811. [=context=]:
  1812. The [=Repository=] that this commit belongs to
  1813. [=attributedTo=]:
  1814. The commit author; if their actor URI is unknown, it MAY be their email
  1815. address as a `mailto` URI
  1816. [=created=]:
  1817. A value of type [=dateTime=] (i.e. an ISO 8601 datetime value) specifying
  1818. the time at which the commit was written by its author
  1819. [=committedBy=]:
  1820. The entity that committed the commit's changes into their local copy of the
  1821. repo, before the commit was pushed; if their actor URI is unknown, it MAY
  1822. be their email address as a `mailto` URI
  1823. [=committed=]:
  1824. The time the commit was committed by its committer
  1825. [=hash=]:
  1826. The hash identifying the commit, e.g. the commit SHA1 hash in Git; the
  1827. patch info SHA1 hash in Darcs
  1828. [=summary=]:
  1829. The commit's one-line title as HTML-escaped plain text; if the commit title
  1830. and description are a single commit message string, then the title is the
  1831. 1st line of the commit message
  1832. [=description=]:
  1833. A JSON object with a [=mediaType=] field and a [=content=] field, where
  1834. `mediaType` SHOULD be "text/plain" and `content` is the commit's
  1835. possibly-multi-line description; if the commit title and description are a
  1836. single commit message string, then the description is everything after the
  1837. 1st line of the commit message (possibly with leading whitespace stripped)
  1838. </pre>
  1839. <div class=example>
  1840. <xmp highlight=json-ld>
  1841. {
  1842. "@context": [
  1843. "https://www.w3.org/ns/activitystreams",
  1844. "https://forgefed.org/ns"
  1845. ],
  1846. "id": "https://example.dev/alice/myrepo/commits/109ec9a09c7df7fec775d2ba0b9d466e5643ec8c",
  1847. "type": "Commit",
  1848. "context": "https://example.dev/alice/myrepo",
  1849. "attributedTo": "https://example.dev/bob",
  1850. "created": "2019-07-11T12:34:56Z",
  1851. "committedBy": "https://example.dev/alice",
  1852. "committed": "2019-07-26T23:45:01Z",
  1853. "hash": "109ec9a09c7df7fec775d2ba0b9d466e5643ec8c",
  1854. "summary": "Add an installation script, fixes issue #89",
  1855. "description": {
  1856. "mediaType": "text/plain",
  1857. "content": "It's about time people can install it on their computers!"
  1858. }
  1859. }
  1860. </xmp>
  1861. </div>
  1862. ## Branch
  1863. To represent a repository branch, use the ForgeFed [=Branch=] type.
  1864. It can be a real built-in version control system branch (such as a Git branch)
  1865. or a copy of the repo used as a branch (e.g. in Darcs, which doesn't implement
  1866. branches, and the way to have branches is to keep multiple versions of the
  1867. repo).
  1868. Properties:
  1869. <pre class=simpledef>
  1870. [=type=]:
  1871. [=Branch=]
  1872. [=context=]:
  1873. The [=Repository=] that this branch belongs to
  1874. [=name=]:
  1875. The user given name of the branch, e.g. "main"
  1876. [=ref=]:
  1877. The unique identifier of the branch within the repo, e.g. "refs/heads/main"
  1878. [=team=]:
  1879. If the branch has its own access/authority/visibility settings, this can be
  1880. a [=Collection=] of the actors who have push/edit access to the branch
  1881. </pre>
  1882. <div class=example>
  1883. <xmp highlight=json-ld>
  1884. {
  1885. "@context": [
  1886. "https://www.w3.org/ns/activitystreams",
  1887. "https://forgefed.org/ns"
  1888. ],
  1889. "id": "https://example.dev/luke/myrepo/branches/master",
  1890. "type": "Branch",
  1891. "context": "https://example.dev/luke/myrepo",
  1892. "name": "master",
  1893. "ref": "refs/heads/master"
  1894. }
  1895. </xmp>
  1896. </div>
  1897. ## Repository ## {#Repository}
  1898. To represent a version control repository, use the ForgeFed
  1899. [=Repository=] type.
  1900. Properties:
  1901. <pre class=simpledef>
  1902. [=type=]:
  1903. [=Repository=]
  1904. [=name=]:
  1905. The user given name of the repository, e.g. "My cool repo"
  1906. [=cloneUri=]:
  1907. The endpoint from which the content of the repository can be obtained via
  1908. the native protocol (Git, Hg, etc.)
  1909. [=attributedTo=]:
  1910. The actor(s) in charge of the repository, e.g. a person or an organization;
  1911. if their actor URI is unknown, it MAY be their email address as a `mailto`
  1912. URI
  1913. [=published=]:
  1914. The time the repository was created on the server
  1915. [=summary=]:
  1916. A one-line user provided description of the repository, as HTML, e.g.
  1917. "`<p>A command-line tool that does cool things</p>`"
  1918. [=team=]:
  1919. [=Collection=] of actors who have management/push access to the repository,
  1920. or the subset of them who is available and wants to be
  1921. contacted/notified/responsible on repo access related activities/requests
  1922. [=forks=]:
  1923. [=OrderedCollection=] of repositories that are forks of this repository
  1924. [=ticketsTrackedBy=]:
  1925. The ticket tracker that tracks tickets for this repository, this can be the
  1926. repository itself if it manages its own tickets
  1927. [=sendPatchesTo=]:
  1928. The actor that tracks patches for this repository, this can be the
  1929. repository itself if it manages its own patches and merge requests. For
  1930. example it may be some external tracker or service, or the user or team to
  1931. whom the repository belongs.
  1932. [=context=]:
  1933. The [=Project=](s) to which this repository belongs
  1934. </pre>
  1935. <div class=example>
  1936. <xmp highlight=json-ld>
  1937. {
  1938. "@context": [
  1939. "https://www.w3.org/ns/activitystreams",
  1940. "https://w3id.org/security/v1",
  1941. "https://forgefed.org/ns"
  1942. ],
  1943. "id": "https://dev.example/aviva/treesim",
  1944. "cloneUri": "https://dev.example/aviva/treesim.git",
  1945. "type": "Repository",
  1946. "publicKey": {
  1947. "id": "https://dev.example/aviva/treesim#main-key",
  1948. "owner": "https://dev.example/aviva/treesim",
  1949. "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....."
  1950. },
  1951. "inbox": "https://dev.example/aviva/treesim/inbox",
  1952. "outbox": "https://dev.example/aviva/treesim/outbox",
  1953. "followers": "https://dev.example/aviva/treesim/followers",
  1954. "team": "https://dev.example/aviva/treesim/team",
  1955. "ticketsTrackedBy": "https://dev.example/aviva/treesim",
  1956. "sendPatchesTo": "https://dev.example/aviva/treesim",
  1957. "name": "Tree Growth 3D Simulation",
  1958. "attributedTo": "https://example.dev/bob",
  1959. "summary": "<p>Tree growth 3D simulator for my nature exploration game</p>"
  1960. }
  1961. </xmp>
  1962. </div>
  1963. ## Push ## {#Push}
  1964. To represent an event of [=Commit=]s being pushed to a
  1965. [=Repository=], use a ForgeFed [=Push=] activity.
  1966. Properties:
  1967. <pre class=simpledef>
  1968. [=type=]:
  1969. [=Push=]
  1970. [=actor=]:
  1971. The [=Repository=] to which the push was made, and that is publishing this
  1972. Push activity
  1973. [=attributedTo=]:
  1974. The entity (person, bot, etc.) that pushed the commits
  1975. [=target=]:
  1976. The specific repo history tip onto which the commits were added, this is
  1977. either a [=Branch=] (for VCSs that have branches) or a [=Repository=] (for
  1978. VCSs that don't have branches, only a single history line). If it's a
  1979. branch, it MUST be a branch belonging to the repository specified by
  1980. [=actor=]. And if it's a repository, it MUST be identical to the one
  1981. specified by [=actor=].
  1982. [=hashBefore=]:
  1983. Repo/branch/tip hash before adding the new commits
  1984. [=hashAfter=]:
  1985. Repo/branch/tip hash after adding the new commits
  1986. [=object=]:
  1987. An [=OrderedCollection=] of the [=Commit=]s being pushed, in **reverse
  1988. chronological order**. The [=items=] (or [=orderedItems=]) property of the
  1989. collection MUST contain either the whole list of commits being pushed, or a
  1990. prefix i.e. continuous subset from the beginning of the list (therefore the
  1991. **latest** commits). [=earlyItems=] MAY be used for listing a suffix i.e.
  1992. continuous subset from the end (therefore the **earliest** commits).
  1993. </pre>
  1994. <div class=example>
  1995. <xmp highlight=json-ld>
  1996. {
  1997. "@context": [
  1998. "https://www.w3.org/ns/activitystreams",
  1999. "https://forgefed.org/ns"
  2000. ],
  2001. "id": "https://dev.example/aviva/outbox/E26bE",
  2002. "type": "Push",
  2003. "actor": "https://dev.example/aviva",
  2004. "to": [
  2005. "https://dev.example/aviva/followers",
  2006. "https://dev.example/aviva/game-of-life",
  2007. "https://dev.example/aviva/game-of-life/team",
  2008. "https://dev.example/aviva/game-of-life/followers"
  2009. ],
  2010. "context": "https://dev.example/aviva/game-of-life",
  2011. "target": "https://dev.example/aviva/game-of-life/branches/master",
  2012. "hashBefore": "017cbb00bc20d1cae85f46d638684898d095f0ae",
  2013. "hashAfter": "be9f48a341c4bb5cd79ae7ab85fbf0c05d2837bb",
  2014. "object": {
  2015. "totalItems": 2,
  2016. "type": "OrderedCollection",
  2017. "orderedItems": [
  2018. {
  2019. "id": "https://dev.example/aviva/game-of-life/commits/be9f48a341c4bb5cd79ae7ab85fbf0c05d2837bb",
  2020. "type": "Commit",
  2021. "attributedTo": "https://dev.example/aviva",
  2022. "context": "https://dev.example/aviva/game-of-life",
  2023. "hash": "be9f48a341c4bb5cd79ae7ab85fbf0c05d2837bb",
  2024. "created": "2019-12-02T16:07:32Z",
  2025. "summary": "Add widget to alter simulation speed"
  2026. },
  2027. {
  2028. "id": "https://dev.example/aviva/game-of-life/commits/fa37fe100a8b1e69933889c5bf3caf95cd3ae1e6",
  2029. "type": "Commit",
  2030. "attributedTo": "https://dev.example/aviva",
  2031. "context": "https://dev.example/aviva/game-of-life",
  2032. "hash": "fa37fe100a8b1e69933889c5bf3caf95cd3ae1e6",
  2033. "created": "2019-12-02T15:51:52Z",
  2034. "summary": "Set window title correctly, fixes issue #7"
  2035. }
  2036. ]
  2037. }
  2038. }
  2039. </xmp>
  2040. </div>
  2041. ## Ticket ## {#Ticket}
  2042. To represent a work item in a project, use the ForgeFed [=Ticket=]
  2043. type.
  2044. TODO decide on ticket categories/subtypes and update below
  2045. TODO decide on property for titles, update below
  2046. TODO properly document `history` or remove it from example
  2047. Properties:
  2048. <pre class=simpledef>
  2049. [=type=]:
  2050. [=Ticket=]
  2051. [=context=]:
  2052. The [=TicketTracker=] or [=PatchTracker=] to which this ticket belongs
  2053. [=attributedTo=]:
  2054. The actor (person, bot, etc.) who submitted the ticket
  2055. [=summary=]:
  2056. The ticket's one-line title, as HTML-escaped plain text
  2057. [=content=], [=mediaType=]:
  2058. The ticket's (possibly multi-line) detailed description text, in rendered
  2059. form
  2060. [=source=]:
  2061. Source form of the ticket's description
  2062. [=published=]:
  2063. The time the ticket submission was accepted (which may not be the same as
  2064. the time the ticket was submitted)
  2065. [=followers=]:
  2066. Collection of the followers of the ticket, actors who want to be notified
  2067. on activity related to the ticket
  2068. [=team=]:
  2069. Collection of project team members who have responsibility for work on this
  2070. ticket and want to be notified on activities related to it
  2071. [=replies=]:
  2072. Collection of direct comments made on the ticket (but not comments made *on
  2073. other* comments on the ticket)
  2074. [=dependants=]:
  2075. Collection of [=Ticket=]s which depend on this ticket
  2076. [=dependencies=]:
  2077. Collection of [=Ticket=]s on which this ticket depends
  2078. [=isResolved=]:
  2079. Whether the work on this ticket is done
  2080. [=resolvedBy=]:
  2081. If the work on this ticket is done, who marked the ticket as resolved, or
  2082. which activity did so
  2083. [=resolved=]:
  2084. When the ticket has been marked as resolved
  2085. </pre>
  2086. There's an important distinction between these two kinds of tickets:
  2087. - Task:
  2088. A work item which tracks some task to be done, in which the task and its
  2089. results are described in text, but the work itself is done elsewhere. This
  2090. is often called "issue" in software project hosting platforms. Tasks are
  2091. general-purpose work items that aren't specific to software development or
  2092. software projects.
  2093. - Merge request:
  2094. A work item that includes a proposal or request to apply some specific
  2095. changes to a specific [=Repository=]. The work requested by the work item
  2096. is to review and (decide whether to) merge the proposed patches to the
  2097. repository. This kind of work item is often called "Pull Request" or "Merge
  2098. Request" on software project hosting platforms.
  2099. ### Task / Issue
  2100. A task is represented as a [[#Ticket]] as described above, with the
  2101. following additional requirements:
  2102. - [=context=] is the [=TicketTracker=] to which this task belongs
  2103. - There is no [=attachment=] of type [=Offer=] (but there may be attachment of other types)
  2104. <div class=example>
  2105. <xmp highlight=json-ld>
  2106. {
  2107. "@context": [
  2108. "https://www.w3.org/ns/activitystreams",
  2109. "https://forgefed.org/ns"
  2110. ],
  2111. "id": "https://dev.example/aviva/game-of-life/issues/107",
  2112. "type": "Ticket",
  2113. "context": "https://dev.example/aviva/game-of-life",
  2114. "attributedTo": "https://forge.example/luke",
  2115. "summary": "Window title is empty",
  2116. "content": "<p>When I start the simulation, window title disappears suddenly</p>",
  2117. "mediaType": "text/html",
  2118. "source": {
  2119. "mediaType": "text/markdown; variant=Commonmark",
  2120. "content": "When I start the simulation, window title disappears suddenly",
  2121. },
  2122. "published": "2019-11-04T07:00:04.465807Z",
  2123. "followers": "https://dev.example/aviva/game-of-life/issues/107/followers",
  2124. "team": "https://dev.example/aviva/game-of-life/issues/107/team",
  2125. "replies": "https://dev.example/aviva/game-of-life/issues/107/discussion",
  2126. "history": "https://dev.example/aviva/game-of-life/issues/107/activity",
  2127. "dependants": "https://dev.example/aviva/game-of-life/issues/107/rdeps",
  2128. "dependencies": "https://dev.example/aviva/game-of-life/issues/107/deps",
  2129. "isResolved": true,
  2130. "resolvedBy": "https://code.example/martin",
  2131. "resolved": "2020-02-07T06:45:03.281314Z"
  2132. }
  2133. </xmp>
  2134. </div>
  2135. ### Merge Request / Pull Request
  2136. A merge request is represented as a [[#Ticket]] as described above, with
  2137. the following additional requirements:
  2138. - [=context=] is the [=PatchTracker=] to which this merge request belongs
  2139. - There is no [=attachment=] of type [=Offer=] (but there may be attachment of other types)
  2140. - There is exactly one [=attachment=] of type [=Offer=], as described below
  2141. - There MAY be more [=attachment=]s, but they MUST NOT be of type [=Offer=]
  2142. In that special [=attachment=] of type [=Offer=]:
  2143. - [=type=] is [=Offer=]
  2144. - [=origin=] is the [=Repository=] or [=Branch=] from which the proposed changes are proposed to be merged into the target repository/branch
  2145. - [=target=] is the [=Repository=] or [=Branch=] into which the changes are proposed to be merged
  2146. - [=object=] is an [=OrderedCollection=] of [=Patch=]es in reverse
  2147. chronological order, in which, in addition to standard [=OrderedCollection=]
  2148. properties:
  2149. - [=context=] is (the [=id=] of) the [[#Ticket]]
  2150. - [=previousVersions=] is a list of previous versions
  2151. of the merge request's proposed changes, i.e. previous versions of this
  2152. [=OrderedCollection=]; each of those uses
  2153. [=currentVersion=] to point back to this latest
  2154. version
  2155. <div class=example>
  2156. <xmp highlight=json-ld>
  2157. {
  2158. "@context": [
  2159. "https://www.w3.org/ns/activitystreams",
  2160. "https://forgefed.org/ns"
  2161. ],
  2162. "id": "https://dev.example/aviva/game-of-life/pulls/825",
  2163. "type": "Ticket",
  2164. "context": "https://dev.example/aviva/game-of-life",
  2165. "attributedTo": "https://forge.example/luke",
  2166. "summary": "Fix the empty window title bug",
  2167. "content": "<p>This fixes the bug making the title disappear</p>",
  2168. "mediaType": "text/html",
  2169. "source": {
  2170. "mediaType": "text/markdown; variant=Commonmark",
  2171. "content": "This fixes the bug making the title disappear",
  2172. },
  2173. "published": "2022-09-15T14:52:00.125987Z",
  2174. "followers": "https://dev.example/aviva/game-of-life/pulls/825/followers",
  2175. "replies": "https://dev.example/aviva/game-of-life/pulls/825/discussion",
  2176. "isResolved": false,
  2177. "attachment": {
  2178. "type": "Offer",
  2179. "origin": {
  2180. "type": "Branch",
  2181. "context": "https://forge.example/luke/game-of-life",
  2182. "ref": "refs/heads/fix-title-bug"
  2183. },
  2184. "target": {
  2185. "type": "Branch",
  2186. "context": "https://dev.example/aviva/game-of-life",
  2187. "ref": "refs/heads/main"
  2188. },
  2189. "object": {
  2190. "id": "https://dev.example/aviva/game-of-life/pulls/825/versions/1",
  2191. "type": "OrderedCollection",
  2192. "totalItems": 1,
  2193. "items": [
  2194. {
  2195. "type": "Patch",
  2196. "attributedTo": "https://forge.example/luke",
  2197. "context": "https://dev.example/aviva/game-of-life/pulls/825/versions/1",
  2198. "mediaType": "application/x-git-patch",
  2199. "content": "From c9ae5f4ff4a330b6e1196ceb7db1665bd4c1..."
  2200. }
  2201. ],
  2202. "context": "https://dev.example/aviva/game-of-life/pulls/825"
  2203. }
  2204. }
  2205. }
  2206. </xmp>
  2207. </div>
  2208. ## Patch
  2209. <pre class=simpledef>
  2210. [=type=]:
  2211. [=Patch=]
  2212. [=attributedTo=]:
  2213. The [=Person=] who has written the patch
  2214. [=context=]:
  2215. An [=OrderedCollection=] representing a sequence of patches, being
  2216. submitted together as a proposed change to a certain [=Repository=], and
  2217. this patch is an item in that collection
  2218. [=content=]:
  2219. A description of the changes that this patch proposes, encoded in the
  2220. format specified by [=mediaType=]
  2221. [=mediaType=]:
  2222. A native patch format used by the Version Control System of the
  2223. [=Repository=] to which the patch is proposed, and in which the [=content=]
  2224. of this patch is encoded
  2225. </pre>
  2226. <div class=example>
  2227. <xmp highlight=json-ld>
  2228. {
  2229. "@context": [
  2230. "https://www.w3.org/ns/activitystreams",
  2231. "https://forgefed.org/ns"
  2232. ],
  2233. "id": "https://dev.example/aviva/game-of-life/pulls/825/versions/1/patches/1",
  2234. "type": "Patch",
  2235. "attributedTo": "https://forge.example/luke",
  2236. "context": "https://dev.example/aviva/game-of-life/pulls/825/versions/1",
  2237. "mediaType": "application/x-git-patch",
  2238. "content": "From c9ae5f4ff4a330b6e1196ceb7db1665bd4c1..."
  2239. }
  2240. </xmp>
  2241. </div>
  2242. # Access Control
  2243. ## Giving Access
  2244. ### Invite ### {#Invite}
  2245. To offer some actor access to a shared resource (such as a repository or a
  2246. ticket tracker), use an ActivityPub [=Invite=] activity.
  2247. Properties:
  2248. <pre class=simpledef>
  2249. [=type=]:
  2250. [=Invite=]
  2251. [=actor=]:
  2252. The entity (person, bot, etc.) that is offering access
  2253. [=instrument=]:
  2254. A [=Role=] specifying which operations on the resource are being allowed
  2255. [=target=]:
  2256. The resource, access to which is being given (for example, a repository)
  2257. [=object=]:
  2258. The actor who is being gives access to the resource
  2259. [=capability=]:
  2260. A previously published `Grant`, giving the `actor` permission to invite
  2261. more actors to access the resource
  2262. </pre>
  2263. <div class=example>
  2264. <xmp highlight=json-ld>
  2265. {
  2266. "@context": [
  2267. "https://www.w3.org/ns/activitystreams",
  2268. "https://forgefed.org/ns"
  2269. ],
  2270. "id": "https://dev.example/aviva/outbox/B47d3",
  2271. "type": "Invite",
  2272. "actor": "https://dev.example/aviva",
  2273. "to": [
  2274. "https://dev.example/aviva/followers",
  2275. "https://coding.community/repos/game-of-life",
  2276. "https://coding.community/repos/game-of-life/followers",
  2277. "https://software.site/bob",
  2278. "https://software.site/bob/followers"
  2279. ],
  2280. "instrument": "maintain",
  2281. "target": "https://coding.community/repos/game-of-life",
  2282. "object": "https://software.site/bob",
  2283. "capability": "https://coding.community/repos/game-of-life/outbox/2c53A"
  2284. }
  2285. </xmp>
  2286. </div>
  2287. ### Join ### {#Join}
  2288. To request access to a shared resource, use an ActivityPub [=Join=] activity.
  2289. Properties:
  2290. <pre class=simpledef>
  2291. [=type=]:
  2292. [=Join=]
  2293. [=actor=]:
  2294. The entity (person, bot, etc.) that is requesting access
  2295. [=instrument=]:
  2296. A [=Role=] specifying which operations on the resource are being requested
  2297. [=object=]:
  2298. The resource, access to which is being given (for example, a repository)
  2299. [=capability=]:
  2300. *(optional)* A previously published `Grant`, giving the `actor` permission
  2301. to gain access to the resource without the approval of another actor. If
  2302. `capability` isn't provided, the resource won't grant access before someone
  2303. with adequate access approves the Join request.
  2304. </pre>
  2305. <div class=example>
  2306. <xmp highlight=json-ld>
  2307. {
  2308. "@context": [
  2309. "https://www.w3.org/ns/activitystreams",
  2310. "https://forgefed.org/ns"
  2311. ],
  2312. "id": "https://software.site/bob/outbox/c97E3",
  2313. "type": "Join",
  2314. "actor": "https://software.site/bob",
  2315. "to": [
  2316. "https://coding.community/repos/game-of-life",
  2317. "https://coding.community/repos/game-of-life/followers",
  2318. "https://software.site/bob/followers"
  2319. ],
  2320. "instrument": "maintain",
  2321. "object": "https://coding.community/repos/game-of-life",
  2322. "capability": "https://coding.community/repos/game-of-life/outbox/d38Fa"
  2323. }
  2324. </xmp>
  2325. </div>
  2326. ### Grant ### {#Grant}
  2327. To give some actor access to a shared resource, use a ForgeFed
  2328. [=Grant=] activity.
  2329. Properties:
  2330. <pre class=simpledef>
  2331. [=type=]:
  2332. [=Grant=]
  2333. [=actor=]:
  2334. The entity (person, bot, etc.) that is giving access
  2335. [=object=]:
  2336. A [=Role=] specifying which operations on the resource are being allowed
  2337. [=context=]:
  2338. The resource, access to which is being given (for example, a repository)
  2339. [=target=]:
  2340. The actor who is being gives access to the resource
  2341. [=fulfills=]:
  2342. The activity that triggered the sending of the `Grant`, such as a related
  2343. `Invite` (another example&#x3a; if Alice [=Create=]s a new repository, the
  2344. repository may automatically send back a [=Grant=] giving Alice admin
  2345. access, and this Grant's `fulfills` refers to the [=Create=] that Alice
  2346. sent)
  2347. [=result=]:
  2348. A URI that can be used later for verifying that the given access is still
  2349. approved, thus allowing the actor granting the access to revoke it.
  2350. Alternatively, a JSON object where [=id=] is the URI and [=duration=] MAY
  2351. be specified to allow to skip the revocation check if the duration time
  2352. hasn't yet passed since the last check. If [=duration=] is specified, it
  2353. MUST be positive, and specify only an integral number of seconds that is
  2354. less than `2^63`, and no other component.
  2355. [=allows=]:
  2356. Modes of invocation and/or delegation that this `Grant` is meant to be used
  2357. for
  2358. [=delegates=]:
  2359. If this `Grant` is a delegation, i.e. it is passing on some access that it
  2360. has received, `delegates` specifies the parent `Grant` that it has received
  2361. and now passing on
  2362. [=startTime=]:
  2363. *(optional)* The time at which the Grant becomes valid
  2364. [=endTime=]:
  2365. *(recommended)* The time at which the Grant expires
  2366. </pre>
  2367. <div class=example>
  2368. <xmp highlight=json-ld>
  2369. {
  2370. "@context": [
  2371. "https://www.w3.org/ns/activitystreams",
  2372. "https://forgefed.org/ns"
  2373. ],
  2374. "id": "https://coding.community/repos/game-of-life/outbox/9fA8c",
  2375. "type": "Grant",
  2376. "actor": "https://coding.community/repos/game-of-life",
  2377. "to": [
  2378. "https://dev.example/aviva",
  2379. "https://dev.example/aviva/followers",
  2380. "https://coding.community/repos/game-of-life/followers",
  2381. "https://software.site/bob",
  2382. "https://software.site/bob/followers"
  2383. ],
  2384. "object": "maintain",
  2385. "context": "https://coding.community/repos/game-of-life",
  2386. "target": "https://software.site/bob",
  2387. "fulfills": "https://dev.example/aviva/outbox/B47d3",
  2388. "allows": "invoke",
  2389. "endTime": "2023-12-31T23:00:00-08:00"
  2390. }
  2391. </xmp>
  2392. </div>
  2393. ## Canceling Access
  2394. ### Remove ### {#Remove}
  2395. To disable an actor's membership in a shared resource, invalidating their
  2396. access to it, use an ActivityPub [=Remove=] activity.
  2397. Properties:
  2398. <pre class=simpledef>
  2399. [=type=]:
  2400. [=Remove=]
  2401. [=actor=]:
  2402. The actor (person, bot, etc.) that is disabling access disabled
  2403. [=object=]:
  2404. The actor whose access to the resource is being taken away
  2405. [=origin=]:
  2406. The resource, access to which is being taken away (for example, a
  2407. repository)
  2408. [=capability=]:
  2409. A previously published `Grant`, giving the `actor` permission to disable
  2410. the [=object=] actor's access to the resource
  2411. </pre>
  2412. <div class=example>
  2413. <xmp highlight=json-ld>
  2414. {
  2415. "@context": [
  2416. "https://www.w3.org/ns/activitystreams",
  2417. "https://forgefed.org/ns"
  2418. ],
  2419. "id": "https://dev.example/aviva/outbox/F941b",
  2420. "type": "Remove",
  2421. "actor": "https://dev.example/aviva",
  2422. "to": [
  2423. "https://dev.example/aviva/followers",
  2424. "https://coding.community/repos/game-of-life",
  2425. "https://coding.community/repos/game-of-life/followers",
  2426. "https://software.site/bob",
  2427. "https://software.site/bob/followers"
  2428. ],
  2429. "origin": "https://coding.community/repos/game-of-life",
  2430. "object": "https://software.site/bob",
  2431. "capability": "https://coding.community/repos/game-of-life/outbox/2c53A"
  2432. }
  2433. </xmp>
  2434. </div>
  2435. ### Leave ### {#Leave}
  2436. To withdraw your consent for membership in a shared resource, invalidating
  2437. your access to it, use an ActivityPub [=Leave=] activity.
  2438. Properties:
  2439. <pre class=simpledef>
  2440. [=type=]:
  2441. [=Leave=]
  2442. [=actor=]:
  2443. The actor (person, bot, etc.) that is requesting to disable their own
  2444. access
  2445. [=object=]:
  2446. The resource, access to which is being disabled (for example, a repository)
  2447. </pre>
  2448. <div class=example>
  2449. <xmp highlight=json-ld>
  2450. {
  2451. "@context": [
  2452. "https://www.w3.org/ns/activitystreams",
  2453. "https://forgefed.org/ns"
  2454. ],
  2455. "id": "https://software.site/bob/outbox/d08F4",
  2456. "type": "Leave",
  2457. "actor": "https://software.site/bob",
  2458. "to": [
  2459. "https://coding.community/repos/game-of-life",
  2460. "https://coding.community/repos/game-of-life/followers",
  2461. "https://software.site/bob/followers"
  2462. ],
  2463. "object": "https://coding.community/repos/game-of-life"
  2464. }
  2465. </xmp>
  2466. </div>
  2467. ### Revoke ### {#Revoke}
  2468. Another activity that can be used for disabling access is [=Revoke=].
  2469. While [[#Remove]] and [[#Leave]] are meant for undoing the effects
  2470. of [[#Invite]] and [[#Join]], `Revoke` is provided as an opposite of
  2471. [[#Grant]]. See the Behavior specification for more information about the
  2472. usage of these different activity types in revocation of access to shared
  2473. resources.
  2474. Properties:
  2475. <pre class=simpledef>
  2476. [=type=]:
  2477. [=Revoke=]
  2478. [=actor=]:
  2479. The actor (person, bot, etc.) that is revoking access
  2480. [=fulfills=]:
  2481. An activity that triggered the sending of the `Revoke`, such as a related
  2482. `Remove` or `Leave`
  2483. [=object=]:
  2484. specific [[#Grant]] activities being undone, i.e. the access that they
  2485. granted is now disabled and it cannot be used anymore as the [=capability=]
  2486. of activities. Each Grant may either be mentioned by its [=id=] URI, or be
  2487. included as a full object that includes an [[fep-8b32|integrity proof]].
  2488. </pre>
  2489. <div class=example>
  2490. <xmp highlight=json-ld>
  2491. {
  2492. "@context": [
  2493. "https://www.w3.org/ns/activitystreams",
  2494. "https://forgefed.org/ns"
  2495. ],
  2496. "id": "https://coding.community/repos/game-of-life/outbox/1C0e2",
  2497. "type": "Revoke",
  2498. "actor": "https://coding.community/repos/game-of-life",
  2499. "to": [
  2500. "https://coding.community/repos/game-of-life/followers",
  2501. "https://software.site/bob",
  2502. "https://software.site/bob/followers"
  2503. ],
  2504. "object": "https://coding.community/repos/game-of-life/outbox/9fA8c"
  2505. }
  2506. </xmp>
  2507. </div>
  2508. ### Undo a Grant ### {#undo-grant}
  2509. The Behavior spec describes flows in which the [[#Revoke]] activity is
  2510. used by resources (more accurately, by the actors managing them) to announce
  2511. that they're disabling [[#Grant]]s that they previously sent. To allow for
  2512. a clear distinction, another activity is provided here, for *other* actors to
  2513. *request* the revocation of specific [[#Grant]]s: The ActivityPub [=Undo=]
  2514. activity.
  2515. It's likely that `Grant`s would exist behind-the-scenes in applications, and
  2516. human actors would then use activities such as `Remove` and `Leave` for
  2517. disabling access. But the ability to disable specific `Grant`s may be required
  2518. for ensuring and maintaining system security, therefore `Undo` is provided here
  2519. as well.
  2520. Properties:
  2521. <pre class=simpledef>
  2522. [=type=]:
  2523. [=Undo=]
  2524. [=actor=]:
  2525. The actor (person, bot, etc.) that is revoking access
  2526. [=object=]:
  2527. specific [[#Grant]] activities being undone, i.e. the access that they
  2528. granted is now disabled and it cannot be used anymore as the [=capability=]
  2529. of activities
  2530. [=capability=]:
  2531. A previously published `Grant`, giving the `actor` permission to disable
  2532. the [=object=] actor's access to the resource
  2533. </pre>
  2534. # Vocabulary # {#vocab}
  2535. ## Types
  2536. The base URI of all ForgeFed terms is `https://forgefed.org/ns#`.
  2537. The ForgeFed vocabulary has a JSON-LD context whose URI is
  2538. `https://forgefed.org/ns`. Implementers MUST either include the
  2539. ActivityPub and ForgeFed contexts in their object definitions, or other
  2540. contexts that would result with the ActivityPub and ForgeFed terms being
  2541. assigned they correct full URIs. Implementers MAY include additional contexts
  2542. and terms as appropriate.
  2543. A typical `@context` of a ForgeFed object may look like this:
  2544. <div class=example>
  2545. <xmp highlight=json-ld>
  2546. "@context": [
  2547. "https://www.w3.org/ns/activitystreams",
  2548. "https://forgefed.org/ns"
  2549. ]
  2550. </xmp>
  2551. </div>
  2552. ### Activities
  2553. #### Related to access control
  2554. <pre class=simpledef>
  2555. Name: <dfn dfn export>Grant</dfn>
  2556. URI: https://forgefed.org/ns#Grant
  2557. Extends: [=Activity=]
  2558. Description:
  2559. Indicates that [=target=] is being given (by the [=actor=]) access to a
  2560. resource specified by [=context=] under the role/permission specified by
  2561. [=object=].
  2562. </pre>
  2563. <div class=example>
  2564. <xmp highlight=json-ld line-highlight=7>
  2565. {
  2566. "@context": [
  2567. "https://www.w3.org/ns/activitystreams",
  2568. "https://forgefed.org/ns"
  2569. ],
  2570. "id": "https://example.dev/aviva/outbox/reBGo",
  2571. "type": "Grant",
  2572. "actor": "https://example.dev/aviva",
  2573. "to": [
  2574. "https://example.dev/aviva/followers",
  2575. "https://example.dev/aviva/myproject",
  2576. "https://example.dev/aviva/myproject/followers",
  2577. "https://example.dev/bob",
  2578. "https://example.dev/bob/followers"
  2579. ],
  2580. "object": "write",
  2581. "context": "https://example.dev/aviva/myproject",
  2582. "target": "https://example.dev/bob"
  2583. }
  2584. </xmp>
  2585. </div>
  2586. <pre class=simpledef>
  2587. Name: <dfn dfn export>Revoke</dfn>
  2588. URI: https://forgefed.org/ns#Revoke
  2589. Extends: [=Activity=]
  2590. Description:
  2591. Indicates that the [=actor=] is canceling [=target=]'s access to a resource
  2592. specified by [=context=] under the role specified by [=instrument=], making
  2593. the [=Grant=] activities specified by [=object=] unusable anymore in other
  2594. activities' [=capability=] field.
  2595. </pre>
  2596. <div class=example>
  2597. <xmp highlight=json-ld line-highlight=7>
  2598. {
  2599. "@context": [
  2600. "https://www.w3.org/ns/activitystreams",
  2601. "https://forgefed.org/ns"
  2602. ],
  2603. "id": "https://example.dev/myproject/outbox/nlTxb",
  2604. "type": "Revoke",
  2605. "actor": "https://example.dev/myproject",
  2606. "to": [
  2607. "https://example.dev/myproject/followers",
  2608. "https://example.dev/users/aviva"
  2609. ],
  2610. "object": "https://example.dev/myproject/outbox/reBGo",
  2611. "instrument": "https://example.dev/roles/developer",
  2612. "context": "https://example.dev/myproject",
  2613. "target": "https://example.dev/users/aviva"
  2614. }
  2615. </xmp>
  2616. </div>
  2617. #### Related to repositories
  2618. <pre class=simpledef>
  2619. Name: <dfn dfn export>Push</dfn>
  2620. URI: https://forgefed.org/ns#Push
  2621. Extends: [=Activity=]
  2622. Description:
  2623. Indicates that new content has been pushed to the [=Repository=].
  2624. </pre>
  2625. <div class=example>
  2626. <xmp highlight=json-ld line-highlight=7>
  2627. {
  2628. "@context": [
  2629. "https://www.w3.org/ns/activitystreams",
  2630. "https://forgefed.org/ns"
  2631. ],
  2632. "id": "https://example.dev/aviva/myproject/outbox/reBGo",
  2633. "type": "Push",
  2634. "actor": "https://example.dev/aviva/myproject",
  2635. "attributedTo": "https://example.dev/aviva",
  2636. "to": [
  2637. "https://example.dev/aviva",
  2638. "https://example.dev/aviva/followers",
  2639. "https://example.dev/aviva/myproject/followers"
  2640. ],
  2641. "summary": "<p>Aviva pushed a commit to myproject</p>",
  2642. "object": {
  2643. "type": "OrderedCollection",
  2644. "totalItems": 1,
  2645. "items": [
  2646. {
  2647. "id": "https://example.dev/aviva/myproject/commits/d96596230322716bd6f87a232a648ca9822a1c20",
  2648. "type": "Commit",
  2649. "attributedTo": "https://example.dev/aviva",
  2650. "context": "https://example.dev/aviva/myproject",
  2651. "hash": "d96596230322716bd6f87a232a648ca9822a1c20",
  2652. "created": "2019-11-03T13:43:59Z",
  2653. "summary": "Provide hints in sign-up form fields",
  2654. }
  2655. ]
  2656. },
  2657. "target": "https://example.dev/aviva/myproject/branches/master"
  2658. }
  2659. </xmp>
  2660. </div>
  2661. ### Actors
  2662. #### Software development components
  2663. <pre class=simpledef>
  2664. Name: <dfn dfn export>Repository</dfn>
  2665. URI: https://forgefed.org/ns#Repository
  2666. Extends: [=Object=]
  2667. Description:
  2668. Represents a version control system repository.
  2669. </pre>
  2670. <div class=example>
  2671. <xmp highlight=json-ld line-highlight=8>
  2672. {
  2673. "@context": [
  2674. "https://www.w3.org/ns/activitystreams",
  2675. "https://w3id.org/security/v1",
  2676. "https://forgefed.org/ns"
  2677. ],
  2678. "id": "https://dev.example/aviva/treesim",
  2679. "type": "Repository",
  2680. "publicKey": {
  2681. "id": "https://dev.example/aviva/treesim#main-key",
  2682. "owner": "https://dev.example/aviva/treesim",
  2683. "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....."
  2684. },
  2685. "inbox": "https://dev.example/aviva/treesim/inbox",
  2686. "outbox": "https://dev.example/aviva/treesim/outbox",
  2687. "followers": "https://dev.example/aviva/treesim/followers",
  2688. "team": "https://dev.example/aviva/treesim/team",
  2689. "name": "Tree Growth 3D Simulation",
  2690. "summary": "<p>Tree growth 3D simulator for my nature exploration game</p>"
  2691. }
  2692. </xmp>
  2693. </div>
  2694. <pre class=simpledef>
  2695. Name: <dfn dfn export>TicketTracker</dfn>
  2696. URI: https://forgefed.org/ns#TicketTracker
  2697. Extends: [=Object=]
  2698. Description:
  2699. Represents a [[wikipedia-ticket-tracker|ticket tracker]], i.e. a project
  2700. managing a list of work items.
  2701. </pre>
  2702. <div class=example>
  2703. <xmp highlight=json-ld line-highlight=8>
  2704. {
  2705. "@context": [
  2706. "https://www.w3.org/ns/activitystreams",
  2707. "https://w3id.org/security/v2",
  2708. "https://forgefed.org/ns"
  2709. ],
  2710. "id": "https://dev.example/aviva/treesim",
  2711. "type": ["Repository", "TicketTracker"],
  2712. "publicKey": {
  2713. "id": "https://dev.example/aviva/treesim#main-key",
  2714. "owner": "https://dev.example/aviva/treesim",
  2715. "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....."
  2716. },
  2717. "inbox": "https://dev.example/aviva/treesim/inbox",
  2718. "outbox": "https://dev.example/aviva/treesim/outbox",
  2719. "followers": "https://dev.example/aviva/treesim/followers",
  2720. "name": "Tree Growth 3D Simulation",
  2721. "summary": "<p>Tree growth 3D simulator for my nature exploration game</p>"
  2722. }
  2723. </xmp>
  2724. </div>
  2725. <pre class=simpledef>
  2726. Name: <dfn dfn export>PatchTracker</dfn>
  2727. URI: https://forgefed.org/ns#PatchTracker
  2728. Extends: [=Object=]
  2729. Description:
  2730. Represents a tracker of [[wikipedia-pr|merge requests]], i.e. a project
  2731. managing a list of patches or branches submitted as proposed changes to a
  2732. given [=Repository=].
  2733. </pre>
  2734. <div class=example>
  2735. <xmp highlight=json-ld line-highlight=8>
  2736. {
  2737. "@context": [
  2738. "https://www.w3.org/ns/activitystreams",
  2739. "https://w3id.org/security/v2",
  2740. "https://forgefed.org/ns"
  2741. ],
  2742. "id": "https://dev.example/aviva/treesim",
  2743. "type": ["Repository", "TicketTracker", "PatchTracker"],
  2744. "publicKey": {
  2745. "id": "https://dev.example/aviva/treesim#main-key",
  2746. "owner": "https://dev.example/aviva/treesim",
  2747. "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....."
  2748. },
  2749. "inbox": "https://dev.example/aviva/treesim/inbox",
  2750. "outbox": "https://dev.example/aviva/treesim/outbox",
  2751. "followers": "https://dev.example/aviva/treesim/followers",
  2752. "name": "Tree Growth 3D Simulation",
  2753. "summary": "<p>Tree growth 3D simulator for my nature exploration game</p>"
  2754. }
  2755. </xmp>
  2756. </div>
  2757. #### Organizational structure tools
  2758. <pre class=simpledef>
  2759. Name: <dfn dfn export>Project</dfn>
  2760. URI: https://forgefed.org/ns#Project
  2761. Extends: [=Object=]
  2762. Description:
  2763. Represents a project, a planned endeavor that involves usage of tools
  2764. related to the software development lifecycle. It may be a software
  2765. project, but may also be totally unrelated to software development. For
  2766. example, it may be a book that is being written using Markdown files kept
  2767. in a Git repository. A [=Project=] object is a way to collect forge related
  2768. components together under one title.
  2769. </pre>
  2770. <div class=example>
  2771. <xmp highlight=json-ld line-highlight=8>
  2772. {
  2773. "@context": [
  2774. "https://www.w3.org/ns/activitystreams",
  2775. "https://w3id.org/security/v2",
  2776. "https://forgefed.org/ns"
  2777. ],
  2778. "id": "https://dev.example/projects/wanderer",
  2779. "type": "Project",
  2780. "name": "Wanderer",
  2781. "summary": "3D nature exploration game",
  2782. "components": {
  2783. "type": "Collection",
  2784. "totalItems": 7,
  2785. "items": [
  2786. "https://dev.example/repos/opengl-vegetation",
  2787. "https://dev.example/repos/opengl-vegetation/patch-tracker",
  2788. "https://dev.example/repos/treesim",
  2789. "https://dev.example/repos/treesim/patch-tracker",
  2790. "https://dev.example/repos/wanderer",
  2791. "https://dev.example/repos/wanderer/patch-tracker",
  2792. "https://dev.example/issue-trackers/wanderer"
  2793. ]
  2794. },
  2795. "publicKey": {
  2796. "id": "https://dev.example/projects/wanderer#main-key",
  2797. "owner": "https://dev.example/projects/wanderer",
  2798. "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....."
  2799. },
  2800. "inbox": "https://dev.example/projects/wanderer/inbox",
  2801. "outbox": "https://dev.example/projects/wanderer/outbox",
  2802. "followers": "https://dev.example/projects/wanderer/followers"
  2803. }
  2804. </xmp>
  2805. </div>
  2806. <pre class=simpledef>
  2807. Name: <dfn dfn export>Team</dfn>
  2808. URI: https://forgefed.org/ns#Team
  2809. Extends: [=Object=]
  2810. Description:
  2811. Represents a group of people working together, collaborating on shared
  2812. resources. Each member [=Person=] in the team has a defined role, affecting
  2813. the level of access they have to the team's shared resources and to
  2814. managing the team itself.
  2815. </pre>
  2816. <div class=example>
  2817. <xmp highlight=json-ld line-highlight=8>
  2818. {
  2819. "@context": [
  2820. "https://www.w3.org/ns/activitystreams",
  2821. "https://w3id.org/security/v2",
  2822. "https://forgefed.org/ns"
  2823. ],
  2824. "id": "https://dev.example/teams/mobilizon-dev-team",
  2825. "type": "Team",
  2826. "name": "Mobilizon Development Team",
  2827. "summary": "We're creating a federated tool for organizing events!",
  2828. "members": {
  2829. "type": "Collection",
  2830. "totalItems": 3,
  2831. "items": [
  2832. { "type": "Relationship",
  2833. "subject": "https://dev.example/teams/mobilizon-dev-team",
  2834. "relationship": "hasMember",
  2835. "object": "https://dev.example/people/alice",
  2836. "tag": "https://roles.example/admin"
  2837. },
  2838. { "type": "Relationship",
  2839. "subject": "https://dev.example/teams/mobilizon-dev-team",
  2840. "relationship": "hasMember",
  2841. "object": "https://dev.example/people/bob",
  2842. "tag": "maintain"
  2843. },
  2844. { "type": "Relationship",
  2845. "subject": "https://dev.example/teams/mobilizon-dev-team",
  2846. "relationship": "hasMember",
  2847. "object": "https://dev.example/people/celine",
  2848. "tag": "develop"
  2849. }
  2850. ]
  2851. },
  2852. "subteams": {
  2853. "type": "Collection",
  2854. "totalItems": 2,
  2855. "items": [
  2856. "https://dev.example/teams/mobilizon-backend-team",
  2857. "https://dev.example/teams/mobilizon-frontend-team"
  2858. ]
  2859. },
  2860. "context": "https://dev.example/teams/framasoft-developers",
  2861. "publicKey": {
  2862. "id": "https://dev.example/teams/mobilizon-dev-team#main-key",
  2863. "owner": "https://dev.example/teams/mobilizon-dev-team",
  2864. "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....."
  2865. },
  2866. "inbox": "https://dev.example/teams/mobilizon-dev-team/inbox",
  2867. "outbox": "https://dev.example/teams/mobilizon-dev-team/outbox",
  2868. "followers": "https://dev.example/teams/mobilizon-dev-team/followers"
  2869. }
  2870. </xmp>
  2871. </div>
  2872. ### Objects
  2873. <pre class=simpledef>
  2874. Name: <dfn dfn export>CapabilityUsage</dfn>
  2875. URI: https://forgefed.org/ns#CapabilityUsage
  2876. Extends: [=Object=]
  2877. Values:
  2878. This specification defines 3&#x3a; [=gatherAndConvey=], [=distribute=] and
  2879. [=invoke]
  2880. Description:
  2881. Represents a mode of using a [=Grant=] as an Object Capability (OCAP).
  2882. There are two conceptual operations for `Grant`s&#x3a; Invocation (acting
  2883. on the resource under the specified role) and Delegation (passing on the
  2884. access to more actors, possibly with reduced privileges). A value of this
  2885. type refers to one or both of these operations, and possibly to more
  2886. specific conditions and restrictions on applying them.
  2887. </pre>
  2888. <div class=example>
  2889. <xmp highlight=json-ld line-highlight=7>
  2890. TODO
  2891. </xmp>
  2892. </div>
  2893. <pre class=simpledef>
  2894. Name: <dfn dfn export>Role</dfn>
  2895. URI: https://forgefed.org/ns#Role
  2896. Extends: [=Object=]
  2897. Values:
  2898. [=visit=], [=report=], [=triage=], [=write=], [=maintain=], [=admin=],
  2899. [=delegate=]
  2900. Description:
  2901. Represents a role that an actor has within a [=Team=], or a role defining
  2902. the level of access an actor has to a resource.
  2903. </pre>
  2904. <div class=example>
  2905. <xmp highlight=json-ld line-highlight=7>
  2906. TODO
  2907. </xmp>
  2908. </div>
  2909. <pre class=simpledef>
  2910. Name: <dfn dfn export>Branch</dfn>
  2911. URI: https://forgefed.org/ns#Branch
  2912. Extends: [=Object=]
  2913. Description:
  2914. Represents a named variable reference to a version of the [=Repository=],
  2915. typically used for committing changes in parallel to other development, and
  2916. usually eventually merging the changes into the main history line.
  2917. </pre>
  2918. <div class=example>
  2919. <xmp highlight=json-ld line-highlight=7>
  2920. {
  2921. "@context": [
  2922. "https://www.w3.org/ns/activitystreams",
  2923. "https://forgefed.org/ns"
  2924. ],
  2925. "id": "https://example.dev/luke/myrepo/branches/master",
  2926. "type": "Branch",
  2927. "name": "master",
  2928. "context": "https://example.dev/luke/myrepo",
  2929. "ref": "refs/heads/master"
  2930. }
  2931. </xmp>
  2932. </div>
  2933. <pre class=simpledef>
  2934. Name: <dfn dfn export>Commit</dfn>
  2935. URI: https://forgefed.org/ns#Commit
  2936. Extends: [=Object=]
  2937. Description:
  2938. Represents a named set of changes in the history of a [=Repository=]. This
  2939. is called "commit" in Git, Mercurial and Monotone; "patch" in Darcs;
  2940. sometimes called "change set". Note that `Commit` is a set of changes that
  2941. already exists in a repo's history, while a [=Patch=] is a separate
  2942. proposed change set, that *could* be applied and pushed to a repo,
  2943. resulting with a `Commit`.
  2944. </pre>
  2945. <div class=example>
  2946. <xmp highlight=json-ld line-highlight=7>
  2947. {
  2948. "@context": [
  2949. "https://www.w3.org/ns/activitystreams",
  2950. "https://forgefed.org/ns"
  2951. ],
  2952. "id": "https://example.dev/alice/myrepo/commits/109ec9a09c7df7fec775d2ba0b9d466e5643ec8c",
  2953. "type": "Commit",
  2954. "context": "https://example.dev/alice/myrepo",
  2955. "attributedTo": "https://example.dev/bob",
  2956. "committedBy": "https://example.dev/alice",
  2957. "hash": "109ec9a09c7df7fec775d2ba0b9d466e5643ec8c",
  2958. "summary": "Add an installation script, fixes issue #89",
  2959. "description": {
  2960. "mediaType": "text/plain",
  2961. "content": "It's about time people can install on their computers!"
  2962. },
  2963. "created": "2019-07-11T12:34:56Z",
  2964. "committed": "2019-07-26T23:45:01Z"
  2965. }
  2966. </xmp>
  2967. </div>
  2968. <pre class=simpledef>
  2969. Name: <dfn dfn export>Patch</dfn>
  2970. URI: https://forgefed.org/ns#Patch
  2971. Extends: [=Object=]
  2972. Description:
  2973. Represents a named set of changes that are being proposed for applying to a
  2974. specific [=Repository=].
  2975. </pre>
  2976. <div class=example>
  2977. <xmp highlight=json-ld line-highlight=7>
  2978. {
  2979. "@context": [
  2980. "https://www.w3.org/ns/activitystreams",
  2981. "https://forgefed.org/ns"
  2982. ],
  2983. "id": "https://dev.example/aviva/game-of-life/pulls/825/versions/1/patches/1",
  2984. "type": "Patch",
  2985. "attributedTo": "https://forge.example/luke",
  2986. "context": "https://dev.example/aviva/game-of-life/pulls/825/versions/1",
  2987. "mediaType": "application/x-git-patch",
  2988. "content": "From c9ae5f4ff4a330b6e1196ceb7db1665bd4c1..."
  2989. }
  2990. </xmp>
  2991. </div>
  2992. <pre class=simpledef>
  2993. Name: <dfn dfn export>TicketDependency</dfn>
  2994. URI: https://forgefed.org/ns#TicketDependency
  2995. Extends: [=Relationship=]
  2996. Description:
  2997. Represents a relationship between 2 [=Ticket=]s, in which the resolution of
  2998. one ticket requires the other ticket to be resolved too. It MUST specify
  2999. the [=subject=], [=object=] and [=relationship=] properties, and the
  3000. `relationship` property MUST be [=dependsOn=].
  3001. </pre>
  3002. <div class=example>
  3003. <xmp highlight=json-ld line-highlight=6>
  3004. {
  3005. "@context": [
  3006. "https://www.w3.org/ns/activitystreams",
  3007. "https://forgefed.org/ns"
  3008. ],
  3009. "type": ["Relationship", "TicketDependency"],
  3010. "id": "https://example.dev/ticket-deps/2342593",
  3011. "attributedTo": "https://example.dev/alice",
  3012. "summary": "Alice's ticket depends on Bob's ticket",
  3013. "published": "2019-07-11T12:34:56Z",
  3014. "subject": "https://example.dev/alice/myproj/issues/42",
  3015. "relationship": "dependsOn",
  3016. "object": "https://dev.community/bob/coolproj/issues/85"
  3017. }
  3018. </xmp>
  3019. </div>
  3020. <pre class=simpledef>
  3021. Name: <dfn dfn export>Ticket</dfn>
  3022. URI: https://forgefed.org/ns#Ticket
  3023. Extends: [=Object=]
  3024. Description:
  3025. Represents an item that requires work or attention. Tickets exist in the
  3026. context of a project (which may or may not be a version-control
  3027. repository), and are used to track ideas, proposals, tasks, bugs and more.
  3028. </pre>
  3029. <div class=example>
  3030. <xmp highlight=json-ld line-highlight=6>
  3031. {
  3032. "@context": [
  3033. "https://www.w3.org/ns/activitystreams",
  3034. "https://forgefed.org/ns"
  3035. ],
  3036. "type": "Ticket",
  3037. "id": "https://example.dev/alice/myrepo/issues/42",
  3038. "context": "https://example.dev/alice/myrepo",
  3039. "attributedTo": "https://dev.community/bob",
  3040. "summary": "Nothing works!",
  3041. "content": "<p>Please fix. <i>Everything</i> is broken!</p>",
  3042. "mediaType": "text/html",
  3043. "source": {
  3044. "content": "Please fix. *Everything* is broken!",
  3045. "mediaType": "text/markdown; variant=CommonMark"
  3046. },
  3047. "assignedTo": "https://example.dev/alice",
  3048. "isResolved": false
  3049. }
  3050. </xmp>
  3051. </div>
  3052. ## Properties
  3053. ### General-purpose
  3054. <pre class=simpledef>
  3055. Name: <dfn dfn export>earlyItems</dfn>
  3056. URI: https://forgefed.org/ns#earlyItems
  3057. Domain: [=OrderedCollection=]
  3058. Range: Ordered list of [ [=Object=] | [=Link=] ]
  3059. Functional: No
  3060. Inverse of: None
  3061. Description:
  3062. In an ordered collection (or an ordered collection page) in which [=items=]
  3063. (or [=orderedItems=]) contains a continuous subset of the collection's
  3064. items from one end, `earlyItems` identifiers a continuous subset from the
  3065. other end. For example, if `items` lists the chronologically latest items,
  3066. `earlyItems` would list the chrologically earliest items. The ordering rule
  3067. for items in `earlyItems` MUST be the same as in `items`. For examle, if
  3068. `items` lists items in reverse chronogical order, then so does
  3069. `earlyItems`.
  3070. </pre>
  3071. <div class=example>
  3072. <xmp highlight=json-ld line-highlight=14>
  3073. {
  3074. "@context": [
  3075. "https://www.w3.org/ns/activitystreams",
  3076. "https://forgefed.org/ns"
  3077. ],
  3078. "id": "https://dev.example/aviva/outbox",
  3079. "type": "OrderedCollection",
  3080. "totalItems": 712,
  3081. "orderedItems": [
  3082. "https://dev.example/aviva/outbox/712",
  3083. "https://dev.example/aviva/outbox/711",
  3084. "https://dev.example/aviva/outbox/710"
  3085. ],
  3086. "earlyItems": [
  3087. "https://dev.example/aviva/outbox/3",
  3088. "https://dev.example/aviva/outbox/2",
  3089. "https://dev.example/aviva/outbox/1"
  3090. ]
  3091. }
  3092. </xmp>
  3093. </div>
  3094. <pre class=simpledef>
  3095. Name: <dfn dfn export>previousVersions</dfn>
  3096. URI: https://forgefed.org/ns#previousVersions
  3097. Domain: [=Object=]
  3098. Range: `rdf:List` of objects of the same `@type` as the subject
  3099. Functional: Yes
  3100. Inverse of: None, but see [=currentVersion=]
  3101. Description:
  3102. Specifies the previous versions of the subject, as an ordered list in
  3103. reverse chronological order.
  3104. </pre>
  3105. <div class=example>
  3106. <xmp highlight=json-ld line-highlight=10>
  3107. {
  3108. "@context": [
  3109. "https://www.w3.org/ns/activitystreams",
  3110. "https://forgefed.org/ns"
  3111. ],
  3112. "id": "https://dev.example/aviva/notes/107",
  3113. "type": "Note",
  3114. "attributedTo": "https://dev.example/aviva",
  3115. "content": "I agree!!!!! (edit: fixed a typo)",
  3116. "previousVersions": [
  3117. "https://dev.example/aviva/notes/107_old_version",
  3118. "https://dev.example/aviva/notes/107_very_old_version",
  3119. "https://dev.example/aviva/notes/107_ancient_version"
  3120. ]
  3121. }
  3122. </xmp>
  3123. </div>
  3124. <pre class=simpledef>
  3125. Name: <dfn dfn export>currentVersion</dfn>
  3126. URI: https://forgefed.org/ns#currentVersion
  3127. Domain: [=Object=]
  3128. Range: [=Object=], of the same `@type` as the subject
  3129. Functional: Yes
  3130. Inverse of: None, but see [=previousVersions=]
  3131. Description:
  3132. Specifies the latest. current, up-to-date version of the subject. Once the
  3133. subject specifies the `currentVersion` property, it SHOULD NOT get any
  3134. changes to any other properties. The exception is `currentVersion` itself,
  3135. which MUST be updated whenever needed, to always point to the latest
  3136. version.
  3137. </pre>
  3138. <div class=example>
  3139. <xmp highlight=json-ld line-highlight=10>
  3140. {
  3141. "@context": [
  3142. "https://www.w3.org/ns/activitystreams",
  3143. "https://forgefed.org/ns"
  3144. ],
  3145. "id": "https://dev.example/aviva/notes/107_old_version",
  3146. "type": "Note",
  3147. "attributedTo": "https://dev.example/aviva",
  3148. "content": "I agree!!111",
  3149. "currentVersion": "https://dev.example/aviva/notes/107"
  3150. }
  3151. </xmp>
  3152. </div>
  3153. ### Projects
  3154. <pre class=simpledef>
  3155. Name: <dfn dfn export>components</dfn>
  3156. URI: https://forgefed.org/ns#components
  3157. Domain: [=Project=]
  3158. Range: [=Collection=]
  3159. Functional: Yes
  3160. Inverse of:
  3161. None, but see the usage of [=context=] in the Modeling specification, e.g.
  3162. in [[#Repository]]
  3163. Description:
  3164. Identifies a [=Collection=] listing actors whose services and resources are
  3165. considered to be components of this project.
  3166. </pre>
  3167. <div class=example>
  3168. <xmp highlight=json-ld line-highlight=11>
  3169. {
  3170. "@context": [
  3171. "https://www.w3.org/ns/activitystreams",
  3172. "https://forgefed.org/ns"
  3173. ],
  3174. "id": "https://dev.example/projects/wanderer",
  3175. "type": "Project",
  3176. "name": "Wanderer",
  3177. "summary": "3D nature exploration game",
  3178. "components": {
  3179. "type": "Collection",
  3180. "totalItems": 7,
  3181. "items": [
  3182. "https://dev.example/repos/opengl-vegetation",
  3183. "https://dev.example/repos/opengl-vegetation/patch-tracker",
  3184. "https://dev.example/repos/treesim",
  3185. "https://dev.example/repos/treesim/patch-tracker",
  3186. "https://dev.example/repos/wanderer",
  3187. "https://dev.example/repos/wanderer/patch-tracker",
  3188. "https://dev.example/issue-trackers/wanderer"
  3189. ]
  3190. },
  3191. "inbox": "https://dev.example/projects/wanderer/inbox",
  3192. "outbox": "https://dev.example/projects/wanderer/outbox",
  3193. "followers": "https://dev.example/projects/wanderer/followers"
  3194. }
  3195. </xmp>
  3196. </div>
  3197. <pre class=simpledef>
  3198. Name: <dfn dfn export>subprojects</dfn>
  3199. URI: https://forgefed.org/ns#subprojects
  3200. Domain: [=Project=]
  3201. Range: [=Collection=] of [=Project=]s
  3202. Functional: Yes
  3203. Inverse of:
  3204. None, but see the usage of [=context=] in [[#Project]]
  3205. Description:
  3206. Identifies a [=Collection=] listing the subprojects of this [=Project=].
  3207. </pre>
  3208. <div class=example>
  3209. <xmp highlight=json-ld line-highlight=11>
  3210. {
  3211. "@context": [
  3212. "https://www.w3.org/ns/activitystreams",
  3213. "https://forgefed.org/ns"
  3214. ],
  3215. "id": "https://dev.example/projects/wanderer",
  3216. "type": "Project",
  3217. "name": "Wanderer",
  3218. "summary": "3D nature exploration game",
  3219. "subprojects": {
  3220. "type": "Collection",
  3221. "totalItems": 2,
  3222. "items": [
  3223. "https://dev.example/projects/nature-3d-models",
  3224. "https://dev.example/projects/wanderer-fundraising"
  3225. ]
  3226. },
  3227. "inbox": "https://dev.example/projects/wanderer/inbox",
  3228. "outbox": "https://dev.example/projects/wanderer/outbox",
  3229. "followers": "https://dev.example/projects/wanderer/followers"
  3230. }
  3231. </xmp>
  3232. </div>
  3233. ### Team membership and nesting
  3234. <pre class=simpledef>
  3235. Name: <dfn dfn export>hasMember</dfn>
  3236. URI: https://forgefed.org/ns#hasMember
  3237. Domain: [=Team=]
  3238. Range: [=Person=]
  3239. Functional: No
  3240. Inverse of: None
  3241. Description:
  3242. Identifier a [=Person=] who is a member of this [=Team=].
  3243. </pre>
  3244. <div class=example>
  3245. <xmp highlight=json-ld line-highlight=9>
  3246. TODO
  3247. </xmp>
  3248. </div>
  3249. <pre class=simpledef>
  3250. Name: <dfn dfn export>members</dfn>
  3251. URI: https://forgefed.org/ns#members
  3252. Domain: [=Team=]
  3253. Range:
  3254. [=Collection=] of [=Relationship=]s whose [=relationship=] is [=hasMember=]
  3255. and whose [=subject=] is this `Team`.
  3256. Functional: Yes
  3257. Inverse of: None
  3258. Description:
  3259. Identifies a collection of the members of this [=Team=], represented as
  3260. [=hasMember=] [=Relationship=]s.
  3261. </pre>
  3262. <div class=example>
  3263. <xmp highlight=json-ld line-highlight=9>
  3264. TODO
  3265. </xmp>
  3266. </div>
  3267. <pre class=simpledef>
  3268. Name: <dfn dfn export>subteams</dfn>
  3269. URI: https://forgefed.org/ns#subteams
  3270. Domain: [=Team=]
  3271. Range: [=Collection=] of [=Team=]s.
  3272. Functional: Yes
  3273. Inverse of: None
  3274. Description:
  3275. Identifies a collection of the subteams of this [=Team=], i.e. teams whose
  3276. members inherit the access that this team's members have to projects and to
  3277. project components (such as [=Repository=]s).
  3278. </pre>
  3279. <div class=example>
  3280. <xmp highlight=json-ld line-highlight=9>
  3281. TODO
  3282. </xmp>
  3283. </div>
  3284. ### Ticket assignment and resolution
  3285. <pre class=simpledef>
  3286. Name: <dfn dfn export>assignedTo</dfn>
  3287. URI: https://forgefed.org/ns#assignedTo
  3288. Domain: [=Ticket=]
  3289. Range: [=Person=]
  3290. Functional: Yes
  3291. Inverse of: None
  3292. Description:
  3293. Identifies the [=Person=] assigned to work on this [=Ticket=].
  3294. </pre>
  3295. <div class=example>
  3296. <xmp highlight=json-ld line-highlight=9>
  3297. TODO
  3298. </xmp>
  3299. </div>
  3300. <pre class=simpledef>
  3301. Name: <dfn dfn export>isResolved</dfn>
  3302. URI: https://forgefed.org/ns#isResolved
  3303. Domain: [=Ticket=]
  3304. Range: `xsd:boolean`
  3305. Functional: Yes
  3306. Inverse of: None
  3307. Description:
  3308. Specifies whether the [=Ticket=] is closed, i.e. the work on it is done and
  3309. it doesn't need to attract attention anymore.
  3310. </pre>
  3311. <div class=example>
  3312. <xmp highlight=json-ld line-highlight=9>
  3313. TODO
  3314. </xmp>
  3315. </div>
  3316. <pre class=simpledef>
  3317. Name: <dfn dfn export>resolvedBy</dfn>
  3318. URI: https://forgefed.org/ns#resolvedBy
  3319. Domain: [=Ticket=]
  3320. Range: [=Object=] than is an actor, or [=Activity=]
  3321. Functional: Yes
  3322. Inverse of: None
  3323. Description:
  3324. Identifies the Actor who has resolved the [=Ticket=], or the activity that
  3325. has resolved the Ticket.
  3326. </pre>
  3327. <div class=example>
  3328. <xmp highlight=json-ld line-highlight=9>
  3329. TODO
  3330. </xmp>
  3331. </div>
  3332. <pre class=simpledef>
  3333. Name: <dfn dfn export>resolved</dfn>
  3334. URI: https://forgefed.org/ns#resolved
  3335. Domain: [=Ticket=]
  3336. Range: `xsd:dateTime`
  3337. Functional: Yes
  3338. Inverse of: None
  3339. Description:
  3340. For a resolved [=Ticket=], specifies the time the Ticket has been resolved.
  3341. </pre>
  3342. <div class=example>
  3343. <xmp highlight=json-ld line-highlight=9>
  3344. TODO
  3345. </xmp>
  3346. </div>
  3347. ### Ticket dependencies
  3348. <pre class=simpledef>
  3349. Name: <dfn dfn export>dependsOn</dfn>
  3350. URI: https://forgefed.org/ns#dependsOn
  3351. Domain: [=Ticket=]
  3352. Range: [=Ticket=]
  3353. Functional: No
  3354. Inverse of: [=dependedBy=]
  3355. Description:
  3356. Identifies one or more tickets on which this [=Ticket=] depends, i.e. it
  3357. can't be resolved without those tickets being resolved too.
  3358. </pre>
  3359. <div class=example>
  3360. <xmp highlight=json-ld line-highlight=9>
  3361. TODO
  3362. </xmp>
  3363. </div>
  3364. <pre class=simpledef>
  3365. Name: <dfn dfn export>dependedBy</dfn>
  3366. URI: https://forgefed.org/ns#dependedBy
  3367. Domain: [=Ticket=]
  3368. Range: [=Ticket=]
  3369. Functional: No
  3370. Inverse of: [=dependsOn=]
  3371. Description:
  3372. Identifies one or more tickets which depend on this [=Ticket=], i.e. they
  3373. can't be resolved without this tickets being resolved too.
  3374. </pre>
  3375. <div class=example>
  3376. <xmp highlight=json-ld line-highlight=9>
  3377. TODO
  3378. </xmp>
  3379. </div>
  3380. <pre class=simpledef>
  3381. Name: <dfn dfn export>dependencies</dfn>
  3382. URI: https://forgefed.org/ns#dependencies
  3383. Domain: [=Ticket=]
  3384. Range: [=Collection=] of items of type [=TicketDependency=]
  3385. Functional: Yes
  3386. Inverse of: None
  3387. Description:
  3388. Identifies a [=Collection=] of [=TicketDependency=] which specify tickets
  3389. that this [=Ticket=] depends on, i.e. this ticket is the [=subject=] of the
  3390. [=dependsOn=] relationship.
  3391. </pre>
  3392. <div class=example>
  3393. <xmp highlight=json-ld line-highlight=9>
  3394. TODO
  3395. </xmp>
  3396. </div>
  3397. <pre class=simpledef>
  3398. Name: <dfn dfn export>dependants</dfn>
  3399. URI: https://forgefed.org/ns#dependants
  3400. Domain: [=Ticket=]
  3401. Range: [=Collection=] of items of type [=TicketDependency=]
  3402. Functional: Yes
  3403. Inverse of: None
  3404. Description:
  3405. Identifies a [=Collection=] of [=TicketDependency=] which specify tickets
  3406. that depends on this [=Ticket=], i.e. this ticket is the [=object=] of the
  3407. [=dependsOn=] relationship. Often called "reverse dependencies".
  3408. </pre>
  3409. <div class=example>
  3410. <xmp highlight=json-ld line-highlight=9>
  3411. TODO
  3412. </xmp>
  3413. </div>
  3414. ### Repository cloning
  3415. <pre class=simpledef>
  3416. Name: <dfn dfn export>cloneUri</dfn>
  3417. URI: https://forgefed.org/ns#cloneUri
  3418. Domain: [=Repository=]
  3419. Range: [=Object=]
  3420. Functional: No
  3421. Inverse of: None
  3422. Description:
  3423. An endpoint that can be used with a VCS protocol such as Git or Mercurial
  3424. to access a given repository.
  3425. </pre>
  3426. <div class=example>
  3427. <xmp highlight=json-ld line-highlight=9>
  3428. TODO
  3429. </xmp>
  3430. </div>
  3431. ### Repository pushing
  3432. <pre class=simpledef>
  3433. Name: <dfn dfn export>hashBefore</dfn>
  3434. URI: https://forgefed.org/ns#hashBefore
  3435. Domain: [=Push=]
  3436. Range: `xsd:string` of hexadecimal digit ASCII characters
  3437. Functional: Yes
  3438. Inverse of: None
  3439. Description:
  3440. Specifies the hash of the commit that the pushed branch/repo was pointing
  3441. to *right before* the push happpened.
  3442. </pre>
  3443. <div class=example>
  3444. <xmp highlight=json-ld line-highlight=9>
  3445. TODO
  3446. </xmp>
  3447. </div>
  3448. <pre class=simpledef>
  3449. Name: <dfn dfn export>hashAfter</dfn>
  3450. URI: https://forgefed.org/ns#hashAfter
  3451. Domain: [=Push=]
  3452. Range: `xsd:string` of hexadecimal digit ASCII characters
  3453. Functional: Yes
  3454. Inverse of: None
  3455. Description:
  3456. Specifies the hash of the commit that the pushed branch/repo was pointing
  3457. to *right after* the push happpened.
  3458. </pre>
  3459. <div class=example>
  3460. <xmp highlight=json-ld line-highlight=9>
  3461. TODO
  3462. </xmp>
  3463. </div>
  3464. ### Commits and branches
  3465. <pre class=simpledef>
  3466. Name: <dfn dfn export lt="prop-repository">repository</dfn> (DEPRECATED)
  3467. URI: https://forgefed.org/ns#repository
  3468. Domain: [=Commit=]
  3469. Range: [=Repository=]
  3470. Functional: Yes
  3471. Inverse of: None
  3472. Description:
  3473. Identifies the repository to which a commit belongs. DEPRECATED: Use the
  3474. standard ActivityPub `context` property instead.
  3475. </pre>
  3476. <div class=example>
  3477. <xmp highlight=json-ld line-highlight=9>
  3478. TODO
  3479. </xmp>
  3480. </div>
  3481. <pre class=simpledef>
  3482. Name: <dfn dfn export>description</dfn>
  3483. URI: https://forgefed.org/ns#description
  3484. Domain: [=Commit=]
  3485. Range:
  3486. [=Object=], specifying [=content=] and [=mediaType=]. The `mediaType`
  3487. SHOULD be `"text/plain"`.
  3488. Functional: Yes
  3489. Inverse of: None
  3490. Description:
  3491. Specifies the description text of a [=Commit=], which is an optional
  3492. possibly multi-line text provided in addition to the one-line commit title.
  3493. The range of the `description` property works the same way the range of the
  3494. ActivityPub [=source=] property works.
  3495. </pre>
  3496. <div class=example>
  3497. <xmp highlight=json-ld line-highlight=14>
  3498. {
  3499. "@context": [
  3500. "https://www.w3.org/ns/activitystreams",
  3501. "https://forgefed.org/ns"
  3502. ],
  3503. "id": "https://example.dev/alice/myrepo/commits/109ec9a09c7df7fec775d2ba0b9d466e5643ec8c",
  3504. "type": "Commit",
  3505. "context": "https://example.dev/alice/myrepo",
  3506. "attributedTo": "https://example.dev/bob",
  3507. "hash": "109ec9a09c7df7fec775d2ba0b9d466e5643ec8c",
  3508. "created": "2019-07-11T12:34:56Z",
  3509. "summary": "Add an installation script, fixes issue #89",
  3510. "description": {
  3511. "mediaType": "text/plain",
  3512. "content": "It's about time people can install on their computers!"
  3513. },
  3514. }
  3515. </xmp>
  3516. </div>
  3517. <pre class=simpledef>
  3518. Name: <dfn dfn export>committedBy</dfn>
  3519. URI: https://forgefed.org/ns#committedBy
  3520. Domain: [=Commit=]
  3521. Range: [=Object=]
  3522. Functional: Yes
  3523. Inverse of: None
  3524. Description:
  3525. Identifies the actor (usually a person, but could be something else, e.g. a
  3526. bot) that added a set of changes to the version-control [=Repository=].
  3527. Sometimes the author of the changes and the committer of those changes
  3528. aren't the same actor, in which case the `committedBy` property can be used
  3529. to specify who added the changes to the repository. For example, when
  3530. applying a patch to a repository, e.g. a Git repository, the author would
  3531. be the person who made the patch, and the committer would be the person who
  3532. applied the patch to their copy of the repository.
  3533. </pre>
  3534. <div class=example>
  3535. <xmp highlight=json-ld line-highlight=9>
  3536. TODO
  3537. </xmp>
  3538. </div>
  3539. <pre class=simpledef>
  3540. Name: <dfn dfn export>hash</dfn>
  3541. URI: https://forgefed.org/ns#hash
  3542. Domain: [=Commit=]
  3543. Range: `xsd:string` of hexadecimal digit ASCII characters
  3544. Functional: Yes
  3545. Inverse of: None
  3546. Description:
  3547. Specifies the hash associated with a [=Commit=], which is a unique
  3548. identifier of the commit within the [=Repository=], usually generated as a
  3549. cryptographic hash function of some (or all) of the commit's data or
  3550. metadata. For example, in Git it would be the SHA1 hash of the commit; in
  3551. Darcs it would be the SHA1 hash of the patch info.
  3552. </pre>
  3553. <div class=example>
  3554. <xmp highlight=json-ld line-highlight=9>
  3555. TODO
  3556. </xmp>
  3557. </div>
  3558. <pre class=simpledef>
  3559. Name: <dfn dfn export>committed</dfn>
  3560. URI: https://forgefed.org/ns#committed
  3561. Domain: [=Commit=]
  3562. Range: `xsd:dateTime`
  3563. Functional: Yes
  3564. Inverse of: None
  3565. Description:
  3566. Specifies the time that a set of changes was committed into the
  3567. [=Repository=] and became a [=Commit=] in it. This can be different from
  3568. the time the set of changes was produced, e.g. if one person creates a
  3569. patch and sends to another, and the other person then applies the patch to
  3570. their copy of the repository. We call the former event "created" and the
  3571. latter event "committed", and this latter event is specified by the
  3572. `committed` property.
  3573. </pre>
  3574. <div class=example>
  3575. <xmp highlight=json-ld line-highlight=9>
  3576. TODO
  3577. </xmp>
  3578. </div>
  3579. <pre class=simpledef>
  3580. Name: <dfn dfn export>filesAdded</dfn>
  3581. URI: https://forgefed.org/ns#filesAdded
  3582. Domain: [=Commit=]
  3583. Range: `xsd:string`
  3584. Functional: No
  3585. Inverse of: None
  3586. Description:
  3587. Specifies a filename, as a relative path, relative to the top of the tree
  3588. of files in the [=Repository=], of a file that got added in this
  3589. [=Commit=], and didn't exist in the previous version of the tree.
  3590. </pre>
  3591. <div class=example>
  3592. <xmp highlight=json-ld line-highlight=9>
  3593. TODO
  3594. </xmp>
  3595. </div>
  3596. <pre class=simpledef>
  3597. Name: <dfn dfn export>filesModified</dfn>
  3598. URI: https://forgefed.org/ns#filesModified
  3599. Domain: [=Commit=]
  3600. Range: `xsd:string`
  3601. Functional: No
  3602. Inverse of: None
  3603. Description:
  3604. Specifies a filename, as a relative path, relative to the top of the tree
  3605. of files in the [=Repository=], of a file that existed in the previous
  3606. version of the tree, and its contents got modified in this [=Commit=].
  3607. </pre>
  3608. <div class=example>
  3609. <xmp highlight=json-ld line-highlight=9>
  3610. TODO
  3611. </xmp>
  3612. </div>
  3613. <pre class=simpledef>
  3614. Name: <dfn dfn export>filesRemoved</dfn>
  3615. URI: https://forgefed.org/ns#filesRemoved
  3616. Domain: [=Commit=]
  3617. Range: `xsd:string`
  3618. Functional: No
  3619. Inverse of: None
  3620. Description:
  3621. Specifies a filename, as a relative path, relative to the top of the tree
  3622. of files in the [=Repository=], of a file that existed in the previous
  3623. version of the tree, and got removed from the tree in this [=Commit=].
  3624. </pre>
  3625. <div class=example>
  3626. <xmp highlight=json-ld line-highlight=9>
  3627. TODO
  3628. </xmp>
  3629. </div>
  3630. <pre class=simpledef>
  3631. Name: <dfn dfn export>ref</dfn>
  3632. URI: https://forgefed.org/ns#ref
  3633. Domain: [=Branch=]
  3634. Range: `xsd:string`
  3635. Functional: Yes
  3636. Inverse of: None
  3637. Description:
  3638. Specifies an identifier for a [=Branch=], that is used in the
  3639. [=Repository=] to uniquely refer to it. For example, in Git,
  3640. "refs/heads/master" would be the `ref` of the master branch.
  3641. </pre>
  3642. <div class=example>
  3643. <xmp highlight=json-ld line-highlight=11>
  3644. {
  3645. "@context": [
  3646. "https://www.w3.org/ns/activitystreams",
  3647. "https://forgefed.org/ns"
  3648. ],
  3649. "id": "https://example.dev/luke/myrepo/branches/master",
  3650. "type": "Branch",
  3651. "name": "master",
  3652. "context": "https://example.dev/luke/myrepo",
  3653. "ref": "refs/heads/master"
  3654. }
  3655. </xmp>
  3656. </div>
  3657. ### Activity addressing
  3658. <pre class=simpledef>
  3659. Name: <dfn dfn export lt="prop-team">team</dfn>
  3660. URI: https://forgefed.org/ns#team
  3661. Domain: [=Object=]
  3662. Range: [=Collection=] of actors
  3663. Functional: Yes
  3664. Inverse of: None
  3665. Description:
  3666. Specifies a [=Collection=] of actors who are working on the object, or
  3667. responsible for it, or managing or administrating it, or having edit access
  3668. to it. For example, for a [=Repository=], it could be the people who have
  3669. push/edit access, the "collaborators" of the repository.
  3670. </pre>
  3671. <div class=example>
  3672. A repository *https://dev.example/aviva/treesim*:
  3673. <xmp highlight=json-ld line-highlight=20>
  3674. {
  3675. "@context": [
  3676. "https://www.w3.org/ns/activitystreams",
  3677. "https://w3id.org/security/v1",
  3678. "https://forgefed.org/ns"
  3679. ],
  3680. "id": "https://dev.example/aviva/treesim",
  3681. "type": "Repository",
  3682. "publicKey": {
  3683. "id": "https://dev.example/aviva/treesim#main-key",
  3684. "owner": "https://dev.example/aviva/treesim",
  3685. "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhki....."
  3686. },
  3687. "inbox": "https://dev.example/aviva/treesim/inbox",
  3688. "outbox": "https://dev.example/aviva/treesim/outbox",
  3689. "followers": "https://dev.example/aviva/treesim/followers",
  3690. "name": "Tree Growth 3D Simulation",
  3691. "summary": "<p>Tree growth 3D simulator for my nature exploration game</p>",
  3692. "team": "https://dev.example/aviva/treesim/team"
  3693. }
  3694. </xmp>
  3695. The repository's team *https://dev.example/aviva/treesim/team*:
  3696. <xmp highlight=json-ld line-highlight=4>
  3697. {
  3698. "@context": "https://www.w3.org/ns/activitystreams",
  3699. "id": "https://dev.example/aviva/treesim/team",
  3700. "type": "Collection",
  3701. "totalItems": 3,
  3702. "items": [
  3703. "https://dev.example/aviva",
  3704. "https://dev.example/luke",
  3705. "https://code.community/users/lorax"
  3706. ]
  3707. }
  3708. </xmp>
  3709. </div>
  3710. ### Tracker linking
  3711. <pre class=simpledef>
  3712. Name: <dfn dfn export>ticketsTrackedBy</dfn>
  3713. URI: https://forgefed.org/ns#ticketsTrackedBy
  3714. Domain: [=Object=]
  3715. Range: [=Object=] that is an actor
  3716. Functional: Yes
  3717. Inverse of: [=tracksTicketsFor=]
  3718. Description:
  3719. Identifies the actor which tracks tickets related to the given object. This
  3720. is the actor to whom you send tickets you'd like to open against the
  3721. object.
  3722. </pre>
  3723. <div class=example>
  3724. <xmp highlight=json-ld line-highlight=10>
  3725. {
  3726. "@context": [
  3727. "https://www.w3.org/ns/activitystreams",
  3728. "https://forgefed.org/ns"
  3729. ],
  3730. "id": "https://dev.example/aviva/treesim",
  3731. "type": "Repository",
  3732. "name": "Tree Growth 3D Simulation",
  3733. "summary": "<p>Tree growth 3D simulator for my nature exploration game</p>",
  3734. "ticketsTrackedBy": "https://bugs.example/projects/treesim"
  3735. }
  3736. </xmp>
  3737. </div>
  3738. <pre class=simpledef>
  3739. Name: <dfn dfn export>tracksTicketsFor</dfn>
  3740. URI: https://forgefed.org/ns#tracksTicketsFor
  3741. Domain: [=Object=] that is an actor
  3742. Range: [=Object=]
  3743. Functional: No
  3744. Inverse of: [=ticketsTrackedBy=]
  3745. Description:
  3746. Identifies objects for which which this ticket tracker tracks tickets. When
  3747. you'd like to open a ticket against those objects, you can send them to
  3748. this tracker.
  3749. </pre>
  3750. <div class=example>
  3751. <xmp highlight=json-ld line-highlight=8>
  3752. {
  3753. "@context": [
  3754. "https://www.w3.org/ns/activitystreams",
  3755. "https://forgefed.org/ns"
  3756. ],
  3757. "id": "https://bugs.example/treesim",
  3758. "type": "Project",
  3759. "tracksTicketsFor": [
  3760. "https://dev.example/aviva/liblsystem",
  3761. "https://dev.example/aviva/3d-tree-models",
  3762. "https://dev.example/aviva/treesim"
  3763. ]
  3764. }
  3765. </xmp>
  3766. </div>
  3767. <pre class=simpledef>
  3768. Name: <dfn dfn export>sendPatchesTo</dfn>
  3769. URI: https://forgefed.org/ns#sendPatchesTo
  3770. Domain: [=Repository=]
  3771. Range: [=PatchTracker=]
  3772. Functional: Yes
  3773. Inverse of: [=tracksPatchesFor=]
  3774. Description:
  3775. Identifies the [=PatchTracker=] which tracks patches and merge requests
  3776. related to the given repository. This is the actor to whom you send patches
  3777. and merge requests you'd like to open against the repository.
  3778. </pre>
  3779. <div class=example>
  3780. <xmp highlight=json-ld line-highlight=10>
  3781. {
  3782. "@context": [
  3783. "https://www.w3.org/ns/activitystreams",
  3784. "https://forgefed.org/ns"
  3785. ],
  3786. "id": "https://dev.example/repos/treesim",
  3787. "type": "Repository",
  3788. "name": "Tree Growth 3D Simulation",
  3789. "summary": "<p>Tree growth 3D simulator for my nature exploration game</p>",
  3790. "sendPatchesTo": "https://bugs.example/pr-trackers/treesim"
  3791. }
  3792. </xmp>
  3793. </div>
  3794. <pre class=simpledef>
  3795. Name: <dfn dfn export>tracksPatchesFor</dfn>
  3796. URI: https://forgefed.org/ns#tracksPatchesFor
  3797. Domain: [=PatchTracker=]
  3798. Range: [=Repository=]
  3799. Functional: No
  3800. Inverse of: [=sendPatchesTo=]
  3801. Description:
  3802. Identifies a repository for which which this patch and merge request
  3803. tracker tracks patches and merge requests. When you'd like to open patches
  3804. or merge requests against that repository, you can send them to this
  3805. tracker.
  3806. </pre>
  3807. <div class=example>
  3808. <xmp highlight=json-ld line-highlight=8>
  3809. {
  3810. "@context": [
  3811. "https://www.w3.org/ns/activitystreams",
  3812. "https://forgefed.org/ns"
  3813. ],
  3814. "id": "https://project.example/treesim",
  3815. "type": "PatchTracker",
  3816. "tracksPatchesFor": [
  3817. "https://dev.example/aviva/liblsystem",
  3818. "https://dev.example/aviva/3d-tree-models",
  3819. "https://dev.example/aviva/treesim"
  3820. ]
  3821. }
  3822. </xmp>
  3823. </div>
  3824. ### Repository forking
  3825. <pre class=simpledef>
  3826. Name: <dfn dfn export>forkedFrom</dfn>
  3827. URI: https://forgefed.org/ns#forkedFrom
  3828. Domain: [=Repository=]
  3829. Range: [=Repository=]
  3830. Functional: Yes
  3831. Inverse of: [=forks=]
  3832. Description:
  3833. Identifies the [=Repository=] which this [=Repository=] was created as a
  3834. fork of, i.e. by cloning it.
  3835. </pre>
  3836. <div class=example>
  3837. <xmp highlight=json-ld line-highlight=8>
  3838. {
  3839. "@context": [
  3840. "https://www.w3.org/ns/activitystreams",
  3841. "https://forgefed.org/ns"
  3842. ],
  3843. "id": "https://example.dev/alice/myfork/",
  3844. "type": "Repository",
  3845. "forkedFrom": {
  3846. "type": "Repository",
  3847. "id": "https://example.dev/luke/myrepo/"
  3848. }
  3849. }
  3850. </xmp>
  3851. </div>
  3852. <pre class=simpledef>
  3853. Name: <dfn dfn export>forks</dfn>
  3854. URI: https://forgefed.org/ns#forks
  3855. Domain: [=Repository=]
  3856. Range: [=OrderedCollection=] of items of type [=Repository=]
  3857. Functional: Yes
  3858. Inverse of: [=forkedFrom=]
  3859. Description:
  3860. Identifies an [=OrderedCollection=] of [=Repository=]s which were created
  3861. as forks of this [=Repository=], i.e. by cloning it. The order of the
  3862. collection items is by reverse chronological order of the forking events.
  3863. </pre>
  3864. <div class=example>
  3865. <xmp highlight=json-ld line-highlight=8>
  3866. {
  3867. "@context": [
  3868. "https://www.w3.org/ns/activitystreams",
  3869. "https://forgefed.org/ns"
  3870. ],
  3871. "id": "https://example.dev/luke/myrepo/",
  3872. "type": "Repository",
  3873. "forks": {
  3874. "type": "OrderedCollection",
  3875. "totalItems": 1,
  3876. "orderedItems": [
  3877. {
  3878. "id": "https://example.dev/alice/myfork/",
  3879. "type": "Repository",
  3880. }
  3881. ]
  3882. },
  3883. }
  3884. </xmp>
  3885. </div>
  3886. ### Access control
  3887. <pre class=simpledef>
  3888. Name: <dfn dfn export>fulfills</dfn>
  3889. URI: https://forgefed.org/ns#fulfills
  3890. Domain: [=Activity=]
  3891. Range: [=Activity=]
  3892. Functional: No
  3893. Inverse of: None
  3894. Description:
  3895. For an activity *A* that `fulfills` some other activity *B*, specifies that
  3896. *A* has been published as part of fulfilling the action requested by *B*.
  3897. For example, if Alice creates a new repository using `Create`, she may want
  3898. to instantly automatically start following this new repository using
  3899. `Follow` (to be notified when her friends push commits there). This
  3900. `Follow` `fulfills` the `Create`; it's an activity automatically sent as
  3901. part of creating a new repository.
  3902. </pre>
  3903. <div class=example>
  3904. <xmp highlight=json-ld line-highlight=9>
  3905. TODO
  3906. </xmp>
  3907. </div>
  3908. <pre class=simpledef>
  3909. Name: <dfn dfn export>allows</dfn>
  3910. URI: https://forgefed.org/ns#allows
  3911. Domain: [=Grant=]
  3912. Range: [=CapabilityUsage=]
  3913. Functional: No
  3914. Inverse of: None
  3915. Description:
  3916. Specifies which modes of using this [=Grant=] are being allowd by it. The
  3917. two conceptual operations that `Grant`s support are invocation (acting on
  3918. the resource under the specified role) and delegation (passing on the
  3919. access to more actors, possibly with reduced privileges). This property
  3920. specifies which of these operations are supported, and under which
  3921. conditions. See [=CapabilityUsage=] for specific values to use.
  3922. </pre>
  3923. <div class=example>
  3924. <xmp highlight=json-ld line-highlight=9>
  3925. TODO
  3926. </xmp>
  3927. </div>
  3928. <pre class=simpledef>
  3929. Name: <dfn dfn export>capability</dfn>
  3930. URI: https://forgefed.org/ns#capability
  3931. Domain: [=Activity=]
  3932. Range: [=Grant=]
  3933. Functional: Yes
  3934. Inverse of: None
  3935. Description:
  3936. Specifies a previously published [=Grant=] activity providing relevant
  3937. access permissions. For example, if Alice wants to resolve a [=Ticket=]
  3938. under some project, she will send an activity with `capability` referring
  3939. to the `Grant` activity that gave her collaborator access to that project,
  3940. which happens to include permission to resolve tickets.
  3941. </pre>
  3942. <div class=example>
  3943. <xmp highlight=json-ld line-highlight=9>
  3944. TODO
  3945. </xmp>
  3946. </div>
  3947. <pre class=simpledef>
  3948. Name: <dfn dfn export>managedBy</dfn>
  3949. URI: https://forgefed.org/ns#managedBy
  3950. Domain: [=Object=]
  3951. Range: [=Object=] that is an actor
  3952. Functional: Yes
  3953. Inverse of: None
  3954. Description:
  3955. Identifies the actor that controls the given resource, and to whom
  3956. activities asking to modify the resource may be submitted.
  3957. </pre>
  3958. <div class=example>
  3959. <xmp highlight=json-ld line-highlight=9>
  3960. {
  3961. "@context": [
  3962. "https://www.w3.org/ns/activitystreams",
  3963. "https://forgefed.org/ns"
  3964. ],
  3965. "type": "Ticket",
  3966. "id": "https://example.dev/alice/myrepo/issues/42",
  3967. "context": "https://example.dev/alice/myrepo",
  3968. "managedBy": "https://example.dev/alice/myrepo",
  3969. "attributedTo": "https://dev.community/bob",
  3970. "summary": "Nothing works!",
  3971. "content": "<p>Please fix. <i>Everything</i> is broken!</p>",
  3972. "mediaType": "text/html",
  3973. "source": {
  3974. "content": "Please fix. *Everything* is broken!",
  3975. "mediaType": "text/markdown; variant=CommonMark"
  3976. },
  3977. "isResolved": false
  3978. }
  3979. </xmp>
  3980. </div>
  3981. <pre class=simpledef>
  3982. Name: <dfn dfn export>delegates</dfn>
  3983. URI: https://forgefed.org/ns#delegates
  3984. Domain: [=Grant=]
  3985. Range: [=Grant=]
  3986. Functional: Yes
  3987. Inverse of: None
  3988. Description:
  3989. Actors can use [=Grant=] activities to allow other actors to access their
  3990. resources. They can also allow those other actors to pass on (delegate)
  3991. this access to even more actors. For a `Grant` that delegates access
  3992. provided by an earlier `Grant`, the former uses `delegates` to specify the
  3993. latter. That earlier `Grant` is also called the "parent capability" of this
  3994. `Grant`.
  3995. </pre>
  3996. <div class=example>
  3997. <xmp highlight=json-ld line-highlight=9>
  3998. TODO
  3999. </xmp>
  4000. </div>
  4001. ### Repository mirroring
  4002. <pre class=simpledef>
  4003. Name: <dfn dfn export>mirrors</dfn>
  4004. URI: https://forgefed.org/ns#mirrors
  4005. Domain: [=Repository=]
  4006. Range: [=Repository=]
  4007. Functional: Yes
  4008. Inverse of: [=mirroredBy=]
  4009. Description:
  4010. Identifies the [=Repository=] which this [=Repository=] copies content from
  4011. (i.e. what this repository is a "pull mirror" of).
  4012. </pre>
  4013. <div class=example>
  4014. <xmp highlight=json-ld line-highlight=8>
  4015. {
  4016. "@context": [
  4017. "https://www.w3.org/ns/activitystreams",
  4018. "https://forgefed.org/ns"
  4019. ],
  4020. "id": "https://example.dev/alice/mymirror/",
  4021. "type": "Repository",
  4022. "mirrors": {
  4023. "type": "Repository",
  4024. "id": "https://example.dev/luke/myrepo/"
  4025. }
  4026. }
  4027. </xmp>
  4028. </div>
  4029. <pre class=simpledef>
  4030. Name: <dfn dfn export>mirroredBy</dfn>
  4031. URI: https://forgefed.org/ns#mirroredBy
  4032. Domain: [=Repository=]
  4033. Range: [=Repository=]
  4034. Functional: No
  4035. Inverse of: [=mirrors=]
  4036. Description:
  4037. Identifies a [=Repository=] which copies content from this repository (i.e.
  4038. "pull mirror" of this repository).
  4039. </pre>
  4040. <div class=example>
  4041. <xmp highlight=json-ld line-highlight=8>
  4042. {
  4043. "@context": [
  4044. "https://www.w3.org/ns/activitystreams",
  4045. "https://forgefed.org/ns"
  4046. ],
  4047. "id": "https://example.dev/luke/myrepo/",
  4048. "type": "Repository",
  4049. "mirroredBy": {
  4050. "type": "Repository",
  4051. "id": "https://example.dev/alice/mymirror/"
  4052. }
  4053. }
  4054. </xmp>
  4055. </div>
  4056. <pre class=simpledef>
  4057. Name: <dfn dfn export>mirrorsTo</dfn>
  4058. URI: https://forgefed.org/ns#mirrorsTo
  4059. Domain: [=Repository=]
  4060. Range: [=Repository=]
  4061. Functional: No
  4062. Inverse of: [=mirroredFrom=]
  4063. Description:
  4064. Identifies a [=Repository=] which this repository copies content to (i.e.
  4065. "push mirror" of this repository)
  4066. </pre>
  4067. <div class=example>
  4068. <xmp highlight=json-ld line-highlight=8>
  4069. {
  4070. "@context": [
  4071. "https://www.w3.org/ns/activitystreams",
  4072. "https://forgefed.org/ns"
  4073. ],
  4074. "id": "https://example.dev/alice/myrepo/",
  4075. "type": "Repository",
  4076. "mirrorsTo": {
  4077. "type": "Repository",
  4078. "id": "https://example.dev/alice-backup/myrepo/"
  4079. }
  4080. }
  4081. </xmp>
  4082. </div>
  4083. <pre class=simpledef>
  4084. Name: <dfn dfn export>mirroredFrom</dfn>
  4085. URI: https://forgefed.org/ns#mirroredFrom
  4086. Domain: [=Repository=]
  4087. Range: [=Repository=]
  4088. Functional: Yes
  4089. Inverse of: [=mirrorsTo=]
  4090. Description:
  4091. Identifies the [=Repository=] which copies its content to this
  4092. [=Repository=] (ie. what this repository is a "push mirror" of).
  4093. </pre>
  4094. <div class=example>
  4095. <xmp highlight=json-ld line-highlight=8>
  4096. {
  4097. "@context": [
  4098. "https://www.w3.org/ns/activitystreams",
  4099. "https://forgefed.org/ns"
  4100. ],
  4101. "id": "https://example.dev/alice-backup/myrepo/",
  4102. "type": "Repository",
  4103. "mirroredFrom": {
  4104. "type": "Repository",
  4105. "id": "https://example.dev/alice/myrepo/"
  4106. }
  4107. }
  4108. </xmp>
  4109. </div>
  4110. ## Values
  4111. ### Capability uses
  4112. <pre class=simpledef>
  4113. Name: <dfn dfn export>gatherAndConvey</dfn>
  4114. URI: https://forgefed.org/ns#gatherAndConvey
  4115. Type: [=CapabilityUsage=]
  4116. Conditions:
  4117. <ul>
  4118. <li>
  4119. The `Grant`'s [=target=] MUST be a [=Project=]
  4120. </li>
  4121. <li>
  4122. It may delegate the `Grant`, allowing only `gatherAndConvey`, to
  4123. parent projects
  4124. </li>
  4125. <li>
  4126. It may delegate the `Grant`, allowing only `distribute`, to teams
  4127. to which it allows to access it
  4128. </li>
  4129. <li>
  4130. It may delegate the `Grant`, allowing `invoke` only, to people to
  4131. which it allows to access it
  4132. </li>
  4133. </ul>
  4134. </pre>
  4135. <pre class=simpledef>
  4136. Name: <dfn dfn export>distribute</dfn>
  4137. URI: https://forgefed.org/ns#distribute
  4138. Type: [=CapabilityUsage=]
  4139. Conditions:
  4140. <ul>
  4141. <li>
  4142. The `Grant`'s [=target=] MUST be a [=Team=]
  4143. </li>
  4144. <li>
  4145. It may delegate the `Grant`, allowing `distribute` only, to its
  4146. subteams
  4147. </li>
  4148. <li>
  4149. It may delegate the `Grant`, allowing `invoke` only, to its members
  4150. </li>
  4151. </ul>
  4152. </pre>
  4153. <pre class=simpledef>
  4154. Name: <dfn dfn export>invoke</dfn>
  4155. URI: https://forgefed.org/ns#invoke
  4156. Type: [=CapabilityUsage=]
  4157. Conditions:
  4158. <ul>
  4159. <li>
  4160. The `Grant`'s [=target=] may invoke it, i.e. use it as the
  4161. [=capability=] in another activity, that requests to access or
  4162. modify the resource specified by the `Grant`'s [=context=]
  4163. </li>
  4164. </ul>
  4165. </pre>
  4166. ### Roles
  4167. <pre class=simpledef>
  4168. Name: <dfn dfn export>visit</dfn>
  4169. URI: https://forgefed.org/ns#visit
  4170. Type: [=Role=]
  4171. Description:
  4172. Authorizes the [=Grant=] recipient (i.e. [=target=]) to view the [=Grant=]
  4173. resource (i.e. [=context=]), which includes retrieving objects via HTTP and
  4174. pulling/cloning VCS repos
  4175. </pre>
  4176. <pre class=simpledef>
  4177. Name: <dfn dfn export>report</dfn>
  4178. URI: https://forgefed.org/ns#report
  4179. Type: [=Role=]
  4180. Description:
  4181. Authorizes the [=Grant=] recipient (i.e. [=target=]) to do on the [=Grant=]
  4182. resource (i.e. [=context=]) anything that the [=visit=] role authorizes,
  4183. and also to do basic community participation tasks:
  4184. [Open an issue](#opening-issue),
  4185. [submit a PR](#opening-mr),
  4186. [create comments](#commenting)
  4187. and discussion threads,
  4188. edit public wikis,
  4189. submit PR reviews.
  4190. </pre>
  4191. <pre class=simpledef>
  4192. Name: <dfn dfn export>triage</dfn>
  4193. URI: https://forgefed.org/ns#triage
  4194. Type: [=Role=]
  4195. Description:
  4196. Authorizes the [=Grant=] recipient (i.e. [=target=]) to do on the [=Grant=]
  4197. resource (i.e. [=context=]) anything that the [=report=] role authorizes,
  4198. and also to edit issue/PR propeties (labels, milestones, due dates, etc.),
  4199. close and reopen issues and PRs, assign and unassign people to issues and
  4200. PRs, request PR reviews, hide disruptive comments (a moderation action),
  4201. lock and move discussions.
  4202. </pre>
  4203. <pre class=simpledef>
  4204. Name: <dfn dfn export>write</dfn>
  4205. URI: https://forgefed.org/ns#write
  4206. Type: [=Role=]
  4207. Description:
  4208. Authorizes the [=Grant=] recipient (i.e. [=target=]) to do on the [=Grant=]
  4209. resource (i.e. [=context=]) anything that the [=triage=] role authorizes,
  4210. and also to
  4211. apply PR suggested changes,
  4212. edit non-public wikis,
  4213. create/edit/delete labels,
  4214. merge a PR,
  4215. [push to VCS repositories](#pushing),
  4216. create/edit/run/cancel CI recipes,
  4217. manage releases,
  4218. publish packages,
  4219. create web IDE coding sessions.
  4220. </pre>
  4221. <pre class=simpledef>
  4222. Name: <dfn dfn export>maintain</dfn>
  4223. URI: https://forgefed.org/ns#maintain
  4224. Type: [=Role=]
  4225. Description:
  4226. Authorizes the [=Grant=] recipient (i.e. [=target=]) to do on the [=Grant=]
  4227. resource (i.e. [=context=]) anything that the [=write=] role authorizes,
  4228. and also to edit project and component descriptions and settings unrelated
  4229. to access, enable/disable components, configure "Pages" publishing of
  4230. static websites from repos, push to repos' protected branches.
  4231. </pre>
  4232. <pre class=simpledef>
  4233. Name: <dfn dfn export>admin</dfn>
  4234. URI: https://forgefed.org/ns#admin
  4235. Type: [=Role=]
  4236. Description:
  4237. Authorizes the [=Grant=] recipient (i.e. [=target=]) to do on the [=Grant=]
  4238. resource (i.e. [=context=]) anything that the [=maintain=] role authorizes,
  4239. and also to
  4240. [manage access to projects, components and teams](#managing-access),
  4241. merge PRs even without reviews,
  4242. delete issues,
  4243. change project/component/team visibility,
  4244. edit project/component/team access-related settings,
  4245. change a repo's default branch,
  4246. manage webhooks and deployment,
  4247. move components and projects between projects,
  4248. archive projects/components,
  4249. delete components/projects/teams.
  4250. </pre>
  4251. <pre class=simpledef>
  4252. Name: <dfn dfn export>delegate</dfn>
  4253. URI: https://forgefed.org/ns#delegate
  4254. Type: [=Role=]
  4255. Description:
  4256. Authorizes the [=Grant=] recipient (i.e. [=target=]) to send access
  4257. delegations to the [=Grant=] sender (i.e. [=actor=])
  4258. </pre>
  4259. <pre class=biblio>
  4260. {
  4261. "wikipedia-ticket-tracker": {
  4262. "href": "https://en.wikipedia.org/wiki/Issue_tracking_system",
  4263. "title": "Wikipedia: Issue tracking system"
  4264. },
  4265. "wikipedia-pr": {
  4266. "href": "https://en.wikipedia.org/wiki/Distributed_version_control#Pull_requests",
  4267. "title": "Wikipedia: Pull requests"
  4268. },
  4269. "fep-8b32": {
  4270. "href": "https://codeberg.org/fediverse/fep/src/branch/main/feps/fep-8b32.md",
  4271. "title": "FEP-8b32: Object Integrity Proofs"
  4272. }
  4273. }
  4274. </pre>
  4275. <pre class=anchors>
  4276. urlPrefix: https://www.w3.org/TR/xmlschema11-2/#; type: dfn; spec: xmlschema11-2
  4277. text: dateTime
  4278. urlPrefix: http://purl.org/dc/terms/; type: dfn; spec: dcterms
  4279. text: created
  4280. urlPrefix: https://www.w3.org/TR/activitystreams-vocabulary/#dfn-; type: dfn; spec: activitystreams-vocabulary
  4281. text: Accept
  4282. text: Add
  4283. text: Create
  4284. text: Invite
  4285. text: Join
  4286. text: Leave
  4287. text: Offer
  4288. text: Reject
  4289. text: Remove
  4290. text: Undo
  4291. urlPrefix: https://www.w3.org/TR/activitystreams-vocabulary/#dfn-; type: dfn; spec: activitystreams-vocabulary
  4292. text: Activity
  4293. text: Collection
  4294. text: Image
  4295. text: Link
  4296. text: Note
  4297. text: Object
  4298. text: OrderedCollection
  4299. text: Person
  4300. urlPrefix: https://www.w3.org/TR/activitystreams-vocabulary/#dfn-; type: dfn; spec: activitystreams-vocabulary
  4301. text: actor
  4302. text: attachment
  4303. text: attributedTo
  4304. text: content
  4305. text: context
  4306. text: duration
  4307. text: endTime
  4308. text: id
  4309. text: inbox
  4310. text: inReplyTo
  4311. text: instrument
  4312. text: items
  4313. text: mediaType
  4314. text: name
  4315. text: object
  4316. text: orderedItems
  4317. text: origin
  4318. text: published
  4319. text: relationship
  4320. text: replies
  4321. text: result
  4322. text: source
  4323. text: startTime
  4324. text: subject
  4325. text: summary
  4326. text: tag
  4327. text: target
  4328. text: to
  4329. text: type
  4330. urlPrefix: https://www.w3.org/TR/activitypub/#; type: dfn; spec: activitypub
  4331. text: followers
  4332. </pre>