Skip to main content

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