Repository: openai/codex
File: codex-rs/core/src/skills/loader.rs (Rust)

Code before:
      - "./data"
    write:
      - "./output"
"#,
        );

        let cfg = make_config(&codex_home).await;
        let outcome = load_skills_for_test(&cfg);

        assert!(
            outcome.errors.is_empty(),
            "unexpected errors: {:?}",
            outcome.errors
        );
        assert_eq!(outcome.skills.len(), 1);
        assert_eq!(
            outcome.skills[0].permission_profile,
            Some(PermissionProfile {
                network: Some(true),
                file_system: Some(FileSystemPermissions {
                    read: Some(vec![PathBuf::from("./data")]),
                    write: Some(vec![PathBuf::from("./output")]),
                }),
                macos: None,
            })
        );
        #[cfg(target_os = "macos")]
        let macos_seatbelt_profile_extensions =
            Some(crate::seatbelt_permissions::MacOsSeatbeltProfileExtensions::default());
        #[cfg(not(target_os = "macos"))]
        let macos_seatbelt_profile_extensions = None;
        assert_eq!(
            outcome.skills[0].permissions,
            Some(Permissions {
                approval_policy: Constrained::allow_any(crate::protocol::AskForApproval::Never),
                sandbox_policy: Constrained::allow_any(
                    crate::protocol::SandboxPolicy::WorkspaceWrite {
                        writable_roots: vec![
                            AbsolutePathBuf::try_from(normalized(
                                skill_dir.join("output").as_path(),
                            ))
                            .expect("absolute output path")
                        ],
                        read_only_access: crate::protocol::ReadOnlyAccess::Restricted {
                            include_platform_defaults: true,
                            readable_roots: vec![
                                AbsolutePathBuf::try_from(normalized(
                                    skill_dir.join("data").as_path(),
                                ))
                                .expect("absolute data path")
                            ],

Review comment (security):
We should move from `PathBuf` to `AbsolutePathBuf` in `FileSystemPermissions`, but then we have to be sure to deserialize the YAML using `AbsolutePathBufGuard`.

Code after:
            r#"
permissions:
  network: true
  file_system:
    read:
      - "./data"
    write:
      - "./output"
"#,
        );

        let cfg = make_config(&codex_home).await;
        let outcome = load_skills_for_test(&cfg);

        assert!(
            outcome.errors.is_empty(),
            "unexpected errors: {:?}",
            outcome.errors
        );
        assert_eq!(outcome.skills.len(), 1);
        assert_eq!(
            outcome.skills[0].permission_profile,
            Some(PermissionProfile {
                network: Some(true),
                file_system: Some(FileSystemPermissions {
                    read: Some(vec![PathBuf::from("./data")]),
                    write: Some(vec![PathBuf::from("./output")]),
                }),
                macos: None,
            })
        );
        #[cfg(target_os = "macos")]
        let macos_seatbelt_profile_extensions =
            Some(crate::seatbelt_permissions::MacOsSeatbeltProfileExtensions::default());
        #[cfg(not(target_os = "macos"))]
        let macos_seatbelt_profile_extensions = None;
        assert_eq!(
            outcome.skills[0].permissions,
            Some(Permissions {
                approval_policy: Constrained::allow_any(crate::protocol::AskForApproval::Never),
                sandbox_policy: Constrained::allow_any(
                    crate::protocol::SandboxPolicy::WorkspaceWrite {
                        writable_roots: vec![
                            AbsolutePathBuf::try_from(normalized(
                                skill_dir.join("output").as_path(),
                            ))
                            .expect("absolute output path")
                        ],
                        read_only_access: crate::protocol::ReadOnlyAccess::Restricted {
                            include_platform_defaults: true,
                            readable_roots: vec![