8 Commits
Author SHA1 Message Date
rblundon 0d674e0c4b update vault 2026-10-23 17:34:02 -05:00
rblundon de9e340151 added 1password token to vault 2026-10-23 17:15:03 -05:00
JARVISandClaude Opus 5.5 be7d4a4378 multica_agent_host: install the 1Password CLI from 1Password's signed repo (WDWL-37)
Agents get `op` so op:// references resolve at command time and secret
values stay out of prompts and transcripts. Installed per 1Password's
apt instructions (signed-by keyring, debsig policy + keyring,
1password-cli), with the key fingerprint-checked before it is trusted;
EL via their yum repo. multica_op_version pins, "" tracks the repo.
Tag: multica_op.

Optional, default-off hook writes OP_SERVICE_ACCOUNT_TOKEN from the
playbook (ansible-vault) to a 0600 file owned by the daemon user. It is
deliberately not wired into the daemon environment: the user unit
belongs to the multica CLI, and the delivery design is pending.

Rolled out with --tags multica_op to haunted-mansion and spaceship-earth;
second run changed=0, op 2.41.1 as multica, debsig verifies the .deb.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 17:11:27 -05:00
JARVISandClaude Opus 5.5 01e6ad90f0 traefik: serve gitea on mad-tea-party.wdw-labs.cloud too, add SAN (WDWL-27)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:51:28 -05:00
JARVISandClaude Opus 5.5 008fd5bf7b gitea: template compose from role vars; bump to 28.2.0 / postgres 17.11 (WDWL-27)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:51:28 -05:00
JARVISandClaude Opus 5.5 fc2ad85e19 obsidian_headless: grant the service user on shared folders too (WDWL-22)
Content multica creates in inbox/ is owned multica:multica, so obsync fell
into "other" (---) and Sync could neither read nor upload Wong's
submissions. Found after the real Sync sign-in on spaceship-earth; the
earlier verify only tested the obsync -> multica direction.

Shared folders now carry user:obsync:rwx as an access and a default entry
alongside the shared user's, and verify tests the multica -> obsync
direction (read + rewrite, as merge needs). Second run changed=0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 21:28:52 -05:00
JARVISandClaude Opus 5.5 2d039ae32f multica_agent_host: merge declared keys into the daemon user's Claude settings (WDWL-22)
The npm-installed Claude Code on spaceship-earth updated itself from the
pinned 2.1.304 to 2.1.308 right after its first login, so every play would
downgrade it and it would update again. New multica_claude_settings is
merged (recursively, not templated, since Claude writes the file too) into
~multica/.claude/settings.json.

provision-agent-host.yml sets DISABLE_AUTOUPDATER=1 and mirrors the model
mix already live on haunted-mansion: model sonnet, subagents haiku,
MAX_THINKING_TOKENS 4000, BASH_MAX_OUTPUT_LENGTH 20000, thinking off.

spaceship-earth: back on 2.1.304 and staying there; second run changed=0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 16:38:00 -05:00
JARVISandClaude Opus 5.5 94c77daf13 multica_agent_host: daemon lifecycle via systemd; fix login guard (WDWL-22)
Found provisioning spaceship-earth:

- Login was not idempotent: `multica auth status` prints to stderr (0.6.5),
  and the guard read stdout only, so every run re-logged in and restarted
  the daemon. The guard now reads both streams; the status read is no_log
  because it echoes a token prefix.
- `multica daemon start` / `daemon restart` fork the daemon inside the
  caller's session (Ansible's SSH session scope), outside the systemd user
  unit, which stays inactive: the same orphan seen on haunted-mansion on
  2026-10-21. Start/restart now go through `systemctl --user`, after a
  daemon-reload when autostart was (re)registered. A daemon found running
  outside its unit is stopped first. The unit name is read from
  `autostart status`, so --profile hosts resolve their own unit.

spaceship-earth: second run changed=0, daemon in multica-daemon.service.
Not yet run against haunted-mansion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 16:04:46 -05:00
19 changed files with 1100 additions and 502 deletions

No files matched your search

