routing/
lib.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5pub mod availability;
6pub mod bedrock;
7pub mod capability_source;
8pub mod component_instance;
9pub mod config;
10pub mod error;
11pub mod legacy_router;
12pub mod mapper;
13pub mod path;
14pub mod policy;
15pub mod resolving;
16pub mod rights;
17pub mod subdir;
18pub mod walk_state;
19
20use crate::bedrock::request_metadata::{
21    dictionary_metadata, directory_metadata, protocol_metadata, resolver_metadata, runner_metadata,
22    service_metadata,
23};
24use crate::capability_source::{
25    CapabilitySource, ComponentCapability, ComponentSource, InternalCapability, VoidSource,
26};
27use crate::component_instance::{ComponentInstanceInterface, ResolvedInstanceInterface};
28use crate::error::RoutingError;
29use crate::legacy_router::{
30    CapabilityVisitor, ErrorNotFoundFromParent, ErrorNotFoundInChild, ExposeVisitor, NoopVisitor,
31    OfferVisitor, RouteBundle, Sources,
32};
33use crate::mapper::DebugRouteMapper;
34use crate::rights::RightsWalker;
35use crate::walk_state::WalkState;
36use cm_rust::{
37    Availability, CapabilityTypeName, DebugProtocolRegistration, ExposeConfigurationDecl,
38    ExposeDecl, ExposeDeclCommon, ExposeDictionaryDecl, ExposeDirectoryDecl, ExposeProtocolDecl,
39    ExposeResolverDecl, ExposeRunnerDecl, ExposeServiceDecl, ExposeSource, ExposeTarget,
40    OfferConfigurationDecl, OfferDeclCommon, OfferDictionaryDecl, OfferDirectoryDecl,
41    OfferEventStreamDecl, OfferProtocolDecl, OfferResolverDecl, OfferRunnerDecl, OfferServiceDecl,
42    OfferSource, OfferStorageDecl, OfferTarget, RegistrationDeclCommon, RegistrationSource,
43    ResolverRegistration, RunnerRegistration, SourceName, StorageDecl, StorageDirectorySource,
44    UseConfigurationDecl, UseDecl, UseDeclCommon, UseDictionaryDecl, UseDirectoryDecl,
45    UseEventStreamDecl, UseProtocolDecl, UseRunnerDecl, UseServiceDecl, UseSource, UseStorageDecl,
46};
47use cm_types::{IterablePath, Name, RelativePath};
48use from_enum::FromEnum;
49use itertools::Itertools;
50use moniker::{ChildName, ExtendedMoniker, Moniker, MonikerError};
51use router_error::Explain;
52use sandbox::{
53    Capability, CapabilityBound, Connector, Data, Dict, DirConnector, Request, Routable, Router,
54    RouterResponse,
55};
56use std::fmt::Debug;
57use std::sync::Arc;
58use subdir::SubDir;
59use {fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_io as fio, zx_status as zx};
60
61pub use bedrock::dict_ext::{DictExt, GenericRouterResponse};
62pub use bedrock::lazy_get::LazyGet;
63pub use bedrock::weak_instance_token_ext::{WeakInstanceTokenExt, test_invalid_instance_token};
64pub use bedrock::with_porcelain::WithPorcelain;
65#[cfg(feature = "serde")]
66use serde::{Deserialize, Serialize};
67
68/// A request to route a capability, together with the data needed to do so.
69#[derive(Clone, Debug)]
70pub enum RouteRequest {
71    // Route a capability from an ExposeDecl.
72    ExposeDirectory(ExposeDirectoryDecl),
73    ExposeProtocol(ExposeProtocolDecl),
74    ExposeService(RouteBundle<ExposeServiceDecl>),
75    ExposeRunner(ExposeRunnerDecl),
76    ExposeResolver(ExposeResolverDecl),
77    ExposeConfig(ExposeConfigurationDecl),
78    ExposeDictionary(ExposeDictionaryDecl),
79
80    // Route a capability from a realm's environment.
81    Resolver(ResolverRegistration),
82
83    // Route the directory capability that backs a storage capability.
84    StorageBackingDirectory(StorageDecl),
85
86    // Route a capability from a UseDecl.
87    UseDirectory(UseDirectoryDecl),
88    UseEventStream(UseEventStreamDecl),
89    UseProtocol(UseProtocolDecl),
90    UseService(UseServiceDecl),
91    UseStorage(UseStorageDecl),
92    UseRunner(UseRunnerDecl),
93    UseConfig(UseConfigurationDecl),
94    UseDictionary(UseDictionaryDecl),
95
96    // Route a capability from an OfferDecl.
97    OfferDirectory(OfferDirectoryDecl),
98    OfferEventStream(OfferEventStreamDecl),
99    OfferProtocol(OfferProtocolDecl),
100    OfferService(RouteBundle<OfferServiceDecl>),
101    OfferStorage(OfferStorageDecl),
102    OfferRunner(OfferRunnerDecl),
103    OfferResolver(OfferResolverDecl),
104    OfferConfig(OfferConfigurationDecl),
105    OfferDictionary(OfferDictionaryDecl),
106}
107
108impl From<UseDecl> for RouteRequest {
109    fn from(decl: UseDecl) -> Self {
110        match decl {
111            UseDecl::Directory(decl) => Self::UseDirectory(decl),
112            UseDecl::Protocol(decl) => Self::UseProtocol(decl),
113            UseDecl::Service(decl) => Self::UseService(decl),
114            UseDecl::Storage(decl) => Self::UseStorage(decl),
115            UseDecl::EventStream(decl) => Self::UseEventStream(decl),
116            UseDecl::Runner(decl) => Self::UseRunner(decl),
117            UseDecl::Config(decl) => Self::UseConfig(decl),
118            UseDecl::Dictionary(decl) => Self::UseDictionary(decl),
119        }
120    }
121}
122
123impl RouteRequest {
124    pub fn from_expose_decls(exposes: Vec<&ExposeDecl>) -> Result<Self, RoutingError> {
125        let first_expose = exposes.first().expect("invalid empty expose list");
126        let first_type_name = CapabilityTypeName::from(*first_expose);
127        assert!(
128            exposes.iter().all(|e| {
129                let type_name: CapabilityTypeName = CapabilityTypeName::from(*e);
130                first_type_name == type_name && first_expose.target_name() == e.target_name()
131            }),
132            "invalid expose input: {:?}",
133            exposes
134        );
135        match first_expose {
136            ExposeDecl::Protocol(e) => {
137                assert!(exposes.len() == 1, "multiple exposes: {:?}", exposes);
138                Ok(Self::ExposeProtocol(e.clone()))
139            }
140            ExposeDecl::Service(_) => {
141                // Gather the exposes into a bundle. Services can aggregate, in which case
142                // multiple expose declarations map to one expose directory entry.
143                let exposes: Vec<_> = exposes
144                    .into_iter()
145                    .filter_map(|e| match e {
146                        cm_rust::ExposeDecl::Service(e) => Some(e.clone()),
147                        _ => None,
148                    })
149                    .collect();
150                Ok(Self::ExposeService(RouteBundle::from_exposes(exposes)))
151            }
152            ExposeDecl::Directory(e) => {
153                assert!(exposes.len() == 1, "multiple exposes");
154                Ok(Self::ExposeDirectory(e.clone()))
155            }
156            ExposeDecl::Runner(e) => {
157                assert!(exposes.len() == 1, "multiple exposes");
158                Ok(Self::ExposeRunner(e.clone()))
159            }
160            ExposeDecl::Resolver(e) => {
161                assert!(exposes.len() == 1, "multiple exposes");
162                Ok(Self::ExposeResolver(e.clone()))
163            }
164            ExposeDecl::Config(e) => {
165                assert!(exposes.len() == 1, "multiple exposes");
166                Ok(Self::ExposeConfig(e.clone()))
167            }
168            ExposeDecl::Dictionary(e) => {
169                assert!(exposes.len() == 1, "multiple exposes");
170                Ok(Self::ExposeDictionary(e.clone()))
171            }
172        }
173    }
174
175    /// Returns the availability of the RouteRequest if supported.
176    pub fn availability(&self) -> Option<Availability> {
177        use crate::RouteRequest::*;
178        match self {
179            UseDirectory(UseDirectoryDecl { availability, .. })
180            | UseEventStream(UseEventStreamDecl { availability, .. })
181            | UseProtocol(UseProtocolDecl { availability, .. })
182            | UseService(UseServiceDecl { availability, .. })
183            | UseConfig(UseConfigurationDecl { availability, .. })
184            | UseStorage(UseStorageDecl { availability, .. })
185            | UseDictionary(UseDictionaryDecl { availability, .. }) => Some(*availability),
186
187            ExposeDirectory(decl) => Some(*decl.availability()),
188            ExposeProtocol(decl) => Some(*decl.availability()),
189            ExposeService(decl) => Some(*decl.availability()),
190            ExposeRunner(decl) => Some(*decl.availability()),
191            ExposeResolver(decl) => Some(*decl.availability()),
192            ExposeConfig(decl) => Some(*decl.availability()),
193            ExposeDictionary(decl) => Some(*decl.availability()),
194
195            OfferRunner(decl) => Some(*decl.availability()),
196            OfferResolver(decl) => Some(*decl.availability()),
197            OfferDirectory(decl) => Some(*decl.availability()),
198            OfferEventStream(decl) => Some(*decl.availability()),
199            OfferProtocol(decl) => Some(*decl.availability()),
200            OfferConfig(decl) => Some(*decl.availability()),
201            OfferStorage(decl) => Some(*decl.availability()),
202            OfferDictionary(decl) => Some(*decl.availability()),
203
204            OfferService(_) | Resolver(_) | StorageBackingDirectory(_) | UseRunner(_) => None,
205        }
206    }
207}
208
209impl std::fmt::Display for RouteRequest {
210    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211        match self {
212            Self::ExposeDirectory(e) => {
213                write!(f, "directory `{}`", e.target_name)
214            }
215            Self::ExposeProtocol(e) => {
216                write!(f, "protocol `{}`", e.target_name)
217            }
218            Self::ExposeService(e) => {
219                write!(f, "service {:?}", e)
220            }
221            Self::ExposeRunner(e) => {
222                write!(f, "runner `{}`", e.target_name)
223            }
224            Self::ExposeResolver(e) => {
225                write!(f, "resolver `{}`", e.target_name)
226            }
227            Self::ExposeConfig(e) => {
228                write!(f, "config `{}`", e.target_name)
229            }
230            Self::ExposeDictionary(e) => {
231                write!(f, "dictionary `{}`", e.target_name)
232            }
233            Self::Resolver(r) => {
234                write!(f, "resolver `{}`", r.resolver)
235            }
236            Self::UseDirectory(u) => {
237                write!(f, "directory `{}`", u.source_name)
238            }
239            Self::UseProtocol(u) => {
240                write!(f, "protocol `{}`", u.source_name)
241            }
242            Self::UseService(u) => {
243                write!(f, "service `{}`", u.source_name)
244            }
245            Self::UseStorage(u) => {
246                write!(f, "storage `{}`", u.source_name)
247            }
248            Self::UseEventStream(u) => {
249                write!(f, "event stream `{}`", u.source_name)
250            }
251            Self::UseRunner(u) => {
252                write!(f, "runner `{}`", u.source_name)
253            }
254            Self::UseConfig(u) => {
255                write!(f, "config `{}`", u.source_name)
256            }
257            Self::UseDictionary(u) => {
258                write!(f, "dictionary `{}`", u.source_name)
259            }
260            Self::StorageBackingDirectory(u) => {
261                write!(f, "storage backing directory `{}`", u.backing_dir)
262            }
263            Self::OfferDirectory(o) => {
264                write!(f, "directory `{}`", o.target_name)
265            }
266            Self::OfferProtocol(o) => {
267                write!(f, "protocol `{}`", o.target_name)
268            }
269            Self::OfferService(o) => {
270                write!(f, "service {:?}", o)
271            }
272            Self::OfferEventStream(o) => {
273                write!(f, "event stream `{}`", o.target_name)
274            }
275            Self::OfferStorage(o) => {
276                write!(f, "storage `{}`", o.target_name)
277            }
278            Self::OfferResolver(o) => {
279                write!(f, "resolver `{}`", o.target_name)
280            }
281            Self::OfferRunner(o) => {
282                write!(f, "runner `{}`", o.target_name)
283            }
284            Self::OfferConfig(o) => {
285                write!(f, "config `{}`", o.target_name)
286            }
287            Self::OfferDictionary(o) => {
288                write!(f, "dictionary `{}`", o.target_name)
289            }
290        }
291    }
292}
293
294/// The data returned after successfully routing a capability to its source.
295#[derive(Debug)]
296pub struct RouteSource {
297    pub source: CapabilitySource,
298    pub relative_path: RelativePath,
299}
300
301impl RouteSource {
302    pub fn new(source: CapabilitySource) -> Self {
303        Self { source, relative_path: Default::default() }
304    }
305
306    pub fn new_with_relative_path(source: CapabilitySource, relative_path: RelativePath) -> Self {
307        Self { source, relative_path }
308    }
309}
310
311/// Performs a debug route from the `target` for the capability defined in `request`. The source of
312/// the route is returned if the route is valid, otherwise a routing error is returned.
313///
314/// If the capability is not allowed to be routed to the `target`, per the
315/// [`crate::model::policy::GlobalPolicyChecker`], then an error is returned.
316///
317/// This function will only be used for developer tools once the bedrock routing refactor has been
318/// completed, but for now it's the only way to route capabilities which are unsupported in
319/// bedrock.
320///
321/// For capabilities which are not supported in bedrock, the `mapper` is invoked on every step in
322/// the routing process and can be used to record the routing steps. Once all capabilities are
323/// supported in bedrock routing, the `mapper` argument will be removed.
324pub async fn route_capability<C>(
325    request: RouteRequest,
326    target: &Arc<C>,
327    mapper: &mut dyn DebugRouteMapper,
328) -> Result<RouteSource, RoutingError>
329where
330    C: ComponentInstanceInterface + 'static,
331{
332    match request {
333        // Route from an ExposeDecl
334        RouteRequest::ExposeDirectory(expose_dir_decl) => {
335            route_capability_inner::<DirConnector, _>(
336                &target.component_sandbox().await?.component_output.capabilities(),
337                &expose_dir_decl.target_name,
338                directory_metadata(
339                    expose_dir_decl.availability,
340                    expose_dir_decl.rights.and_then(|v| Some(v.into())),
341                    Some(expose_dir_decl.subdir.into()),
342                ),
343                target,
344            )
345            .await
346        }
347        RouteRequest::ExposeProtocol(expose_protocol_decl) => {
348            let sandbox = target.component_sandbox().await?;
349            let dictionary = match &expose_protocol_decl.target {
350                ExposeTarget::Parent => sandbox.component_output.capabilities(),
351                ExposeTarget::Framework => sandbox.component_output.framework(),
352            };
353            route_capability_inner::<Connector, _>(
354                &dictionary,
355                &expose_protocol_decl.target_name,
356                protocol_metadata(expose_protocol_decl.availability),
357                target,
358            )
359            .await
360        }
361        RouteRequest::ExposeService(expose_bundle) => {
362            let first_expose = expose_bundle.iter().next().expect("can't route empty bundle");
363            route_capability_inner::<DirConnector, _>(
364                &target.component_sandbox().await?.component_output.capabilities(),
365                first_expose.target_name(),
366                service_metadata(*first_expose.availability()),
367                target,
368            )
369            .await
370        }
371        RouteRequest::ExposeRunner(expose_runner_decl) => {
372            let sandbox = target.component_sandbox().await?;
373            let dictionary = match &expose_runner_decl.target {
374                ExposeTarget::Parent => sandbox.component_output.capabilities(),
375                ExposeTarget::Framework => sandbox.component_output.framework(),
376            };
377            route_capability_inner::<Connector, _>(
378                &dictionary,
379                &expose_runner_decl.target_name,
380                runner_metadata(Availability::Required),
381                target,
382            )
383            .await
384        }
385        RouteRequest::ExposeResolver(expose_resolver_decl) => {
386            let sandbox = target.component_sandbox().await?;
387            let dictionary = match &expose_resolver_decl.target {
388                ExposeTarget::Parent => sandbox.component_output.capabilities(),
389                ExposeTarget::Framework => sandbox.component_output.framework(),
390            };
391            route_capability_inner::<Connector, _>(
392                &dictionary,
393                &expose_resolver_decl.target_name,
394                resolver_metadata(Availability::Required),
395                target,
396            )
397            .await
398        }
399        RouteRequest::ExposeDictionary(expose_dictionary_decl) => {
400            let sandbox = target.component_sandbox().await?;
401            let dictionary = match &expose_dictionary_decl.target {
402                ExposeTarget::Parent => sandbox.component_output.capabilities(),
403                ExposeTarget::Framework => sandbox.component_output.framework(),
404            };
405            route_capability_inner::<Dict, _>(
406                &dictionary,
407                &expose_dictionary_decl.target_name,
408                dictionary_metadata(expose_dictionary_decl.availability),
409                target,
410            )
411            .await
412        }
413        RouteRequest::ExposeConfig(expose_config_decl) => {
414            route_config_from_expose(expose_config_decl, target, mapper).await
415        }
416
417        // Route a resolver or runner from an environment
418        RouteRequest::Resolver(resolver_registration) => {
419            let component_sandbox = target.component_sandbox().await?;
420            let source_dictionary = match &resolver_registration.source {
421                RegistrationSource::Parent => component_sandbox.component_input.capabilities(),
422                RegistrationSource::Self_ => component_sandbox.program_output_dict.clone(),
423                RegistrationSource::Child(static_name) => {
424                    let child_name = ChildName::parse(static_name).expect(
425                        "invalid child name, this should be prevented by manifest validation",
426                    );
427                    let child_component = target.lock_resolved_state().await?.get_child(&child_name).expect("resolver registration references nonexistent static child, this should be prevented by manifest validation");
428                    let child_sandbox = child_component.component_sandbox().await?;
429                    child_sandbox.component_output.capabilities().clone()
430                }
431            };
432            route_capability_inner::<Connector, _>(
433                &source_dictionary,
434                &resolver_registration.resolver,
435                resolver_metadata(Availability::Required),
436                target,
437            )
438            .await
439        }
440        // Route the backing directory for a storage capability
441        RouteRequest::StorageBackingDirectory(storage_decl) => {
442            route_storage_backing_directory(storage_decl, target, mapper).await
443        }
444
445        // Route from a UseDecl
446        RouteRequest::UseDirectory(use_directory_decl) => {
447            let subdir = match use_directory_decl.source {
448                UseSource::Self_ => None,
449                _ => Some(SubDir::from(use_directory_decl.subdir)),
450            };
451            route_capability_inner::<DirConnector, _>(
452                &target.component_sandbox().await?.program_input.namespace(),
453                &use_directory_decl.target_path,
454                directory_metadata(
455                    use_directory_decl.availability,
456                    Some(use_directory_decl.rights.into()),
457                    subdir,
458                ),
459                target,
460            )
461            .await
462        }
463        RouteRequest::UseEventStream(use_event_stream_decl) => {
464            route_event_stream(use_event_stream_decl, target, mapper).await
465        }
466        RouteRequest::UseProtocol(use_protocol_decl) => {
467            if let Some(target_path) = use_protocol_decl.target_path.as_ref() {
468                route_capability_inner::<Connector, _>(
469                    &target.component_sandbox().await?.program_input.namespace(),
470                    target_path,
471                    protocol_metadata(use_protocol_decl.availability),
472                    target,
473                )
474                .await
475            } else {
476                let numbered_handle = use_protocol_decl
477                    .numbered_handle
478                    .expect("validation guarantees numbered_handle is set");
479                let numbered_handle = Name::from(numbered_handle);
480                route_capability_inner::<Connector, _>(
481                    &target.component_sandbox().await?.program_input.numbered_handles(),
482                    &numbered_handle,
483                    protocol_metadata(use_protocol_decl.availability),
484                    target,
485                )
486                .await
487            }
488        }
489        RouteRequest::UseService(use_service_decl) => {
490            route_capability_inner::<DirConnector, _>(
491                &target.component_sandbox().await?.program_input.namespace(),
492                &use_service_decl.target_path,
493                service_metadata(use_service_decl.availability),
494                target,
495            )
496            .await
497        }
498        RouteRequest::UseStorage(use_storage_decl) => {
499            route_storage(use_storage_decl, target, mapper).await
500        }
501        RouteRequest::UseRunner(_use_runner_decl) => {
502            let router =
503                target.component_sandbox().await?.program_input.runner().expect("we have a use declaration for a runner but the program input dictionary has no runner, this should be impossible");
504            perform_route::<Connector, _>(router, runner_metadata(Availability::Required), target)
505                .await
506        }
507        RouteRequest::UseConfig(use_config_decl) => {
508            route_config(use_config_decl, target, mapper).await
509        }
510        RouteRequest::UseDictionary(use_dictionary_decl) => {
511            route_capability_inner::<Dict, _>(
512                &target.component_sandbox().await?.program_input.namespace(),
513                &use_dictionary_decl.target_path,
514                dictionary_metadata(use_dictionary_decl.availability),
515                target,
516            )
517            .await
518        }
519
520        // Route from a OfferDecl
521        RouteRequest::OfferProtocol(offer_protocol_decl) => {
522            let target_dictionary =
523                get_dictionary_for_offer_target(target, &offer_protocol_decl).await?;
524            let metadata = protocol_metadata(offer_protocol_decl.availability);
525            metadata
526                .insert(
527                    Name::new(crate::bedrock::with_policy_check::SKIP_POLICY_CHECKS).unwrap(),
528                    Capability::Data(Data::Uint64(1)),
529                )
530                .unwrap();
531            route_capability_inner::<Connector, _>(
532                &target_dictionary,
533                &offer_protocol_decl.target_name,
534                metadata,
535                target,
536            )
537            .await
538        }
539        RouteRequest::OfferDictionary(offer_dictionary_decl) => {
540            let target_dictionary =
541                get_dictionary_for_offer_target(target, &offer_dictionary_decl).await?;
542            let metadata = dictionary_metadata(offer_dictionary_decl.availability);
543            metadata
544                .insert(
545                    Name::new(crate::bedrock::with_policy_check::SKIP_POLICY_CHECKS).unwrap(),
546                    Capability::Data(Data::Uint64(1)),
547                )
548                .unwrap();
549            route_capability_inner::<Dict, _>(
550                &target_dictionary,
551                &offer_dictionary_decl.target_name,
552                metadata,
553                target,
554            )
555            .await
556        }
557        RouteRequest::OfferDirectory(offer_directory_decl) => {
558            let target_dictionary =
559                get_dictionary_for_offer_target(target, &offer_directory_decl).await?;
560            let metadata = directory_metadata(
561                offer_directory_decl.availability,
562                offer_directory_decl.rights.and_then(|v| Some(v.into())),
563                Some(offer_directory_decl.subdir.into()),
564            );
565            metadata
566                .insert(
567                    Name::new(crate::bedrock::with_policy_check::SKIP_POLICY_CHECKS).unwrap(),
568                    Capability::Data(Data::Uint64(1)),
569                )
570                .unwrap();
571            route_capability_inner::<DirConnector, _>(
572                &target_dictionary,
573                &offer_directory_decl.target_name,
574                metadata,
575                target,
576            )
577            .await
578        }
579        RouteRequest::OfferStorage(offer_storage_decl) => {
580            route_storage_from_offer(offer_storage_decl, target, mapper).await
581        }
582        RouteRequest::OfferService(offer_service_bundle) => {
583            let first_offer = offer_service_bundle.iter().next().expect("can't route empty bundle");
584            let target_dictionary = get_dictionary_for_offer_target(target, first_offer).await?;
585            let metadata = service_metadata(first_offer.availability);
586            metadata
587                .insert(
588                    Name::new(crate::bedrock::with_policy_check::SKIP_POLICY_CHECKS).unwrap(),
589                    Capability::Data(Data::Uint64(1)),
590                )
591                .unwrap();
592            route_capability_inner::<DirConnector, _>(
593                &target_dictionary,
594                &first_offer.target_name,
595                metadata,
596                target,
597            )
598            .await
599        }
600        RouteRequest::OfferEventStream(offer_event_stream_decl) => {
601            route_event_stream_from_offer(offer_event_stream_decl, target, mapper).await
602        }
603        RouteRequest::OfferRunner(offer_runner_decl) => {
604            let target_dictionary =
605                get_dictionary_for_offer_target(target, &offer_runner_decl).await?;
606            let metadata = runner_metadata(Availability::Required);
607            metadata
608                .insert(
609                    Name::new(crate::bedrock::with_policy_check::SKIP_POLICY_CHECKS).unwrap(),
610                    Capability::Data(Data::Uint64(1)),
611                )
612                .unwrap();
613            route_capability_inner::<Connector, _>(
614                &target_dictionary,
615                &offer_runner_decl.target_name,
616                metadata,
617                target,
618            )
619            .await
620        }
621        RouteRequest::OfferResolver(offer_resolver_decl) => {
622            let target_dictionary =
623                get_dictionary_for_offer_target(target, &offer_resolver_decl).await?;
624            let metadata = resolver_metadata(Availability::Required);
625            metadata
626                .insert(
627                    Name::new(crate::bedrock::with_policy_check::SKIP_POLICY_CHECKS).unwrap(),
628                    Capability::Data(Data::Uint64(1)),
629                )
630                .unwrap();
631            route_capability_inner::<Connector, _>(
632                &target_dictionary,
633                &offer_resolver_decl.target_name,
634                metadata,
635                target,
636            )
637            .await
638        }
639        RouteRequest::OfferConfig(offer) => route_config_from_offer(offer, target, mapper).await,
640    }
641}
642
643pub enum Never {}
644
645async fn route_capability_inner<T, C>(
646    dictionary: &Dict,
647    path: &impl IterablePath,
648    metadata: Dict,
649    target: &Arc<C>,
650) -> Result<RouteSource, RoutingError>
651where
652    C: ComponentInstanceInterface + 'static,
653    T: CapabilityBound + Debug,
654    Router<T>: TryFrom<Capability>,
655{
656    let router = dictionary
657        .get_capability(path)
658        .and_then(|c| Router::<T>::try_from(c).ok())
659        .ok_or_else(|| RoutingError::BedrockNotPresentInDictionary {
660            moniker: target.moniker().clone().into(),
661            name: path.iter_segments().join("/"),
662        })?;
663    perform_route::<T, C>(router, metadata, target).await
664}
665
666async fn perform_route<T, C>(
667    router: impl Routable<T>,
668    metadata: Dict,
669    target: &Arc<C>,
670) -> Result<RouteSource, RoutingError>
671where
672    C: ComponentInstanceInterface + 'static,
673    T: CapabilityBound + Debug,
674    Router<T>: TryFrom<Capability>,
675{
676    let request = Request { metadata };
677    let data = match router.route(Some(request), true, target.as_weak().into()).await? {
678        RouterResponse::<T>::Debug(d) => d,
679        d => panic!("Debug route did not return a debug response: {d:?}"),
680    };
681    Ok(RouteSource::new(data.try_into().unwrap()))
682}
683
684async fn get_dictionary_for_offer_target<C, O>(
685    target: &Arc<C>,
686    offer: &O,
687) -> Result<Dict, RoutingError>
688where
689    C: ComponentInstanceInterface + 'static,
690    O: OfferDeclCommon,
691{
692    match offer.target() {
693        OfferTarget::Child(child_ref) if child_ref.collection.is_none() => {
694            // For static children we can find their inputs in the component's sandbox.
695            let child_input_name = Name::new(&child_ref.name)
696                .map_err(MonikerError::InvalidMonikerPart)
697                .expect("static child names must be short");
698            let target_sandbox = target.component_sandbox().await?;
699            let child_input = target_sandbox.child_inputs.get(&child_input_name).ok_or(
700                RoutingError::OfferFromChildInstanceNotFound {
701                    child_moniker: child_ref.clone().into(),
702                    moniker: target.moniker().clone(),
703                    capability_id: offer.target_name().clone().to_string(),
704                },
705            )?;
706            Ok(child_input.capabilities())
707        }
708        OfferTarget::Child(child_ref) => {
709            // Offers targeting dynamic children are trickier. The input to the dynamic
710            // child wasn't created as part of the parent's sandbox, and dynamic offers
711            // (like the one we're currently looking at) won't have their routes reflected
712            // in the general component input for the collection. To work around this, we
713            // look up the dynamic child from the parent and access its component input
714            // from there. Unlike the code path for static children, this causes the child
715            // to be resolved.
716            let child = target
717                .lock_resolved_state()
718                .await?
719                .get_child(&ChildName::from(child_ref.clone()))
720                .ok_or(RoutingError::OfferFromChildInstanceNotFound {
721                    child_moniker: child_ref.clone().into(),
722                    moniker: target.moniker().clone(),
723                    capability_id: offer.target_name().clone().to_string(),
724                })?;
725            Ok(child.component_sandbox().await?.component_input.capabilities())
726        }
727        OfferTarget::Collection(collection_name) => {
728            // Offers targeting collections start at the component input generated for the
729            // collection, which is in the component's sandbox.
730            let target_sandbox = target.component_sandbox().await?;
731            let collection_input = target_sandbox.collection_inputs.get(collection_name).ok_or(
732                RoutingError::OfferFromCollectionNotFound {
733                    collection: collection_name.to_string(),
734                    moniker: target.moniker().clone(),
735                    capability: offer.target_name().clone(),
736                },
737            )?;
738            Ok(collection_input.capabilities())
739        }
740        OfferTarget::Capability(dictionary_name) => {
741            // Offers targeting another capability are for adding the capability to a dictionary
742            // declared by the same component. These dictionaries are stored in the target's
743            // sandbox.
744            let target_sandbox = target.component_sandbox().await?;
745            let capability =
746                target_sandbox.declared_dictionaries.get(dictionary_name).ok().flatten().ok_or(
747                    RoutingError::BedrockNotPresentInDictionary {
748                        name: dictionary_name.to_string(),
749                        moniker: target.moniker().clone().into(),
750                    },
751                )?;
752            match capability {
753                Capability::Dictionary(dictionary) => Ok(dictionary),
754                other_type => Err(RoutingError::BedrockWrongCapabilityType {
755                    actual: other_type.debug_typename().to_string(),
756                    expected: "Dictionary".to_string(),
757                    moniker: target.moniker().clone().into(),
758                }),
759            }
760        }
761    }
762}
763
764/// Routes an EventStream capability from `target` to its source, starting from `offer_decl`.
765async fn route_event_stream_from_offer<C>(
766    offer_decl: OfferEventStreamDecl,
767    target: &Arc<C>,
768    mapper: &mut dyn DebugRouteMapper,
769) -> Result<RouteSource, RoutingError>
770where
771    C: ComponentInstanceInterface + 'static,
772{
773    let allowed_sources = Sources::new(CapabilityTypeName::EventStream).builtin();
774
775    let mut availability_visitor = offer_decl.availability;
776    let source = legacy_router::route_from_offer(
777        RouteBundle::from_offer(offer_decl.into()),
778        target.clone(),
779        allowed_sources,
780        &mut availability_visitor,
781        mapper,
782    )
783    .await?;
784    Ok(RouteSource::new(source))
785}
786
787async fn route_storage_from_offer<C>(
788    offer_decl: OfferStorageDecl,
789    target: &Arc<C>,
790    mapper: &mut dyn DebugRouteMapper,
791) -> Result<RouteSource, RoutingError>
792where
793    C: ComponentInstanceInterface + 'static,
794{
795    let mut availability_visitor = offer_decl.availability;
796    let allowed_sources = Sources::new(CapabilityTypeName::Storage).component();
797    let source = legacy_router::route_from_offer(
798        RouteBundle::from_offer(offer_decl.into()),
799        target.clone(),
800        allowed_sources,
801        &mut availability_visitor,
802        mapper,
803    )
804    .await?;
805    Ok(RouteSource::new(source))
806}
807
808async fn route_config_from_offer<C>(
809    offer_decl: OfferConfigurationDecl,
810    target: &Arc<C>,
811    mapper: &mut dyn DebugRouteMapper,
812) -> Result<RouteSource, RoutingError>
813where
814    C: ComponentInstanceInterface + 'static,
815{
816    let allowed_sources = Sources::new(CapabilityTypeName::Config).builtin().component();
817    let source = legacy_router::route_from_offer(
818        RouteBundle::from_offer(offer_decl.into()),
819        target.clone(),
820        allowed_sources,
821        &mut NoopVisitor::new(),
822        mapper,
823    )
824    .await?;
825    Ok(RouteSource::new(source))
826}
827
828async fn route_config_from_expose<C>(
829    expose_decl: ExposeConfigurationDecl,
830    target: &Arc<C>,
831    mapper: &mut dyn DebugRouteMapper,
832) -> Result<RouteSource, RoutingError>
833where
834    C: ComponentInstanceInterface + 'static,
835{
836    let allowed_sources = Sources::new(CapabilityTypeName::Config).component().capability();
837    let source = legacy_router::route_from_expose(
838        RouteBundle::from_expose(expose_decl.into()),
839        target.clone(),
840        allowed_sources,
841        &mut NoopVisitor::new(),
842        mapper,
843    )
844    .await?;
845
846    target.policy_checker().can_route_capability(&source, target.moniker())?;
847    Ok(RouteSource::new(source))
848}
849
850/// The accumulated state of routing a Directory capability.
851#[derive(Clone, Debug)]
852pub struct DirectoryState {
853    rights: WalkState<RightsWalker>,
854    pub subdir: RelativePath,
855    availability_state: Availability,
856}
857
858impl DirectoryState {
859    fn new(rights: RightsWalker, subdir: RelativePath, availability: &Availability) -> Self {
860        DirectoryState {
861            rights: WalkState::at(rights),
862            subdir,
863            availability_state: availability.clone(),
864        }
865    }
866
867    fn advance_with_offer(
868        &mut self,
869        moniker: &ExtendedMoniker,
870        offer: &OfferDirectoryDecl,
871    ) -> Result<(), RoutingError> {
872        self.availability_state =
873            availability::advance_with_offer(moniker, self.availability_state, offer)?;
874        self.advance(moniker, offer.rights.clone(), offer.subdir.clone())
875    }
876
877    fn advance_with_expose(
878        &mut self,
879        moniker: &ExtendedMoniker,
880        expose: &ExposeDirectoryDecl,
881    ) -> Result<(), RoutingError> {
882        self.availability_state =
883            availability::advance_with_expose(moniker, self.availability_state, expose)?;
884        self.advance(moniker, expose.rights.clone(), expose.subdir.clone())
885    }
886
887    fn advance(
888        &mut self,
889        moniker: &ExtendedMoniker,
890        rights: Option<fio::Operations>,
891        mut subdir: RelativePath,
892    ) -> Result<(), RoutingError> {
893        self.rights = self.rights.advance(rights.map(|r| RightsWalker::new(r, moniker.clone())))?;
894        if !subdir.extend(self.subdir.clone()) {
895            return Err(RoutingError::PathTooLong {
896                moniker: moniker.clone(),
897                path: format!("{}/{}", subdir, self.subdir),
898                keyword: "subdir".into(),
899            });
900        }
901        self.subdir = subdir;
902        Ok(())
903    }
904
905    fn finalize(
906        &mut self,
907        moniker: &ExtendedMoniker,
908        rights: RightsWalker,
909        mut subdir: RelativePath,
910    ) -> Result<(), RoutingError> {
911        self.rights = self.rights.finalize(Some(rights))?;
912        if !subdir.extend(self.subdir.clone()) {
913            return Err(RoutingError::PathTooLong {
914                moniker: moniker.clone(),
915                path: format!("{}/{}", subdir, self.subdir),
916                keyword: "subdir".into(),
917            });
918        }
919        self.subdir = subdir;
920        Ok(())
921    }
922}
923
924impl OfferVisitor for DirectoryState {
925    fn visit(
926        &mut self,
927        moniker: &ExtendedMoniker,
928        offer: &cm_rust::OfferDecl,
929    ) -> Result<(), RoutingError> {
930        match offer {
931            cm_rust::OfferDecl::Directory(dir) => match dir.source {
932                OfferSource::Framework => self.finalize(
933                    moniker,
934                    RightsWalker::new(fio::RX_STAR_DIR, moniker.clone()),
935                    dir.subdir.clone(),
936                ),
937                _ => self.advance_with_offer(moniker, dir),
938            },
939            _ => Ok(()),
940        }
941    }
942}
943
944impl ExposeVisitor for DirectoryState {
945    fn visit(
946        &mut self,
947        moniker: &ExtendedMoniker,
948        expose: &cm_rust::ExposeDecl,
949    ) -> Result<(), RoutingError> {
950        match expose {
951            cm_rust::ExposeDecl::Directory(dir) => match dir.source {
952                ExposeSource::Framework => self.finalize(
953                    moniker,
954                    RightsWalker::new(fio::RX_STAR_DIR, moniker.clone()),
955                    dir.subdir.clone(),
956                ),
957                _ => self.advance_with_expose(moniker, dir),
958            },
959            _ => Ok(()),
960        }
961    }
962}
963
964impl CapabilityVisitor for DirectoryState {
965    fn visit(
966        &mut self,
967        moniker: &ExtendedMoniker,
968        capability: &cm_rust::CapabilityDecl,
969    ) -> Result<(), RoutingError> {
970        match capability {
971            cm_rust::CapabilityDecl::Directory(dir) => self.finalize(
972                moniker,
973                RightsWalker::new(dir.rights, moniker.clone()),
974                Default::default(),
975            ),
976            _ => Ok(()),
977        }
978    }
979}
980
981/// Verifies that the given component is in the index if its `storage_id` is StaticInstanceId.
982/// - On success, Ok(()) is returned
983/// - RoutingError::ComponentNotInIndex is returned on failure.
984pub async fn verify_instance_in_component_id_index<C>(
985    source: &CapabilitySource,
986    instance: &Arc<C>,
987) -> Result<(), RoutingError>
988where
989    C: ComponentInstanceInterface + 'static,
990{
991    let (storage_decl, source_moniker) = match source {
992        CapabilitySource::Component(ComponentSource {
993            capability: ComponentCapability::Storage(storage_decl),
994            moniker,
995        }) => (storage_decl, moniker.clone()),
996        CapabilitySource::Void(VoidSource { .. }) => return Ok(()),
997        _ => unreachable!("unexpected storage source"),
998    };
999
1000    if storage_decl.storage_id == fdecl::StorageId::StaticInstanceId
1001        && instance.component_id_index().id_for_moniker(instance.moniker()).is_none()
1002    {
1003        return Err(RoutingError::ComponentNotInIdIndex {
1004            source_moniker,
1005            target_name: instance.moniker().leaf().map(Into::into),
1006        });
1007    }
1008    Ok(())
1009}
1010
1011/// Routes a Storage capability from `target` to its source, starting from `use_decl`.
1012/// Returns the StorageDecl and the storage component's instance.
1013pub async fn route_to_storage_decl<C>(
1014    use_decl: UseStorageDecl,
1015    target: &Arc<C>,
1016    mapper: &mut dyn DebugRouteMapper,
1017) -> Result<CapabilitySource, RoutingError>
1018where
1019    C: ComponentInstanceInterface + 'static,
1020{
1021    let mut availability_visitor = use_decl.availability;
1022    let allowed_sources = Sources::new(CapabilityTypeName::Storage).component();
1023    let source = legacy_router::route_from_use(
1024        use_decl.into(),
1025        target.clone(),
1026        allowed_sources,
1027        &mut availability_visitor,
1028        mapper,
1029    )
1030    .await?;
1031    Ok(source)
1032}
1033
1034/// Routes a Storage capability from `target` to its source, starting from `use_decl`.
1035/// The backing Directory capability is then routed to its source.
1036async fn route_storage<C>(
1037    use_decl: UseStorageDecl,
1038    target: &Arc<C>,
1039    mapper: &mut dyn DebugRouteMapper,
1040) -> Result<RouteSource, RoutingError>
1041where
1042    C: ComponentInstanceInterface + 'static,
1043{
1044    let source = route_to_storage_decl(use_decl, &target, mapper).await?;
1045    verify_instance_in_component_id_index(&source, target).await?;
1046    target.policy_checker().can_route_capability(&source, target.moniker())?;
1047    Ok(RouteSource::new(source))
1048}
1049
1050/// Routes the backing Directory capability of a Storage capability from `target` to its source,
1051/// starting from `storage_decl`.
1052async fn route_storage_backing_directory<C>(
1053    storage_decl: StorageDecl,
1054    target: &Arc<C>,
1055    mapper: &mut dyn DebugRouteMapper,
1056) -> Result<RouteSource, RoutingError>
1057where
1058    C: ComponentInstanceInterface + 'static,
1059{
1060    // Storage rights are always READ+WRITE.
1061    let mut state = DirectoryState::new(
1062        RightsWalker::new(fio::RW_STAR_DIR, target.moniker().clone()),
1063        Default::default(),
1064        &Availability::Required,
1065    );
1066    let allowed_sources = Sources::new(CapabilityTypeName::Directory).component().namespace();
1067    let source = legacy_router::route_from_registration(
1068        StorageDeclAsRegistration::from(storage_decl.clone()),
1069        target.clone(),
1070        allowed_sources,
1071        &mut state,
1072        mapper,
1073    )
1074    .await?;
1075
1076    target.policy_checker().can_route_capability(&source, target.moniker())?;
1077
1078    Ok(RouteSource::new_with_relative_path(source, state.subdir))
1079}
1080
1081/// Finds a Configuration capability that matches the given use.
1082async fn route_config<C>(
1083    use_decl: UseConfigurationDecl,
1084    target: &Arc<C>,
1085    mapper: &mut dyn DebugRouteMapper,
1086) -> Result<RouteSource, RoutingError>
1087where
1088    C: ComponentInstanceInterface + 'static,
1089{
1090    let allowed_sources = Sources::new(CapabilityTypeName::Config).component().capability();
1091    let mut availability_visitor = use_decl.availability().clone();
1092    let source = legacy_router::route_from_use(
1093        use_decl.clone().into(),
1094        target.clone(),
1095        allowed_sources,
1096        &mut availability_visitor,
1097        mapper,
1098    )
1099    .await;
1100    // If the route was not found, but it's a transitional availability then return
1101    // a successful Void capability.
1102    let source = match source {
1103        Ok(s) => s,
1104        Err(e) => {
1105            if *use_decl.availability() == Availability::Transitional
1106                && e.as_zx_status() == zx::Status::NOT_FOUND
1107            {
1108                CapabilitySource::Void(VoidSource {
1109                    capability: InternalCapability::Config(use_decl.source_name),
1110                    moniker: target.moniker().clone(),
1111                })
1112            } else {
1113                return Err(e);
1114            }
1115        }
1116    };
1117
1118    target.policy_checker().can_route_capability(&source, target.moniker())?;
1119    Ok(RouteSource::new(source))
1120}
1121
1122/// Routes an EventStream capability from `target` to its source, starting from `use_decl`.
1123///
1124/// If the capability is not allowed to be routed to the `target`, per the
1125/// [`crate::model::policy::GlobalPolicyChecker`], then an error is returned.
1126pub async fn route_event_stream<C>(
1127    use_decl: UseEventStreamDecl,
1128    target: &Arc<C>,
1129    mapper: &mut dyn DebugRouteMapper,
1130) -> Result<RouteSource, RoutingError>
1131where
1132    C: ComponentInstanceInterface + 'static,
1133{
1134    let allowed_sources = Sources::new(CapabilityTypeName::EventStream).builtin();
1135    let mut availability_visitor = use_decl.availability;
1136    let source = legacy_router::route_from_use(
1137        use_decl.into(),
1138        target.clone(),
1139        allowed_sources,
1140        &mut availability_visitor,
1141        mapper,
1142    )
1143    .await?;
1144    target.policy_checker().can_route_capability(&source, target.moniker())?;
1145    Ok(RouteSource::new(source))
1146}
1147
1148/// Intermediate type to masquerade as Registration-style routing start point for the storage
1149/// backing directory capability.
1150#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1151#[derive(Debug, Clone, PartialEq, Eq)]
1152pub struct StorageDeclAsRegistration {
1153    source: RegistrationSource,
1154    name: Name,
1155}
1156
1157impl From<StorageDecl> for StorageDeclAsRegistration {
1158    fn from(decl: StorageDecl) -> Self {
1159        Self {
1160            name: decl.backing_dir,
1161            source: match decl.source {
1162                StorageDirectorySource::Parent => RegistrationSource::Parent,
1163                StorageDirectorySource::Self_ => RegistrationSource::Self_,
1164                StorageDirectorySource::Child(child) => RegistrationSource::Child(child),
1165            },
1166        }
1167    }
1168}
1169
1170impl SourceName for StorageDeclAsRegistration {
1171    fn source_name(&self) -> &Name {
1172        &self.name
1173    }
1174}
1175
1176impl RegistrationDeclCommon for StorageDeclAsRegistration {
1177    const TYPE: &'static str = "storage";
1178
1179    fn source(&self) -> &RegistrationSource {
1180        &self.source
1181    }
1182}
1183
1184/// An umbrella type for registration decls, making it more convenient to record route
1185/// maps for debug use.
1186#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
1187#[derive(FromEnum, Debug, Clone, PartialEq, Eq)]
1188pub enum RegistrationDecl {
1189    Resolver(ResolverRegistration),
1190    Runner(RunnerRegistration),
1191    Debug(DebugProtocolRegistration),
1192    Directory(StorageDeclAsRegistration),
1193}
1194
1195impl From<&RegistrationDecl> for cm_rust::CapabilityTypeName {
1196    fn from(registration: &RegistrationDecl) -> Self {
1197        match registration {
1198            RegistrationDecl::Directory(_) => Self::Directory,
1199            RegistrationDecl::Resolver(_) => Self::Resolver,
1200            RegistrationDecl::Runner(_) => Self::Runner,
1201            RegistrationDecl::Debug(_) => Self::Protocol,
1202        }
1203    }
1204}
1205
1206// Error trait impls
1207
1208impl ErrorNotFoundFromParent for cm_rust::UseDecl {
1209    fn error_not_found_from_parent(moniker: Moniker, capability_name: Name) -> RoutingError {
1210        RoutingError::UseFromParentNotFound { moniker, capability_id: capability_name.into() }
1211    }
1212}
1213
1214impl ErrorNotFoundFromParent for cm_rust::DebugProtocolRegistration {
1215    fn error_not_found_from_parent(moniker: Moniker, capability_name: Name) -> RoutingError {
1216        RoutingError::EnvironmentFromParentNotFound {
1217            moniker,
1218            capability_name,
1219            capability_type: cm_rust::CapabilityTypeName::Protocol.to_string(),
1220        }
1221    }
1222}
1223
1224impl ErrorNotFoundInChild for cm_rust::DebugProtocolRegistration {
1225    fn error_not_found_in_child(
1226        moniker: Moniker,
1227        child_moniker: ChildName,
1228        capability_name: Name,
1229    ) -> RoutingError {
1230        RoutingError::EnvironmentFromChildExposeNotFound {
1231            moniker,
1232            child_moniker,
1233            capability_name,
1234            capability_type: cm_rust::CapabilityTypeName::Protocol.to_string(),
1235        }
1236    }
1237}
1238
1239impl ErrorNotFoundInChild for cm_rust::UseDecl {
1240    fn error_not_found_in_child(
1241        moniker: Moniker,
1242        child_moniker: ChildName,
1243        capability_name: Name,
1244    ) -> RoutingError {
1245        RoutingError::UseFromChildExposeNotFound {
1246            child_moniker,
1247            moniker,
1248            capability_id: capability_name.into(),
1249        }
1250    }
1251}
1252
1253impl ErrorNotFoundInChild for cm_rust::ExposeDecl {
1254    fn error_not_found_in_child(
1255        moniker: Moniker,
1256        child_moniker: ChildName,
1257        capability_name: Name,
1258    ) -> RoutingError {
1259        RoutingError::ExposeFromChildExposeNotFound {
1260            moniker,
1261            child_moniker,
1262            capability_id: capability_name.into(),
1263        }
1264    }
1265}
1266
1267impl ErrorNotFoundInChild for cm_rust::OfferDecl {
1268    fn error_not_found_in_child(
1269        moniker: Moniker,
1270        child_moniker: ChildName,
1271        capability_name: Name,
1272    ) -> RoutingError {
1273        RoutingError::OfferFromChildExposeNotFound {
1274            moniker,
1275            child_moniker,
1276            capability_id: capability_name.into(),
1277        }
1278    }
1279}
1280
1281impl ErrorNotFoundFromParent for cm_rust::OfferDecl {
1282    fn error_not_found_from_parent(moniker: Moniker, capability_name: Name) -> RoutingError {
1283        RoutingError::OfferFromParentNotFound { moniker, capability_id: capability_name.into() }
1284    }
1285}
1286
1287impl ErrorNotFoundInChild for StorageDeclAsRegistration {
1288    fn error_not_found_in_child(
1289        moniker: Moniker,
1290        child_moniker: ChildName,
1291        capability_name: Name,
1292    ) -> RoutingError {
1293        RoutingError::StorageFromChildExposeNotFound {
1294            moniker,
1295            child_moniker,
1296            capability_id: capability_name.into(),
1297        }
1298    }
1299}
1300
1301impl ErrorNotFoundFromParent for StorageDeclAsRegistration {
1302    fn error_not_found_from_parent(moniker: Moniker, capability_name: Name) -> RoutingError {
1303        RoutingError::StorageFromParentNotFound { moniker, capability_id: capability_name.into() }
1304    }
1305}
1306
1307impl ErrorNotFoundFromParent for RunnerRegistration {
1308    fn error_not_found_from_parent(moniker: Moniker, capability_name: Name) -> RoutingError {
1309        RoutingError::UseFromEnvironmentNotFound {
1310            moniker,
1311            capability_name,
1312            capability_type: "runner".to_string(),
1313        }
1314    }
1315}
1316
1317impl ErrorNotFoundInChild for RunnerRegistration {
1318    fn error_not_found_in_child(
1319        moniker: Moniker,
1320        child_moniker: ChildName,
1321        capability_name: Name,
1322    ) -> RoutingError {
1323        RoutingError::EnvironmentFromChildExposeNotFound {
1324            moniker,
1325            child_moniker,
1326            capability_name,
1327            capability_type: "runner".to_string(),
1328        }
1329    }
1330}
1331
1332impl ErrorNotFoundFromParent for ResolverRegistration {
1333    fn error_not_found_from_parent(moniker: Moniker, capability_name: Name) -> RoutingError {
1334        RoutingError::EnvironmentFromParentNotFound {
1335            moniker,
1336            capability_name,
1337            capability_type: "resolver".to_string(),
1338        }
1339    }
1340}
1341
1342impl ErrorNotFoundInChild for ResolverRegistration {
1343    fn error_not_found_in_child(
1344        moniker: Moniker,
1345        child_moniker: ChildName,
1346        capability_name: Name,
1347    ) -> RoutingError {
1348        RoutingError::EnvironmentFromChildExposeNotFound {
1349            moniker,
1350            child_moniker,
1351            capability_name,
1352            capability_type: "resolver".to_string(),
1353        }
1354    }
1355}