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#[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 oci_version_min: String,
39 oci_version_max: String,
41 hooks: Option<Vec<String>>,
44 mount_options: Option<Vec<String>>,
48 linux: Option<LinuxFeature>,
50 annotations: Option<HashMap<String, String>>,
53 potentially_unsafe_config_annotations: Option<Vec<String>>,
57}
58
59#[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 namespaces: Option<Vec<LinuxNamespaceType>>,
85 capabilities: Option<Vec<String>>,
88 cgroup: Option<Cgroup>,
90 seccomp: Option<Seccomp>,
92 apparmor: Option<Apparmor>,
94 selinux: Option<Selinux>,
96 intel_rdt: Option<IntelRdt>,
98 memory_policy: Option<MemoryPolicy>,
100 mount_extensions: Option<MountExtensions>,
102 net_devices: Option<NetDevices>,
104}
105
106#[derive(
108 Builder,
109 Clone,
110 Debug,
111 Default,
112 Deserialize,
113 Eq,
114 MutGetters,
115 Getters,
116 Setters,
117 PartialEq,
118 Serialize,
119)]
120#[serde(rename_all = "camelCase")]
121#[builder(
122 default,
123 pattern = "owned",
124 setter(into, strip_option),
125 build_fn(error = "OciSpecError")
126)]
127#[getset(get_mut = "pub", get = "pub", set = "pub")]
128pub struct Cgroup {
129 v1: Option<bool>,
133 v2: Option<bool>,
137 systemd: Option<bool>,
141 systemd_user: Option<bool>,
145 rdma: Option<bool>,
149}
150
151#[derive(
153 Builder,
154 Clone,
155 Debug,
156 Default,
157 Deserialize,
158 Eq,
159 MutGetters,
160 Getters,
161 Setters,
162 PartialEq,
163 Serialize,
164)]
165#[serde(rename_all = "camelCase")]
166#[builder(
167 default,
168 pattern = "owned",
169 setter(into, strip_option),
170 build_fn(error = "OciSpecError")
171)]
172#[getset(get_mut = "pub", get = "pub", set = "pub")]
173pub struct Seccomp {
174 enabled: Option<bool>,
177 actions: Option<Vec<LinuxSeccompAction>>,
180 operators: Option<Vec<String>>,
183 archs: Option<Vec<Arch>>,
186 known_flags: Option<Vec<String>>,
189 supported_flags: Option<Vec<String>>,
194}
195
196#[derive(
198 Builder,
199 Clone,
200 Debug,
201 Default,
202 Deserialize,
203 Eq,
204 MutGetters,
205 Getters,
206 Setters,
207 PartialEq,
208 Serialize,
209)]
210#[serde(rename_all = "camelCase")]
211#[builder(
212 default,
213 pattern = "owned",
214 setter(into, strip_option),
215 build_fn(error = "OciSpecError")
216)]
217#[getset(get_mut = "pub", get = "pub", set = "pub")]
218pub struct Apparmor {
219 enabled: Option<bool>,
223}
224
225#[derive(
227 Builder,
228 Clone,
229 Debug,
230 Default,
231 Deserialize,
232 Eq,
233 MutGetters,
234 Getters,
235 Setters,
236 PartialEq,
237 Serialize,
238)]
239#[serde(rename_all = "camelCase")]
240#[builder(
241 default,
242 pattern = "owned",
243 setter(into, strip_option),
244 build_fn(error = "OciSpecError")
245)]
246#[getset(get_mut = "pub", get = "pub", set = "pub")]
247pub struct Selinux {
248 enabled: Option<bool>,
252}
253
254#[derive(
256 Builder,
257 Clone,
258 Debug,
259 Default,
260 Deserialize,
261 Eq,
262 MutGetters,
263 Getters,
264 Setters,
265 PartialEq,
266 Serialize,
267)]
268#[serde(rename_all = "camelCase")]
269#[builder(
270 default,
271 pattern = "owned",
272 setter(into, strip_option),
273 build_fn(error = "OciSpecError")
274)]
275#[getset(get_mut = "pub", get = "pub", set = "pub")]
276pub struct IntelRdt {
277 enabled: Option<bool>,
280}
281
282#[derive(
284 Builder,
285 Clone,
286 Debug,
287 Default,
288 Deserialize,
289 Eq,
290 MutGetters,
291 Getters,
292 Setters,
293 PartialEq,
294 Serialize,
295)]
296#[serde(rename_all = "camelCase")]
297#[builder(
298 default,
299 pattern = "owned",
300 setter(into, strip_option),
301 build_fn(error = "OciSpecError")
302)]
303#[getset(get_mut = "pub", get = "pub", set = "pub")]
304pub struct MemoryPolicy {
305 modes: Option<Vec<String>>,
307 flags: Option<Vec<String>>,
309}
310
311#[derive(
313 Builder,
314 Clone,
315 Debug,
316 Default,
317 Deserialize,
318 Eq,
319 MutGetters,
320 Getters,
321 Setters,
322 PartialEq,
323 Serialize,
324)]
325#[serde(rename_all = "camelCase")]
326#[builder(
327 default,
328 pattern = "owned",
329 setter(into, strip_option),
330 build_fn(error = "OciSpecError")
331)]
332#[getset(get_mut = "pub", get = "pub", set = "pub")]
333pub struct MountExtensions {
334 idmap: Option<IDMap>,
336}
337
338#[derive(
340 Builder,
341 Clone,
342 Debug,
343 Default,
344 Deserialize,
345 Eq,
346 MutGetters,
347 Getters,
348 Setters,
349 PartialEq,
350 Serialize,
351)]
352#[serde(rename_all = "camelCase")]
353#[builder(
354 default,
355 pattern = "owned",
356 setter(into, strip_option),
357 build_fn(error = "OciSpecError")
358)]
359#[getset(get_mut = "pub", get = "pub", set = "pub")]
360pub struct NetDevices {
361 enabled: Option<bool>,
364}
365
366#[derive(
368 Builder,
369 Clone,
370 Debug,
371 Default,
372 Deserialize,
373 Eq,
374 MutGetters,
375 Getters,
376 Setters,
377 PartialEq,
378 Serialize,
379)]
380#[serde(rename_all = "camelCase")]
381#[builder(
382 default,
383 pattern = "owned",
384 setter(into, strip_option),
385 build_fn(error = "OciSpecError")
386)]
387#[getset(get_mut = "pub", get = "pub", set = "pub")]
388pub struct IDMap {
389 enabled: Option<bool>,
393}
394
395#[cfg(test)]
396mod tests {
397 use std::ops::Deref;
398
399 use super::*;
400
401 #[test]
402 fn test_parse_features() {
403 let example_json = r#"
404{
405 "ociVersionMin": "1.0.0",
406 "ociVersionMax": "1.1.0-rc.2",
407 "hooks": [
408 "prestart",
409 "createRuntime",
410 "createContainer",
411 "startContainer",
412 "poststart",
413 "poststop"
414 ],
415 "mountOptions": [
416 "async",
417 "atime",
418 "bind",
419 "defaults",
420 "dev",
421 "diratime",
422 "dirsync",
423 "exec",
424 "iversion",
425 "lazytime",
426 "loud",
427 "mand",
428 "noatime",
429 "nodev",
430 "nodiratime",
431 "noexec",
432 "noiversion",
433 "nolazytime",
434 "nomand",
435 "norelatime",
436 "nostrictatime",
437 "nosuid",
438 "nosymfollow",
439 "private",
440 "ratime",
441 "rbind",
442 "rdev",
443 "rdiratime",
444 "relatime",
445 "remount",
446 "rexec",
447 "rnoatime",
448 "rnodev",
449 "rnodiratime",
450 "rnoexec",
451 "rnorelatime",
452 "rnostrictatime",
453 "rnosuid",
454 "rnosymfollow",
455 "ro",
456 "rprivate",
457 "rrelatime",
458 "rro",
459 "rrw",
460 "rshared",
461 "rslave",
462 "rstrictatime",
463 "rsuid",
464 "rsymfollow",
465 "runbindable",
466 "rw",
467 "shared",
468 "silent",
469 "slave",
470 "strictatime",
471 "suid",
472 "symfollow",
473 "sync",
474 "tmpcopyup",
475 "unbindable"
476 ],
477 "linux": {
478 "namespaces": [
479 "cgroup",
480 "ipc",
481 "mount",
482 "network",
483 "pid",
484 "user",
485 "uts"
486 ],
487 "capabilities": [
488 "CAP_CHOWN",
489 "CAP_DAC_OVERRIDE",
490 "CAP_DAC_READ_SEARCH",
491 "CAP_FOWNER",
492 "CAP_FSETID",
493 "CAP_KILL",
494 "CAP_SETGID",
495 "CAP_SETUID",
496 "CAP_SETPCAP",
497 "CAP_LINUX_IMMUTABLE",
498 "CAP_NET_BIND_SERVICE",
499 "CAP_NET_BROADCAST",
500 "CAP_NET_ADMIN",
501 "CAP_NET_RAW",
502 "CAP_IPC_LOCK",
503 "CAP_IPC_OWNER",
504 "CAP_SYS_MODULE",
505 "CAP_SYS_RAWIO",
506 "CAP_SYS_CHROOT",
507 "CAP_SYS_PTRACE",
508 "CAP_SYS_PACCT",
509 "CAP_SYS_ADMIN",
510 "CAP_SYS_BOOT",
511 "CAP_SYS_NICE",
512 "CAP_SYS_RESOURCE",
513 "CAP_SYS_TIME",
514 "CAP_SYS_TTY_CONFIG",
515 "CAP_MKNOD",
516 "CAP_LEASE",
517 "CAP_AUDIT_WRITE",
518 "CAP_AUDIT_CONTROL",
519 "CAP_SETFCAP",
520 "CAP_MAC_OVERRIDE",
521 "CAP_MAC_ADMIN",
522 "CAP_SYSLOG",
523 "CAP_WAKE_ALARM",
524 "CAP_BLOCK_SUSPEND",
525 "CAP_AUDIT_READ",
526 "CAP_PERFMON",
527 "CAP_BPF",
528 "CAP_CHECKPOINT_RESTORE"
529 ],
530 "cgroup": {
531 "v1": true,
532 "v2": true,
533 "systemd": true,
534 "systemdUser": true,
535 "rdma": true
536 },
537 "seccomp": {
538 "enabled": true,
539 "actions": [
540 "SCMP_ACT_ALLOW",
541 "SCMP_ACT_ERRNO",
542 "SCMP_ACT_KILL",
543 "SCMP_ACT_KILL_PROCESS",
544 "SCMP_ACT_KILL_THREAD",
545 "SCMP_ACT_LOG",
546 "SCMP_ACT_NOTIFY",
547 "SCMP_ACT_TRACE",
548 "SCMP_ACT_TRAP"
549 ],
550 "operators": [
551 "SCMP_CMP_EQ",
552 "SCMP_CMP_GE",
553 "SCMP_CMP_GT",
554 "SCMP_CMP_LE",
555 "SCMP_CMP_LT",
556 "SCMP_CMP_MASKED_EQ",
557 "SCMP_CMP_NE"
558 ],
559 "archs": [
560 "SCMP_ARCH_AARCH64",
561 "SCMP_ARCH_ARM",
562 "SCMP_ARCH_MIPS",
563 "SCMP_ARCH_MIPS64",
564 "SCMP_ARCH_MIPS64N32",
565 "SCMP_ARCH_MIPSEL",
566 "SCMP_ARCH_MIPSEL64",
567 "SCMP_ARCH_MIPSEL64N32",
568 "SCMP_ARCH_PPC",
569 "SCMP_ARCH_PPC64",
570 "SCMP_ARCH_PPC64LE",
571 "SCMP_ARCH_RISCV64",
572 "SCMP_ARCH_S390",
573 "SCMP_ARCH_S390X",
574 "SCMP_ARCH_X32",
575 "SCMP_ARCH_X86",
576 "SCMP_ARCH_X86_64"
577 ],
578 "knownFlags": [
579 "SECCOMP_FILTER_FLAG_TSYNC",
580 "SECCOMP_FILTER_FLAG_SPEC_ALLOW",
581 "SECCOMP_FILTER_FLAG_LOG"
582 ],
583 "supportedFlags": [
584 "SECCOMP_FILTER_FLAG_TSYNC",
585 "SECCOMP_FILTER_FLAG_SPEC_ALLOW",
586 "SECCOMP_FILTER_FLAG_LOG"
587 ]
588 },
589 "apparmor": {
590 "enabled": true
591 },
592 "selinux": {
593 "enabled": true
594 },
595 "intelRdt": {
596 "enabled": true
597 },
598 "memoryPolicy": {
599 "modes": [
600 "MPOL_DEFAULT",
601 "MPOL_BIND",
602 "MPOL_INTERLEAVE",
603 "MPOL_WEIGHTED_INTERLEAVE",
604 "MPOL_PREFERRED",
605 "MPOL_PREFERRED_MANY",
606 "MPOL_LOCAL"
607 ],
608 "flags": [
609 "MPOL_F_NUMA_BALANCING",
610 "MPOL_F_RELATIVE_NODES",
611 "MPOL_F_STATIC_NODES"
612 ]
613 },
614 "netDevices": {
615 "enabled": true
616 }
617 },
618 "annotations": {
619 "io.github.seccomp.libseccomp.version": "2.5.4",
620 "org.opencontainers.runc.checkpoint.enabled": "true",
621 "org.opencontainers.runc.commit": "v1.1.0-534-g26851168",
622 "org.opencontainers.runc.version": "1.1.0+dev"
623 }
624}"#;
625
626 let features: Features = serde_json::from_str(example_json).unwrap();
628 assert_eq!(features.oci_version_min().deref(), "1.0.0".to_string());
629 assert_eq!(features.oci_version_max().deref(), "1.1.0-rc.2".to_string());
630
631 assert_eq!(
632 features.hooks.as_ref().unwrap(),
633 &[
634 "prestart",
635 "createRuntime",
636 "createContainer",
637 "startContainer",
638 "poststart",
639 "poststop"
640 ]
641 );
642
643 assert_eq!(
644 features.mount_options.as_ref().unwrap(),
645 &[
646 "async",
647 "atime",
648 "bind",
649 "defaults",
650 "dev",
651 "diratime",
652 "dirsync",
653 "exec",
654 "iversion",
655 "lazytime",
656 "loud",
657 "mand",
658 "noatime",
659 "nodev",
660 "nodiratime",
661 "noexec",
662 "noiversion",
663 "nolazytime",
664 "nomand",
665 "norelatime",
666 "nostrictatime",
667 "nosuid",
668 "nosymfollow",
669 "private",
670 "ratime",
671 "rbind",
672 "rdev",
673 "rdiratime",
674 "relatime",
675 "remount",
676 "rexec",
677 "rnoatime",
678 "rnodev",
679 "rnodiratime",
680 "rnoexec",
681 "rnorelatime",
682 "rnostrictatime",
683 "rnosuid",
684 "rnosymfollow",
685 "ro",
686 "rprivate",
687 "rrelatime",
688 "rro",
689 "rrw",
690 "rshared",
691 "rslave",
692 "rstrictatime",
693 "rsuid",
694 "rsymfollow",
695 "runbindable",
696 "rw",
697 "shared",
698 "silent",
699 "slave",
700 "strictatime",
701 "suid",
702 "symfollow",
703 "sync",
704 "tmpcopyup",
705 "unbindable"
706 ]
707 );
708
709 let linux = features.linux().as_ref().unwrap();
710
711 assert_eq!(
712 linux.namespaces.as_ref().unwrap(),
713 &[
714 LinuxNamespaceType::Cgroup,
715 LinuxNamespaceType::Ipc,
716 LinuxNamespaceType::Mount,
717 LinuxNamespaceType::Network,
718 LinuxNamespaceType::Pid,
719 LinuxNamespaceType::User,
720 LinuxNamespaceType::Uts,
721 ]
722 );
723
724 assert_eq!(
725 linux.capabilities.as_ref().unwrap(),
726 &[
727 "CAP_CHOWN",
728 "CAP_DAC_OVERRIDE",
729 "CAP_DAC_READ_SEARCH",
730 "CAP_FOWNER",
731 "CAP_FSETID",
732 "CAP_KILL",
733 "CAP_SETGID",
734 "CAP_SETUID",
735 "CAP_SETPCAP",
736 "CAP_LINUX_IMMUTABLE",
737 "CAP_NET_BIND_SERVICE",
738 "CAP_NET_BROADCAST",
739 "CAP_NET_ADMIN",
740 "CAP_NET_RAW",
741 "CAP_IPC_LOCK",
742 "CAP_IPC_OWNER",
743 "CAP_SYS_MODULE",
744 "CAP_SYS_RAWIO",
745 "CAP_SYS_CHROOT",
746 "CAP_SYS_PTRACE",
747 "CAP_SYS_PACCT",
748 "CAP_SYS_ADMIN",
749 "CAP_SYS_BOOT",
750 "CAP_SYS_NICE",
751 "CAP_SYS_RESOURCE",
752 "CAP_SYS_TIME",
753 "CAP_SYS_TTY_CONFIG",
754 "CAP_MKNOD",
755 "CAP_LEASE",
756 "CAP_AUDIT_WRITE",
757 "CAP_AUDIT_CONTROL",
758 "CAP_SETFCAP",
759 "CAP_MAC_OVERRIDE",
760 "CAP_MAC_ADMIN",
761 "CAP_SYSLOG",
762 "CAP_WAKE_ALARM",
763 "CAP_BLOCK_SUSPEND",
764 "CAP_AUDIT_READ",
765 "CAP_PERFMON",
766 "CAP_BPF",
767 "CAP_CHECKPOINT_RESTORE"
768 ],
769 );
770
771 assert_eq!(
772 linux.cgroup.as_ref().unwrap(),
773 &Cgroup {
774 v1: Some(true),
775 v2: Some(true),
776 systemd: Some(true),
777 systemd_user: Some(true),
778 rdma: Some(true),
779 }
780 );
781
782 assert_eq!(
783 linux.seccomp.as_ref().unwrap(),
784 &Seccomp {
785 enabled: Some(true),
786 actions: Some(vec![
787 LinuxSeccompAction::ScmpActAllow,
788 LinuxSeccompAction::ScmpActErrno,
789 LinuxSeccompAction::ScmpActKill,
790 LinuxSeccompAction::ScmpActKillProcess,
791 LinuxSeccompAction::ScmpActKillThread,
792 LinuxSeccompAction::ScmpActLog,
793 LinuxSeccompAction::ScmpActNotify,
794 LinuxSeccompAction::ScmpActTrace,
795 LinuxSeccompAction::ScmpActTrap
796 ]),
797 operators: Some(vec![
798 "SCMP_CMP_EQ".to_string(),
799 "SCMP_CMP_GE".to_string(),
800 "SCMP_CMP_GT".to_string(),
801 "SCMP_CMP_LE".to_string(),
802 "SCMP_CMP_LT".to_string(),
803 "SCMP_CMP_MASKED_EQ".to_string(),
804 "SCMP_CMP_NE".to_string()
805 ]),
806 archs: Some(vec![
807 Arch::ScmpArchAarch64,
808 Arch::ScmpArchArm,
809 Arch::ScmpArchMips,
810 Arch::ScmpArchMips64,
811 Arch::ScmpArchMips64n32,
812 Arch::ScmpArchMipsel,
813 Arch::ScmpArchMipsel64,
814 Arch::ScmpArchMipsel64n32,
815 Arch::ScmpArchPpc,
816 Arch::ScmpArchPpc64,
817 Arch::ScmpArchPpc64le,
818 Arch::ScmpArchRiscv64,
819 Arch::ScmpArchS390,
820 Arch::ScmpArchS390x,
821 Arch::ScmpArchX32,
822 Arch::ScmpArchX86,
823 Arch::ScmpArchX86_64,
824 ]),
825 known_flags: Some(vec![
826 "SECCOMP_FILTER_FLAG_TSYNC".to_string(),
827 "SECCOMP_FILTER_FLAG_SPEC_ALLOW".to_string(),
828 "SECCOMP_FILTER_FLAG_LOG".to_string()
829 ]),
830 supported_flags: Some(vec![
831 "SECCOMP_FILTER_FLAG_TSYNC".to_string(),
832 "SECCOMP_FILTER_FLAG_SPEC_ALLOW".to_string(),
833 "SECCOMP_FILTER_FLAG_LOG".to_string()
834 ])
835 },
836 );
837
838 assert_eq!(
839 linux.apparmor.as_ref().unwrap(),
840 &Apparmor {
841 enabled: Some(true)
842 }
843 );
844
845 assert_eq!(
846 linux.selinux.as_ref().unwrap(),
847 &Selinux {
848 enabled: Some(true)
849 }
850 );
851
852 assert_eq!(
853 linux.intel_rdt.as_ref().unwrap(),
854 &IntelRdt {
855 enabled: Some(true)
856 }
857 );
858
859 assert_eq!(
860 linux.memory_policy.as_ref().unwrap(),
861 &MemoryPolicy {
862 modes: Some(vec![
863 "MPOL_DEFAULT".to_string(),
864 "MPOL_BIND".to_string(),
865 "MPOL_INTERLEAVE".to_string(),
866 "MPOL_WEIGHTED_INTERLEAVE".to_string(),
867 "MPOL_PREFERRED".to_string(),
868 "MPOL_PREFERRED_MANY".to_string(),
869 "MPOL_LOCAL".to_string(),
870 ]),
871 flags: Some(vec![
872 "MPOL_F_NUMA_BALANCING".to_string(),
873 "MPOL_F_RELATIVE_NODES".to_string(),
874 "MPOL_F_STATIC_NODES".to_string(),
875 ]),
876 }
877 );
878
879 assert_eq!(
880 linux.net_devices.as_ref().unwrap(),
881 &NetDevices {
882 enabled: Some(true)
883 }
884 );
885
886 assert_eq!(
887 features.annotations().as_ref().unwrap(),
888 &[
889 (
890 "io.github.seccomp.libseccomp.version".to_string(),
891 "2.5.4".to_string()
892 ),
893 (
894 "org.opencontainers.runc.checkpoint.enabled".to_string(),
895 "true".to_string()
896 ),
897 (
898 "org.opencontainers.runc.commit".to_string(),
899 "v1.1.0-534-g26851168".to_string()
900 ),
901 (
902 "org.opencontainers.runc.version".to_string(),
903 "1.1.0+dev".to_string()
904 )
905 ]
906 .iter()
907 .cloned()
908 .collect()
909 );
910
911 assert_eq!(
912 features.potentially_unsafe_config_annotations().as_ref(),
913 None,
914 );
915 }
916}