From 6a6e07d49f5d32fa9e55d4a16c8cb221396740f4 Mon Sep 17 00:00:00 2001 From: pkova Date: Mon, 4 Sep 2023 22:09:52 +0300 Subject: [PATCH 1/8] lull, ames: add %dear task to receive lane from unix --- pkg/arvo/sys/lull.hoon | 2 ++ pkg/arvo/sys/vane/ames.hoon | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/pkg/arvo/sys/lull.hoon b/pkg/arvo/sys/lull.hoon index 158d432f9..4fbefc172 100644 --- a/pkg/arvo/sys/lull.hoon +++ b/pkg/arvo/sys/lull.hoon @@ -764,6 +764,7 @@ :: Messaging Tasks :: :: %hear: packet from unix + :: %dear: lane from unix :: %heed: track peer's responsiveness; gives %clog if slow :: %jilt: stop tracking peer's responsiveness :: %cork: request to delete message flow @@ -794,6 +795,7 @@ +$ task $+ ames-task $% [%hear =lane =blob] + [%dear =ship =lane] [%heed =ship] [%jilt =ship] [%cork =ship] diff --git a/pkg/arvo/sys/vane/ames.hoon b/pkg/arvo/sys/vane/ames.hoon index aa80b2021..e8ca3fa9b 100644 --- a/pkg/arvo/sys/vane/ames.hoon +++ b/pkg/arvo/sys/vane/ames.hoon @@ -2092,6 +2092,27 @@ %^ enqueue-alien-todo ship ship-state |= todos=alien-agenda todos(heeds (~(del in heeds.todos) duct)) + :: +on-dear: handle lane from unix + :: + ++ on-dear + |= [=ship =lane] + ^+ event-core + ?: ?=(%.y -.lane) + event-core + =/ ip=@if (end [0 32] p.lane) + =/ pt=@ud (cut 0 [32 16] p.lane) + ?: =(%czar (clan:title ship)) + %- %^ ev-trace odd.veb ship + |.("ignoring %dear lane {(scow %if ip)}:{(scow %ud pt)} for galaxy") + event-core + =/ peer-state=(unit peer-state) (get-peer-state ship) + ?~ peer-state + %- %^ ev-trace odd.veb ship + |.("no peer-state for ship, ignoring %dear") + event-core + %- %^ ev-trace rcv.veb ship + |.("incoming %dear lane {(scow %if ip)}:{(scow %ud pt)}") + abet:(on-dear:(abed-peer:pe ship u.peer-state) lane) :: +on-hear: handle raw packet receipt :: ++ on-hear @@ -3273,6 +3294,11 @@ =. keens (~(put by keens) path *keen-state) fi-abet:(fi-start:(abed:fi path) duct) :: + ++ on-dear + |= =lane + ^+ peer-core + peer-core(route.peer-state `[%.y lane]) + :: ++ on-tame ^+ peer-core peer-core(route.peer-state ~) @@ -4934,6 +4960,7 @@ ?- -.task %born on-born:event-core %hear (on-hear:event-core [lane blob ~]:task) + %dear (on-dear:event-core +.task) %heed (on-heed:event-core ship.task) %init on-init:event-core %jilt (on-jilt:event-core ship.task) From b427c9e800869c324614a6c311b9b60532a1de8d Mon Sep 17 00:00:00 2001 From: fang Date: Tue, 1 Aug 2023 00:20:13 +0200 Subject: [PATCH 2/8] eyre: serve 503 if bound agent is not running Previously, for endpoints bound to agents, we would pass the request onto the agent even if the agents wasn't currently running. Here, we make eyre check to see if the agent is actually running, before passing the request on. If the bound agent is not running, eyre serves a 503 synchronously instead. This way, we avoid cluttering up the gall queue for the bound agent. --- pkg/arvo/sys/vane/eyre.hoon | 25 ++++++++++++++++++------- tests/sys/vane/eyre.hoon | 16 ++++++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/pkg/arvo/sys/vane/eyre.hoon b/pkg/arvo/sys/vane/eyre.hoon index a9af7d9f0..454d956cb 100644 --- a/pkg/arvo/sys/vane/eyre.hoon +++ b/pkg/arvo/sys/vane/eyre.hoon @@ -789,8 +789,7 @@ %. (~(put by connections.state) duct connection) (trace 2 |.("{} creating local")) :: - :_ state - (subscribe-to-app [%ours ~] app.act inbound-request.connection) + (request-to-app [%ours ~] app.act inbound-request.connection) :: +request: starts handling an inbound http request :: ++ request @@ -964,8 +963,7 @@ == :: %app - :_ state - (subscribe-to-app identity app.action inbound-request.connection) + (request-to-app identity app.action inbound-request.connection) :: %authentication (handle-request:authentication secure host address [suv identity] request) @@ -1100,11 +1098,24 @@ %^ return-static-data-on-duct status 'text/html' (error-page status authenticated url.request tape) -- - :: +subscribe-to-app: subscribe to app and poke it with request data + :: +request-to-app: subscribe to app and poke it with request data :: - ++ subscribe-to-app + ++ request-to-app |= [=identity app=term =inbound-request:eyre] - ^- (list move) + ^- (quip move server-state) + :: if the agent isn't running, we synchronously serve a 503 + :: + ?. !<(? q:(need (need (rof ~ /eyre %gu [our app da+now] /$)))) + %^ return-static-data-on-duct 503 'text/html' + %: error-page + 503 + ?=(%ours -.identity) + url.request.inbound-request + "%{(trip app)} not running" + == + :: otherwise, subscribe to the agent and poke it with the request + :: + :_ state :~ %+ deal-as /watch-response/[eyre-id] [identity our app %watch /http-response/[eyre-id]] diff --git a/tests/sys/vane/eyre.hoon b/tests/sys/vane/eyre.hoon index 3599e27ef..ab029cac7 100644 --- a/tests/sys/vane/eyre.hoon +++ b/tests/sys/vane/eyre.hoon @@ -375,6 +375,7 @@ |= [gang pov=path =view =beam] ^- (unit (unit cage)) ?: =(%gd view) ``noun+!>(%base) + ?: =(%gu view) ``noun+!>(=(%app1 q.beam)) ?: &(=(%ca view) =(/gen/handler/hoon s.beam)) :+ ~ ~ vase+!>(!>(|=(* |=(* [[%404 ~] ~])))) @@ -553,6 +554,21 @@ (take /watch-response/[eyre-id] ~[/http-blah] sign) =/ headers ['content-type' 'text/html']~ (expect-moves mos (ex-continue-response `[3 'ya!'] %.n) ~) +:: +++ test-dead-app-request + %- eval-mare + =/ m (mare ,~) + ;< ~ bind:m perform-init-wo-timer + ;< ~ bind:m (wait ~d1) + :: dead-app binds successfully + :: + ;< ~ bind:m (connect %dead-app /) + ;< ~ bind:m (wait ~d1) + :: outside requests a path that dead-app has bound to + :: + ;< mos=(list move) bind:m (get '/' ~) + =/ body `(error-page:eyre-gate 503 %.n '/' "%dead-app not running") + (expect-moves mos (ex-response 503 ['content-type' 'text/html']~ body) ~) :: tests an app redirecting to the login handler, which then receives a post :: and redirects back to app :: From 4affae8181092cb718d3e9e63805e87e710a6638 Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 13 Sep 2023 13:37:39 +0200 Subject: [PATCH 3/8] eyre: GETting non-existent channels creates them Previously, a channel could only be created by sending a PUT request, and a GET request to receive the channel's stream would only succeed after channel creation had happened that way. This forces client libraries, that generally have an explicit "set up" step before allowing normal operation, to do strange things, like sending faux pokes (commonly hi-ing oneself) before connecting to the channel's stream as normal. Here, we update the GET request handling for channels to allow requests for non-existent channels. When this happens, the channel will be created, and eyre tracks the request as normal. We do some... gentle restructuring... of +on-get-request:by-channel to let the new creation case share code with the "already exists" codepath. In the process, we find that duct-to-key was never getting updated in the case where we replace the original channel request/connection with the new incoming one. We fix this, it's trivial. We also identify two other areas with vaguely-incorrect behavior, but consider them less important and out of scope. We also add a test case for "create channel through GET". --- pkg/arvo/sys/vane/eyre.hoon | 120 +++++++++++++++++++++--------------- tests/sys/vane/eyre.hoon | 26 ++++++-- 2 files changed, 92 insertions(+), 54 deletions(-) diff --git a/pkg/arvo/sys/vane/eyre.hoon b/pkg/arvo/sys/vane/eyre.hoon index 454d956cb..09d04a30f 100644 --- a/pkg/arvo/sys/vane/eyre.hoon +++ b/pkg/arvo/sys/vane/eyre.hoon @@ -2122,7 +2122,7 @@ duct-to-key.channel-state (~(del by duct-to-key.channel-state.state) duct) == - :: +set-timeout-timer-for: sets a timeout timer on a channel + :: +update-timeout-timer-for: sets a timeout timer on a channel :: :: This creates a channel if it doesn't exist, cancels existing timers :: if they're already set (we cannot have duplicate timers), and (if @@ -2196,53 +2196,76 @@ ++ on-get-request |= [channel-id=@t [session-id=@uv =identity] =request:http] ^- [(list move) server-state] - :: if there's no channel-id, we must 404 - ::TODO but arm description says otherwise? - :: - ?~ maybe-channel=(~(get by session.channel-state.state) channel-id) - %^ return-static-data-on-duct 404 'text/html' - (error-page 404 | url.request ~) - :: find the channel creator's identity, make sure it matches - :: - ?. =(identity identity.u.maybe-channel) - %^ return-static-data-on-duct 403 'text/html' - (error-page 403 | url.request ~) - :: find the requested "mode" and make sure it doesn't conflict - :: =/ mode=?(%json %jam) (find-channel-mode %'GET' header-list.request) - ?. =(mode mode.u.maybe-channel) - %^ return-static-data-on-duct 406 'text/html' - =; msg=tape (error-page 406 %.y url.request msg) - "channel already established in {(trip mode.u.maybe-channel)} mode" - :: when opening an event-stream, we must cancel our timeout timer - :: if there's no duct already bound. Else, kill the old request - :: and replace it - :: - =^ cancel-moves state - ?. ?=([%| *] state.u.maybe-channel) - :_ state - (cancel-timeout-move channel-id p.state.u.maybe-channel)^~ - =/ cancel-heartbeat - ?~ heartbeat.u.maybe-channel ~ - :_ ~ - %+ cancel-heartbeat-move channel-id - [date duct]:u.heartbeat.u.maybe-channel - =- [(weld cancel-heartbeat -<) ->] - (handle-response(duct p.state.u.maybe-channel) [%cancel ~]) - :: the request may include a 'Last-Event-Id' header - :: - =/ maybe-last-event-id=(unit @ud) - ?~ maybe-raw-header=(get-header:http 'last-event-id' header-list.request) - ~ - (rush u.maybe-raw-header dum:ag) - :: flush events older than the passed in 'Last-Event-ID' - :: - =? state ?=(^ maybe-last-event-id) - (acknowledge-events channel-id u.maybe-last-event-id) - :: combine the remaining queued events to send to the client - :: - =/ event-replay=wall + =^ [exit=? =wall moves=(list move)] state + :: the request may include a 'Last-Event-Id' header + :: + =/ maybe-last-event-id=(unit @ud) + ?~ maybe-raw-header=(get-header:http 'last-event-id' header-list.request) + ~ + (rush u.maybe-raw-header dum:ag) + :: if the channel doesn't exist yet, simply instantiate it here + :: + ?~ maybe-channel=(~(get by session.channel-state.state) channel-id) + =- [[| ~ ~] state(session.channel-state -)] + %+ ~(put by session.channel-state.state) channel-id + ::NOTE some other fields initialized at the end of this arm + %* . *channel + identity identity + next-id (fall maybe-last-event-id 0) + last-ack now + == + :: if the channel does exist, we put some demands on the get request, + :: and may need to do some cleanup for prior requests. + :: + :: find the channel creator's identity, make sure it matches + :: + ?. =(identity identity.u.maybe-channel) + =^ mos state + %^ return-static-data-on-duct 403 'text/html' + (error-page 403 | url.request ~) + [[& ~ mos] state] + :: make sure the request "mode" doesn't conflict with a prior request + :: + ::TODO or could we change that on the spot, given that only a single + :: request will ever be listening to this channel? + ?. =(mode mode.u.maybe-channel) + =^ mos state + %^ return-static-data-on-duct 406 'text/html' + =; msg=tape (error-page 406 %.y url.request msg) + "channel already established in {(trip mode.u.maybe-channel)} mode" + [[& ~ mos] state] + :: when opening an event-stream, we must cancel our timeout timer + :: if there's no duct already bound. else, kill the old request, + :: we will replace its duct at the end of this arm + :: + =^ cancel-moves state + ?: ?=([%& *] state.u.maybe-channel) + :_ state + (cancel-timeout-move channel-id p.state.u.maybe-channel)^~ + =. duct-to-key.channel-state.state + (~(del by duct-to-key.channel-state.state) p.state.u.maybe-channel) + =/ cancel-heartbeat + ?~ heartbeat.u.maybe-channel ~ + :_ ~ + %+ cancel-heartbeat-move channel-id + [date duct]:u.heartbeat.u.maybe-channel + =- [(weld cancel-heartbeat -<) ->] + (handle-response(duct p.state.u.maybe-channel) [%cancel ~]) + :: flush events older than the passed in 'Last-Event-ID' + :: + =? state ?=(^ maybe-last-event-id) + (acknowledge-events channel-id u.maybe-last-event-id) + ::TODO that did not remove them from the u.maybe-channel queue though! + :: we may want to account for maybe-last-event-id, for efficiency. + :: (the client _should_ ignore events it heard previously if we do + :: end up re-sending them, but _requiring_ that feels kinda risky) + :: + :: combine the remaining queued events to send to the client + :: + =; event-replay=wall + [[| - cancel-moves] state] %- zing %- flop =/ queue events.u.maybe-channel @@ -2260,6 +2283,7 @@ (channel-event-to-tape u.maybe-channel request-id channel-event) ?~ said $ $(events [(event-tape-to-wall id +.u.said) events]) + ?: exit [moves state] :: send the start event to the client :: =^ http-moves state @@ -2270,7 +2294,7 @@ ['cache-control' 'no-cache'] ['connection' 'keep-alive'] == - (wall-to-octs event-replay) + (wall-to-octs wall) complete=%.n == :: associate this duct with this session key @@ -2300,7 +2324,7 @@ heartbeat (some [heartbeat-time duct]) == :: - [[heartbeat :(weld http-moves cancel-moves moves)] state] + [[heartbeat :(weld http-moves moves)] state] :: +acknowledge-events: removes events before :last-event-id on :channel-id :: ++ acknowledge-events diff --git a/tests/sys/vane/eyre.hoon b/tests/sys/vane/eyre.hoon index ab029cac7..4e59d5dd7 100644 --- a/tests/sys/vane/eyre.hoon +++ b/tests/sys/vane/eyre.hoon @@ -262,7 +262,7 @@ == :: ++ ex-channel-response - |= body=@t + |= body=(unit @t) |= mov=move ^- tang ?. ?=([[[%http-blah ~] ~] %give %response %start * * %.n] mov) @@ -273,7 +273,7 @@ ['connection' 'keep-alive'] ['set-cookie' cookie-string] == - =/ body `(as-octs:mimes:html body) + =/ body (bind body as-octs:mimes:html) ;: weld (expect-eq !>(200) !>(status-code.response-header.http-event.p.card.mov)) (expect-eq !>(body) !>(data.http-event.p.card.mov)) @@ -743,6 +743,20 @@ =/ wire /channel/subscription/'0123456789abcdef'/1/~nul/two/~nul (expect-moves mos (ex-gall-deal wire ~nul %two %leave ~) ~) :: +++ test-channel-open-with-get + %- eval-mare + =/ m (mare ,~) + ;< ~ bind:m perform-init-wo-timer + ;< ~ bind:m perform-born + ;< ~ bind:m (wait ~d1) + ;< ~ bind:m perform-authentication-2 + ;< mos=(list move) bind:m + (get '/~/channel/0123456789abcdef' cookie) + ;< now=@da bind:m get-now + =/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' (add now ~s20)) + =/ mov-2 (ex-channel-response ~) + (expect-moves mos mov-1 mov-2 ~) +:: ++ test-channel-results-before-open %- eval-mare =/ m (mare ,~) @@ -776,7 +790,7 @@ ;< now=@da bind:m get-now =/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' (add now ~s20)) =/ mov-2 - %- ex-channel-response + %+ ex-channel-response ~ ''' id: 0 data: {"ok":"ok","id":0,"response":"poke"} @@ -920,7 +934,7 @@ ;< now=@da bind:m get-now =/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' (add now ~s20)) =/ mov-2 - %- ex-channel-response + %+ ex-channel-response ~ ''' id: 0 data: {"ok":"ok","id":0,"response":"poke"} @@ -1022,7 +1036,7 @@ =/ heartbeat (add now ~s20) =/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' heartbeat) =/ mov-2 - %- ex-channel-response + %+ ex-channel-response ~ ''' id: 0 data: {"ok":"ok","id":0,"response":"poke"} @@ -1092,7 +1106,7 @@ =/ heartbeat (add now ~s20) =/ mov-1 (ex-wait /channel/heartbeat/'0123456789abcdef' heartbeat) =/ mov-2 - %- ex-channel-response + %+ ex-channel-response ~ ''' id: 2 data: {"json":[1],"id":1,"response":"diff"} From 34148f9f443988b2d44eae37859a9c3c805d219f Mon Sep 17 00:00:00 2001 From: fang Date: Wed, 13 Sep 2023 13:56:48 +0200 Subject: [PATCH 4/8] eyre: allow PUTting empty channel-request list Previously, we would reject this with a 400 error. Considering the request body is expected to contain "array of requests" and that arrays may be empty, we really should not be rejecting the requests. Prior to 156ca21472, sending the empty array would have been convenient for channel creation. Empty arrays getting rejected forced clients to inject a faux poke (commonly hi-ing oneself). With that recent change, the most common case for wanting to PUT the empty list of requests is largely obsolete, but one can still imagine it being useful for clients that want to keep their channel alive without necessarily being connected to it. This also implements sloppier clients from running into 400 responses when they submit an empty "command queue" for whatever. Regardless, there seems to be no clear reason why the empty request list _shouldn't_ be accepted and processed as normal. We add a small test to ensure eyre accepts this. --- pkg/arvo/sys/vane/eyre.hoon | 5 ----- tests/sys/vane/eyre.hoon | 12 ++++++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/pkg/arvo/sys/vane/eyre.hoon b/pkg/arvo/sys/vane/eyre.hoon index 09d04a30f..e52da9ecf 100644 --- a/pkg/arvo/sys/vane/eyre.hoon +++ b/pkg/arvo/sys/vane/eyre.hoon @@ -2372,11 +2372,6 @@ ?: ?=(%| -.maybe-requests) %^ return-static-data-on-duct 400 'text/html' (error-page 400 & url.request (trip p.maybe-requests)) - :: while weird, the request list could be empty - :: - ?: =(~ p.maybe-requests) - %^ return-static-data-on-duct 400 'text/html' - (error-page 400 %.y url.request "empty list of actions") :: check for the existence of the channel-id :: :: if we have no session, create a new one set to expire in diff --git a/tests/sys/vane/eyre.hoon b/tests/sys/vane/eyre.hoon index 4e59d5dd7..db6e35a98 100644 --- a/tests/sys/vane/eyre.hoon +++ b/tests/sys/vane/eyre.hoon @@ -757,6 +757,18 @@ =/ mov-2 (ex-channel-response ~) (expect-moves mos mov-1 mov-2 ~) :: +++ test-channel-put-zero-requests + %- eval-mare + =/ m (mare ,~) + ;< ~ bind:m perform-init-start-channel-2 + ;< ~ bind:m (wait ~m1) + ;< mos=(list move) bind:m + (put '/~/channel/0123456789abcdef' cookie '[]') + =/ mov-1 ex-204 + =/ mov-2 (ex-rest /channel/timeout/'0123456789abcdef' ~1111.1.2..12.00.00) + =/ mov-3 (ex-wait /channel/timeout/'0123456789abcdef' ~1111.1.2..12.01.00) + (expect-moves mos mov-1 mov-2 mov-3 ~) +:: ++ test-channel-results-before-open %- eval-mare =/ m (mare ,~) From 5fe2d6ea98df15259e9e6fe2675dbb837a2a709a Mon Sep 17 00:00:00 2001 From: Pyry Kovanen Date: Thu, 21 Sep 2023 00:03:32 +0300 Subject: [PATCH 5/8] eyre: allow header-list to contain multiple cookies --- pkg/arvo/sys/vane/eyre.hoon | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/pkg/arvo/sys/vane/eyre.hoon b/pkg/arvo/sys/vane/eyre.hoon index e52da9ecf..fb8915be9 100644 --- a/pkg/arvo/sys/vane/eyre.hoon +++ b/pkg/arvo/sys/vane/eyre.hoon @@ -1358,14 +1358,15 @@ ^- (unit @uv) :: are there cookies passed with this request? :: - :: TODO: In HTTP2, the client is allowed to put multiple 'Cookie' - :: headers. + =/ cookie-header=@t + %+ roll header-list.request + |= [[key=@t value=@t] c=@t] + ?. =(key 'cookie') + c + (cat 3 (cat 3 c ?~(c 0 '; ')) value) + :: is the cookie line valid? :: - ?~ cookie-header=(get-header:http 'cookie' header-list.request) - ~ - :: is the cookie line is valid? - :: - ?~ cookies=(rush u.cookie-header cock:de-purl:html) + ?~ cookies=(rush cookie-header cock:de-purl:html) ~ :: is there an urbauth cookie? :: From 042340e8e471df651cc60da0f4bfaafbab8e07d1 Mon Sep 17 00:00:00 2001 From: pkova Date: Tue, 26 Sep 2023 21:02:41 +0300 Subject: [PATCH 6/8] clay: iterate over all aeons in +read-at-tako --- pkg/arvo/sys/vane/clay.hoon | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 7820f11e1..e3cfd6178 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -4533,7 +4533,12 @@ ?. ?| =(0v0 tak) ?& (~(has by hut.ran) tak) ?| (~(any by hit.dom) |=(=tako =(tak tako))) :: fast-path - (~(has in (reachable-takos (aeon-to-tako:ze let.dom))) tak) + |- ^- ? + ?: (lte let.dom 1) + %.n + ?| (~(has in (reachable-takos (aeon-to-tako:ze let.dom))) tak) + $(let.dom (dec let.dom)) + == == |(?=(~ for) (may-read u.for care.mun tak path.mun)) == == From 55787fed62f453863a8f72084f3758e80ff8092c Mon Sep 17 00:00:00 2001 From: Pyry Kovanen Date: Thu, 28 Sep 2023 19:22:53 +0300 Subject: [PATCH 7/8] clay: return all takos in /cs/bloc scry --- pkg/arvo/sys/vane/clay.hoon | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkg/arvo/sys/vane/clay.hoon b/pkg/arvo/sys/vane/clay.hoon index 7820f11e1..5e1409119 100644 --- a/pkg/arvo/sys/vane/clay.hoon +++ b/pkg/arvo/sys/vane/clay.hoon @@ -4315,8 +4315,12 @@ :- -:!>(*(map lobe page)) ^- (map lobe page) %- %~ rep in - %- reachable-takos - (~(got by hit.dom) let.dom) + |- ^- (set tako) + =/ ts=(set tako) + %- reachable-takos + (~(got by hit.dom) let.dom) + ?: (lte let.dom 1) ts + (~(uni in ts) $(let.dom (dec let.dom))) |= [t=tako o=(map lobe page)] %- ~(gas by o) %+ turn From fb3579c3a9560e2f01e26ae0acf000e7e7df03e9 Mon Sep 17 00:00:00 2001 From: Pyry Kovanen Date: Fri, 29 Sep 2023 16:00:03 +0300 Subject: [PATCH 8/8] runtime-version: parse current version properly --- pkg/arvo/ted/runtime-version.hoon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/arvo/ted/runtime-version.hoon b/pkg/arvo/ted/runtime-version.hoon index d0a679bba..e2c55590b 100644 --- a/pkg/arvo/ted/runtime-version.hoon +++ b/pkg/arvo/ted/runtime-version.hoon @@ -12,7 +12,7 @@ ++ parse-current-version |= current=vere ^- @t - (rear rev.current) + (slav %ta (rear rev.current)) :: ++ is-equal-version |= [latest=@t current=vere]