10 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
rblundon 61dba61025 Merge branch 'main' of gitea.mk-labs.cloud:rblundon/homelab 2026-10-22 16:00:51 -05:00
rblundon b73107be79 update vault 2026-10-22 15:59:59 -05:00
21 changed files with 1102 additions and 501 deletions

No files matched your search

+471 -423
View File
@@ -1,424 +1,472 @@
$ANSIBLE_VAULT;1.1;AES256 $ANSIBLE_VAULT;1.1;AES256
31393939323063366635653130356131666436323762303533333634333166396337383133616565 31303035626165353032623535326564616362663265363634346230393632623233333132636230
6134333735373036313732303663376130653536633031320a306634646132386335633431336263 3263666137666332353136626438663063633165663565360a333934333364653766626263383464
32346162326338643665386432393464303165613930306636336136616239633137336563356564 33356463653166666236623638303561376439373261306334373134386262636534623966633436
6536633364623763370a636563646435363930343838383166336438656365373535326666386432 3330613861353861350a393035363566383862643563376436643665626135373830616231656365
30353534376235626238616662356634653132396138333163343736333631636466343035393337 61623530363761616533376434326230363132666433356238646139393730343264636362333463
65613837643733353664633262323262616331636533306561623364303437613136336238373938 63396239313137376262356664323562306634633064616166316331333862326436393861346632
64353862616166303339613430646534356237623733613035303066623437666261306130326366 33393031646532376462313837343762663266363366353665366266623434326538646239623234
66323331336636316566363532316463346162313239646431613865646462383432316363393661 65623362333166326566303739623466376537353561643034616563356664363266643462323435
38373837353764633435303335373639643431366137373930373464336463376136306263636163 63623436353162376366343836626439623963313764346562363061653832646130396463396530
61616632326530643531383264323565646466633963663732653561333430343162393035386330 35346631666633383435656563366164306432663131326633343563313134323937313961613437
36323566666264646631323939333461656237643736656430346434613566636663663165343665 32383163613439636561383064346238303535613339366234633234633430353232613761636562
35353239303433376635646237653739396533626538633332326462393838356262646430383138 36323461623465653765303533303230303064363762393865326533613336346366386630353339
38633266623464643463326563613232333361336162356561623265643130346537326238386134 61343164333262646239636161313231386133363037666539653666656461653666356239663234
31653061376334663534643130323032626232636565396466643664326263643730306439663337 66373736616232336466623030373366393366393032656138306465636431383937646461383136
63323630363863356561316139343766376132343832663266343232386133383135353861363231 66303733626633386335623835383135363265383062343937306564613234366435383236356537
63643763356361396166643262353866613235383033353562363761363539313334316535653462 66303638626365343066343537306636623935393637616237306337363538616262323735363230
32613139666234646238613837636462653532613631333332386339636334616535326333626431 34343561336634393334323763393836633736383739323661303531626133383834333138656362
61616432336135363536316137616364306337623966646366376233633437363631306662383565 35656463316136373861613636366165383530383465326666616139333130663230356166373633
66626433316135353339643235633933626563363334356234313333356237666665393931373837 62613535656161633530393031663063363031656431303338613864653739323932646333633236
66353535343339343631333662383238343930633630333133656236616335663439393865356564 36346464303564343661653138323433306563306566623966313664643030653934343230626333
36633334643739333035646139666630396239626230613264353237383830653461613634303532 38343732653264376530343933326365363864666539306562366434363161633132373165393234
36303730643632393731373037306261613037373630643137646166316136376633353865396335 65333339356330323562343032343334616439343963623066626538633238663132383965656231
34663233633431323233633038343961626538626161336533316339343539643764643531663666 38346230666230396434613036333466633334386337373437383063336364366130383064633831
34353234346362346263656165393538346435663465386164336465313739656334383339633661 38303630656162376331623335323565356530326539333536623835383132353462353161663061
31613562653062623064353666666564326339626463323435653763366330393463363935313834 37353263646537633561656133393562623034363830663961623331623263303861383465383865
38646534343261636362633464373034373432643438346364306163656164663762373133366239 66303765313830383431636236313937616666303833383738353438643461373166343130353661
35393231323337663633613936653534356361623865636535346263396665373266616231326362 31623166356134343833313736623738303837303332346361316532633434666266386661326337
39393061653563333562313639303031366236336464643864613939373265353961363739353130 64396633373537656135373938663433333230353632366538356135666139363232613664356436
65323761346363336663353763633833373633666661353032363961393834366631616439316161 36346363343638303764623931373263613461303266323766646434626336313933303237353538
66316438316135363038333831303563363137336439313933393333626261616535373932316231 35643165666232653831356530313330633831323461303165623436343861656431313266333662
32333131356330383239336432663761626265313266636233373363343031343339396362316535 31313461663438643062376262343365633534323837336434616431656131626530666637666432
66373234666536316533616635663837363361313862386364343932336430373934613934383062 63383461303562633063343863633832313530373334303234363366363966303866303138316131
64393835303235303835363633393430386439313536653835373164663064383936363335393535 32363034653836633636393864643966333032323830376465663937386238666539373733333838
32346265346337643865303030393234306565386137326637353430353633643939666639636162 38363964363135343764353432383736656561653164396361393337616335633635316536326333
33616537333266396535643536346530613637663464626238666464346661653235623064323763 36376164653565646138356433656639343938643039326165366461643230393364396439666266
37303839643137376438376237323162663636613431306130373562323739343636303936623434 62346163653531383934666562613563633163613239646265623236356132653230303032376364
39643764363065363231613065366232343638343461326635303862663834386633376262613862 37323532303666333964346132613262653236313239623531613933383362623233366632313736
37623662346139623734303239346366633231623937666330326631313637326466363833613534 39313162303930383637663237636237633539663763623661326530656132633233346361663136
36636639323563386161313038313835653061613530343538643665663439383361633365656662 34316462666661343839333634666130346662623136656536366661306433306134323163323561
62643732633634626139643630386531303634393432636235386333653732336234663738346562 31626264623939313033623738313265626637353837613735343166306233333837613336353639
32363832326365383137333566623635376335666134396362343064346131643331666666343463 61356461656561383565623965353738643033333637613039353838623337336138343937613663
38633837623337333061373164393330303161373632386139656336323837383637666138663832 64376163623562633135366563623533383466656234333535393030323631343163643363623463
38323763343237646138636561363436613063323962393362303630623036353537353061643463 35303131383937643632656434366339616266653134656163633661623330666637656335666335
37313863623062653036663733633731623831626130373265326231346363316538643562313036 61373362626463323131666231326636343866336337626637306465613463666335366431373339
37623566643636633938353235653364616266653861613362383464346237313031663063646466 32343136353463336164363664333861326465363334616530643234353165353235653665633135
31643463363138343037646164316433646232616430353338656237623436376534366635306663 64656163333462366437616337343438623835313139623839626237323433303861323963333937
61333166363537386235663563323834336130396166393133313036653631383035336465333435 64323437623630613136646161303363313033316634666531323534383363366232313166343433
62336433613235616234376133366563383630613161383830396165646134323139313437613236 61373832623464653865323364623837303637303234646462633336316630303766633733653131
38656531333137653966326462613534373830616664326362313064613434363338343564616230 35393834336166323334663033613938616232656134313735373434353263306130363130613966
35316461656135336563366637323933363763383165393535383566306332366530623735383034 34626130646534623864316630383235303263626462343732646633303764366234303135383638
39663434336266386535616430656566353137313231353839653565663430363638336530613462 38363362623137623532663365333563363138306336336537623236613766383861313865376131
33326232613964636231386237643063633335373234346165333336393234666233623038363165 61626231663930303162653334666231366435356231303730666664613737303961316163633339
65336139343634303462313335636232363637356437313161393739313966616364333335616261 34393730633966323565343039626231303736313836346237386662653537613132383962643035
30366536623663306535656431383534393530666461626562353262396562323638663036393934 62363233663366383365616632316161386531646230346331343162663537393033646330376538
32313361333439376563353130653537346438363830346138643438613433323731663631363732 37636234633136633363626634303662663765643664623432636530386364663961353330336164
63613738363637613230376337373137656363393261326461313233343466393766623433383338 63306339386364623331663930373335623766306536353663643130613731323261616339616661
33333533623838353630366566636661353730313737366333653537623637636138616233316630 33373138623333633962386161333166393466643565306564326234653165353362313038326538
31363362646565383534343535393266396465323634653262653931623931613565313932363961 62353136663533336361323966633737376133366338396431333435323261363035393561316136
36623161373665393466306161323862303830616333316563653165393736343638613434323766 36323738646138363861636439316531646235396466316138366266316361356664353533346630
30353331633039393461393062323335316662366537333035666536313036346266313839613031 61633538353661646437633433313463326332613261643536386666656637376163393266376530
38396232666165633437343032663565386133633631643863653539396361623232643532393665 65323834393131643731333863623134613638633235333064653238383363653432363736396462
66646334386565383338396461326366393833633037343238306635383663306635356465613932 38393939383139326362623937643364303833663861383130323235313865653831656133613439
61326663363634373737336265643836396238373761356665316464626138643063613632663461 63303533613065626434663066643531306139626133636532633932633037323536373439613461
65646366336633383765373034373834313731356330666363363535343934663366326465616130 61353234356162363936313065636136653636663437663536613563656333353039323863623861
64323533366235313064306536306238666366613839653730373864363861373231633164313034 61393630363237653963323534316130333363663561376133323039326137323766636161653831
37313361613666343531663965366239363735643465323763373362623961303063303536663264 65663937663434333337393863323134386638613435656130396366636139333130353334313762
63366638313332356164616435346335356536336266646263346538393136323537663464643265 63326661373932653561373635633332366332306133626133303066376137633531656562313835
64313730396638353465626330343836313863636666386334313432666230613462363137303732 30393266393161643836326664343731633935356264356136313362386535376466343333656264
64316234306565396464633662653831393934356637613139633362666661383530363032656465 64383663346365373830393333313735623536383732363037616231653164306337323832633661
62366639383433393861316132323634373366376539636462353663303466383233393830646338 37663437653763373563396465333836613964343536636564343665313534616230613162303338
62383837633533326665626161666530346336616436646535663930386462313165653436306633 66303337663361643635663639633832386263663539303361343934613864396534653135353766
34636238306636373136303866353832303265613831316236653832396466643934356464613331 33373862643332356530303964623839663732663536656134316262346334623361653266323263
36653466363561373065363934653434616661323438353166383564343731316662626264313034 31636133356635623166306463306637383333383235323334373736656262393661323564656166
63626638663333303938613636666239316635643931626538633465613465663235383137633839 36666161326436396133336662633465636532633262616132366162346365653433623639323830
61633761336665636164616162313838333937353761363635623033363964616137643035333735 61366466636165303563323738333831373931346563366561333235343539313930396637616461
61656639656263373535356331373633376463326134363031393765623332326136343163346533 61633561636136613665386162646130663864316238356130313931376238353234633137383734
35373732636131303561393462656637386631343736336636323139326234356238336238633637 36343231333266393030333630663863373663386333353039643661353861316366666339366634
61306462373633386136636636383137356437653565346130316262373436663838333065626239 66306334653339303762666135353032643034633739373330333830366436666138343738343534
31643264346363346237643064646263663931353663613036346663623031623064363637356537 64333137303963373438336361663136623064363665343835316661623831396532376362366134
30626336316531313339363937313938393864633733303738393766346537636232326232313833 34386463666532616131643331643436613630353561346430383736616437336466663232616165
63373563613935653965653737383438643566623532303939336231333639623834323639316466 32303434373035323235666564343136333161323839363361326162626465653736306332396530
38653635643032643431326462383634343235663630316264356431396561363932636136656563 33303637616637663566313665356335326266616534613234343839326138393664393062336430
37373466356538366636396130306135636637386632393763333365626339643735616332393236 36626533666137336366613761356438616136643436326437633936663961613434646263336439
65303032343831363332646564633861383865663731343632303263636136353962313232333938 34383538353063616464303931633561323834623761373763343962343663653265613030663036
61333633633935623365393032656133323434626161633438373766333064633161393434366235 32393538626530373838653934626333336161383235333265636665336638353839623061336133
66303566383132313538303637623836623163376665383933336533666530613738303262633333 30643439396638343261613831326131363837366462333031626666623031346236643437386532
35356164653063633039363039663934306333313163363034656463646464656436653438323362 35376133323462336262613563653830396461626362343861333139353038313966636363323836
39383638373337306535313739376230316166386537383736386163663861653939633338656538 65326466653365666338613566323461376333393162366638313733663631353933343962623737
38646431623831353537393835313130623336636535313765633830303164353932336632373131 38323365373263643138393339323937313864356131313032613463306135336134366230346339
36353566373662663437613766623434636165616562353938336631666665343661656363313538 31363966306339383264346464646361306463333031626534346662396336336338616563616338
35376633373535616163623838616561363932643366363235383335373632626131313063646265 37626434366161656238646433323133653430626564616336613461363661633138663932653038
63653236326135616361383339623663373331343735356334363761333766376333346332663733 30646435313436303937643730336434373666386163383439623338393862623838356537393836
61643231643465663933623735336532326431623764396136633863353135633432356362633364 65626165373363653638633164653761353265366461316239383732633837306636343137623962
37633138306266653339643763326330373637663831366465383035613463336336326533333038 33396435343837326338336538646534613131346463393862623234643363323030373164623533
36643961656336626537333161656264383334323063643462336331653663333636376663653065 61316466336132343433346538623761616535306564306566396339393830353235323735343463
66613231643363653163633330373039616138306261393734303536333763313530373738313266 64336462313630303631393839383833323337326337333166383431306638626166313064336336
64356332396137383966393238313033393934306264373234633132613231393132336665663930 39366163613634343933343462393932643666326434336666636262656633393762653536623838
35356364666334313937323931636433636164383562396433316164316232363262363132653435 61353438343165633038363135613665663531646261393534353938653262303763663166643737
66656239613163353866306631323961623731623932383265306339366134346666653664343639 62653935393338663065396462616534326237396434333566396466643238393734313036613532
37623766386538323763353531613530313665326661356566373035323833333033393364343439 61336663393537303031316161363165626661366166616333333761376532306462396463393932
64343133366334346532316439316433346238396639623633373534323338356263643263386332 35633266303665343836626335653238313065336435383634383566643162653337613531636165
39346339346631333733613064393964326234383434626462316330633031346262616338643737 64616635373533616230656335366131623262396163393561346432636363356132636339393861
33353866666532333233313362653765393664323937666435393435373638643039306366633539 65303735333935663232393162653739353964666164343434643737666538316633383930663232
36336132383032623864376563623634623461303564326639366361353961366265336563356436 63303230373233383261633863393638343562343831323834383163616333393762613265333961
38616538303831653533323332363863343666383537633864356665613139356535666136623364 61333032366433613032373263643662653066316162663438666666633430373135653738303763
34646563303636643133386537313038313066303735383437363531333739353166333635333762 62363139316638363463646631656266363333613966333365353666393233623336376338393931
37356532376132393862666236303332666262326135663735643663346234376334643966323339 66353438633435313061336435326336313734656230363061303530383937373965356563326462
35626437376162366638373235366366363166666438363964346361336361623234353337623062 31386661656533303861366333313939303337636264373432343466396633623533323662346536
39363234663765343866353964393438316361343532623766393964373838323363333633323134 39373865613639336265663862653735666239616331363531393138623763326363656437313963
37356263303564303534656338323537303965333138326636303138636534323461633837646462 65393934366430626464633632323738336636376533333963343536616135366131383934376138
62373839396138623739346466383830346535663534313265393761376135653465666630626232 36303562326463373261333538313135366435376138313539316236643334356636373063663930
39316337306161356239633435663166336139626232653261323463386363616636353138633133 62366534643333326362613163356532616266313436626162643132303266353962396365666162
33303134646130643261333630643038343637636132323930363638623266376263653561306634 66386231393161343561393864633566656361333439336663333763363339613439383231346236
66386363656233386639356462643234353464323239336464646236383537306539356662373865 63323635656635353135363535613134383465363331343730646239343936376333353636616639
32653865383932636230656662333530373663643363656166636535663862616330386163613337 63313439346262306634316236383138346166336365393531393930306139306637313831316666
39623864633435313735386163666164646335353562306162346339326231366566613735353033 37636133643839356366363532333466336438643739636136656338653533616231626431613439
32373762313636343761313235306234343639613463616263386130636165393636383662643739 37643565333863383633656233326432636662386437663731373564616135663661313265373430
65303537393437373866316535383066363732366130646533663062623361623565653138383433 65303830313161366437633233326136303330373163343736333835333736643035623062656136
35313335346236353363323434653434333432316531393433306435336238666561613161643531 66383436313165626234326438656665303831386563656330336332653130633964626633623764
64393732333932623266643938396132393235333030373133386638643831633138613835366530 30393933643362653039386332366463633363353834363866343061343236663738613061613739
64633933353465646461356465633239316631666264353530363938343732656233323339633061 39623736393364383635373964323163353338613466663366333631383531333736313265656566
63636364323762633639306336613532333935633132633239333161343933383030663539623732 31313537343039333164326232333166613238626533363832323732333261323864333532383737
31616365323265373461343961313436613436633061356630656433646361373464373962303534 63393664303362636662643130373565356364386362386261626431306631326633373230636531
63643039313565316461386230333964366537346162303838633133323339323636356430373264 35386134326435326539663138343532646533623130363163343164356461366662303833353732
63333364383363613637333463383238303734323130623437333262613763663535303563376631 65653638613437653835653139636563313263656464373166373163633861333761326562313436
35616133366439313362653763643135383061613362306533353638633666396266636337323031 32656130313938663433646265656566646434656337376136383837313263396537346130343536
32653435653639663335333137373964393431633261373436653036393366633639646639643734 31343466356463316338393862643063653331363434646563653238316532343764636538393461
35343639616637653464663964383961636565613363366561353838663464646636393164626162 38666365306532643437333164383661313365363831376233646165656633633236313962643233
63613763386262633936646466316531353164323036613539343938633830626361376135666337 33313763623430336132363639663734363762643732383866373762393533336162666361326638
30373038656339373665613833383439363131323562343435656633353266323762323764633336 64633231623338383633386636343338643138343362636636393239373231643031663865613331
66313561333066626634643531613930316664373434363365626337393833393835656262343662 62646366353439653465616337346363373736616137306339663433303234626536323633633233
66306138383962326366353832306164663561353661323538653861353338633935636630346135 65623131343039613366346665393235626364333063663830393436333633626464326465353832
65343964323839616334363430323563343463333832623766633364616136393934666238303130 30663561306138333831313033396165313063613063626563326562316636393036666638656134
30343662303736626639613034316336313133633630633638356339323831386238373832666232 30306665393137373865663161323435366365393731303764353539656266653035643964373462
33396162666134366439626564333634313666376138323039376636346436343031633361663130 37326639613161373436663335356666323964383737623133623962666138373465346462623635
66646364646235353531336132636339613138336332616165376138313764346630333233613332 30353664336664353539346264363563383330363964316332663734613566363035383735633333
65363432393532646663333465363231363535343961326631393565336363333362613730353733 33613830343633343631313362393037646564636333316231346166393935343739323962633636
39343862636131346438386165396334313230663461336264396666323962643561653139323664 39623063613631383561363030666131636437326537346333653739363434656334383638343635
66323436663539613832346265633962616531363731376261316463373035626434313731623864 33343763363234323137396239653239386533613263366565343865616131666331376465666562
30366561333161303934386562643835373336313530633436326334626537323365663138663366 32383130636462363861326264376362626264393666393366346165633131643734366130313334
33626534363365376633626564326266666431626364623832373865343035393963383838346362 37666336376433313833336131623234306631363832343039613333666134396461636565353432
66353835393439383966376365393966636131306464616636643035383466303064306635343036 37633633616464373639343064613635643466306661306535373935643563623163306336376637
64653738303232356437623937343963313837653931336339396561303864393739356135663664 33313638303436336537663463373535663133356362643763643430313462383538383939393133
36656163653266613330396236633566366331363236643861373338336562323066653766346232 33336632633835346139373731626430626561316366363665353039353134386265323634623861
62386339343161383732353838353764326264376432313865313534343734326538353364623535 65653837393465666230346437336538623765393131656638323238616537326432326531323166
36376535623834303038396139343739353131376338363738646564363931653634323639353331 38363530343335643637666262363763326466376265656534636135376135336563343735306162
37393237623864316433313139376538356538393966663065616131613931616638633536613930 31646231303932616439306666396537316161633032636638653238616637353738373539616664
63613635643565386464303065623966623038376338636663303435313764393838626563313335 66666661633137306331366230616531336461353963623934313635356338633030376461636261
65353636356330613132333338373764353766353363333838333839633635643935376462393030 61316561633366386661383666393961646264396537383439626262373833343036663365393339
30306533656139666534666162366465306163393063633632303330356165643135656433313336 36383862656331643035303635303935346366383534663563653237386435306439653931353566
62653237393834356334613038343736336162343337343666333935653635623834393139313230 63383964353666616433353833626132626362383065306561393539666637653834646633663865
35376233653937326630393939373365643338353765356239646262633632643161626161366465 33346365333262633362326537646633383031313536626462666363373236313663313264636335
64303630333433303631396135343931306363393864663162663538313263313333356262326464 39396330376366636339313133666437393833316161663264373265633962636338306534626335
36383962616163356166636137323230623262343636336364376366323238386663303336653738 38663962303130646239653439626366326661646239333235336635346131376264303562336130
61393138396333623738333766636563623834353737333134303733336165303235303635373361 31663165313665356639613937323165616631656535353564366265316637373135353366623332
31633035626334313336373733646364643333373063613063636434383037323931383466633164 39383333356636323763623630616562633364623638666665663831336665323031343037623930
32396233633233646630333037393635663733373664626665653533303535633034636163643937 36643762646139356661386262373134386431643536663038636236623636633364666333383135
37613537616137303261366533656536376437353839303439373939373764323563313363396134 33613638613261316333333033386461386332303363303138313031666264623039393935633731
31326632663664626364373133346363623239313166653737646335633833393838356131666233 32323937356639343834656465303938623338356633393233353630653039346534643366346535
65613662303338306638623462373961633338346130333463633465373739323436306232333731 62353134643563323966326434353764366436653036623161356239326162343966356164613533
61666237326631323434633063373338663961663837653038326233636666336662303737363935 35626138633537376637376334396535643132336631636137653666363264306166333733393831
38613663363430323135346566306664633930656434653833323539323266373931656131623933 32373563366135336463613734623565666365383266613931656238333631303530363965643938
64613763643664633263353162366231646262643164653437316336343438386665633562366334 39396330326339336336313236336432396262643066396133633036653938613133616531393036
39383261383265323239306266323839326566303666623462666236616266626439356266303134 35323265323966386465663331613062313763663131643663346465623031626662646133333734
61306530326265623132656662653335393962396135356561396231393831653331313765306161 64616131633665653135666562373666333362306233323539393234303866396333646536363238
34353064663032343438316163633333366266363839653662326238336631623863663937316266 31363633363431616263376339376238313162363437376530653366626439333364623764373864
63303936663666326539633138616263326266613534303162346531396333313930366466373161 30333832383532613836376361663934313561373733343166383266616236643034616662313933
62363064653737383264323235393935656534313830653137383834323363663237356230383832 65366637656338653437616166396637323633386334613461363062386630316135366433323935
65363139633961663063633936323339363839663361383361613864343035333135633038626234 31326232323361366563343039663837366337373862353833613336336633636635616565653164
65633662343264616637386463656261316631303536386236393635636430383563383232373938 30316531663432353238663037323866393766373866353766663434633937303032653362323664
34656437343633333438666461343665383066626230376233373236663561666135663433623137 30653334393439363638623539363337666161393532363933653961323662343761313430616538
30343639306333663530646635366166626432336530373363333131383338363966303639363765 35646563373563363761663635646338383566363731363264653330663635386232613565613264
62623537343732396264393933396366376634626239363761663366636433336630393036343162 33306266346361356632326332306534643865323032346330663966333964313535383261316161
64653339633131363035666532613433613735313835616433316665386133623762396363626136 61633535303739343763333031353736643664323731363839353934326132656364366566343462
64653333613561613362333531343961343237383564386239376438613935393066383138613637 30356631313636616165623662356162643261646139373366333433623661313164316664653539
38356232396432623063373138383231383565633264356562303031663538616333363038363264 66373137666130666535356435353738663133353864323537396433346261373131383764373863
32303030633037353130326365386332623634393139343061653136326133653632613330373836 62373836333962333665376539356632383361353561616334653139666363643937633837353839
61363166393766373232633637373265393539316134303961336561373534343137346434663462 36653034333930326135363565363662313731383135636231343666666536363934623034396131
31663232363638373939626432316232646338633863323031646635623735303762313030626664 31323166323763326231333063656139333730373030653631323365343637343536303365643965
34323361333431646636386132363237366636633332343434323765323235316134386636616231 66623733656165333030643139646439343030666633366534396337663236623763376232346465
31333564383739663537663131623066313336333630316336303130326531643539346236326131 39333839336538646262383034646335323066613231353731666132313734663637396563373332
39393034326661653763343761653162666561656564356232383436323864623838363730616566 34663462306565393934383436363865343932613336396238313231323636303765646164356565
34366464353765313663646430656539663764363562356336373634646232383338343737326662 65663463636331633336626438656334393366343338383564383231353364316361386265666566
38393964643261376562336432393863643733656438313462383161613730656235666333643233 63376464656263336461333661383333306566663130363939323131316663633662653738306366
31333633346333663563363730376164363363356264396334393065626165353834623139396235 35626361376163393864653332326463653564373563396531643532343766366261653332313131
32353734316137366131383935313136313337346436663735353331393030366330623937383132 33613463313136336434303039356662313233366137633062636232346365366361636633316565
33366132653534306661633765393833656534316533373163323333613839616165356636373131 34363562613265643437383033393062663165313536366634303661303533663862363234313839
33656534613830656532333533303730323539326439663665363061636431303431373662346462 30613032666164313231633837343532306331366437376530633364656531633534643335616364
36323265343939643936393066303065633637313437613832303062366334343139643864313264 31653764646236656637373036656532366631363164346262353034336564373233626263383333
63653665316638376433373861663630316439636130626333336361316165383535316466626565 37343166653865306565383036333032653335353161626630376436626363663065343336653936
30306662666537623963646432323262386132386130303335653634643436343334333130306261 30613339393064393532643862333530656432343631353766353338363464626535366164666661
63343666363536616236346637633632353839356636623066386238353833623565363932313766 33366634383339666135613430333832316262376162336530343363663666386431653232616664
61653161353835373762333034613563663633353634663562306634373938366130613831336339 30653637353432376132316561373031373330373266333731393338613635653466343464313334
61656265363662333536303633373233623436616238383463333764643362646532393630646664 63636435646466393766653135333037623638356630636239303564353337323135613233336461
34653765613362376238363163326433623963653334306231343135636230396562303662383738 30383537326139343538643633326331366531353732643730326465363566623265303030376534
66366531656562333533653638316336323365343063366332666436366161343730313433633362 34313635346134636337623737633838336239643938316264616435303935363036323339316466
61393461396162316231613265393932343866663537663333623035626635316466326664666237 66653238613463353964383231366563316666376237333631393435666133343636666435643535
37386661346634323438363938656339636434383931613931613262386532646466393333616637 38373635363134346636333563653063656537646331316264626139323631383039303564376461
35336563633164323535326530393134383634363461313366626139616433393935376164646661 32663633623538636232306532623261633563376562366133366665633862313431323032643666
30376638373565633533343730623665303438363361363065373166383662616134653066333132 65363362363065626536653430653562316539396264633865346233343430613333303865636139
65636233373934393336383631313932326266366362393036383434633333333333613937636464 66656632363564363739306666316666346239336432363762373730353637333465363337653466
32316462373532313934303961616138303862386537333439313065393630386637303161393330 62313765336130356532636261366232666462616464383439366334646364383861616166383836
39346137326338386634313838306462616263353065616639323532336531383238666662313664 33346162613132656262663062383962323637333332373062323936313365323864326439373565
38326163653663353332346631376461306663353631363661346337663266323166643062633132 64386235633531663366376332353866366333643736663833396361633836353061323333656132
30393863303130643534313035353631636631336465613738663361626630656561386236326661 36363761353566643432363634323861356534393664373761383565306436303239613532623337
38643630393963333036393534373839616236646466646433313034353163376634393038643838 66366666613932356138636230306434396365356338343437643534343634313432643238353234
65356636356265373339393765613164343834383762353234373831613264356134643739666337 63393338303961353264613666346339396439313838633431366134613931666565333263316632
36333162353239313437643336636438656266646536663939333765633862616530386538643935 37636365616532656339303963633135613830356130376463336335633331333065336538643963
61323864323632626331383461613534336534666533376566323936363031343537363432396431 34616565353630393932393231646433666363356134623363323462386136353139363931326237
61643339643038353432366261663633623631396463373735626433623032626333653939323736 66336637643530616630656231316662356138336266363434363463306236623462303764643162
64633336616536393736636361636238393439386165623039373537326462633332343039303339 31306634313630663530666464303337386664666361633539383531346533626335333939353432
37376339623837323461353739346266623334363439656133326130336563396338363963306433 35316664303938656436363631666465336561626431616663646239313938623961626230366533
61656531636232326539336566616536613836353633316666643633653131343161626332346334 31373961373332313264616433316366626464323462326462613736643137633031646536353766
65363136393539393039653134353734333964613533323061643563373332303935653837356264 66383465376262393133663931663835656236313334656563386266396237363963663430356137
38396136313265333063643937663461633438333039303234653662616666313732393038303937 31383563616165356539356530353566383431656163663130343865623639306165306531363966
37336133333030643133333539613538373461356131653262306630323734663532333932383163 33626638353532643063656132326239363166336334356236313334646538306162386530666131
39643838366263613062316331373537616137343035666130333263663361333730306233663432 33333935653933643331363636623738366263643162396131616364333963323534333263373439
62313539663138326239353932336364383337636564616466633830353030323664303961383865 38396231636532663934326465376161626565333732353037306131343763343162636539373763
37366635653939626238376238613730663333343664393966663461633866366632636630333139 30656135383263653238623062373231636436613733373131646433616336396531316230373937
65636361363339396337663937656533393639363336333930643530346361313832663864633239 39383231386438316432373035626639343266633335653835656262643433393434373333643863
37643439306631353263306664393938633139653633386466306563663333396663393266616438 36303833396363663430393164666439316465313662343162323435653632663737326435356239
31663963626564626461643038653363386636646537626561633464396535323666336264336130 38646531613439633737326539383361356237336561373264663838313535396236373033343535
63653238366565336431663365373436323938363764366137353034663666383537346264343136 35303234656666663766323261613739623930396239636639393936653537383432613165636137
30613734386432356536353431653562363738363762333632626630303738366437313431656365 34613964313136323430383564326265386135316339323962633830373931613037303436633361
66653830663236323865303131373335376630333234646232353731633764643935653631613363 62366438313738633263343833303237383239333534656538393432666332376461326631303637
62343063623133333162343066366232303233353565373739396466376239373163393065323132 30613037666237366666616163303662346230633131393938643636383636313436616539633337
32643636396532363531356530336563626164383164306161633166353262633433393731346631 63363332333662303761396339313766383132373831346266323234313338343430656136643638
31383730316130303137643438316332353132666436333232646435313161663333396537366163 66633964636337353736373464376631306139663539333464303438616334306666623061346537
36633063383238353665613333643262383365396439366265653739386264353436653137343239 33356665666661356363383066376665386266363434636262643430626130323163306634306633
61316465313835643565343733643330326236303463633032303133343662663834653462343837 37343735626361393036343566346230363137326563643666316630636139343865346430356131
62333334613066383537623838313565353430323737376237666164326537656430373032633637 61643535396264663336663866653762336330396135666162303665643733653630346565623236
32626264353461376536376137653433613035346264363332393462353562653537626262656663 35336630616531383931386430336238663963316237643765666534636264623533643930376637
65366237373363383738666134623638613138613962613936353933313061376162396532653635 37633031393532646362333733356165373431363330323863343362643231636361343862633666
31663932343936313831313636316234616130336361653533666431313334323235326565363131 35633834323137626137346230313662373166373039653532636163613231313737396262643364
33343630643764616230376434626234343463393634633534663361373465396566313862633834 38656465346336333965663463393963303136636131383432376465303463616564616631346139
39353964376434633130656535386239373963653832643838313833623839353866386531323062 33336535666133653563303039353737333162616239643261323333316334336335306230303037
63633665383935663965303830623563613734313034653139356435663733393836353834373435 32396339343137386632636636353730336464386537353530353563656464376532326133613933
32333636363937303039323065653134623438383730326262313065633265363866363435623336 33313734346132313066303538303761633333303564343262313636346238323236626566356535
33623536623432376365663264386539303363663463313035356164323038353264363862353964 34376232616335336539333662373563306637613232643732376635323036303666393737316139
38316235373434393964616233346430356463383230393730343437666437343663393263376262 34303663323064623863393262316533376263636332653964343235613338616137366461386132
32393861363264633130656266633261623130613362663537373332626230316161646539323264 39383837663538653533343663613963613066376432626464373061653139323139313937353031
66613533653633633262343134326434336166333634323034623738383539373230616237363565 34663961313435653263306263366366366632356236366162623239363336376166353137623136
65393765613134393465376435626263323633396238663630373564336136386366326631373530 37366434326539333535646339323738336238383835303163363334663737333135643564333763
61633738376236343863363031343835303931363936343364656136376330303566633962323232 61343236616530376335323537636666363537303130383064663666623461303339633564333836
37313266393463373065636466363665383665663362303137613138643530393137613761653633 33373031306639653063313063613763343332303861666533383239366463306538346566356466
36373363336430336366363136323030386537343962623361373265393132636130373464663335 65323161646264326330663164633239336562373564616131306330343765636339353237363134
33396437663064363634363132363038663438396233303364646266393931383862306464366336 36626462313962303132636463326534633035666335376133376131623863666563633066336537
66616131643662393862303166326165396135323765616366333330316563396161366561363132 65623264653066623566626534633662396163393438306239353864616565333531623939663961
63373635613663366232363238386331316461616636663439386434666165306330366337356534 63653461633565326463363165356664373164383631656131633663343336663137636561343363
65643662336138303335623765386465643561613039663536363734616264333431643337323437 61353339613033336462366131366565386338663435346462346136326634646134613234626666
35666533646432336165343761303137633130303164386166356337656337356437613862336132 64386465353962656532656631613735383664653932376334663262306230306130613936353732
30636235643532356236623762363239313163613432636466346538343062316435643735393331 36663538336634346531396438386437633038313830633164353664306533343837353332636530
66623331626566303535623631366135316238346165386430363062383138373132656633633939 30666231666532303437393264623030373461306266316335613465313531396436376563653932
38643765323636393932646363313265333637643535333762633939336162623435346664383231 63383764623635383634646163363435366430383864666632313437356135303934633662343366
35346664393165643239366436346233343566646438363533313964323831303566666264356337 32643834363937393162393666373361306332613233663564653633373935613661633131666432
66663638633064643962346136616333303064356331343031623863353365613661353333656362 66623931643436633964353433383264616462366235336266643630376532336566636632303038
37393062356661383430353365643964343462666436643236386164313932656234383039633537 65363838313539623132636464336632386164306632316230363136643038353135373635626164
30653833626331373930666239623639306433633038643963656634616337366230623265626539 33613239623438663832376137616530643762393666373063623734633164663961386666613137
66323638616330393135356134373735613933373735306330363437373237346532663239343636 36616638653038353235376138323666653866393035393937353631653532353734646663623932
37393937646365343065613233333331353763656535373739663263636233363230636166363530 39653162623833316262633033336363633030336561663231363730396535623738613834376636
38333065386138306165303664393064643836346264373939383535323365383363666436356639 35633434306438643937396532663364343661623134646239306362623432313930643333643834
32323364643937343139633435623734303839383566656539376263356634653838616337386466 35626231393431653238646635616161343733363662376638666166613835356236393135623439
66366632346331323039663863393666376637626137393037623161323931346565343935343863 31623465653532386438376235303036383434616135653438343431333832396563353066643161
38643864643739356331316162633233666162373430623337383734336564633463643338666637 65303361383437323032653033393663386338353164613137643662663231336332643639613530
35656265656461633537643739323833373838653130613831343336356331373737616465646564 34306535643161363064646432663961666537346464393530326665353237356134633162343839
64353734333262303038663631663231326636633532343164643338333237333331316165623032 31396466386335656236343639316136323536363231376632383364353236376339376535326164
34386137386534633432303638653366333962646532336130646139656136656533666533336233 36343334643433636238373363663435383966666133636164623863653232383064326237333234
62646261636630663161313966323862363761333135663864646339393835316437613862383434 38376435373066306462613935313735316232383364333733636261323835646237363262323862
63643436616432653662613531303361616263343365613437303838613332643637383439646664 39356465363132336235613465663762323230623133373237383961363936623763643430643235
32333761666237306232633832363362626239326139363363333530666630383736623839303065 31363931333964656539383739646234666433346663653965373833353633366566303864623863
33383562353733393830646661313632656361623037663262303665393532306335643465353436 63336330343666386135343730623432393934663532656565386531393762633734653438633461
63313834333732366530373366666335353630663633373333343434626664383137646538336666 65323366613334626134636631353631323238643138356164656461643866363061303062626433
33306666383838616435363037333062396461363634383236336130666635666539366462616238 64373662643532303266346333633366383133333339373865363137356632666232363039646538
31316265303961323666633065633961313963663962383837666565366361333836656364346137 61613130363763303563393735373761336164626432356664393063386162646233306166336563
65633030356432343935343139366138666137373734343361616132626630313833323461666265 31633739316662356630353938383861613964333661316237616533363530376230613464333265
61383565666138393937396265306634323939366334663635663566343932656633366333386434 38636133646235643438303163396132616537663630356635346332316364343966393131383931
38303530333034346139366432396663386631663931623761633961626539386234623837376262 31646536303761383866366366303131363634383062623731373434646430323237313730383531
38326235316330643635383934303030663634633834613164623332393365333966316131316161 61366533666162373962326132396166326564623464646136653730326430623631363762396231
35353965396337356463626661333232656236653930373531316163346465333862623734343438 61343333613162373865353165663331336232656139633766356239343162326664313639363135
65643837613962656162343866336634353436346337643761336531346164353765323238636262 39613639373736346531656636646136323237646232343139323164323665363664363665316630
35663432396165306464353266323532343363333232653865616563613030356236323036396266 30373164333166346437323661646463323032336265656339656336306431636537363433363533
64376162323436646532626363363933386433333033363864356334323839613134613935383764 34636464353332663138313132363739353065336564333532366634646238303435646237303533
30626435633531633361366332623861626363366531393861383134636230643032336663666131 61616231333832623036326133316534343566323134376461623338653836346435366433346438
37643630313138623433316562643435323762653438333335323566353264323033373834316631 39366563336436333466636433396230663136306666393334313039656365316264313561613863
66346332373366313234323237343931393437646130386261656565663065636132333035666164 32656238373536343132333135653131643936666231393165643662616434623532393638363666
35663762373131643164323031653365333339326264626234623537326638663432666235343730 34346634326631373739313463356632396366653161616461333432303333363265373561613266
61623961333439633265316431366434356161613166326162383732386166383036313838386539 30316264366465643633323237393562373963396135616465356533653464333536383935663738
64636664366130306365333762646133336465313033306563353633626561356336313966383931 62353537663663363862303038306461363364353133303533663732356366323631363138383632
32613863653662316136376330373335316437376233323930356434663732376631643963383938 62613662616538326435353534373865373231393833633566333534306231363734356435633835
61346262333339613736386333323534396130313935663632663432623162643738313238613438 36343962363739343235373834656135386662326136396331333964306633623931646539313232
34303163333731626664303337393965313237333936663664323565366434643436623539633139 33663162306462333562613632666431316330396630393165633530333737356635323633623430
62363431656634663636646465396238323165376131396635663764356532656534373065663461 64653231663665646436656263323032353530613731336331383131643937623333656138646664
34383765333933383561646430633235306533303134633939336561623265626431613833346161 35366638333562373431663038643331346634316431646130663666643464343037373266353966
63616662616239393566396332313430393563313063383836623331393965623065643535333734 34663736333839333835383437363562326436363962313066613864663665373438353932316330
63323431633533373632663939343830663530353533373730323939363931353438373338313466 62373066373634346434616234376535306133386331663438613061623965383333323364663664
64326461393564383961326463326335376238353034656531643732633461353862636466646264 32336438376262376331663565643466396237323362386261643162633636316138306331343764
64613635333334363237353235393539363766643838396330663437373639323432653165366339 39356361396535373961613930623030353766666133633738366263643830343463633563626462
30353739383739633564313635653763346631343934636437346362373363316339396437323733 30373839373862323164313265316139336364633836356534623835653633646439346436663966
62343733303834323736383834306232333932626166626536356338663862613339353531363935 30343137353765653239626265356338653031633166313432353865373530373437643531333339
38653761663066363265383139373536353638623330333239636361646564303039343930623638 32613636336333373239336230326639663466383466393930336161376663386534393866396161
30313864353833386263613633333335323932643462643133343461626365383238623639306631 61306563373637653962393233663130326535373737396361633236363239633333393838316633
32333538613432393662383434393831306236656236303234656235353637393137326665306661 34656435366662366666313632333739353962343132343265363962343236636439663866623961
38343961356631653631323261386630343263636537323434393736313333323334336639356263 32323935363538313531376637356636623666346535313939626333386564323765303961343961
34653237313930636237396264653336396132343364616339393061306435663632636433373065 35306234333738386266343333373733326634666362396432323561613437306533333536323337
37383139363666393634323636386166666331346564333336386463626433376137646561353730 38626439626338376536343439343431356338353264633661613035393636633863303133616464
33633661616238623363366532336363386137333363346463303435353130643132313665643264 35353861653463386634313437323639633965323432636164343862353030323033386566623963
37613430633733353837626238303833343463363662303831303734336165383432663562613433 32303962353632326239613537623834373534356238633433633131313763353662353036333132
38613564643230326163333863633961323239376136323833326361653862643664666233306564 34613236316331373937666631386462653539623135656533386164613064383666346239356635
39653738343431616563333563666132323639366461343039363436613236646131343332363737 65666164386635346166383963366135623934336636613963393862656131396466386335616161
63633036646232646566623632383636303861646131373330623436333338346163316232363339 63633334386665666165643664363065396665353061323063613635643864313330643433313661
31346163623032353861343234333337623536386366643037393265316533356261313136313237 36616632633037323338636630643037643334613236653137343530653032326335306238323766
61663032363466626239336435303137636366626339623730653334313862306539633933336438 62356266656235333434396435646332363639356163363365623136306432643131663131386139
65663436623033336263383438353838353037363266636438346266363363633630386438396464 39666137313563373462653638646230643762393962373963623161366233393462343036373738
35346630336231393137366535333261313662663564653963316364653035613030323461643433 63636464393263356331663030646433663737323233646461323963383335363962616337373934
33623934666562646537623936666361386633393364343363323532306134623461366334393439 39623865623835623163323164626162393038303931343036383738306463643431383364663564
32643164306237393031663537636535396635623861383163343538633335383466643733653338 36623563363363326665303731643531666434323338373935643736306138666665313035306136
38306161643436346230383763313138393435356435336466303831613261356336366234366632 37666230373034333261643431333262646238396436346366383063616531653961623834346336
64323362373833336664323936323361616562653531373962396533623937386238333965333463 30306336323665366131323462626330343136346334343435313630653135333637383731613963
63366633373732643939306462356163366464333364613738393732326130303262626537323966 66636537386336313235386234356238306361623962363263313039393362353665346664363637
38313837643431393232633531663165373565343739363032336538363435613336616663613463 63646433393464623663653431323133393235313834646266396265343633663732396638363532
30333739366165613165636561373965356363346231646462626235636431623233663038373761 63663336653638643638336566383239303563393764303065636138376336623166356634396432
61363863316137393033306634343034666466346631393465646565646333343463363362363066 64353763386230626566646634316437383963653462346435336536363462333038303966663931
38366139386634313533323932666335336131393766666538386632336264303531306264336431 38613732306431323937393336386133396362323939356330363132653736373433373834663433
61303838616139376332613838376331336266316566613738643537393162623032346431666137 66366333613263396131396434386565333065623335353661363336373530393934646630306337
64666339393332376636646533636531303266633530633436326563396462313838616232353162 62623062633038316530303865373662323332353065386430643530383335316565356135373666
38363535396461326131323936336661656364663965313462326534323461313839313264333231 32323731663461303138613064346138613333353534376232303538323132313039386264323732
34633163626336316666386133336133306666353632333033353533376462616265356438373733 61653033356337653735323330303462303439666464393262623062663736626661306139303837
66666233333830393437333635326239373239303032633765303735646162386237306438646366 34663330313539336663363830363963613561336664633330326265343333653839663462353230
65333534666637653165653362613130626432373731656636396662616533333635303964373263 39373938626266616239643939353937303635343661346535663564616136386337633533376137
65646531633731323438636165303938356265383030653066393031383438303236323763623963 61636135393836643764633838633361393230303730383932333564363739633137343930336331
33383130616364383438663133646233623864376131323765623261353834633331353265303731 63343937383763363436366335663763343534383963363266346637363437336635376566366230
36306462396530356433356537393335323965663236646637306139363861353139626666333032 36633535356239386238646136376431383061633939656663373735383235326663623365306438
34306438383737656136313539623837663232306137333465613938353161356530646666643539 64366433336638333235663437353463633937396136663764623166353864613162303832383566
62333038306665383362393137613962323064653135376137626638613133363535646561353063 38303664303962396362643631336536353264616335643332353137366431396464326635396634
39386165333663336439386132303334306330373730666536373236333438636663626530663239 38333038373933663236623632363431386337616566313765663633323163663933303337663938
36663039616662636334663864323635636439616465623438393630383832353366323861613162 32613133343730396666653461373161313139303063393639613932393864376337323363376332
35333666313236653433343836623931333765613837343835363762663563363266303561623735 66623266613962663066353335326230616438616562626337363965626564663666353064353530
64353937623133306263393738303666323066353964373033383065316463383462326437653034 61393934643933343132306265653235383430653837316365383265353565343762616135633866
35663831653336663231636165633433663530313138373035313462393531653339303365646233 64633766653133653335333061303233393038633665363566633238323530373239656661666161
61303765396464653037306630623738306366383735386135316266356165376637396630643361 64393262656162356665646661383861303765383232363639303065363061303332336562333732
36656237663565303433313332386534356534653463313363626264313132373266383662343233 31303363653136313732646362303838343838373533373338313838653633643136666631363638
33326264636365303630653834646539653865663465326437623461363937653232386166373233 31613738396463663931393064643132373564373837333337343832633837336663336262616665
66353164383130633832666438336261666537623164363263306433633337666335656134353765 63326134376538313466353333623633383861613534373534336464396261643233656130643765
39373134623061653134636364643935373233396237386334653561313833343762323832313564 31393631653630333233623339666535323031613939613835303764646161646132306635643161
37356238656430623763396439383965323136323066346636313465633336393931373931633131 37313361323165393034366365396139643233386637323734633463613931656238663537373562
36363262336636316533396465613736663662306232323739363336666233386565373837326562 37396265373364316561393433363635326365356338623038656439623539623139326235336632
65643661626264303434613837623761333934633438326666386538303264643334383833616631 32396264366634646330346232376636313038656164323134653866383864363864383965356666
36646564383436346234303336666666313165396461373938316634323830383135343830666339 65336363333035383637303934383533313663326431323637626133363338363538633634333035
63303737613439633335376163616432623366333933643135363664626437636433323731663166 34653961623933376534613239663037396432316237313137396339623239393635383966663164
33303535643634633764643832633263376338313732376130336331653032663137613031333963 65636266633439376135613832383634343633323366663833323533386239643762303638623738
39643561383633383932653066363461663331383962373631636632356336396134653330373961 35626335373135636261616138363739633134623738633966366139643365323264326239646636
62643433363830306337663262383261386131626263303762663061353936623034316432613963 37373231656436343431613830303662336138376437613938343439633534666563323930663938
65333738326264313235303730303165386463353965613264383631666463326434656235323630 65643036653265396237343164336365666337633361616433393561356537316438336331666365
33656265313363306565626662303139353938306237346166663534353936633235383735656366 63313964373235346534326639643264613539326366653938646663333365666538373530363064
39646330656533353030353537636362316261353966373739636336633334633262343336623762 63326431393130336165613632393662663563393066346562383534613833346661363933386135
31383637376566616464316132346639626464366262343032363739336330616363373437346334 63366636346539383636356662306162353161646132336630303739313866366434383464396136
37326133633234373231346632613463383530323661386364376634336135363438376239663263 39643163623433636164626563306138653265623563353262333831303438363739393762333464
66363238643833333461626437356165346435386363356230346562376566386538633638376362 32313664353563663364366636313366313639313134356332336562363864663862666632623832
39313834633264613839396233653162313735313230346666393161643966626230383066623863 66333236343136653439353066326434633032353139323563616666336239343730336530613761
33613365323835343039336631336138656566306161643132333562373630383533613336373435 62376231633237313732393835346665396634316263356630396463343137363936623064306461
37383532356336303738343565326265336631393336666136626334313539383730653462373963 39663935353463323565386333613464363438653237633666613261343833386336333261323561
38346666663834333564646461356636336133316439303062643534303837633661303032393633 33303662613239333362383661636235643861393734333463343464633930396434303562613034
35636231333561343761626431373966623966346466633563626538336430646236613466303331 36383130356635623665306362623235373364666137636336313066323933613836373431623635
35363736366630363166396433653438643563326464636466633866353263633534313365353334 30326465323366306566636637313631363963316566323039396430396139336234306330316465
37383963363035303735666330323435623531303366663866643334366461313336303334616337 34623339396136643938353066633036643837363562646539653533303035333562373436373031
32343362336366623566356361646638633237306531396264643437356133653931396433383262 30353438636430376265613038303633656230353934636163383465303363613936613236663366
34303039353836373738623339393136386538643738326264323334623962323838636464663832 63626637633432303463306666356562363065313335356530346539323961313035393865666633
63656234636364386663333733663332393639613335666237653739316138383536366662393061 36646332376238663166666264376132336637316561616532623534633430646139373532663138
38393137383331386362386565303135656231336163363839323332613530336435623365393361 66313066363435303864623866393462346137633730323066623337663335366461393632626138
34343839373963666366633564343531326264323538393231373032663935343935396661313139 38636635626365613561313334616230363936383231356465383439313138613136356462316634
61626662636235653335653761666137313430353533383033363762396636366463363635386437 63666131386339666464356533386333663562373733353434616666666639386365633732303737
32383835653833643866633265666661363837396337616236306636333633616337336233353966 30663364636336343362316135323236346639663939373365396561663766313362393838633737
39613232653635373534373039636437393630303063623033366563366664633233323565363732 36323835343731663235363234306332616336313035636235393038316438366538616162626634
33336132653261643835336430613263323832333065663131343830316438306139653736326232 36343836373966383538353034313264313732653635396233613835636461646231353365616163
65313764386231623434643738383536323232373463393239323865313061366364656536626261 35383835333466343934333065303538366361616436626338333137343332613965323964323836
37353831366538653130356330303630313536336661353738303230336435333663393365656239 66323665333461323864346635393636333163396334663264393337313863646139396664613163
31386561636437303432613765353932306635366234383631346261646461346338366165633033 30653637613864646631666364373162313939353339613732643637353635653665326164383261
63363066363966373430376634633733323233313466303033663463323932376461366634323831 30336135313766323933383232323630356139343934643863356434333663653830636561613731
64656431316533613930376337323736633361386565376238336165323364316264666235316636 65613861333639393434646436646131353563663864376564626439316261303161336336383739
65666334363638336263626332346436366262626537356163356362666539616636623336343265 32356635656637633066303638376436353261616232313065303431653036656235323337353933
64616265333138333334636633613466656434333961316539326137656565346430646564313030 39623930396239323766346362336131653137663533343133333937626535656236343639613363
32653430303463613532313734666264336631333134626339613535346664306534343530343139 62396338636336323531653564366133643866366432353566366661393263666164653630363738
66663737343038313563623039633261393364343235656563663366383039393933353262323462 65316562333131643966376634396335383131366233326231386432623364323235613635373635
64376433386533353132313739393934306566613632613933343036633338353435353631643262 35303931636466303130303233326531343539366238376363333138666234636532363965383239
61356534373562333466366163333338303637623732373063646465656536313435333034666536 62383734363734643165373734343963626538396237323530643333666131366365353538666662
38303335376632616136363334356331313032333765626331663139643335383039333561663264 37643939643661383138383638363431343330363931306162303963366230636364633066373537
61353735306131656635333062613365343131383531393838376531626631396233613130646236 39353462613265363439633961346331323864326536656536376534666534623936653231313263
65396561633464626137313737323164646236303866366538616661323331653536613936353734 30336232636434646666393566653164653834336563313236323965306663663431656239656163
35616661383063313837376433343836353064643937386138626636373263326662346663343138 66393136333937393863396531376561656538316164356265343532663262336539363662643962
64363164646561613230323436373333623036316231643364366565313534383665666563306430 61643031383037653964383661386238636633646232323565363162643239393330373263326432
32383539633661376366316261333730316531376133376166646136623737626664656461303336 30643561623733336234373962376239346663363537656462366134623563363762613462393333
39653031636233646239626536306337623631353539373762663230393361313862633233633634 34346431393136613866386338303066343463316233633933363636656630363638363264376263
30663561313761613064376232613166663433316635623134386262386231386262613161333864 38343564376564616665666432376336383833633765383263383137306235303934373230653862
62626333343062363565663863383038363031333632336664323161383239306466643464623233 34333233303037326432396365393339613261663266373465306635616435616363316563326436
38623034623031343130613139383631656231343134373039333237343065313139313766326465 38626532363862373832386335323335646462633138396162663134393036666166633337373638
38383135306539363261386531363034653637663235353836343331376337356436393132633933 36376562656434363835303336343638306538373733353062313530316363353161663732303836
36313166643338353963616466623764363166663239356139346333373761653636386435663363 63393363306336376564633462373265313539313130373434383539363462623131613862333936
65303934393339353265613332366233373665376562383562663166303838363233393563353730 62336630346133366264663665663431313437633762663530636266623935313766346233633438
34663937313864346230306330323230666234373364666135306461363265373031343865313339 36326164333839323562313930653038363262326539393932303237663563346664363032336630
32356130613261323435656266323231633164376132353065336331663562666132396635653964 38353530346166356231323062663666623961623835656265306561373332613937303739663965
61343633323532653238396131373466393561386434356536383134623534303333333336303738 61303765353437333465323165396438623838333635303164653764336633363633303935336264
66353039643466353266366436663636363438383964353635663664316463373238326164333433 33383934396630663564313163633466393861326330646461386536373336633135623030646266
38623335653366623961303161316261653038373837643733363534343663393065316130663035 37333134616531636135373063396330666538313736623563363432323936633163643162333466
63623931383263316333333863623836623635353862396439623264613234306538633466366131 31323739663931653235346235663832396437303932383066613633316362613563363530396463
61373237323337656162303366336363386139613635616135323035343764333166346337353034 64623363366237616632326531633932343231366430366633333633336462336634613033363830
65626535623034343232333735326438303438646263303261326664656339633762326338336137 36333661343765303336393263656231313739323038363038303436396130396335343539336561
39653730393164316530633635306333613333623064336635373732313431306631383737326338 65396532663637663234373431616536653661626665363634303265393931353232316236386433
33303931626431643465316438666432613564616238343237383165366262303237613961383630 63656266613965366439326630336533363166323935393230333930353166393465623438393830
36643439626633306263316437653866343362623536303032343137366535356165313430393264 39343332613462323437653865343333353338326636363735366462303766343433623136363739
33316339323838663062623566646365663734663339653638636363363861313361326166663630 35393630646537646333363931393764653036306261306633353463333939613837316265643961
34633433326633613035663639386434663430626464623761623931353639306232386533363538 62346234373039343066336534363065636339313031353264313537393063346566366263373339
38666636613432303739313030353830343535636633353664666661643531356138613731363563 65623539316635386532346435303631303030656262396535663433346138333963353732616562
32616239343063386536383462633332303136343333306131616563326438653136313830303038 32643334663139616439303639313333303064396563376361303933393437356664636331343631
32613961366634303562653436626132643338336235383638653961303262383565626632376363 33326565656632656638656331653435643433646533383036653264663232313730346331333139
65613865663638653739356365383731333664363732643834356339623138613838343631303433 33393238363165656137383130373137616132393366373930353161363232656532363936303038
65326262373963646361306432303336376638383061303164643030393633333737363166366339 34353463303666363730353235323034386230373333653263373238343863333233663261616431
34616637363261376462356230376166373630313862643732616431303161653965373032336366 34316135363537613762383036366333386165346361386165663939623639323535313237353365
64656138336237386362643638316465373464353862666236336532343436633534363966333031 63373135633538303232643065323232353434356365393464373963623066316138636661616632
39623933306631633366366138303237366638623435323766383562626233396436616261663738 34333332386432633933303465353564636361316435356163633765383833303437656535356130
63363632323335336366343264396662383562366430323866653635663962393136373732646331 62363863633433323231353932663534313166373734353837303861336162633438656237653137
33333963373261613161623733626138613037653136643735323331653338373830343633303263 31356330306236353432373431306631306561633264656663383266653266633661633237643461
30356261323766333161633738376238336666353733383666626634313437326462383335616138 34383566636162396234303233303534613461366466626135643336633635363037376638346338
656664303532663862373935343637336266 65356334303633306536643966336561646531623633663664653461326237383331303232666666
33363765393334326130633634396163616639383339306137393364333233633539353263306663
38313866363737653932616339653230613830336132643361373933323466303038613831353066
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
@@ -117,4 +117,4 @@ baseline_journald_max_retention: "30day"
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# MOTD branding # MOTD branding
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
baseline_motd_banner: "mk-labs" baseline_motd_banner: "wdw-labs"
+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:
+1 -1
View File
@@ -2,7 +2,7 @@
variable "proxmox_api_url" { variable "proxmox_api_url" {
type = string type = string
description = "Proxmox API endpoint URL (e.g., https://fantasyland.mk-labs.net:8006)" description = "Proxmox API endpoint URL (e.g., https://fantasyland.local.mk-labs.cloud:8006)"
} }
variable "proxmox_api_token" { variable "proxmox_api_token" {