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

Code before:
        return;
    };

    let Expr::NumberLiteral(ast::ExprNumberLiteral {
        value: ast::Number::Int(int),
        ..
    }) = mode_arg
    else {
        return;
    };

    let mode_literal = &checker.locator().contents()[mode_arg.range()];

    if mode_literal.starts_with("0o") || mode_literal.starts_with("0O") || mode_literal == "0" {
        return;
    }

    let Some(mode) = int.as_u16() else {
        checker.report_diagnostic(NonOctalPermissions, mode_arg.range());
        return;
    };

    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));
}

Review comment (security):
I think  you can accomplish the same thing with this format string:


```suggestion
        "current value {mode_literal} will be interpreted as {:#o}, permissions: {}",
```

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

    let Some(mode) = int.as_u16() else {
        return;
    };

    diagnostic.info(format_args!(
        "Current value of {mode_literal} ({:#05o}) sets permissions: {}",
        mode & 0o7777,
        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_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,
    }
}