+471 -426
View File
@@ -1,427 +1,472 @@
$ANSIBLE_VAULT;1.1;AES256 $ANSIBLE_VAULT;1.1;AES256
31356235343830393937633039386366623238373864353438353332653038616330623365343135 31303035626165353032623535326564616362663265363634346230393632623233333132636230
3961393463613335663138383233323964393832626466620a393763616364363030323833386565 3263666137666332353136626438663063633165663565360a333934333364653766626263383464
30666333366332313262313836613962363537353065646361316230386434366534666338336636 33356463653166666236623638303561376439373261306334373134386262636534623966633436
3930363231393333610a613039646430663233613163376131333637383866656564333765633565 3330613861353861350a393035363566383862643563376436643665626135373830616231656365
32333338316539363034316132313631643632316337356164373765373736366639623362343738 61623530363761616533376434326230363132666433356238646139393730343264636362333463
63326164623535326461323234333933656132313836643139316339333831323331393030323233 63396239313137376262356664323562306634633064616166316331333862326436393861346632
34643932626464353861616534326130373362646437613131326464313737623965366361616266 33393031646532376462313837343762663266363366353665366266623434326538646239623234
37393934333761303163346465366464393964313831393266303434313061356333373430346339 65623362333166326566303739623466376537353561643034616563356664363266643462323435
33393331393461303163306639386239656139613833386235363335333837316666323637346462 63623436353162376366343836626439623963313764346562363061653832646130396463396530
35346634383936333631303338356433323865623030663336323663373962623531313562626666 35346631666633383435656563366164306432663131326633343563313134323937313961613437
33393063613137646631666363386161636462343262313935386535386361346464396133613736 32383163613439636561383064346238303535613339366234633234633430353232613761636562
31383464613130353034396264643766646161343664363435383639656234623035343833653832 36323461623465653765303533303230303064363762393865326533613336346366386630353339
63356130646136396463636533616334643638333239636437663030393064326362393736373233 61343164333262646239636161313231386133363037666539653666656461653666356239663234
34396166653932326632376535373762663633303261303536396334303937316431346133353830 66373736616232336466623030373366393366393032656138306465636431383937646461383136
37626337313861306164366130643131383133323337643637666535316132373238373066306339 66303733626633386335623835383135363265383062343937306564613234366435383236356537
38343865613937663366376630333365633039333430653762313864303737633661356232373133 66303638626365343066343537306636623935393637616237306337363538616262323735363230
64303934623937313863323431396638383932383836613830336235656530613234316238353364 34343561336634393334323763393836633736383739323661303531626133383834333138656362
32306561343362643431623239333638316239323164386634623736313261313936616239396431 35656463316136373861613636366165383530383465326666616139333130663230356166373633
64373934313663313139316331623436663832393131373562393436326265656562363137636461 62613535656161633530393031663063363031656431303338613864653739323932646333633236
33613864356464366239306639653264363565306331636137396466336163336631353163383430 36346464303564343661653138323433306563306566623966313664643030653934343230626333
30303034383136356465643238663034623036363562353037343832616136363539656432346639 38343732653264376530343933326365363864666539306562366434363161633132373165393234
34636536383533333538346237653731633331643137303966316138333633373564383034383438 65333339356330323562343032343334616439343963623066626538633238663132383965656231
34666465323032356333613935363161306431666533353061626536633839396234613662623062 38346230666230396434613036333466633334386337373437383063336364366130383064633831
63313338346138653765393537356639373035643935373735323166376336626166396562316535 38303630656162376331623335323565356530326539333536623835383132353462353161663061
39343236356665363038326132313437303236646161333638393939653033623664306563613730 37353263646537633561656133393562623034363830663961623331623263303861383465383865
34383538656139646436333765623861303739613939633962316139386463643666366464303935 66303765313830383431636236313937616666303833383738353438643461373166343130353661
32366239656366393832376436623534653539376661363737343865663633316138663061643866 31623166356134343833313736623738303837303332346361316532633434666266386661326337
65393930386162393663303135396237623633656230303036646431633236376465633835336364 64396633373537656135373938663433333230353632366538356135666139363232613664356436
63643332616433303766396561386433363836343836663430636530616135653966336131383533 36346363343638303764623931373263613461303266323766646434626336313933303237353538
64613933306165303564303835616132613839636432653137356131343732343736313237356436 35643165666232653831356530313330633831323461303165623436343861656431313266333662
35663033353163346363366635333231366432316434306362616265653832313963303338343538 31313461663438643062376262343365633534323837336434616431656131626530666637666432
61363966306162323932393037626335613133363936393166626433653463363661343732306465 63383461303562633063343863633832313530373334303234363366363966303866303138316131
32373839653865326333613165353461613531383666323938653034623936303562363331643363 32363034653836633636393864643966333032323830376465663937386238666539373733333838
37326164323935626239396239646465616464613332636662353539363233343032616636613237 38363964363135343764353432383736656561653164396361393337616335633635316536326333
62316663643134663038626535663262336266646565336236643234663561313264626238313136 36376164653565646138356433656639343938643039326165366461643230393364396439666266
65383364643537393436666465653437653334663934333765626233303835643732373334663639 62346163653531383934666562613563633163613239646265623236356132653230303032376364
62643064383535366630306666383365353963306563323533653664643132383832346435323465 37323532303666333964346132613262653236313239623531613933383362623233366632313736
30326466623265326437383063353833383131393166313231633032333137326563633734636263 39313162303930383637663237636237633539663763623661326530656132633233346361663136
61623466613436393237656435623335623133343032333535373430633836346566353039646238 34316462666661343839333634666130346662623136656536366661306433306134323163323561
34363338343065323765313466306130643462303061336265623833343139353336383234366362 31626264623939313033623738313265626637353837613735343166306233333837613336353639
30383465376635356462313533643961613437333930396134626463383464323661396431643234 61356461656561383565623965353738643033333637613039353838623337336138343937613663
30353737396262653336376137646137353362353066366634613034313938613234323931333365 64376163623562633135366563623533383466656234333535393030323631343163643363623463
39323733613864346132633461323563396161643738333634316564353934376537353663386636 35303131383937643632656434366339616266653134656163633661623330666637656335666335
36373335343439643432396266386665396266643063616331666438363066643162356265373732 61373362626463323131666231326636343866336337626637306465613463666335366431373339
31616537656266363866656133316663383634343735616266653161613139636164653566303666 32343136353463336164363664333861326465363334616530643234353165353235653665633135
35396566653136343038636239626561303966346636333635363836366538616233386164316633 64656163333462366437616337343438623835313139623839626237323433303861323963333937
30626135303434636335623366383566366532313937313133313664313462316438323964376130 64323437623630613136646161303363313033316634666531323534383363366232313166343433
61363166306232363737616432316666623166313962366462656464626537323538316337626635 61373832623464653865323364623837303637303234646462633336316630303766633733653131
64366533383264356430343066373664646534396538306335333861356237346164373235643239 35393834336166323334663033613938616232656134313735373434353263306130363130613966
31633264396338303061376633376564356231336338376135386639393031656437363662613861 34626130646534623864316630383235303263626462343732646633303764366234303135383638
33373934313862396238353863663530633337383633623565623937623734616664626534383061 38363362623137623532663365333563363138306336336537623236613766383861313865376131
34353862393537633932393338653265353633643166383564363766636539636334643534333736 61626231663930303162653334666231366435356231303730666664613737303961316163633339
62666332313730666661303462656162303338326433393934313536326365663235346263313330 34393730633966323565343039626231303736313836346237386662653537613132383962643035
34623539383031653538333762396361336235643936386366323235346162326635393062646263 62363233663366383365616632316161386531646230346331343162663537393033646330376538
36343638613134353966363261613632313963363236326364366133353838616636323138316561 37636234633136633363626634303662663765643664623432636530386364663961353330336164
63356237663864333334343461396364656231333939636264343966343266346430363965633764 63306339386364623331663930373335623766306536353663643130613731323261616339616661
38636562626366636438343538666632643964393463353836323536333961613961613166373963 33373138623333633962386161333166393466643565306564326234653165353362313038326538
62356336396536613238353531616237616334616231363836616561333866643033666336336439 62353136663533336361323966633737376133366338396431333435323261363035393561316136
65646362393933306534326137396561346338336263383134383263373836323034653932646463 36323738646138363861636439316531646235396466316138366266316361356664353533346630
62326364336438623137623862386438396164643432333135346462363761333437653532373361 61633538353661646437633433313463326332613261643536386666656637376163393266376530
32306161313238363365633131663334376135613336363937313263663537313733313762656134 65323834393131643731333863623134613638633235333064653238383363653432363736396462
33613838326137343061306431363237373661333163373739326339303732623131393633646565 38393939383139326362623937643364303833663861383130323235313865653831656133613439
38663963663338623362653364343337383636323730306431313830316261666264326464303235 63303533613065626434663066643531306139626133636532633932633037323536373439613461
64313662326434646366386166396464653666323735323931343436653763363535396636613938 61353234356162363936313065636136653636663437663536613563656333353039323863623861
37386435303139663965623963383861353030626530653061636132326233373165613231316232 61393630363237653963323534316130333363663561376133323039326137323766636161653831
38616539303630316565366161383664316337333665323631663430363764313736643934623638 65663937663434333337393863323134386638613435656130396366636139333130353334313762
35346264666461623533623963306238613530633034333662653561353030646437346537623065 63326661373932653561373635633332366332306133626133303066376137633531656562313835
37376263366630666430383833373966353730396239626133333330306232643037643231336433 30393266393161643836326664343731633935356264356136313362386535376466343333656264
62653332623461653565376531386464353237383665323538363061633831353534656366333933 64383663346365373830393333313735623536383732363037616231653164306337323832633661
37373235376564613665303462393634623836663835383738356138323136316432663637353434 37663437653763373563396465333836613964343536636564343665313534616230613162303338
36336338623364383334363565643334613631386330633466396336336539383762383162363631 66303337663361643635663639633832386263663539303361343934613864396534653135353766
32393230623938623433333632663365313165306165643433643131366237366131616263333465 33373862643332356530303964623839663732663536656134316262346334623361653266323263
38333739636234326139393361386131383232373362343636653862356535613230343232333365 31636133356635623166306463306637383333383235323334373736656262393661323564656166
30316261623036373531383238373164313961386532393663643736363131623533373366613565 36666161326436396133336662633465636532633262616132366162346365653433623639323830
37653133383930663037363232353032616133653763306564383434366233613066373331363162 61366466636165303563323738333831373931346563366561333235343539313930396637616461
61366530303731333235313537366436363237303561336232663363396562313735613461363331 61633561636136613665386162646130663864316238356130313931376238353234633137383734
30336561643035336430643666643565653538616536646263303265663739653132353233343834 36343231333266393030333630663863373663386333353039643661353861316366666339366634
36613332313430313138636464393139316466373738313330383762623963376363663839386366 66306334653339303762666135353032643034633739373330333830366436666138343738343534
36636265383436643661653465383561306663303461633335373331323733663936373334353164 64333137303963373438336361663136623064363665343835316661623831396532376362366134
35353138306233626363616636633236643130373432636161646563333937623334636163653637 34386463666532616131643331643436613630353561346430383736616437336466663232616165
31613431363963396266303637363833303635376239356337613935636165326265303166383062 32303434373035323235666564343136333161323839363361326162626465653736306332396530
32326165636331356466363766643766363266666530363739383535623863393135663331623737 33303637616637663566313665356335326266616534613234343839326138393664393062336430
61303261313563643665626435343362656632363263656235316230646135616163346630363335 36626533666137336366613761356438616136643436326437633936663961613434646263336439
36633564383761346163383166326562313464316362613531633565646365326538356565386630 34383538353063616464303931633561323834623761373763343962343663653265613030663036
35396334353834343733643931376261336435373362386339353138386435663961623064343438 32393538626530373838653934626333336161383235333265636665336638353839623061336133
34633639383037653437653461346563373733663536313862386262393933623434313163313136 30643439396638343261613831326131363837366462333031626666623031346236643437386532
64333531656462353966353362646636353634646433333361633166653338373938326639343732 35376133323462336262613563653830396461626362343861333139353038313966636363323836
30313163613532633163663965393434393735383730653430663762336262393564303263643935 65326466653365666338613566323461376333393162366638313733663631353933343962623737
32313564393835353762363662373631643430393938643265393462643864633465643636306664 38323365373263643138393339323937313864356131313032613463306135336134366230346339
32363936303737363934373536383136613636323538363565306563653438343961373566363463 31363966306339383264346464646361306463333031626534346662396336336338616563616338
34323338636161316537383036643638366430303964376435356164333666313833303264666464 37626434366161656238646433323133653430626564616336613461363661633138663932653038
64383766356630313130626235663364653730666638363336353938323735356434336539383132 30646435313436303937643730336434373666386163383439623338393862623838356537393836
61633334383661613039373136613735306662633734346538663838653132343066313166333834 65626165373363653638633164653761353265366461316239383732633837306636343137623962
33386533306466613037383636636432363435616266373664636631623264396538626366616164 33396435343837326338336538646534613131346463393862623234643363323030373164623533
63363831616562653034666231386365666639343330303964313165616462623865663266326531 61316466336132343433346538623761616535306564306566396339393830353235323735343463
38306337376133613932656631393532613431323964643532386234303335643731373265643536 64336462313630303631393839383833323337326337333166383431306638626166313064336336
39336233363530313533663163616462333466656364666262313132636633613863343766656465 39366163613634343933343462393932643666326434336666636262656633393762653536623838
38393339386335623234646437393061366230643432636163306432633365356330306234396530 61353438343165633038363135613665663531646261393534353938653262303763663166643737
37346466333961383538356236303630353131376330613437656536393766383062323235643465 62653935393338663065396462616534326237396434333566396466643238393734313036613532
38663034393633383661363632386431343364333664396530323066306365366539366336333265 61336663393537303031316161363165626661366166616333333761376532306462396463393932
34343865633834333564343237336661613437363333373032393661633034643161623461306362 35633266303665343836626335653238313065336435383634383566643162653337613531636165
33613663613966636235333664313731333064613033613639656232626365366461373535376532 64616635373533616230656335366131623262396163393561346432636363356132636339393861
37613365393237333037653730323432386162616165663335653565666565656438373337376232 65303735333935663232393162653739353964666164343434643737666538316633383930663232
35663933646636336535653431613337313562386137363137616561346435636562656337653265 63303230373233383261633863393638343562343831323834383163616333393762613265333961
62396430663033373234366535633838306335306263616561323438343736326664653436663432 61333032366433613032373263643662653066316162663438666666633430373135653738303763
61396237383030316436306130663039623963343362326465333933373061643165353465383761 62363139316638363463646631656266363333613966333365353666393233623336376338393931
66336433356538313761616663363438316165653763306431353139656361346631336538343936 66353438633435313061336435326336313734656230363061303530383937373965356563326462
37643363363662626362643333613431363032323938396365373337643235353333393232373862 31386661656533303861366333313939303337636264373432343466396633623533323662346536
38316664383838623836343938663231623237306566353036633265316361636565366134646562 39373865613639336265663862653735666239616331363531393138623763326363656437313963
61383161313664633736613463393035363637633836636634363231326230613437663438343362 65393934366430626464633632323738336636376533333963343536616135366131383934376138
64313362653131316433303561366536373436383865333138376663353035343731363934633537 36303562326463373261333538313135366435376138313539316236643334356636373063663930
37663832316265356535643561623435336563663362663766306662326564383865373565333134 62366534643333326362613163356532616266313436626162643132303266353962396365666162
37343035363763373236656239376665663536366131306439643331663731656234386432653665 66386231393161343561393864633566656361333439336663333763363339613439383231346236
30393632653939393564363634373334623865626231653639356633653136363630306539356361 63323635656635353135363535613134383465363331343730646239343936376333353636616639
34396238393339616333393734633835626463353932616262383263336439366262303966333666 63313439346262306634316236383138346166336365393531393930306139306637313831316666
39666536363537633030393730343037623265643438313166333064303635663430323435383438 37636133643839356366363532333466336438643739636136656338653533616231626431613439
31313364336662363365303262653566303830633930666639656234373037366238643431626562 37643565333863383633656233326432636662386437663731373564616135663661313265373430
31373137663434366564373833656233636165636636653738383035393936343063303761353265 65303830313161366437633233326136303330373163343736333835333736643035623062656136
66393938643238393338343930363233326463643237633137393566316438393266613731346162 66383436313165626234326438656665303831386563656330336332653130633964626633623764
39393630316164613139393436316533333632366638663437366266323837633937613539643434 30393933643362653039386332366463633363353834363866343061343236663738613061613739
38316132306333633666633433623565323463636664336536616266306262653064363931316165 39623736393364383635373964323163353338613466663366333631383531333736313265656566
34383233343964326363363235343165653339653162326161323932373631353665353164653731 31313537343039333164326232333166613238626533363832323732333261323864333532383737
34333665313065306439393431336632356536646334376562646232353938313836313735616238 63393664303362636662643130373565356364386362386261626431306631326633373230636531
63623765313564353463653133333536343937663165396463303531616365616363383938313939 35386134326435326539663138343532646533623130363163343164356461366662303833353732
37373530363830386338393661306261616432363737303236613232616232643666653464613937 65653638613437653835653139636563313263656464373166373163633861333761326562313436
35313631616166386330653730653062646234333432336135316235356166343139316538353337 32656130313938663433646265656566646434656337376136383837313263396537346130343536
38663265633166383563623561656632386364663365326662323036316436386639663761323861 31343466356463316338393862643063653331363434646563653238316532343764636538393461
33313937343632626561663233323862636335373930366233326163623831363765643236666463 38666365306532643437333164383661313365363831376233646165656633633236313962643233
65386234646363313039646266636435366462383266396337383439623437306166663536363966 33313763623430336132363639663734363762643732383866373762393533336162666361326638
34333762366161373531633036356139646338363031366561363863393830353336343337363664 64633231623338383633386636343338643138343362636636393239373231643031663865613331
32366263343464663338306562636664333035616165363538333764616139663063326232326664 62646366353439653465616337346363373736616137306339663433303234626536323633633233
63623264303965353632303230653636313162373061396436643064353632323731633435623232 65623131343039613366346665393235626364333063663830393436333633626464326465353832
63313263616339613065313138613032626635646236353462306263376638643966313332393939 30663561306138333831313033396165313063613063626563326562316636393036666638656134
36643637653261663830313564316364643832383330353165613666333733646138633432633763 30306665393137373865663161323435366365393731303764353539656266653035643964373462
61633431396432313863343466306266666133646266336536646635666631613633346430633539 37326639613161373436663335356666323964383737623133623962666138373465346462623635
63313964353937386636626532303532353133366237383566393061326265316163613665326131 30353664336664353539346264363563383330363964316332663734613566363035383735633333
38613232366132313762393436646265326361323736643338623035323336326539616432386630 33613830343633343631313362393037646564636333316231346166393935343739323962633636
65346333643936343835376364626539303265313239376338653835343232646362656366646264 39623063613631383561363030666131636437326537346333653739363434656334383638343635
61626463363665363737323331356361616364626565333561303836313966323461663438333933 33343763363234323137396239653239386533613263366565343865616131666331376465666562
65643533346362626137363762363663383761353364363164393062383830383931653262383564 32383130636462363861326264376362626264393666393366346165633131643734366130313334
35333532646661623731663938656339323739663964666238653963323232666664313237363137 37666336376433313833336131623234306631363832343039613333666134396461636565353432
38626438313265336263626365643763393532613831343763393130343766663335343431613038 37633633616464373639343064613635643466306661306535373935643563623163306336376637
31393938303162346236303635306239613335656338643362376539346335373130323935393133 33313638303436336537663463373535663133356362643763643430313462383538383939393133
62356533393363626139323632663865373837306337393433353963396231643937373762653837 33336632633835346139373731626430626561316366363665353039353134386265323634623861
38306331656262343832333136333536383035323532383766383538653831386531353936363936 65653837393465666230346437336538623765393131656638323238616537326432326531323166
66623762663266663135373165303233646262653465633930373832383364386263383831366461 38363530343335643637666262363763326466376265656534636135376135336563343735306162
32643533386438613533326566336538633632313331396535326562336263646334336362346634 31646231303932616439306666396537316161633032636638653238616637353738373539616664
30366562623663313638356233633433306564303065316337323862663533366366353230373434 66666661633137306331366230616531336461353963623934313635356338633030376461636261
64656437626135633932616230333339373934613666383565626535663939313930373230313130 61316561633366386661383666393961646264396537383439626262373833343036663365393339
39333434643834356634383133383533396264663831383736326162323431393464613736616539 36383862656331643035303635303935346366383534663563653237386435306439653931353566
38326533623734353937373135386664613635636264383130346263326462303531316232386131 63383964353666616433353833626132626362383065306561393539666637653834646633663865
30663833633738363533333662376461313331636230346538313764633135303331613039316363 33346365333262633362326537646633383031313536626462666363373236313663313264636335
34623937386336646339373366663563626430343866303239363661313634636333616232336438 39396330376366636339313133666437393833316161663264373265633962636338306534626335
66616132363337393334646333623737336633303331393030326561613835613164303965393932 38663962303130646239653439626366326661646239333235336635346131376264303562336130
65313665303932373331656434353634343561353236643932623464393566333037386334363066 31663165313665356639613937323165616631656535353564366265316637373135353366623332
39373163313838663163323666636337663161343664646661616438393333363365363065353732 39383333356636323763623630616562633364623638666665663831336665323031343037623930
61666666666563626432383639393038633233663561303561353238613832373633653436316366 36643762646139356661386262373134386431643536663038636236623636633364666333383135
65333030623565336266646563333336373339616231366334316336666463633964323630373634 33613638613261316333333033386461386332303363303138313031666264623039393935633731
34346131626466316163366362326265613363333933336463623961306637353639346537316336 32323937356639343834656465303938623338356633393233353630653039346534643366346535
63383561353339393963396339663738333765663934383038313631363733356562373935333765 62353134643563323966326434353764366436653036623161356239326162343966356164613533
38663735636562336564636235306135666530303762623331663931366163363734316539333734 35626138633537376637376334396535643132336631636137653666363264306166333733393831
33303638643166303165653062396231613862313165373564626432313961643835383038316437 32373563366135336463613734623565666365383266613931656238333631303530363965643938
35653639656362633631336635363035633635623035653439353561343739626637656566333065 39396330326339336336313236336432396262643066396133633036653938613133616531393036
61626536366535376237366664646534383534323331633035326632656132646364363133636133 35323265323966386465663331613062313763663131643663346465623031626662646133333734
65643065383337356136633534383033396563353034383462386230623261636337303537646463 64616131633665653135666562373666333362306233323539393234303866396333646536363238
38356538356434393864303563336563343566306638353138656561663930316230353433386362 31363633363431616263376339376238313162363437376530653366626439333364623764373864
61643561383739366362666633616365343235393363623035316263313738633662323961613931 30333832383532613836376361663934313561373733343166383266616236643034616662313933
35393234373730616133316462363661663866323466333839656462636133613936643137653833 65366637656338653437616166396637323633386334613461363062386630316135366433323935
62333030343861356365616339363134353463656162616636303430356136363638313861313637 31326232323361366563343039663837366337373862353833613336336633636635616565653164
37613731663639633865353332653835316631663364646139623631613138633162366432333532 30316531663432353238663037323866393766373866353766663434633937303032653362323664
30306432653133333637623631626165633537623265313237323532303566383334633337306564 30653334393439363638623539363337666161393532363933653961323662343761313430616538
31643163633934633161316663336334316237353735313063376436393166313033313665366265 35646563373563363761663635646338383566363731363264653330663635386232613565613264
35363864386265386139353735663238366663396366653164613833383336653230383763316134 33306266346361356632326332306534643865323032346330663966333964313535383261316161
37386633376538366633343963303339323338303263343862396631613733336261356536396264 61633535303739343763333031353736643664323731363839353934326132656364366566343462
37623236383565323331306531316563356238316237636631613736316437643965613634666437 30356631313636616165623662356162643261646139373366333433623661313164316664653539
32366661346466353261336130363233613036633863303161303931346462633763353038363136 66373137666130666535356435353738663133353864323537396433346261373131383764373863
36363762353231373933616265643039666237333334326134396531643463336238303862313465 62373836333962333665376539356632383361353561616334653139666363643937633837353839
62346431336663633661303034376165643539323061653363613635343761326363616139313933 36653034333930326135363565363662313731383135636231343666666536363934623034396131
64613430353539376131653439346337353733663830306333373966393162366235393364336532 31323166323763326231333063656139333730373030653631323365343637343536303365643965
38613936303965646231323138643464636133393037363538373562396230363434386230363934 66623733656165333030643139646439343030666633366534396337663236623763376232346465
30656361323137326335316536663231376536646565643363323462363165633139346535313733 39333839336538646262383034646335323066613231353731666132313734663637396563373332
61666434643537363135613862656462653732306665623037363638613832323530653836643137 34663462306565393934383436363865343932613336396238313231323636303765646164356565
37323233316131343039643137333532653165316137303032373635346539656635363265396565 65663463636331633336626438656334393366343338383564383231353364316361386265666566
34663263396265383532306264376430313237616438383639313863663664393066643565623636 63376464656263336461333661383333306566663130363939323131316663633662653738306366
30376136373833653462646561396238356638336432376630306465333133623538636333623961 35626361376163393864653332326463653564373563396531643532343766366261653332313131
33316263373862643166623030316239383433313365313439386534336532653436633034643938 33613463313136336434303039356662313233366137633062636232346365366361636633316565
34613737333933303934653635636239363332376436303063643566663536353266303363626539 34363562613265643437383033393062663165313536366634303661303533663862363234313839
64393737383037383336373663383163303538343438306361656164356563653236383563633735 30613032666164313231633837343532306331366437376530633364656531633534643335616364
61376362303866646130666234616362323830643238353433613831353635373636306363623262 31653764646236656637373036656532366631363164346262353034336564373233626263383333
65393266313430653133316639326330383936303566613534316366613637623465643739323234 37343166653865306565383036333032653335353161626630376436626363663065343336653936
36646138353135666265646137653138656262303864653839333839633336643466343066653865 30613339393064393532643862333530656432343631353766353338363464626535366164666661
31323538353566663638316136653438353835613137653364393032383935396134333030623831 33366634383339666135613430333832316262376162336530343363663666386431653232616664
66333431326362303038343032316436356237373932316531313437613762636238663364356535 30653637353432376132316561373031373330373266333731393338613635653466343464313334
30393931613231303936366436316438396535303561393538633465623064623039386430393230 63636435646466393766653135333037623638356630636239303564353337323135613233336461
31336630663839336364336332623165613763303331383830663161613966623530323266396531 30383537326139343538643633326331366531353732643730326465363566623265303030376534
39393931363365366334643231363732646631626533653636373364393463333661653833653964 34313635346134636337623737633838336239643938316264616435303935363036323339316466
35656361623463396664306134313365333664616436313761313837363038343632373032356163 66653238613463353964383231366563316666376237333631393435666133343636666435643535
66653030393665626264663761313266383362393565633864636436326238343836383066363438 38373635363134346636333563653063656537646331316264626139323631383039303564376461
66656164373936663732333565313466366631336464316335663361663563363765333938653437 32663633623538636232306532623261633563376562366133366665633862313431323032643666
63346563356234333936666437396462613262633834333938343635613761396632633462633837 65363362363065626536653430653562316539396264633865346233343430613333303865636139
64303563376431643930343366626336656238616162366566613166623637656533653263383832 66656632363564363739306666316666346239336432363762373730353637333465363337653466
66643465626636303136383235383739393265313964373238393563613438346132383566353061 62313765336130356532636261366232666462616464383439366334646364383861616166383836
39393334643839613538343966383736646664373363373234376639636637326639383734313562 33346162613132656262663062383962323637333332373062323936313365323864326439373565
32306163326563366534303862386638643534636162353235626438373237343135376339663164 64386235633531663366376332353866366333643736663833396361633836353061323333656132
37313836313863646539396231353864623733396163636136313864613030326534663430633062 36363761353566643432363634323861356534393664373761383565306436303239613532623337
62373238313435346637623334623631343339323131643363383863323530333236313632653364 66366666613932356138636230306434396365356338343437643534343634313432643238353234
38346165396336623838623630336264313565396436646536393237646163333338346338653438 63393338303961353264613666346339396439313838633431366134613931666565333263316632
34396537373535616339626164356635333837623234316630373333646333343034376336383739 37636365616532656339303963633135613830356130376463336335633331333065336538643963
62346366383134626162376134643738623965653963303334353936613665313061653661616438 34616565353630393932393231646433666363356134623363323462386136353139363931326237
37643032393033313265396536353433323735613766326164323461623238316335623131343932 66336637643530616630656231316662356138336266363434363463306236623462303764643162
31313763303235366436613939366634646434326233303637653235323539626264306238353733 31306634313630663530666464303337386664666361633539383531346533626335333939353432
63383666636464313064623736316466323539376365376134663763343530333839313165643432 35316664303938656436363631666465336561626431616663646239313938623961626230366533
36663238333231306134313866303332623134323631646330373563656431363537323861353632 31373961373332313264616433316366626464323462326462613736643137633031646536353766
30306334366131633865633366353666306238326537633461323965303437656538643136386262 66383465376262393133663931663835656236313334656563386266396237363963663430356137
61386162626633343266666338363563663965643761636462663333373539396634313766323139 31383563616165356539356530353566383431656163663130343865623639306165306531363966
65653564333531373561393239343036616238363162633462353962393336396530383430353265 33626638353532643063656132326239363166336334356236313334646538306162386530666131
38373539613339313964356166666630376130313830356137326465653166633135346262613839 33333935653933643331363636623738366263643162396131616364333963323534333263373439
34623038396635373936333535343330623338663235653137393335346536343331383034666139 38396231636532663934326465376161626565333732353037306131343763343162636539373763
61333965386132666439616639623165663034383633303136393730396232336139306664663233 30656135383263653238623062373231636436613733373131646433616336396531316230373937
61613731646538633265323439666535346636333531326230366238653331303830646131343430 39383231386438316432373035626639343266633335653835656262643433393434373333643863
61383735386361356262326632663666383162316232393338363633323463613732623064623232 36303833396363663430393164666439316465313662343162323435653632663737326435356239
39623231643734363937623134336632623562356531333635633031636536383362343634373461 38646531613439633737326539383361356237336561373264663838313535396236373033343535
35633665383130636336363364616466346462663962376164336331663165316661393934396136 35303234656666663766323261613739623930396239636639393936653537383432613165636137
36623836636438373761376338303534353832653433396266376638636231616631356262323736 34613964313136323430383564326265386135316339323962633830373931613037303436633361
36383466643661363062373062663039333566633763316334626334373663633062376335663461 62366438313738633263343833303237383239333534656538393432666332376461326631303637
61316564303432333730333638303566313132646636643639626131343165663063333838333635 30613037666237366666616163303662346230633131393938643636383636313436616539633337
36663139643730333630633766383132396636666632366164346537363732353830613939663262 63363332333662303761396339313766383132373831346266323234313338343430656136643638
66623433633434646432313138643639366265396333626564623562323865616261663064363630 66633964636337353736373464376631306139663539333464303438616334306666623061346537
66313134356536646633366262356331336134366265316166633831653434646232333730356661 33356665666661356363383066376665386266363434636262643430626130323163306634306633
66663431653363666639333632366261613764393665393535373934616433653834646361373438 37343735626361393036343566346230363137326563643666316630636139343865346430356131
36363164363932663463623161373736353233393934633537613932333732376436623031303962 61643535396264663336663866653762336330396135666162303665643733653630346565623236
30643830353665616636663066306536336236373064376530306135646234326131613130306433 35336630616531383931386430336238663963316237643765666534636264623533643930376637
62653463306332346530336130623633393636393762633230323063646237626130353335336563 37633031393532646362333733356165373431363330323863343362643231636361343862633666
65646538313634333535333564663337623233613238303638616263383764653230343661343065 35633834323137626137346230313662373166373039653532636163613231313737396262643364
30626533643465333733366430316162316134323431643166316631623965323334316263396131 38656465346336333965663463393963303136636131383432376465303463616564616631346139
64303932663464383131386239336166353363333664353031646462363862663165376565356562 33336535666133653563303039353737333162616239643261323333316334336335306230303037
65346539633036343031396662623233613739656633653430663737613662303331396230353038 32396339343137386632636636353730336464386537353530353563656464376532326133613933
62333333383462653138653162626333326466653631643634636135663232393437343332333964 33313734346132313066303538303761633333303564343262313636346238323236626566356535
38623062656633313762353438313839373935373964393938396536633233613161666166626139 34376232616335336539333662373563306637613232643732376635323036303666393737316139
66323363323039323666303934373631343737313866343665643131386431373336333630346261 34303663323064623863393262316533376263636332653964343235613338616137366461386132
65646666303633623166643635326165303838646532393663666266303536343634633533346664 39383837663538653533343663613963613066376432626464373061653139323139313937353031
31386264656165376264653266663332316536303665323239613630386233373565353763323739 34663961313435653263306263366366366632356236366162623239363336376166353137623136
31373232623735366563303731626163356537393034313962653263333831363632343561316337 37366434326539333535646339323738336238383835303163363334663737333135643564333763
33663430333836633061643566303638316133323361343931303331353234613065366133363931 61343236616530376335323537636666363537303130383064663666623461303339633564333836
33316564313939383137653330353935396532386563623939363336383537386639376262376561 33373031306639653063313063613763343332303861666533383239366463306538346566356466
31323837346166396332373735316230653531343166393539386364646461376265373564636637 65323161646264326330663164633239336562373564616131306330343765636339353237363134
65663430333564393861343261316562386564393836303834633638346638383633353164303438 36626462313962303132636463326534633035666335376133376131623863666563633066336537
34343463353538663431306332636166623066376135323261613735393837363666666465323866 65623264653066623566626534633662396163393438306239353864616565333531623939663961
63356530346532656131383835363133353938636630333231353964373765636162613062363937 63653461633565326463363165356664373164383631656131633663343336663137636561343363
32393461356530383531363131326164356562383762643832353037393931316666353331396437 61353339613033336462366131366565386338663435346462346136326634646134613234626666
37616230383338613931646135306539636335636238373065346236333966393631346266343737 64386465353962656532656631613735383664653932376334663262306230306130613936353732
37383135613133383763306531326436323233393231376165633538653036393833373538653030 36663538336634346531396438386437633038313830633164353664306533343837353332636530
61336331313430326638373138376661633731306165653661313766663134383163653731393934 30666231666532303437393264623030373461306266316335613465313531396436376563653932
63643438353663646539623935356635303236616231646431356262383233643333393531376534 63383764623635383634646163363435366430383864666632313437356135303934633662343366
65663437633761646564333366626335336534626362353964316236643066306439366565373735 32643834363937393162393666373361306332613233663564653633373935613661633131666432
30373965366137643363653533366430303965636631383664303239623938616135303030373962 66623931643436633964353433383264616462366235336266643630376532336566636632303038
65346635663562306566303236663563623036366465353739626564393839643530353033323737 65363838313539623132636464336632386164306632316230363136643038353135373635626164
66643665303132346566333866663736376637393966366263636462396637663461646434376566 33613239623438663832376137616530643762393666373063623734633164663961386666613137
61353464313337333938303866663036646566623032393036646431343739646436356632353361 36616638653038353235376138323666653866393035393937353631653532353734646663623932
39366262376235663139666631643734376461613862613838653062313466663266646139323831 39653162623833316262633033336363633030336561663231363730396535623738613834376636
37313961383638353139353635633133636561306361323065323733633532333235323031653930 35633434306438643937396532663364343661623134646239306362623432313930643333643834
39306534343635646135646337353161303737396266343135363938383664346338373730366531 35626231393431653238646635616161343733363662376638666166613835356236393135623439
32396533323264666433616330373232623330383762323263333432383066313838663931333838 31623465653532386438376235303036383434616135653438343431333832396563353066643161
30636230333235653238356633353030663136343462353530643531376234336161656361633438 65303361383437323032653033393663386338353164613137643662663231336332643639613530
64336361636437636236373532346131393431373537633663396534363764653563393064313665 34306535643161363064646432663961666537346464393530326665353237356134633162343839
36616266333938643061613361653532356133663431333435343634373564656531383035353632 31396466386335656236343639316136323536363231376632383364353236376339376535326164
38383863616133363937633937643062623831356232346238326236313536393738346263313530 36343334643433636238373363663435383966666133636164623863653232383064326237333234
35303865666530393330343936356131326164653765623031323535363266393265333232333464 38376435373066306462613935313735316232383364333733636261323835646237363262323862
36356536613264353962323665333238666638373637306431343566656532383735363863313366 39356465363132336235613465663762323230623133373237383961363936623763643430643235
61666465316437383934653534363766356635666364383036366664356534333465366530633365 31363931333964656539383739646234666433346663653965373833353633366566303864623863
62353134313939373666623966666335663031616563373931386564383039613833323434326238 63336330343666386135343730623432393934663532656565386531393762633734653438633461
66373132323762653031363763353831353336396137376364383138366264396134343262306133 65323366613334626134636631353631323238643138356164656461643866363061303062626433
34393865653666663035633637373661366463303335353031373431386161616437353161326638 64373662643532303266346333633366383133333339373865363137356632666232363039646538
32633339356434633363313030636464376535383534346436663634396636376630613634653635 61613130363763303563393735373761336164626432356664393063386162646233306166336563
61383734313234396666303136393633363536326265643863656562356239326536353632363764 31633739316662356630353938383861613964333661316237616533363530376230613464333265
32383663306139373532643037303365346336643331336331663630333136323437663930333366 38636133646235643438303163396132616537663630356635346332316364343966393131383931
34366162356435316436313663633936323931383832373465323537653436623237323666333737 31646536303761383866366366303131363634383062623731373434646430323237313730383531
35303962396266336633623563663064613934613837356563636330323431346334326234663433 61366533666162373962326132396166326564623464646136653730326430623631363762396231
31313665653836616631653661626162613032313737373939323232386635393533363962373966 61343333613162373865353165663331336232656139633766356239343162326664313639363135
61396639366131323131623436633439363234333032636137646230656463306265333334393736 39613639373736346531656636646136323237646232343139323164323665363664363665316630
32323262643066306631316336356461633764646664653339626162366366353566373565653635 30373164333166346437323661646463323032336265656339656336306431636537363433363533
63363438396264666565383164363639303637646330333064363762393731613133633934666131 34636464353332663138313132363739353065336564333532366634646238303435646237303533
65323932373235373863623434373439343661396137656564396663653336396633393331663032 61616231333832623036326133316534343566323134376461623338653836346435366433346438
65363432373338313137356666623338303064393232636535356262383038323166393235653338 39366563336436333466636433396230663136306666393334313039656365316264313561613863
63613536626365666437376638633665626531366330313230663135353538303232356366326161 32656238373536343132333135653131643936666231393165643662616434623532393638363666
64303863643030316564643262303664653463653463393461313538343464313638653461643966 34346634326631373739313463356632396366653161616461333432303333363265373561613266
61653733343339613864666665373033353062363165376530323362663763306132336230396533 30316264366465643633323237393562373963396135616465356533653464333536383935663738
64373762626263626638643763336635616364323561633536326165326466393736333836376462 62353537663663363862303038306461363364353133303533663732356366323631363138383632
37303365396539376538663866633761313136326563623365373739373439393630376262373138 62613662616538326435353534373865373231393833633566333534306231363734356435633835
35663064636561626434313035346131633530326431653664373036356464313435333333386438 36343962363739343235373834656135386662326136396331333964306633623931646539313232
34396166643435663734363434316436386637643836313438333731323261303737653932666664 33663162306462333562613632666431316330396630393165633530333737356635323633623430
62313761383832373235353239313830326635633430313762656265313838623163366637633736 64653231663665646436656263323032353530613731336331383131643937623333656138646664
30316230353338626561393763663932663666613331653834346131343434663232623434353838 35366638333562373431663038643331346634316431646130663666643464343037373266353966
66396262383937353530366163313532343731353338633065393632353264343136386538616334 34663736333839333835383437363562326436363962313066613864663665373438353932316330
31383365666534303564616364343464313233643932326539313738386131646535316638396133 62373066373634346434616234376535306133386331663438613061623965383333323364663664
35636339396339323765336137626438643631653963333362356438663531626634633336303733 32336438376262376331663565643466396237323362386261643162633636316138306331343764
34626138336238323063623536333837336666613630626462636661353962303330323134326231 39356361396535373961613930623030353766666133633738366263643830343463633563626462
66396665383033386634373766383461616334383130356337323763353130653732333136303166 30373839373862323164313265316139336364633836356534623835653633646439346436663966
32303364616239616439336639633233666230396334666531643464653433333532313737363835 30343137353765653239626265356338653031633166313432353865373530373437643531333339
63623737383830646334643039643739636235333963643163336464373133333731633765393764 32613636336333373239336230326639663466383466393930336161376663386534393866396161
66616236346430323464393739326364333735663937643737356631393766623734636262336266 61306563373637653962393233663130326535373737396361633236363239633333393838316633
31376535613266613362313363666262383837663533316636323262316364633461656262363762 34656435366662366666313632333739353962343132343265363962343236636439663866623961
39613635343165326164646636343431623230353561363566666636656237373363646230363435 32323935363538313531376637356636623666346535313939626333386564323765303961343961
64343435633039336337313562353638363664373137396366303839303766316230323861396331 35306234333738386266343333373733326634666362396432323561613437306533333536323337
36346230353163336538303961626261383031366330613636323263346139356339616537393236 38626439626338376536343439343431356338353264633661613035393636633863303133616464
30306537663861323931323536373833643330313338363435383461383330656266613439333262 35353861653463386634313437323639633965323432636164343862353030323033386566623963
39643930313537386538323436636134643639656265336137666663666637363135643137333063 32303962353632326239613537623834373534356238633433633131313763353662353036333132
63346133313066643566643432356537383532326163356437386363353965303737656261656132 34613236316331373937666631386462653539623135656533386164613064383666346239356635
63386338643565383033353832663634633736323432336561383763356239303936333038396639 65666164386635346166383963366135623934336636613963393862656131396466386335616161
33616364346165323962313033666335323233343462353434663832386561376339666366393161 63633334386665666165643664363065396665353061323063613635643864313330643433313661
62656532636238613264643833336264616634623236643534363565303531656131646263613830 36616632633037323338636630643037643334613236653137343530653032326335306238323766
30323161623864386130316431313435383637316337333032633035303564636534326634646565 62356266656235333434396435646332363639356163363365623136306432643131663131386139
32333465303061626536303231386434363033636665366339376432376432383134353938663331 39666137313563373462653638646230643762393962373963623161366233393462343036373738
31323633386631383038376438313761323839646139616564383734366534376134366330336166 63636464393263356331663030646433663737323233646461323963383335363962616337373934
32323430663335653335376637313065383731383936663765303664356661636366616136656535 39623865623835623163323164626162393038303931343036383738306463643431383364663564
65346637313766326233376232646137313839616339636161613066653133613230623838326662 36623563363363326665303731643531666434323338373935643736306138666665313035306136
62313037393231643966353638316164333563343264616563633365333437356133373336386561 37666230373034333261643431333262646238396436346366383063616531653961623834346336
65323665356463326537326239396339613839306131656538323066656134333833656539623462 30306336323665366131323462626330343136346334343435313630653135333637383731613963
61386263646434636236643534636464363731656566383831656635336437363962306263633233 66636537386336313235386234356238306361623962363263313039393362353665346664363637
36646263636638396461313138306563656565613336356132393532626161343863633239636438 63646433393464623663653431323133393235313834646266396265343633663732396638363532
30393663323562623764663638646431336265303764356233323566613934306132333735623962 63663336653638643638336566383239303563393764303065636138376336623166356634396432
36626462343039313765333535633835303664393664366635393264373139346639636537313038 64353763386230626566646634316437383963653462346435336536363462333038303966663931
30383133376361303336363239653931653436663630666665383161333138346239616338313338 38613732306431323937393336386133396362323939356330363132653736373433373834663433
33343138666263623534396239633462383936646564313833373435346432323532336466373937 66366333613263396131396434386565333065623335353661363336373530393934646630306337
64386537653332646439643764643563393738323565346630616432316164663161313337366531 62623062633038316530303865373662323332353065386430643530383335316565356135373666
38396564386635323466386339613765326638333532623639303136656331633038336539393062 32323731663461303138613064346138613333353534376232303538323132313039386264323732
66613035306632373562666466306336353333333039346134383263313834666434313237376530 61653033356337653735323330303462303439666464393262623062663736626661306139303837
64373539383166363864366531323333323565366465383937333732613437366264396532616433 34663330313539336663363830363963613561336664633330326265343333653839663462353230
37623438653438656162626666343033346638636564653061396562343564626535616233353334 39373938626266616239643939353937303635343661346535663564616136386337633533376137
63373565383039383737333534663637666231323132313162373436666362383963303162373835 61636135393836643764633838633361393230303730383932333564363739633137343930336331
62656434313463336462643764333735653166306265636638326131613736393230326634333135 63343937383763363436366335663763343534383963363266346637363437336635376566366230
36666633626235343630306637386164313562323439663037386166303430393065386238383434 36633535356239386238646136376431383061633939656663373735383235326663623365306438
35396664336331336561633232333934343832626230343935393433326430653632393562366532 64366433336638333235663437353463633937396136663764623166353864613162303832383566
37346235343762336430653733353235643831633230646135333761613832336234646262623865 38303664303962396362643631336536353264616335643332353137366431396464326635396634
34386230623338613764303536343533623432336332396665626131363364643465666639636664 38333038373933663236623632363431386337616566313765663633323163663933303337663938
32376461393532313839393766623463386537643733616161313330623739626533643562303262 32613133343730396666653461373161313139303063393639613932393864376337323363376332
37356339353836303235343762393838343363623331646464646163363363663638626433636230 66623266613962663066353335326230616438616562626337363965626564663666353064353530
38323038363931353830633737383865353934373238313634613961373566336639326131653335 61393934643933343132306265653235383430653837316365383265353565343762616135633866
32623238313339396261333531373437336266363964386237366663336164323566313864396337 64633766653133653335333061303233393038633665363566633238323530373239656661666161
35636566616462353565383731386236356230303333336431666633613264373331663430346434 64393262656162356665646661383861303765383232363639303065363061303332336562333732
36663166363430373534346236363332346562653463373261346331653032613436616637623936 31303363653136313732646362303838343838373533373338313838653633643136666631363638
63393663666230663835623835633936656538323739356231353563623939383463353330326464 31613738396463663931393064643132373564373837333337343832633837336663336262616665
38373531653537376637633436616335633866656163303937636438643162653231393963356537 63326134376538313466353333623633383861613534373534336464396261643233656130643765
63306630313635363637656665373337363232336135346230643765376631343734303766633764 31393631653630333233623339666535323031613939613835303764646161646132306635643161
66356236643338356631373832323863353866336333316333626232396463303466643434646232 37313361323165393034366365396139643233386637323734633463613931656238663537373562
65623838353539353962346661383865626532613930363330326334316565343330343538636434 37396265373364316561393433363635326365356338623038656439623539623139326235336632
33626433623361313430313361323966353732303035626366323835383631343634316634623562 32396264366634646330346232376636313038656164323134653866383864363864383965356666
39313166376365373638303338326263616566643566636361633332373862623037336163636366 65336363333035383637303934383533313663326431323637626133363338363538633634333035
31626365663862303563626130393266316237643266383139643864613134373734663238633639 34653961623933376534613239663037396432316237313137396339623239393635383966663164
33613761383431383463383037313139393833633761633635356538313635383166386639326362 65636266633439376135613832383634343633323366663833323533386239643762303638623738
36346662626139353837376565633633363964343665356632646232393433326437353532613365 35626335373135636261616138363739633134623738633966366139643365323264326239646636
34323666633131653233393062366637336630303662306634363262666439353964653436363534 37373231656436343431613830303662336138376437613938343439633534666563323930663938
64656238363036343164656434343262393936306230333639393932663233363062666264656361 65643036653265396237343164336365666337633361616433393561356537316438336331666365
64363233303636646138323662623532333063646339306635633039653931333865356535396665 63313964373235346534326639643264613539326366653938646663333365666538373530363064
38346362366165336339646162623739653433353966613762373534306634643530316538356433 63326431393130336165613632393662663563393066346562383534613833346661363933386135
65393034366562663466313432396431636462383239326438643437316361343561393234306338 63366636346539383636356662306162353161646132336630303739313866366434383464396136
37333664666132343263343763333137316564363963306663363265376263393964386630646636 39643163623433636164626563306138653265623563353262333831303438363739393762333464
66316334323439663630373131643330636266633032376236383564643138356337353566363966 32313664353563663364366636313366313639313134356332336562363864663862666632623832
31323662613461353336396637366636366336353763666264626431653935663332363930303633 66333236343136653439353066326434633032353139323563616666336239343730336530613761
64643862393963613936323838653661646464353662613430336535363833663161323764303036 62376231633237313732393835346665396634316263356630396463343137363936623064306461
34396130633438323566366566303932363937653536653638303931646535353239393738323337 39663935353463323565386333613464363438653237633666613261343833386336333261323561
31316237356531373034646565653138396536326339376135613935366130333061636135613164 33303662613239333362383661636235643861393734333463343464633930396434303562613034
62386134626234623734333339393763393536623964343032316666366632633863643839353530 36383130356635623665306362623235373364666137636336313066323933613836373431623635
63366631646535323133353235613338383864613265613562653861653138333066396134653833 30326465323366306566636637313631363963316566323039396430396139336234306330316465
30313237646466333139323037376564646161613131393232333233633863396536363038396165 34623339396136643938353066633036643837363562646539653533303035333562373436373031
66643163386337333666626261336537353461666331353162346330616332616330653936616439 30353438636430376265613038303633656230353934636163383465303363613936613236663366
62356635323036323363653566313764396566346533646437323932366134303830356331303730 63626637633432303463306666356562363065313335356530346539323961313035393865666633
63363933396337653239343163366236386162333032356465326237623563386234656339643536 36646332376238663166666264376132336637316561616532623534633430646139373532663138
38393636376536616638303637393537393465656563353232623435323730353561303830363434 66313066363435303864623866393462346137633730323066623337663335366461393632626138
64346532303834363338643838346163313963303638346239373936303335373039323636343534 38636635626365613561313334616230363936383231356465383439313138613136356462316634
62623563343361613166633465373966343534633864303564393766656465393964396237353464 63666131386339666464356533386333663562373733353434616666666639386365633732303737
30666532393332323162313464663931356335333263643332373431343036636536316435303765 30663364636336343362316135323236346639663939373365396561663766313362393838633737
66633161653136653038366162353538623563653237666131383163333636373035643062626236 36323835343731663235363234306332616336313035636235393038316438366538616162626634
36303837376161363762353964363239656565396666356462633864343833373237303362316161 36343836373966383538353034313264313732653635396233613835636461646231353365616163
35323931616535633166646163616535363863616237363238316264363733636230323864363530 35383835333466343934333065303538366361616436626338333137343332613965323964323836
32353533666339656464303234366562616332633434393736663631656434373730313165313062 66323665333461323864346635393636333163396334663264393337313863646139396664613163
63373939313332346235386566613537343339363365623836313835343165386133643837336161 30653637613864646631666364373162313939353339613732643637353635653665326164383261
31666139393664363765646233323965653831333435376565653132313861613565393833613463 30336135313766323933383232323630356139343934643863356434333663653830636561613731
34623338313765386331643235303361363033393438353432383963663133306465613530323434 65613861333639393434646436646131353563663864376564626439316261303161336336383739
64306364326261303433623062313261613532303333656136363536353066313630363633353938 32356635656637633066303638376436353261616232313065303431653036656235323337353933
63623566613262646531616332376333633934666337376638616231653939646661316264376531 39623930396239323766346362336131653137663533343133333937626535656236343639613363
37346436323339633839393665383735653465313538366262366538623462306439363730386666 62396338636336323531653564366133643866366432353566366661393263666164653630363738
66383736623636333139346434663933303766333130323333383536316333363165633762336235 65316562333131643966376634396335383131366233326231386432623364323235613635373635
34613638626161326165346662613433316164323533376265353261303535336431323065623964 35303931636466303130303233326531343539366238376363333138666234636532363965383239
32636265653736363763316430636133376539376361616631643965353732656336333835356536 62383734363734643165373734343963626538396237323530643333666131366365353538666662
38373933623063316135353762663735376533663065336233363133613833373464633365346339 37643939643661383138383638363431343330363931306162303963366230636364633066373537
36613530663735663735353264373966643134306464343431633963366337616239623135663361 39353462613265363439633961346331323864326536656536376534666534623936653231313263
61303532323564306266656537636264663739356235393535633139646131346662353437306138 30336232636434646666393566653164653834336563313236323965306663663431656239656163
63313239623832376362353632326563633562663265623534643032306562343535613035656162 66393136333937393863396531376561656538316164356265343532663262336539363662643962
31353862366233663535396134643433306338333638613737623161376334653631316236383532 61643031383037653964383661386238636633646232323565363162643239393330373263326432
66316364313637633732363935636266393364636635373061353132383866306330333734616562 30643561623733336234373962376239346663363537656462366134623563363762613462393333
64633132336634643034633834623536383631363933653463663364643262623565393461613735 34346431393136613866386338303066343463316233633933363636656630363638363264376263
31343962333461393431643233396561376365666337313961616338313736373439323433393061 38343564376564616665666432376336383833633765383263383137306235303934373230653862
34636665323331653731346566656164316163666131396431333063656634373433306262666437 34333233303037326432396365393339613261663266373465306635616435616363316563326436
62363939326131663035633264613861376131623332666533653666373262613035636437346461 38626532363862373832386335323335646462633138396162663134393036666166633337373638
66336362393935633862323631393163373633306334366434346434333664313732636337313165 36376562656434363835303336343638306538373733353062313530316363353161663732303836
31356132646265346537363761393462393630653239396535383164323739636632306531626531 63393363306336376564633462373265313539313130373434383539363462623131613862333936
63643536366464383831333663376136643435636361666266333035616530333832336163636436 62336630346133366264663665663431313437633762663530636266623935313766346233633438
32613437333336323332376238623336373465323937353130643232656238643334313332303465 36326164333839323562313930653038363262326539393932303237663563346664363032336630
32306539626632323062343230666636653566376530633263373964623364363234316264346462 38353530346166356231323062663666623961623835656265306561373332613937303739663965
31656665336165643831333039376163623332633634643961316635396533356531323134356162 61303765353437333465323165396438623838333635303164653764336633363633303935336264
36363731373337376265303261313737663235306164666532303539656565343462333034366530 33383934396630663564313163633466393861326330646461386536373336633135623030646266
66643165646461303235653435613266383034333664323165646238616236663339633361383565 37333134616531636135373063396330666538313736623563363432323936633163643162333466
31616438623866633664323037343238383663343936643636333361633666336638333262316531 31323739663931653235346235663832396437303932383066613633316362613563363530396463
36663139313466303736336331326666666638333938613031353439313765343530626537393933 64623363366237616632326531633932343231366430366633333633336462336634613033363830
38383863643337363038386135326463363736373434646434343035613063343738383965366434 36333661343765303336393263656231313739323038363038303436396130396335343539336561
63613038353065353538323130323163383763383030666335383066373536336166393666333763 65396532663637663234373431616536653661626665363634303265393931353232316236386433
37663861353636633464396532666434313363323838346235643364393039366566313264333538 63656266613965366439326630336533363166323935393230333930353166393465623438393830
30353962613263623838656336353134373564383864383130356664376531626137353064643562 39343332613462323437653865343333353338326636363735366462303766343433623136363739
33393261346662346538666130303138623765383166626537636363313138646536623436643666 35393630646537646333363931393764653036306261306633353463333939613837316265643961
39626461383038633461306431363364636364623333663766396365653732333433346664316139 62346234373039343066336534363065636339313031353264313537393063346566366263373339
39333961366433633238386335343934383134663133633030386133386433633261383332306163 65623539316635386532346435303631303030656262396535663433346138333963353732616562
34373536346335616265666666386364646461653433386239653730656635663665643233323630 32643334663139616439303639313333303064396563376361303933393437356664636331343631
39616336386238333830363465636437323762633833633938323731653538613636653239373333 33326565656632656638656331653435643433646533383036653264663232313730346331333139
30636464343262356165313932356666663765376136663065666433616639613539323237303238 33393238363165656137383130373137616132393366373930353161363232656532363936303038
61386637373130626265373336326531653631343339613938376136346262626362653237633164 34353463303666363730353235323034386230373333653263373238343863333233663261616431
61616636626563613738613964376561376262343837396430653438623066663937653032326530 34316135363537613762383036366333386165346361386165663939623639323535313237353365
33396334653131356337376638356664313333343366373139623766393736326438376130646564 63373135633538303232643065323232353434356365393464373963623066316138636661616632
63333230306139303238323235353061616666643764333864646365356135376638643038313037 34333332386432633933303465353564636361316435356163633765383833303437656535356130
66316636643165333739356530663962346135323431386535356161393239616231326432393439 62363863633433323231353932663534313166373734353837303861336162633438656237653137
38326163363938373330386262386664313761613631356430633861346631623765663062643865 31356330306236353432373431306631306561633264656663383266653266633661633237643461
61353937383533633638313138316466313863656136393666353730303434613031313731333534 34383566636162396234303233303534613461366466626135643336633635363037376638346338
31306361613234626332386339653162393734623536613638343164663963326532623133663732 65356334303633306536643966336561646531623633663664653461326237383331303232666666
37343336326133626132383465306266623132643861376564636461383132306561613635373135 33363765393334326130633634396163616639383339306137393364333233633539353263306663
65386432316133393134386334653633666330623039336335396433623530633765383732333635 38313866363737653932616339653230613830336132643361373933323466303038613831353066
6431363665353131633562626461643631353938376163613361 30653963343637326364363537343437376661303937316464656234636161313235613839346464
38386636336262356561623566343931626237653663353137633935653830383033393035666565
62626239333731623337616636386361376565663966613562383639303338643737333063333161
61613937393865393037313932363639343562303561653633343266353237356666663966633331
33333430636439313464373632396163326531636231623066396462373738653366646238636535
37343461323565376339376362356364663239653463343362613966653337343733613366306431
64353862653365323336393330333863323564613664613838653036336466323239343161663430
63373039333433396238376134353666356632396434303166346134333562323862653361626134
33353138623863623739376134643561303565373261326133626630313035313563663763313131
31613832643063356261363639616265316332353864393764383532333538393938336433353333
62366334343139656139623165323935646439383437353636326666393935663333653533666132
39396539376263623834373137323430643538383336313932376166386465303361383166366463
30373466333663343835343730383331316536383261333934323166333765633339383161303630
65336631393638333638383431663035336162333062613630323130643663383135643161373736
31643465366539626136316565373666623631356434313633653633323533373531666265306235
62366237653136626238393462633165336532633734336662373130336538343162383366633166
63333333643038613561633137366233316432363836316333353839313432613837323364393031
32653165616432386565656666383737356430666239313363396263306335316435356232356238
32613032376536323130646439613832343364306431616337343730616239383730613139373365
37373638393264633935383166313130633864646635643734653832313037613132663666353666
33376466313838633530666136343132316530613662346431633063396165386133666230363333
66346630633366396137356430636330373562336638393936303438333531656661616161373939
35663037373332366262323731633166383336393236396461363535643535356138303266323862
39643332373534376234636133353735346662366435663930643464636135636633306366383835
38333137656264623765323239306365306661346466633638373735613735633063383139373464
34653934376565656438633235386433636434316565646634303332313636613662363661306138
31313562616364633832623934306461313739376236323334623761326335343334353561303762
66633937363234313039343534353435623035636234363462306363343035636536363262353165
33623930343234613964663332383833383433383537636163616137373134373032333439633937
38623033653437316336663931306235623264363934633139396132366430363133616163663033
63613631663963303635316161306131326137613439353564353438396564313635623030643935
39333866633130393062303332346566653461353036313134626131363766323632323465656363
32336131643466623139356639613035623531653061393666353431323638373735623066333564
63303664373765633830346534333439663963393163333764343162303265663465346130376164
61376631393438386430626663653936383330643131376431303136333030346466336439326466
64663962373731306462643662373166383333313164626135633136373930393734373932663663
34386235653037326332653432653435636132636263363938666561333436643734653264636431
31653439663264623837326561383464623163666237653433623433373336383931303066663265
34313663663966383133666534323366323739653336643437303564386363386363373033356464
35633364623062353561613331306463396162333037343037363966323330636131386530376338
33376234636462613239386134396335376563623039323033323064306537653136653239636161
38353766633562623135343461653433663338353939633330353462323737353536366564306134
39663034653039633463386230393032616638353737656438653662653833643861393235636331
30383039393130623362303533613535313365663434313662323633373039393762633731666232
37643635313865336637376666363432336563613735646433653337346566613764366466346365
646230383034313737303435323762633061
@@ -20,6 +20,17 @@
# multica_workspaces_root_mount: "/mnt/utilidor" # multica_workspaces_root_mount: "/mnt/utilidor"
multica_agent_clis: multica_agent_clis:
- claude - claude
# Merged into the daemon user's ~/.claude/settings.json. Mirrors the model
# mix already live on haunted-mansion (unpinned runs on sonnet, subagents
# on haiku), and stops the npm install self-updating past the pin.
multica_claude_settings:
model: sonnet
alwaysThinkingEnabled: false
env:
DISABLE_AUTOUPDATER: "1"
CLAUDE_CODE_SUBAGENT_MODEL: haiku
MAX_THINKING_TOKENS: "4000"
BASH_MAX_OUTPUT_LENGTH: "20000"
# --- Secret source ---------------------------------------------------- # --- Secret source ----------------------------------------------------
# This homelab keeps Ansible secrets in ansible-vault encrypted files, so # This homelab keeps Ansible secrets in ansible-vault encrypted files, so
@@ -45,6 +56,12 @@
# Environment variable on the control node: # Environment variable on the control node:
# multica_pat: "{{ lookup('env', 'MULTICA_PAT') }}" # multica_pat: "{{ lookup('env', 'MULTICA_PAT') }}"
# 1Password service account token for `op`. Off until the service
# account exists and the delivery design is agreed (WDWL-37). Same shape as
# the PAT: a per-host dictionary in group_vars/all/vault.
# multica_op_deliver_token: true
# multica_op_service_account_token: "{{ vault_op_service_account_tokens[inventory_hostname_short] }}"
# The role's own PAT assert is no_log, so a missing dictionary entry would # The role's own PAT assert is no_log, so a missing dictionary entry would
# surface there only as "censored". This checks key presence, never the # surface there only as "censored". This checks key presence, never the
# value, so its failure can name the host. # value, so its failure can name the host.
+4
View File
@@ -6,6 +6,10 @@
# Directory layout on mad-tea-party # Directory layout on mad-tea-party
gitea_compose_dir: /opt/gitea gitea_compose_dir: /opt/gitea
# Image versions
gitea_version: "28.2.0"
gitea_postgres_version: "17.11"
# Gitea application settings # Gitea application settings
gitea_domain: gitea.mk-labs.cloud gitea_domain: gitea.mk-labs.cloud
gitea_root_url: "https://{{ gitea_domain }}" gitea_root_url: "https://{{ gitea_domain }}"
+3 -3
View File
@@ -15,9 +15,9 @@
# ── Compose & env ────────────────────────────────────────────────────────────── # ── Compose & env ──────────────────────────────────────────────────────────────
- name: Deploy Gitea compose file from boilerplate - name: Deploy Gitea compose file
ansible.builtin.copy: ansible.builtin.template:
src: "{{ playbook_dir }}/../../boilerplates/gitea/compose.yaml" src: compose.yaml.j2
dest: "{{ gitea_compose_dir }}/compose.yaml" dest: "{{ gitea_compose_dir }}/compose.yaml"
owner: root owner: root
group: root group: root
@@ -0,0 +1,64 @@
# ------------------------------------------------------------------------------
# FILE: ansible/roles/gitea/templates/compose.yaml.j2
# DESCRIPTION: Gitea + PostgreSQL compose stack. Values come from role defaults.
# Postgres stays on 17.x; a major bump needs dump + restore.
# ------------------------------------------------------------------------------
services:
gitea:
image: docker.io/gitea/gitea:{{ gitea_version }}
restart: unless-stopped
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=gitea_db
- GITEA__database__NAME={{ gitea_db_name }}
- GITEA__database__USER={{ gitea_db_user }}
- GITEA__database__PASSWD=${DATABASE_PASSWORD}
- GITEA__server__SSH_PORT={{ gitea_ssh_port }}
- GITEA__server__ROOT_URL={{ gitea_root_url }}
- GITEA__server__DOMAIN={{ gitea_domain }}
- GITEA__server__HTTP_PORT={{ gitea_http_port }}
- GITEA__service__TRUSTED_PROXIES={{ gitea_trusted_proxies }}
networks:
- gitea_backend
ports:
- "{{ gitea_http_port }}:{{ gitea_http_port }}"
- "{{ gitea_ssh_port }}:22"
volumes:
- gitea_data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
depends_on:
gitea_db:
condition: service_healthy
gitea_db:
image: docker.io/library/postgres:{{ gitea_postgres_version }}
restart: unless-stopped
environment:
- TZ={{ gitea_timezone }}
- POSTGRES_USER={{ gitea_db_user }}
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
- POSTGRES_DB={{ gitea_db_name }}
networks:
- gitea_backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U {{ gitea_db_user }}"]
start_period: 30s
interval: 10s
timeout: 10s
retries: 5
volumes:
- gitea_db:/var/lib/postgresql/data
volumes:
gitea_data:
driver: local
gitea_db:
driver: local
networks:
gitea_backend:
driver: bridge
+67 -3
View File
@@ -37,6 +37,8 @@ otherwise clean at the `production` profile.
| Node.js, pinned, from nodejs.org with SHASUMS256 verification | yes, when an npm-installed agent CLI is selected | | Node.js, pinned, from nodejs.org with SHASUMS256 verification | yes, when an npm-installed agent CLI is selected |
| `multica` CLI, pinned, from the GitHub release with `checksums.txt` verification | yes | | `multica` CLI, pinned, from the GitHub release with `checksums.txt` verification | yes |
| Agent CLIs (`claude`, `hermes`, …) | yes | | Agent CLIs (`claude`, `hermes`, …) | yes |
| 1Password CLI (`op`), from 1Password's signed apt/yum repository | yes (`multica_op_install`) |
| 1Password service account token, as a 0600 file for the daemon user | opt-in (`multica_op_deliver_token`); not exported to the daemon |
| `workspaces_root`, on the intended mount, writable by the daemon user | yes | | `workspaces_root`, on the intended mount, writable by the daemon user | yes |
| Multica authentication (`multica login --token`) | yes | | Multica authentication (`multica login --token`) | yes |
| CLI config (`server_url`, `app_url`, `workspaces_root`, `device_name`, …) | yes | | CLI config (`server_url`, `app_url`, `workspaces_root`, `device_name`, …) | yes |
@@ -236,6 +238,9 @@ See `defaults/main.yml` for the annotated list. The ones you will actually set:
| `multica_user` | `multica` | Daemon service account. | | `multica_user` | `multica` | Daemon service account. |
| `multica_profile` | `""` | `--profile`, to isolate config/daemon state/workspaces. | | `multica_profile` | `""` | `--profile`, to isolate config/daemon state/workspaces. |
| `multica_allow_remote_install_scripts` | `false` | Required for `hermes`; see below. | | `multica_allow_remote_install_scripts` | `false` | Required for `hermes`; see below. |
| `multica_op_install` | `true` | 1Password CLI from 1Password's apt/yum repo. |
| `multica_op_version` | `""` | `""` tracks the repo (upgrades on every run); set e.g. `2.41.1` to pin. |
| `multica_op_deliver_token` | `false` | Write `multica_op_service_account_token` to `multica_op_token_file`. |
### Adding an agent CLI ### Adding an agent CLI
@@ -307,13 +312,19 @@ Every step reads before it writes:
| CLI install | `multica --version` equals the pin | | CLI install | `multica --version` equals the pin |
| Agent CLI install | `command -v <binary>` and its version command | | Agent CLI install | `command -v <binary>` and its version command |
| Config | `multica config show` parsed and compared key by key | | Config | `multica config show` parsed and compared key by key |
| Login | `multica auth status` already names `multica_server_url` | | Login | `multica auth status` already names `multica_server_url` (it prints to **stderr**; the guard reads both streams) |
| Autostart | `multica daemon autostart status` | | Autostart | `multica daemon autostart status` |
| Daemon start | `multica daemon status --output json` reports `running` | | Daemon start | `systemctl --user is-active <unit>`; a daemon running *outside* the unit is stopped first, then the unit is started |
A binary, config or credential change notifies a `multica daemon restart` A binary, config or credential change notifies a `systemctl --user restart`
handler, which is flushed *before* verification reads the daemon's state back. handler, which is flushed *before* verification reads the daemon's state back.
The role never calls `multica daemon start` or `multica daemon restart`. Both
fork the daemon inside the caller's session (Ansible's SSH session scope),
outside the unit's cgroup. The unit then shows `inactive`, nothing supervises
the process, and a later `systemctl --user start` collides with it on
`daemon.lock`.
A converged host reports zero changed tasks. A converged host reports zero changed tasks.
## Verification ## Verification
@@ -360,6 +371,58 @@ ssh -t scratch-vm 'sudo -iu multica claude'
That step only becomes automatable if the host moves from a subscription to an That step only becomes automatable if the host moves from a subscription to an
API key. API key.
## 1Password CLI
`op` lets an agent resolve `op://vault/item/field` references at the moment
it runs a command (`op run -- cmd`, `op inject -i tpl -o out`, `op read`), so
the secret value never has to appear in a prompt, an issue or a transcript.
The 1Password desktop-app integration (and the Claude Code plugin built on it)
needs a GUI session, so headless agent hosts use a **service account** instead.
Install, Debian/Ubuntu, exactly as 1Password documents it, with one addition:
- the key at `multica_op_key_url` is fingerprint-checked against
`multica_op_key_fingerprint` before it is dearmored, so apt never trusts a
substituted key;
- dearmored to `/usr/share/keyrings/1password-archive-keyring.gpg` (apt,
`signed-by=`) and to `/usr/share/debsig/keyrings/AC2D62742012EA22/debsig.gpg`
with the policy in `/etc/debsig/policies/AC2D62742012EA22/` (debsig-verify);
- `1password-cli` from `downloads.1password.com/linux/debian/<arch> stable`.
EL uses 1Password's yum repository with `gpgcheck` and `repo_gpgcheck`.
The play then runs `op --version` as the daemon user, in the daemon user's
environment.
### The service account token
The role can deliver the token, but by default does not:
```yaml
multica_op_deliver_token: true
multica_op_service_account_token: "{{ vault_op_service_account_tokens[inventory_hostname_short] }}"
```
writes it to `multica_op_token_file`
(`~multica/.config/op-service-account/token`, directory 0700, file 0600,
owned by the daemon user). That is all it does. **The role does not put the
token into the daemon's environment**, for two reasons:
1. The daemon's systemd user unit is written and owned by the multica CLI
(`multica daemon autostart`). The role must not template or edit it, or it
silently freezes the CLI's `ExecStart`, environment and restart semantics.
2. Anything in the daemon's environment is inherited by every agent process
it spawns, where a casual `env` or `printenv` puts it in a transcript.
How the token reaches `op` is a separate decision, not yet made. Until then
an agent can use it explicitly:
```bash
OP_SERVICE_ACCOUNT_TOKEN="$(cat ~/.config/op-service-account/token)" op run -- <cmd>
```
`op` reads the token only from `OP_SERVICE_ACCOUNT_TOKEN`; it has no
token-file option.
## Known gaps ## Known gaps
- **Provider CLI login.** Unavoidable for subscription auth. - **Provider CLI login.** Unavoidable for subscription auth.
@@ -381,6 +444,7 @@ API key.
| `multica_auth` | `multica login` | | `multica_auth` | `multica login` |
| `multica_daemon` | autostart + start | | `multica_daemon` | autostart + start |
| `multica_verify` | the assertions | | `multica_verify` | the assertions |
| `multica_op` | 1Password CLI, and the token file when enabled |
| `multica` | all of the above | | `multica` | all of the above |
Preflight and the service-account step are tagged `always`: they build Preflight and the service-account step are tagged `always`: they build
@@ -129,6 +129,43 @@ multica_agent_cli_catalog:
manual_login: true manual_login: true
manual_login_hint: "configure Hermes credentials as {{ multica_user }} (Hermes reads 1Password natively; confirm against its docs)" manual_login_hint: "configure Hermes credentials as {{ multica_user }} (Hermes reads 1Password natively; confirm against its docs)"
# Keys MERGED (recursively) into the daemon user's ~/.claude/settings.json.
# Merged, not templated: Claude Code writes that file itself. Keys not named
# here are left alone. Empty = don't touch the file.
#
# An npm-installed Claude Code updates itself in place, which silently breaks
# the package_version pin above (and the next play downgrades it again).
# Setting env.DISABLE_AUTOUPDATER: "1" here is what makes the pin hold.
multica_claude_settings: {}
# -----------------------------------------------------------------------------
# 1Password CLI (op)
# -----------------------------------------------------------------------------
# Lets agents resolve op:// references with `op run` / `op inject` / `op read`,
# so secret values never pass through a prompt or a transcript. Installed from
# 1Password's signed apt/yum repository.
multica_op_install: true
# "" = whatever the repository serves, upgraded on every run. Set e.g. "2.41.1"
# to pin. 1Password's apt index carries only the newest build, so a pin older
# than that cannot be installed on a fresh host.
multica_op_version: ""
multica_op_key_url: "https://downloads.1password.com/linux/keys/1password.asc"
# Code signing for 1Password <codesign@1password.com>. The play refuses a key
# at multica_op_key_url with any other fingerprint.
multica_op_key_fingerprint: "3FEF9748469ADBE15DA7CA80AC2D62742012EA22"
multica_op_debsig_policy_url: "https://downloads.1password.com/linux/debian/debsig/1password.pol"
multica_op_apt_base_url: "https://downloads.1password.com/linux/debian"
multica_op_rpm_base_url: "https://downloads.1password.com/linux/rpm/stable"
# Service account token delivery. Off by default. When on, the token is written
# to multica_op_token_file (0600, owned by the daemon user) and nowhere else.
# The role does NOT export it into the daemon environment; see the README.
# Supply the VALUE from the playbook, like multica_pat, e.g.
# multica_op_service_account_token: "{{ vault_op_service_account_tokens[inventory_hostname_short] }}"
multica_op_deliver_token: false
multica_op_service_account_token: ""
multica_op_token_file: "{{ multica_user_home }}/.config/op-service-account/token"
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Node.js (installed only when a selected agent CLI needs npm) # Node.js (installed only when a selected agent CLI needs npm)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@@ -1,7 +1,9 @@
--- ---
# Through systemd, not `multica daemon restart`: that respawns the daemon in
# the caller's session, outside the unit (see tasks/daemon.yml).
- name: Restart multica daemon - name: Restart multica daemon
ansible.builtin.command: ansible.builtin.command:
argv: "{{ _multica_cmd + ['daemon', 'restart'] }}" argv: [systemctl, --user, restart, "{{ _multica_unit | default('multica-daemon.service') }}"]
become: true become: true
become_user: "{{ multica_user }}" become_user: "{{ multica_user }}"
environment: "{{ _multica_user_env }}" environment: "{{ _multica_user_env }}"
@@ -1,6 +1,10 @@
--- ---
# `multica auth status` prints the server and user when authenticated and exits # `multica auth status` prints the server and user when authenticated and exits
# non-zero otherwise, so it is the idempotency guard for login. # non-zero otherwise, so it is the idempotency guard for login.
#
# It prints to STDERR, not stdout (0.6.5). A stdout-only guard never matches,
# so every run re-logs in and restarts the daemon. It also echoes a token
# prefix, hence no_log.
- name: Auth | Read the current authentication state - name: Auth | Read the current authentication state
ansible.builtin.command: ansible.builtin.command:
argv: "{{ _multica_cmd + ['auth', 'status'] }}" argv: "{{ _multica_cmd + ['auth', 'status'] }}"
@@ -11,13 +15,15 @@
changed_when: false changed_when: false
failed_when: false failed_when: false
check_mode: false check_mode: false
no_log: true
- name: Auth | Decide whether a login is needed - name: Auth | Decide whether a login is needed
ansible.builtin.set_fact: ansible.builtin.set_fact:
_multica_needs_login: >- _multica_needs_login: >-
{{ multica_force_relogin | bool {{ multica_force_relogin | bool
or _multica_auth_status.rc != 0 or _multica_auth_status.rc != 0
or multica_server_url.rstrip('/') not in (_multica_auth_status.stdout | default('')) }} or multica_server_url.rstrip('/') not in
((_multica_auth_status.stdout | default('')) ~ (_multica_auth_status.stderr | default(''))) }}
# no_log is mandatory: without it Ansible records the full argv — including the # no_log is mandatory: without it Ansible records the full argv — including the
# PAT — in play output, CI logs, and every callback plugin. # PAT — in play output, CI logs, and every callback plugin.
@@ -0,0 +1,34 @@
---
- name: Claude settings | Ensure ~/.claude exists
ansible.builtin.file:
path: "{{ multica_user_home }}/.claude"
state: directory
owner: "{{ multica_user }}"
group: "{{ multica_group }}"
mode: "0700"
become: true
- name: Claude settings | Read the current settings
ansible.builtin.slurp:
src: "{{ multica_user_home }}/.claude/settings.json"
register: _multica_claude_settings_raw
failed_when: false
become: true
- name: Claude settings | Merge the declared keys over them
ansible.builtin.set_fact:
_multica_claude_settings_current: >-
{{ (_multica_claude_settings_raw.content | b64decode | from_json)
if _multica_claude_settings_raw.content is defined else {} }}
- name: Claude settings | Write them back if anything differs
ansible.builtin.copy:
dest: "{{ multica_user_home }}/.claude/settings.json"
content: "{{ _multica_claude_settings_current | combine(multica_claude_settings, recursive=true) | to_nice_json }}\n"
owner: "{{ multica_user }}"
group: "{{ multica_group }}"
mode: "0600"
become: true
when: >-
_multica_claude_settings_current | combine(multica_claude_settings, recursive=true)
!= _multica_claude_settings_current
@@ -43,8 +43,61 @@
- multica_autostart | bool - multica_autostart | bool
- _multica_autostart_status.rc != 0 - _multica_autostart_status.rc != 0
or 'enabled' not in (_multica_autostart_status.stdout | default('') | lower) or 'enabled' not in (_multica_autostart_status.stdout | default('') | lower)
register: _multica_autostart_enable
changed_when: true changed_when: true
# Lifecycle goes through systemd, never `multica daemon start|restart`. Those
# fork the daemon inside the CALLER's session (here, Ansible's SSH session
# scope), outside the unit's cgroup: the unit stays inactive, nothing
# supervises the process, and the next `systemctl --user start` collides with
# it on daemon.lock. Seen on haunted-mansion (2026-10-21) and spaceship-earth
# (2026-10-22).
#
# The unit name comes from `autostart status` ("Location: .../<name>.service")
# so a --profile host resolves its own unit.
- name: Daemon | Re-read the autostart registration
ansible.builtin.command:
argv: "{{ _multica_cmd + ['daemon', 'autostart', 'status'] }}"
become: true
become_user: "{{ multica_user }}"
environment: "{{ _multica_user_env }}"
register: _multica_autostart_reread
changed_when: false
failed_when: false
check_mode: false
when: _multica_autostart_enable is changed
- name: Daemon | Resolve the systemd user unit
ansible.builtin.set_fact:
_multica_unit: >-
{{ ((_s.stdout | default('')) ~ '\n' ~ (_s.stderr | default('')))
| regex_search('Location:\s*\S*/([^/\s]+\.service)', '\1')
| default(['multica-daemon.service'], true) | first }}
vars:
_s: "{{ _multica_autostart_reread if _multica_autostart_enable is changed else _multica_autostart_status }}"
# `autostart enable` may rewrite the unit file while the user manager still
# holds the old definition.
- name: Daemon | Reload the user manager after a (re)registration
ansible.builtin.command:
argv: [systemctl, --user, daemon-reload]
become: true
become_user: "{{ multica_user }}"
environment: "{{ _multica_user_env }}"
when: _multica_autostart_enable is changed
changed_when: true
- name: Daemon | Read the unit state
ansible.builtin.command:
argv: [systemctl, --user, is-active, "{{ _multica_unit }}"]
become: true
become_user: "{{ multica_user }}"
environment: "{{ _multica_user_env }}"
register: _multica_unit_state
changed_when: false
failed_when: false
check_mode: false
- name: Daemon | Read daemon status - name: Daemon | Read daemon status
ansible.builtin.command: ansible.builtin.command:
argv: "{{ _multica_cmd + ['daemon', 'status', '--output', 'json'] }}" argv: "{{ _multica_cmd + ['daemon', 'status', '--output', 'json'] }}"
@@ -56,15 +109,27 @@
failed_when: false failed_when: false
check_mode: false check_mode: false
- name: Daemon | Start it if it is not already running # Running, but not under the unit: an orphan. Stop it so the unit can own the
# lock and the process.
- name: Daemon | Stop a daemon running outside its unit
ansible.builtin.command: ansible.builtin.command:
argv: "{{ _multica_cmd + ['daemon', 'start'] }}" argv: "{{ _multica_cmd + ['daemon', 'stop'] }}"
become: true become: true
become_user: "{{ multica_user }}" become_user: "{{ multica_user }}"
environment: "{{ _multica_user_env }}" environment: "{{ _multica_user_env }}"
when: >- when:
_multica_daemon_status.rc != 0 - (_multica_unit_state.stdout | trim) != 'active'
or ((_multica_daemon_status.stdout | from_json).status | default('')) != 'running' - _multica_daemon_status.rc == 0
- ((_multica_daemon_status.stdout | from_json).status | default('')) == 'running'
changed_when: true
- name: Daemon | Start the unit if it is not active
ansible.builtin.command:
argv: [systemctl, --user, start, "{{ _multica_unit }}"]
become: true
become_user: "{{ multica_user }}"
environment: "{{ _multica_user_env }}"
when: (_multica_unit_state.stdout | trim) != 'active'
changed_when: true changed_when: true
# Anything that changed the binary, the config or the credentials restarts the # Anything that changed the binary, the config or the credentials restarts the
@@ -27,6 +27,23 @@
ansible.builtin.import_tasks: agent_clis.yml ansible.builtin.import_tasks: agent_clis.yml
tags: [multica, multica_agents] tags: [multica, multica_agents]
- name: Claude Code settings
ansible.builtin.import_tasks: claude_settings.yml
when:
- "'claude' in multica_agent_clis"
- multica_claude_settings | length > 0
tags: [multica, multica_agents, multica_claude_settings]
- name: 1Password CLI
ansible.builtin.import_tasks: op_cli.yml
when: multica_op_install | bool
tags: [multica, multica_op]
- name: 1Password service account token
ansible.builtin.import_tasks: op_token.yml
when: multica_op_deliver_token | bool
tags: [multica, multica_op]
- name: CLI configuration - name: CLI configuration
ansible.builtin.import_tasks: config.yml ansible.builtin.import_tasks: config.yml
tags: [multica, multica_config] tags: [multica, multica_config]
@@ -0,0 +1,187 @@
---
# 1Password CLI from 1Password's own signed package repository, never a
# curl-piped binary. Mirrors https://developer.1password.com/docs/cli/get-started
# (Linux, APT / YUM), with the signing key's fingerprint checked before apt or
# dnf is allowed to trust it.
- name: 1Password CLI | Require a supported OS family
ansible.builtin.assert:
that:
- ansible_facts['os_family'] in ['Debian', 'RedHat']
fail_msg: >-
The 1Password CLI install supports Debian- and RedHat-family hosts only
(found {{ ansible_facts['os_family'] }}). Set multica_op_install: false.
quiet: true
# --- Debian / Ubuntu ---------------------------------------------------------
- name: 1Password CLI | Install gnupg and debsig-verify
ansible.builtin.apt:
name: [gnupg, debsig-verify]
state: present
become: true
when: ansible_facts['os_family'] == 'Debian'
- name: 1Password CLI | Fetch the signing key
ansible.builtin.get_url:
url: "{{ multica_op_key_url }}"
dest: /usr/share/keyrings/1password-archive-keyring.asc
owner: root
group: root
mode: "0644"
register: _multica_op_key_asc
become: true
when: ansible_facts['os_family'] == 'Debian'
- name: 1Password CLI | Read the signing key's fingerprint
ansible.builtin.command:
argv: [gpg, --show-keys, --with-colons, /usr/share/keyrings/1password-archive-keyring.asc]
register: _multica_op_key_info
changed_when: false
check_mode: false
become: true
when:
- ansible_facts['os_family'] == 'Debian'
- not (ansible_check_mode and _multica_op_key_asc is changed)
# Under --check on a fresh host the key was only pretend-downloaded, so there is
# nothing to read; the real run checks it.
# A key that does not match is never dearmored, so apt never trusts it.
- name: 1Password CLI | Require the expected signing key
ansible.builtin.assert:
that:
- multica_op_key_fingerprint in (_multica_op_key_info.stdout_lines
| select('match', '^fpr:') | map('split', ':') | map(attribute=9) | list)
fail_msg: >-
{{ multica_op_key_url }} is not the key with fingerprint
{{ multica_op_key_fingerprint }}. Refusing to trust it.
quiet: true
when:
- ansible_facts['os_family'] == 'Debian'
- _multica_op_key_info is not skipped
- name: 1Password CLI | Look for the dearmored keyrings
ansible.builtin.stat:
path: "{{ item }}"
loop:
- /usr/share/keyrings/1password-archive-keyring.gpg
- /usr/share/debsig/keyrings/AC2D62742012EA22/debsig.gpg
register: _multica_op_keyrings
become: true
when: ansible_facts['os_family'] == 'Debian'
- name: 1Password CLI | Create the debsig policy and keyring directories
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: root
group: root
mode: "0755"
loop:
- /etc/debsig/policies/AC2D62742012EA22
- /usr/share/debsig/keyrings/AC2D62742012EA22
register: _multica_op_debsig_dirs
become: true
when: ansible_facts['os_family'] == 'Debian'
# Same key, two consumers: apt (repository metadata) and debsig-verify (the
# signature on each .deb).
- name: 1Password CLI | Dearmor the key for apt and debsig
ansible.builtin.command:
argv: [gpg, --batch, --yes, --dearmor, --output, "{{ item.item }}", /usr/share/keyrings/1password-archive-keyring.asc]
loop: "{{ _multica_op_keyrings.results }}"
loop_control:
label: "{{ item.item }}"
when:
- ansible_facts['os_family'] == 'Debian'
- _multica_op_key_asc is changed or not item.stat.exists
changed_when: true
become: true
- name: 1Password CLI | Install the debsig policy
ansible.builtin.get_url:
url: "{{ multica_op_debsig_policy_url }}"
dest: /etc/debsig/policies/AC2D62742012EA22/1password.pol
owner: root
group: root
mode: "0644"
become: true
when:
- ansible_facts['os_family'] == 'Debian'
- not (ansible_check_mode and _multica_op_debsig_dirs is changed)
- name: 1Password CLI | Add the apt repository
ansible.builtin.apt_repository:
repo: >-
deb [arch={{ _multica_arch }} signed-by=/usr/share/keyrings/1password-archive-keyring.gpg]
{{ multica_op_apt_base_url }}/{{ _multica_arch }} stable main
filename: 1password
state: present
update_cache: true
register: _multica_op_repo_deb
become: true
when: ansible_facts['os_family'] == 'Debian'
- name: 1Password CLI | Install the package
ansible.builtin.apt:
name: >-
{{ '1password-cli=' ~ multica_op_version ~ '*'
if multica_op_version | length > 0 else '1password-cli' }}
state: "{{ 'present' if multica_op_version | length > 0 else 'latest' }}"
allow_downgrade: "{{ multica_op_version | length > 0 }}"
register: _multica_op_pkg_deb
become: true
when:
- ansible_facts['os_family'] == 'Debian'
- not (ansible_check_mode and _multica_op_repo_deb is changed)
# --- EL ----------------------------------------------------------------------
- name: 1Password CLI | Add the yum repository
ansible.builtin.yum_repository:
name: 1password
description: 1Password Stable Channel
baseurl: "{{ multica_op_rpm_base_url }}/$basearch"
gpgkey: "{{ multica_op_key_url }}"
gpgcheck: true
repo_gpgcheck: true
enabled: true
register: _multica_op_repo_rpm
become: true
when: ansible_facts['os_family'] == 'RedHat'
- name: 1Password CLI | Install the package
ansible.builtin.dnf:
name: >-
{{ '1password-cli-' ~ multica_op_version
if multica_op_version | length > 0 else '1password-cli' }}
state: "{{ 'present' if multica_op_version | length > 0 else 'latest' }}"
allow_downgrade: "{{ multica_op_version | length > 0 }}"
register: _multica_op_pkg_rpm
become: true
when:
- ansible_facts['os_family'] == 'RedHat'
- not (ansible_check_mode and _multica_op_repo_rpm is changed)
# --- Verify ------------------------------------------------------------------
# As the daemon user, through its own environment: that is the context agents
# call `op` from.
- name: 1Password CLI | Check the installed version as the daemon user
ansible.builtin.command:
argv: [op, --version]
become: true
become_user: "{{ multica_user }}"
environment: "{{ _multica_user_env }}"
register: _multica_op_version_out
changed_when: false
check_mode: false
failed_when: >-
_multica_op_version_out.rc != 0
or (multica_op_version | length > 0
and _multica_op_version_out.stdout | trim != multica_op_version)
# Under --check, only when the binary is already there to ask.
when: >-
not ansible_check_mode
or (_multica_op_pkg_deb is not skipped and _multica_op_pkg_deb is not changed)
or (_multica_op_pkg_rpm is not skipped and _multica_op_pkg_rpm is not changed)
@@ -0,0 +1,37 @@
---
# Delivers the 1Password service account token to a file only the daemon user
# can read. It deliberately stops there: nothing here puts the token into the
# daemon's environment. The daemon's systemd user unit belongs to the multica
# CLI, so the role must not edit it, and exporting the token to the daemon
# would hand it to every agent process too. See the README.
# no_log: a failed assert would otherwise render the token it inspected.
- name: 1Password token | Require a service account token
ansible.builtin.assert:
that:
- multica_op_service_account_token | length > 0
- multica_op_service_account_token is match('^ops_')
fail_msg: >-
multica_op_deliver_token is true but multica_op_service_account_token is
not a 1Password service account token (ops_...).
quiet: true
no_log: true
- name: 1Password token | Create the token directory
ansible.builtin.file:
path: "{{ multica_op_token_file | dirname }}"
state: directory
owner: "{{ multica_user }}"
group: "{{ multica_group }}"
mode: "0700"
become: true
- name: 1Password token | Write the token file
ansible.builtin.copy:
dest: "{{ multica_op_token_file }}"
content: "{{ multica_op_service_account_token }}\n"
owner: "{{ multica_user }}"
group: "{{ multica_group }}"
mode: "0600"
no_log: true
become: true
+4 -1
View File
@@ -25,7 +25,7 @@ only. Entry point: `playbooks/provision-wong-host.yml`.
| `/srv/obsidian/` | `0710 obsync` | `user:multica:--x` | | `/srv/obsidian/` | `0710 obsync` | `user:multica:--x` |
| `/srv/obsidian/vault/` | `0710 obsync` | `user:multica:--x`, so `multica` can traverse but not list | | `/srv/obsidian/vault/` | `0710 obsync` | `user:multica:--x`, so `multica` can traverse but not list |
| `vault/everpure/`, `vault/wip/` | `0700 obsync` | none | | `vault/everpure/`, `vault/wip/` | `0700 obsync` | none |
| `vault/inbox/` | `0770 obsync` | `user:multica:rwx`, plus the same as a **default** entry | | `vault/inbox/` | `0770 obsync` | `user:multica:rwx` and `user:obsync:rwx`, each also as a **default** entry |
On a directory with an ACL, the mode's group bits are the ACL mask. A On a directory with an ACL, the mode's group bits are the ACL mask. A
`chmod 0700` would therefore void every named entry, which is why the `chmod 0700` would therefore void every named entry, which is why the
@@ -38,6 +38,9 @@ only. Entry point: `playbooks/provision-wong-host.yml`.
- `multica` writes, reads and deletes in `inbox/`. - `multica` writes, reads and deletes in `inbox/`.
- A folder and file created by `obsync` under umask `0077` (the way Sync - A folder and file created by `obsync` under umask `0077` (the way Sync
creates them) stay readable and writable by `multica`. creates them) stay readable and writable by `multica`.
- What `multica` creates stays readable and writable by `obsync`. Those
files are owned `multica:multica`, so without the named `user:obsync`
default entry Sync could not read them and would never upload them.
- `multica` is refused both listing the vault root and listing or writing - `multica` is refused both listing the vault root and listing or writing
`everpure/` and `wip/`. `everpure/` and `wip/`.
@@ -4,8 +4,13 @@
# <parent>/ obsync 0710 + user:<shared>:--x traverse, no listing # <parent>/ obsync 0710 + user:<shared>:--x traverse, no listing
# <vault>/ obsync 0710 + user:<shared>:--x traverse, no listing # <vault>/ obsync 0710 + user:<shared>:--x traverse, no listing
# <vault>/<private>/ obsync 0700 nobody else # <vault>/<private>/ obsync 0700 nobody else
# <vault>/<shared>/ obsync 0770 + user:<u>:rwx, and the same as a # <vault>/<shared>/ obsync 0770 + user:<u>:rwx and user:obsync:rwx,
# DEFAULT entry, so new children inherit # each also as a DEFAULT entry, so new
# children inherit both
#
# The user:obsync entry matters for content the SHARED user creates: that is
# owned <u>:<u>, so without a named entry obsync falls into "other" (---)
# and Sync can neither read nor upload it.
# #
# The owning group is obsync's private group, so its bits grant nobody. On a # The owning group is obsync's private group, so its bits grant nobody. On a
# directory that carries an ACL, the group bits of the mode ARE the ACL mask, # directory that carries an ACL, the group bits of the mode ARE the ACL mask,
@@ -62,6 +67,18 @@
loop_control: loop_control:
label: "{{ item.path }}" label: "{{ item.path }}"
# Each shared folder gets its user AND the service user, both as access and
# default entries.
- name: Layout | Build the shared-folder grants
ansible.builtin.set_fact:
_obh_grants: >-
{{ (obsidian_headless_shared_folders
+ (obsidian_headless_shared_folders
| map(attribute='path')
| map('community.general.dict_kv', 'path') | list
| map('combine', {'user': obsidian_headless_user}) | list))
| unique | list }}
- name: Layout | Grant shared folders (access and default entries) - name: Layout | Grant shared folders (access and default entries)
ansible.posix.acl: ansible.posix.acl:
path: "{{ obsidian_headless_vault_path }}/{{ item.0.path }}" path: "{{ obsidian_headless_vault_path }}/{{ item.0.path }}"
@@ -70,6 +87,6 @@
permissions: rwx permissions: rwx
default: "{{ item.1 }}" default: "{{ item.1 }}"
state: present state: present
loop: "{{ obsidian_headless_shared_folders | product([false, true]) | list }}" loop: "{{ _obh_grants | product([false, true]) | list }}"
loop_control: loop_control:
label: "{{ item.0.path }} -> {{ item.0.user }}{{ ' (default)' if item.1 else '' }}" label: "{{ item.0.path }} -> {{ item.0.user }}{{ ' (default)' if item.1 else '' }}"
@@ -18,6 +18,61 @@
changed_when: false changed_when: false
check_mode: false check_mode: false
# The reverse direction: what the shared user writes, Sync must be able to
# read (to upload it) and rewrite (to merge remote edits into it).
- name: Verify | Content a shared user creates stays usable by the service (create)
ansible.builtin.command:
argv:
- /bin/sh
- -c
- 'd="$1/.obh-verify-rev"; mkdir -p "$d" && echo ok > "$d/note.md"'
- sh
- "{{ obsidian_headless_vault_path }}/{{ item.path }}"
become: true
become_user: "{{ item.user }}"
loop: "{{ obsidian_headless_shared_folders }}"
loop_control:
label: "{{ item.user }} -> {{ item.path }}"
changed_when: false
check_mode: false
- name: Verify | Content a shared user creates stays usable by the service (use)
ansible.builtin.command:
argv:
- /bin/sh
- -c
- 'd="$1/.obh-verify-rev"; grep -q ok "$d/note.md" && echo more >> "$d/note.md" && echo ok > "$d/reply.md"'
- sh
- "{{ obsidian_headless_vault_path }}/{{ item.path }}"
become: true
become_user: "{{ obsidian_headless_user }}"
loop: "{{ obsidian_headless_shared_folders }}"
loop_control:
label: "{{ item.path }}"
register: _obh_reverse
changed_when: false
failed_when: false
check_mode: false
- name: Verify | Remove the reverse probes
ansible.builtin.file:
path: "{{ obsidian_headless_vault_path }}/{{ item.path }}/.obh-verify-rev"
state: absent
loop: "{{ obsidian_headless_shared_folders }}"
loop_control:
label: "{{ item.path }}"
changed_when: false
- name: Verify | The service can read and rewrite shared users' content
ansible.builtin.assert:
that:
- _obh_reverse.results | rejectattr('rc', 'equalto', 0) | list | length == 0
fail_msg: >-
{{ obsidian_headless_user }} cannot read or write content a shared user
created; Sync would never upload it. Check the user:{{ obsidian_headless_user }}
default ACL entry on the shared folder.
quiet: true
# Simulates the service: obsync, umask 0077, creating a folder and a file the # Simulates the service: obsync, umask 0077, creating a folder and a file the
# way Sync does. The shared user must still reach both, via the default ACL. # way Sync does. The shared user must still reach both, via the default ACL.
- name: Verify | Content the service creates in a shared folder inherits the grant (create) - name: Verify | Content the service creates in a shared folder inherits the grant (create)
-58
View File
@@ -1,58 +0,0 @@
services:
gitea:
image: docker.io/gitea/gitea:1.25.4
restart: unless-stopped
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=gitea_db
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=${DATABASE_PASSWORD}
- GITEA__server__SSH_PORT=2221
- GITEA__server__ROOT_URL=https://gitea.mk-labs.cloud
- GITEA__server__DOMAIN=gitea.mk-labs.cloud
- GITEA__server__HTTP_PORT=3000
- GITEA__service__TRUSTED_PROXIES=10.1.71.35
networks:
- gitea_backend
ports:
- "3000:3000"
- "2221:22"
volumes:
- gitea_data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
depends_on:
gitea_db:
condition: service_healthy
gitea_db:
image: docker.io/library/postgres:17.8
restart: unless-stopped
environment:
- TZ=America/Chicago
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
- POSTGRES_DB=gitea
networks:
- gitea_backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gitea"]
start_period: 30s
interval: 10s
timeout: 10s
retries: 5
volumes:
- gitea_db:/var/lib/postgresql/data
volumes:
gitea_data:
driver: local
gitea_db:
driver: local
networks:
gitea_backend:
driver: bridge
+3 -1
View File
@@ -1,13 +1,15 @@
http: http:
routers: routers:
gitea: gitea:
rule: "Host(`gitea.mk-labs.cloud`)" rule: "Host(`gitea.mk-labs.cloud`) || Host(`mad-tea-party.wdw-labs.cloud`)"
entryPoints: entryPoints:
- websecure - websecure
tls: tls:
certResolver: cloudflare certResolver: cloudflare
domains: domains:
- main: "gitea.mk-labs.cloud" - main: "gitea.mk-labs.cloud"
sans:
- "mad-tea-party.wdw-labs.cloud"
service: gitea service: gitea
services: services: