Repository: astral-sh/ruff
File: crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs (Rust)

Code before:

    let mut diagnostic = checker.report_diagnostic(NonOctalPermissions, mode_arg.range());

    diagnostic.info(format!(
        "current value {mode_literal} will be interpreted as 0o{:o}, permissions: {}",
        mode & 0o777,
        get_permissions(mode)
    ));
    // Don't suggest a fix for 0x or 0b literals.
    if mode_literal.starts_with("0x") || mode_literal.starts_with("0b") {
        return;
    }

    if mode_literal.chars().all(|c| c == '0') {
        // Fix e.g. 000 as 0o000
        let edit = Edit::range_replacement(format!("0o{mode_literal}"), mode_arg.range());
        diagnostic.set_fix(Fix::safe_edit(edit));
        return;
    }

    let Some(suggested) = int.as_u16().and_then(suggest_fix) else {
        return;
    };
    let suggested_permissions = get_permissions(suggested);
    diagnostic.info(format!(
        "suggested value: 0o{suggested:o}, permissions: {suggested_permissions}"
    ));
    let edit = Edit::range_replacement(format!("{suggested:#o}"), mode_arg.range());
    diagnostic.set_fix(Fix::unsafe_edit(edit));
}

fn find_func_mode_arg<'a>(call: &'a ExprCall, semantic: &SemanticModel) -> Option<&'a Expr> {
    let qualified_name = semantic.resolve_qualified_name(&call.func)?;

    match qualified_name.segments() {
        ["os", "umask"] => call.arguments.find_argument_value("mode", 0),
        [
            "os",
            "chmod" | "fchmod" | "lchmod" | "mkdir" | "makedirs" | "mkfifo" | "mknod",
        ] => call.arguments.find_argument_value("mode", 1),
        ["os", "open"] => call.arguments.find_argument_value("mode", 2),
        ["dbm", "open"] | ["dbm", "gnu" | "ndbm", "open"] => {
            call.arguments.find_argument_value("mode", 2)
        }
        _ => None,
    }
}

fn find_method_mode_arg<'a>(call: &'a ExprCall, semantic: &SemanticModel) -> Option<&'a Expr> {
    let (type_name, attr_name) = resolve_method_call(&call.func, semantic)?;


Review comment (security):
I think we should capitalize the first letter of each message to match the `help:` message.


```suggestion
        "Suggested value: {suggested:#o}, permissions: {suggested_permissions}"
```

(and same `#o` change as above)

Code after:
    }

    let Some(suggested) = int.as_u16().and_then(suggest_fix) else {
        return;
    };
    let suggested_permissions = get_permissions(suggested);
    diagnostic.info(format_args!(
        "Suggested value of {suggested:#05o} sets permissions: {suggested_permissions}"
    ));
    let edit = Edit::range_replacement(format!("{suggested:#o}"), mode_arg.range());
    diagnostic.set_fix(Fix::unsafe_edit(edit));
}

fn find_func_mode_arg<'a>(call: &'a ExprCall, semantic: &SemanticModel) -> Option<&'a Expr> {
    let qualified_name = semantic.resolve_qualified_name(&call.func)?;

    match qualified_name.segments() {
        ["os", "umask"] => call.arguments.find_argument_value("mode", 0),
        [
            "os",
            "chmod" | "fchmod" | "lchmod" | "mkdir" | "makedirs" | "mkfifo" | "mknod",
        ] => call.arguments.find_argument_value("mode", 1),
        ["os", "open"] => call.arguments.find_argument_value("mode", 2),
        ["dbm", "open"] | ["dbm", "gnu" | "ndbm", "open"] => {
            call.arguments.find_argument_value("mode", 2)
        }
        _ => None,
    }
}

fn find_method_mode_arg<'a>(call: &'a ExprCall, semantic: &SemanticModel) -> Option<&'a Expr> {
    let (type_name, attr_name) = resolve_method_call(&call.func, semantic)?;

    match (type_name.segments(), attr_name) {
        (
            ["pathlib", "Path" | "PosixPath" | "WindowsPath"],
            "chmod" | "lchmod" | "mkdir" | "touch",
        ) => call.arguments.find_argument_value("mode", 0),
        _ => None,
    }
}

fn resolve_method_call<'a>(
    func: &'a Expr,
    semantic: &'a SemanticModel,
) -> Option<(QualifiedName<'a>, &'a str)> {
    let Expr::Attribute(ast::ExprAttribute { attr, value, .. }) = func else {
        return None;
    };

    // First: is this an inlined call like `pathlib.Path.chmod`?