oci_spec/runtime/
features.rs

1use std::collections::HashMap;
2
3use crate::{
4    error::OciSpecError,
5    runtime::{Arch, LinuxNamespaceType, LinuxSeccompAction},
6};
7use derive_builder::Builder;
8use getset::{Getters, MutGetters, Setters};
9use serde::{Deserialize, Serialize};
10
11/// Features represents supported features of the runtime.
12///
13/// This structure is used to report the supported features of the runtime to runtime callers.
14///
15#[derive(
16    Builder,
17    Clone,
18    Debug,
19    Default,
20    Deserialize,
21    Eq,
22    MutGetters,
23    Getters,
24    Setters,
25    PartialEq,
26    Serialize,
27)]
28#[serde(rename_all = "camelCase")]
29#[builder(
30    default,
31    pattern = "owned",
32    setter(into, strip_option),
33    build_fn(error = "OciSpecError")
34)]
35#[getset(get_mut = "pub", get = "pub", set = "pub")]
36pub struct Features {
37    /// The minimum OCI Runtime Spec version recognized by the runtime, e.g., "1.0.0".
38    oci_version_min: String,
39    /// The maximum OCI Runtime Spec version recognized by the runtime, e.g., "1.0.2-dev".
40    oci_version_max: String,
41    /// The list of the recognized hook names, e.g., "createRuntime".
42    /// "None" means "unknown", not "no support for any hook".
43    hooks: Option<Vec<String>>,
44    /// The list of the recognized mount options, e.g., "ro".
45    /// "None" means "unknown", not "no support for any mount option".
46    /// This list does not contain filesystem-specific options passed to mount(2) syscall as (const void *).
47    mount_options: Option<Vec<String>>,
48    /// Information specific to Linux
49    linux: Option<LinuxFeature>,
50    /// Implementation-specific annotation strings,
51    /// such as the implementation version, and third-party extensions.
52    annotations: Option<HashMap<String, String>>,
53    /// The list of the potential unsafe annotations
54    /// that may appear in `config.json`.
55    /// A value that ends with "." is interpreted as a prefix of annotations.
56    potentially_unsafe_config_annotations: Option<Vec<String>>,
57}
58
59/// Linux specific features.
60#[derive(
61    Builder,
62    Clone,
63    Debug,
64    Default,
65    Deserialize,
66    Eq,
67    MutGetters,
68    Getters,
69    Setters,
70    PartialEq,
71    Serialize,
72)]
73#[serde(rename_all = "camelCase")]
74#[builder(
75    default,
76    pattern = "owned",
77    setter(into, strip_option),
78    build_fn(error = "OciSpecError")
79)]
80#[getset(get_mut = "pub", get = "pub", set = "pub")]
81pub struct LinuxFeature {
82    /// The list of the recognized namespaces, e.g., "mount".
83    /// "None" means "unknown", not "no support for any namespace".
84    namespaces: Option<Vec<LinuxNamespaceType>>,
85    /// The list of the recognized capabilities , e.g., "CAP_SYS_ADMIN".
86    /// "None" means "unknown", not "no support for any capability".
87    capabilities: Option<Vec<String>>,
88    /// The available features related to cgroup.
89    cgroup: Option<Cgroup>,
90    /// The available features related to seccomp.
91    seccomp: Option<Seccomp>,
92    /// The available features related to apparmor.
93    apparmor: Option<Apparmor>,
94    /// The available features related to selinux.
95    selinux: Option<Selinux>,
96    /// The available features related to Intel RDT.
97    intel_rdt: Option<IntelRdt>,
98    /// The available features related to mount extensions.
99    mount_extensions: Option<MountExtensions>,
100}
101
102/// Cgroup represents the "cgroup" field.
103#[derive(
104    Builder,
105    Clone,
106    Debug,
107    Default,
108    Deserialize,
109    Eq,
110    MutGetters,
111    Getters,
112    Setters,
113    PartialEq,
114    Serialize,
115)]
116#[serde(rename_all = "camelCase")]
117#[builder(
118    default,
119    pattern = "owned",
120    setter(into, strip_option),
121    build_fn(error = "OciSpecError")
122)]
123#[getset(get_mut = "pub", get = "pub", set = "pub")]
124pub struct Cgroup {
125    /// "v1" field represents whether Cgroup v1 support is compiled in.
126    /// Unrelated to whether the host uses cgroup v1 or not.
127    /// "None" means "unknown", not "false".
128    v1: Option<bool>,
129    /// "v2" field represents whether Cgroup v2 support is compiled in.
130    /// Unrelated to whether the host uses cgroup v2 or not.
131    /// "None" means "unknown", not "false".
132    v2: Option<bool>,
133    /// "systemd" field represents whether systemd-cgroup support is compiled in.
134    /// Unrelated to whether the host uses systemd or not.
135    /// "None" means "unknown", not "false".
136    systemd: Option<bool>,
137    /// "systemdUser" field represents whether user-scoped systemd-cgroup support is compiled in.
138    /// Unrelated to whether the host uses systemd or not.
139    /// "None" means "unknown", not "false".
140    systemd_user: Option<bool>,
141    /// "rdma" field represents whether RDMA cgroup support is compiled in.
142    /// Unrelated to whether the host supports it or not.
143    /// "None" means "unknown", not "false".
144    rdma: Option<bool>,
145}
146
147/// Seccomp represents the "seccomp" field.
148#[derive(
149    Builder,
150    Clone,
151    Debug,
152    Default,
153    Deserialize,
154    Eq,
155    MutGetters,
156    Getters,
157    Setters,
158    PartialEq,
159    Serialize,
160)]
161#[serde(rename_all = "camelCase")]
162#[builder(
163    default,
164    pattern = "owned",
165    setter(into, strip_option),
166    build_fn(error = "OciSpecError")
167)]
168#[getset(get_mut = "pub", get = "pub", set = "pub")]
169pub struct Seccomp {
170    /// "enabled" field represents whether seccomp support is compiled in.
171    /// "None" means "unknown", not "false".
172    enabled: Option<bool>,
173    /// "actions" field represents the list of the recognized actions.
174    /// "None" means "unknown", not "no support for any action".
175    actions: Option<Vec<LinuxSeccompAction>>,
176    /// "operators" field represents the list of the recognized operators.
177    /// "None" means "unknown", not "no support for any operator".
178    operators: Option<Vec<String>>,
179    /// "archs" field represents the list of the recognized architectures.
180    /// "None" means "unknown", not "no support for any architecture".
181    archs: Option<Vec<Arch>>,
182    /// "knownFlags" field represents the list of the recognized filter flags.
183    /// "None" means "unknown", not "no flags are recognized".
184    known_flags: Option<Vec<String>>,
185    /// "supportedFlags" field represents the list of the supported filter flags.
186    /// This list may be a subset of the "knownFlags" due to some of unsupported flags
187    /// by the current kernel and/or libseccomp.
188    /// "None" means "unknown", not "no flags are supported".
189    supported_flags: Option<Vec<String>>,
190}
191
192/// Apparmor represents the "apparmor" field.
193#[derive(
194    Builder,
195    Clone,
196    Debug,
197    Default,
198    Deserialize,
199    Eq,
200    MutGetters,
201    Getters,
202    Setters,
203    PartialEq,
204    Serialize,
205)]
206#[serde(rename_all = "camelCase")]
207#[builder(
208    default,
209    pattern = "owned",
210    setter(into, strip_option),
211    build_fn(error = "OciSpecError")
212)]
213#[getset(get_mut = "pub", get = "pub", set = "pub")]
214pub struct Apparmor {
215    /// "enabled" field represents whether AppArmor support is compiled in.
216    /// Unrelated to whether the host supports AppArmor or not.
217    /// "None" means "unknown", not "false".
218    enabled: Option<bool>,
219}
220
221/// Selinux represents the "selinux" field.
222#[derive(
223    Builder,
224    Clone,
225    Debug,
226    Default,
227    Deserialize,
228    Eq,
229    MutGetters,
230    Getters,
231    Setters,
232    PartialEq,
233    Serialize,
234)]
235#[serde(rename_all = "camelCase")]
236#[builder(
237    default,
238    pattern = "owned",
239    setter(into, strip_option),
240    build_fn(error = "OciSpecError")
241)]
242#[getset(get_mut = "pub", get = "pub", set = "pub")]
243pub struct Selinux {
244    /// "enabled" field represents whether SELinux support is compiled in.
245    /// Unrelated to whether the host supports SELinux or not.
246    /// "None" means "unknown", not "false".
247    enabled: Option<bool>,
248}
249
250/// IntelRdt represents the "intelRdt" field.
251#[derive(
252    Builder,
253    Clone,
254    Debug,
255    Default,
256    Deserialize,
257    Eq,
258    MutGetters,
259    Getters,
260    Setters,
261    PartialEq,
262    Serialize,
263)]
264#[serde(rename_all = "camelCase")]
265#[builder(
266    default,
267    pattern = "owned",
268    setter(into, strip_option),
269    build_fn(error = "OciSpecError")
270)]
271#[getset(get_mut = "pub", get = "pub", set = "pub")]
272pub struct IntelRdt {
273    /// "enabled" field represents whether Intel RDT support is compiled in.
274    /// Unrelated to whether the host supports Intel RDT or not.
275    enabled: Option<bool>,
276}
277
278/// MountExtensions represents the "mountExtensions" field.
279#[derive(
280    Builder,
281    Clone,
282    Debug,
283    Default,
284    Deserialize,
285    Eq,
286    MutGetters,
287    Getters,
288    Setters,
289    PartialEq,
290    Serialize,
291)]
292#[serde(rename_all = "camelCase")]
293#[builder(
294    default,
295    pattern = "owned",
296    setter(into, strip_option),
297    build_fn(error = "OciSpecError")
298)]
299#[getset(get_mut = "pub", get = "pub", set = "pub")]
300pub struct MountExtensions {
301    /// "idMap" field represents the ID mapping support.
302    idmap: Option<IDMap>,
303}
304
305/// IDMap represents the "idmap" field.
306#[derive(
307    Builder,
308    Clone,
309    Debug,
310    Default,
311    Deserialize,
312    Eq,
313    MutGetters,
314    Getters,
315    Setters,
316    PartialEq,
317    Serialize,
318)]
319#[serde(rename_all = "camelCase")]
320#[builder(
321    default,
322    pattern = "owned",
323    setter(into, strip_option),
324    build_fn(error = "OciSpecError")
325)]
326#[getset(get_mut = "pub", get = "pub", set = "pub")]
327pub struct IDMap {
328    /// "enabled" field represents whether idmap mounts supports is compiled in.
329    /// Unrelated to whether the host supports it or not.
330    /// "None" means "unknown", not "false".
331    enabled: Option<bool>,
332}
333
334#[cfg(test)]
335mod tests {
336    use std::ops::Deref;
337
338    use super::*;
339
340    #[test]
341    fn test_parse_features() {
342        let example_json = r#"
343{
344    "ociVersionMin": "1.0.0",
345    "ociVersionMax": "1.1.0-rc.2",
346    "hooks": [
347        "prestart",
348        "createRuntime",
349        "createContainer",
350        "startContainer",
351        "poststart",
352        "poststop"
353    ],
354    "mountOptions": [
355        "async",
356        "atime",
357        "bind",
358        "defaults",
359        "dev",
360        "diratime",
361        "dirsync",
362        "exec",
363        "iversion",
364        "lazytime",
365        "loud",
366        "mand",
367        "noatime",
368        "nodev",
369        "nodiratime",
370        "noexec",
371        "noiversion",
372        "nolazytime",
373        "nomand",
374        "norelatime",
375        "nostrictatime",
376        "nosuid",
377        "nosymfollow",
378        "private",
379        "ratime",
380        "rbind",
381        "rdev",
382        "rdiratime",
383        "relatime",
384        "remount",
385        "rexec",
386        "rnoatime",
387        "rnodev",
388        "rnodiratime",
389        "rnoexec",
390        "rnorelatime",
391        "rnostrictatime",
392        "rnosuid",
393        "rnosymfollow",
394        "ro",
395        "rprivate",
396        "rrelatime",
397        "rro",
398        "rrw",
399        "rshared",
400        "rslave",
401        "rstrictatime",
402        "rsuid",
403        "rsymfollow",
404        "runbindable",
405        "rw",
406        "shared",
407        "silent",
408        "slave",
409        "strictatime",
410        "suid",
411        "symfollow",
412        "sync",
413        "tmpcopyup",
414        "unbindable"
415    ],
416    "linux": {
417        "namespaces": [
418            "cgroup",
419            "ipc",
420            "mount",
421            "network",
422            "pid",
423            "user",
424            "uts"
425        ],
426        "capabilities": [
427            "CAP_CHOWN",
428            "CAP_DAC_OVERRIDE",
429            "CAP_DAC_READ_SEARCH",
430            "CAP_FOWNER",
431            "CAP_FSETID",
432            "CAP_KILL",
433            "CAP_SETGID",
434            "CAP_SETUID",
435            "CAP_SETPCAP",
436            "CAP_LINUX_IMMUTABLE",
437            "CAP_NET_BIND_SERVICE",
438            "CAP_NET_BROADCAST",
439            "CAP_NET_ADMIN",
440            "CAP_NET_RAW",
441            "CAP_IPC_LOCK",
442            "CAP_IPC_OWNER",
443            "CAP_SYS_MODULE",
444            "CAP_SYS_RAWIO",
445            "CAP_SYS_CHROOT",
446            "CAP_SYS_PTRACE",
447            "CAP_SYS_PACCT",
448            "CAP_SYS_ADMIN",
449            "CAP_SYS_BOOT",
450            "CAP_SYS_NICE",
451            "CAP_SYS_RESOURCE",
452            "CAP_SYS_TIME",
453            "CAP_SYS_TTY_CONFIG",
454            "CAP_MKNOD",
455            "CAP_LEASE",
456            "CAP_AUDIT_WRITE",
457            "CAP_AUDIT_CONTROL",
458            "CAP_SETFCAP",
459            "CAP_MAC_OVERRIDE",
460            "CAP_MAC_ADMIN",
461            "CAP_SYSLOG",
462            "CAP_WAKE_ALARM",
463            "CAP_BLOCK_SUSPEND",
464            "CAP_AUDIT_READ",
465            "CAP_PERFMON",
466            "CAP_BPF",
467            "CAP_CHECKPOINT_RESTORE"
468        ],
469        "cgroup": {
470            "v1": true,
471            "v2": true,
472            "systemd": true,
473            "systemdUser": true,
474            "rdma": true
475        },
476        "seccomp": {
477            "enabled": true,
478            "actions": [
479                "SCMP_ACT_ALLOW",
480                "SCMP_ACT_ERRNO",
481                "SCMP_ACT_KILL",
482                "SCMP_ACT_KILL_PROCESS",
483                "SCMP_ACT_KILL_THREAD",
484                "SCMP_ACT_LOG",
485                "SCMP_ACT_NOTIFY",
486                "SCMP_ACT_TRACE",
487                "SCMP_ACT_TRAP"
488            ],
489            "operators": [
490                "SCMP_CMP_EQ",
491                "SCMP_CMP_GE",
492                "SCMP_CMP_GT",
493                "SCMP_CMP_LE",
494                "SCMP_CMP_LT",
495                "SCMP_CMP_MASKED_EQ",
496                "SCMP_CMP_NE"
497            ],
498            "archs": [
499                "SCMP_ARCH_AARCH64",
500                "SCMP_ARCH_ARM",
501                "SCMP_ARCH_MIPS",
502                "SCMP_ARCH_MIPS64",
503                "SCMP_ARCH_MIPS64N32",
504                "SCMP_ARCH_MIPSEL",
505                "SCMP_ARCH_MIPSEL64",
506                "SCMP_ARCH_MIPSEL64N32",
507                "SCMP_ARCH_PPC",
508                "SCMP_ARCH_PPC64",
509                "SCMP_ARCH_PPC64LE",
510                "SCMP_ARCH_RISCV64",
511                "SCMP_ARCH_S390",
512                "SCMP_ARCH_S390X",
513                "SCMP_ARCH_X32",
514                "SCMP_ARCH_X86",
515                "SCMP_ARCH_X86_64"
516            ],
517            "knownFlags": [
518                "SECCOMP_FILTER_FLAG_TSYNC",
519                "SECCOMP_FILTER_FLAG_SPEC_ALLOW",
520                "SECCOMP_FILTER_FLAG_LOG"
521            ],
522            "supportedFlags": [
523                "SECCOMP_FILTER_FLAG_TSYNC",
524                "SECCOMP_FILTER_FLAG_SPEC_ALLOW",
525                "SECCOMP_FILTER_FLAG_LOG"
526            ]
527        },
528        "apparmor": {
529            "enabled": true
530        },
531        "selinux": {
532            "enabled": true
533        },
534        "intelRdt": {
535            "enabled": true
536        }
537    },
538    "annotations": {
539        "io.github.seccomp.libseccomp.version": "2.5.4",
540        "org.opencontainers.runc.checkpoint.enabled": "true",
541        "org.opencontainers.runc.commit": "v1.1.0-534-g26851168",
542        "org.opencontainers.runc.version": "1.1.0+dev"
543    }
544}"#;
545
546        // Parse and check each field
547        let features: Features = serde_json::from_str(example_json).unwrap();
548        assert_eq!(features.oci_version_min().deref(), "1.0.0".to_string());
549        assert_eq!(features.oci_version_max().deref(), "1.1.0-rc.2".to_string());
550
551        assert_eq!(
552            features.hooks.as_ref().unwrap(),
553            &[
554                "prestart",
555                "createRuntime",
556                "createContainer",
557                "startContainer",
558                "poststart",
559                "poststop"
560            ]
561        );
562
563        assert_eq!(
564            features.mount_options.as_ref().unwrap(),
565            &[
566                "async",
567                "atime",
568                "bind",
569                "defaults",
570                "dev",
571                "diratime",
572                "dirsync",
573                "exec",
574                "iversion",
575                "lazytime",
576                "loud",
577                "mand",
578                "noatime",
579                "nodev",
580                "nodiratime",
581                "noexec",
582                "noiversion",
583                "nolazytime",
584                "nomand",
585                "norelatime",
586                "nostrictatime",
587                "nosuid",
588                "nosymfollow",
589                "private",
590                "ratime",
591                "rbind",
592                "rdev",
593                "rdiratime",
594                "relatime",
595                "remount",
596                "rexec",
597                "rnoatime",
598                "rnodev",
599                "rnodiratime",
600                "rnoexec",
601                "rnorelatime",
602                "rnostrictatime",
603                "rnosuid",
604                "rnosymfollow",
605                "ro",
606                "rprivate",
607                "rrelatime",
608                "rro",
609                "rrw",
610                "rshared",
611                "rslave",
612                "rstrictatime",
613                "rsuid",
614                "rsymfollow",
615                "runbindable",
616                "rw",
617                "shared",
618                "silent",
619                "slave",
620                "strictatime",
621                "suid",
622                "symfollow",
623                "sync",
624                "tmpcopyup",
625                "unbindable"
626            ]
627        );
628
629        let linux = features.linux().as_ref().unwrap();
630
631        assert_eq!(
632            linux.namespaces.as_ref().unwrap(),
633            &[
634                LinuxNamespaceType::Cgroup,
635                LinuxNamespaceType::Ipc,
636                LinuxNamespaceType::Mount,
637                LinuxNamespaceType::Network,
638                LinuxNamespaceType::Pid,
639                LinuxNamespaceType::User,
640                LinuxNamespaceType::Uts,
641            ]
642        );
643
644        assert_eq!(
645            linux.capabilities.as_ref().unwrap(),
646            &[
647                "CAP_CHOWN",
648                "CAP_DAC_OVERRIDE",
649                "CAP_DAC_READ_SEARCH",
650                "CAP_FOWNER",
651                "CAP_FSETID",
652                "CAP_KILL",
653                "CAP_SETGID",
654                "CAP_SETUID",
655                "CAP_SETPCAP",
656                "CAP_LINUX_IMMUTABLE",
657                "CAP_NET_BIND_SERVICE",
658                "CAP_NET_BROADCAST",
659                "CAP_NET_ADMIN",
660                "CAP_NET_RAW",
661                "CAP_IPC_LOCK",
662                "CAP_IPC_OWNER",
663                "CAP_SYS_MODULE",
664                "CAP_SYS_RAWIO",
665                "CAP_SYS_CHROOT",
666                "CAP_SYS_PTRACE",
667                "CAP_SYS_PACCT",
668                "CAP_SYS_ADMIN",
669                "CAP_SYS_BOOT",
670                "CAP_SYS_NICE",
671                "CAP_SYS_RESOURCE",
672                "CAP_SYS_TIME",
673                "CAP_SYS_TTY_CONFIG",
674                "CAP_MKNOD",
675                "CAP_LEASE",
676                "CAP_AUDIT_WRITE",
677                "CAP_AUDIT_CONTROL",
678                "CAP_SETFCAP",
679                "CAP_MAC_OVERRIDE",
680                "CAP_MAC_ADMIN",
681                "CAP_SYSLOG",
682                "CAP_WAKE_ALARM",
683                "CAP_BLOCK_SUSPEND",
684                "CAP_AUDIT_READ",
685                "CAP_PERFMON",
686                "CAP_BPF",
687                "CAP_CHECKPOINT_RESTORE"
688            ],
689        );
690
691        assert_eq!(
692            linux.cgroup.as_ref().unwrap(),
693            &Cgroup {
694                v1: Some(true),
695                v2: Some(true),
696                systemd: Some(true),
697                systemd_user: Some(true),
698                rdma: Some(true),
699            }
700        );
701
702        assert_eq!(
703            linux.seccomp.as_ref().unwrap(),
704            &Seccomp {
705                enabled: Some(true),
706                actions: Some(vec![
707                    LinuxSeccompAction::ScmpActAllow,
708                    LinuxSeccompAction::ScmpActErrno,
709                    LinuxSeccompAction::ScmpActKill,
710                    LinuxSeccompAction::ScmpActKillProcess,
711                    LinuxSeccompAction::ScmpActKillThread,
712                    LinuxSeccompAction::ScmpActLog,
713                    LinuxSeccompAction::ScmpActNotify,
714                    LinuxSeccompAction::ScmpActTrace,
715                    LinuxSeccompAction::ScmpActTrap
716                ]),
717                operators: Some(vec![
718                    "SCMP_CMP_EQ".to_string(),
719                    "SCMP_CMP_GE".to_string(),
720                    "SCMP_CMP_GT".to_string(),
721                    "SCMP_CMP_LE".to_string(),
722                    "SCMP_CMP_LT".to_string(),
723                    "SCMP_CMP_MASKED_EQ".to_string(),
724                    "SCMP_CMP_NE".to_string()
725                ]),
726                archs: Some(vec![
727                    Arch::ScmpArchAarch64,
728                    Arch::ScmpArchArm,
729                    Arch::ScmpArchMips,
730                    Arch::ScmpArchMips64,
731                    Arch::ScmpArchMips64n32,
732                    Arch::ScmpArchMipsel,
733                    Arch::ScmpArchMipsel64,
734                    Arch::ScmpArchMipsel64n32,
735                    Arch::ScmpArchPpc,
736                    Arch::ScmpArchPpc64,
737                    Arch::ScmpArchPpc64le,
738                    Arch::ScmpArchRiscv64,
739                    Arch::ScmpArchS390,
740                    Arch::ScmpArchS390x,
741                    Arch::ScmpArchX32,
742                    Arch::ScmpArchX86,
743                    Arch::ScmpArchX86_64,
744                ]),
745                known_flags: Some(vec![
746                    "SECCOMP_FILTER_FLAG_TSYNC".to_string(),
747                    "SECCOMP_FILTER_FLAG_SPEC_ALLOW".to_string(),
748                    "SECCOMP_FILTER_FLAG_LOG".to_string()
749                ]),
750                supported_flags: Some(vec![
751                    "SECCOMP_FILTER_FLAG_TSYNC".to_string(),
752                    "SECCOMP_FILTER_FLAG_SPEC_ALLOW".to_string(),
753                    "SECCOMP_FILTER_FLAG_LOG".to_string()
754                ])
755            },
756        );
757
758        assert_eq!(
759            linux.apparmor.as_ref().unwrap(),
760            &Apparmor {
761                enabled: Some(true)
762            }
763        );
764
765        assert_eq!(
766            linux.selinux.as_ref().unwrap(),
767            &Selinux {
768                enabled: Some(true)
769            }
770        );
771
772        assert_eq!(
773            linux.intel_rdt.as_ref().unwrap(),
774            &IntelRdt {
775                enabled: Some(true)
776            }
777        );
778
779        assert_eq!(
780            features.annotations().as_ref().unwrap(),
781            &[
782                (
783                    "io.github.seccomp.libseccomp.version".to_string(),
784                    "2.5.4".to_string()
785                ),
786                (
787                    "org.opencontainers.runc.checkpoint.enabled".to_string(),
788                    "true".to_string()
789                ),
790                (
791                    "org.opencontainers.runc.commit".to_string(),
792                    "v1.1.0-534-g26851168".to_string()
793                ),
794                (
795                    "org.opencontainers.runc.version".to_string(),
796                    "1.1.0+dev".to_string()
797                )
798            ]
799            .iter()
800            .cloned()
801            .collect()
802        );
803
804        assert_eq!(
805            features.potentially_unsafe_config_annotations().as_ref(),
806            None,
807        );
808    }
809}