From f5da131c422d1705d596942efd606bf86a187506 Mon Sep 17 00:00:00 2001 From: Bhuminjay Date: Fri, 30 Jan 2026 18:20:14 +0530 Subject: [PATCH 1/9] add info for non_octal permissions Signed-off-by: Bhuminjay --- .../rules/ruff/rules/non_octal_permissions.rs | 35 ++++++++++++++++- ..._rules__ruff__tests__RUF064_RUF064.py.snap | 38 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs index 461972614be09..3bc42c52a192b 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs @@ -88,6 +88,23 @@ impl Violation for NonOctalPermissions { } } +fn get_permissions(mode: u16) -> String { + let perm = mode & 0o777; + let mut out = String::with_capacity(9); + let append_permission = |out: &mut String, bits: u16| { + out.push(if bits & 0o4 != 0 { 'r' } else { '-' }); + out.push(if bits & 0o2 != 0 { 'w' } else { '-' }); + out.push(if bits & 0o1 != 0 { 'x' } else { '-' }); + }; + out.push_str("u="); + append_permission(&mut out, (perm >> 6) & 0o7); + out.push_str(", g="); + append_permission(&mut out, (perm >> 3) & 0o7); + out.push_str(", o="); + append_permission(&mut out, perm & 0o7); + out +} + /// RUF064 pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { let mode_arg = find_func_mode_arg(call, checker.semantic()) @@ -111,8 +128,21 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { return; } + let mode = match int.as_u16() { + Some(m) => m, + None => { + 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; @@ -128,7 +158,10 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { 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)); } diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap index 9a88ad5557cc9..b198ecfc4b9f5 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap @@ -12,6 +12,8 @@ RUF064 [*] Non-octal mode 8 | os.chmod("foo", 7777) # Error | help: Replace with octal literal +info: current value 444 will be interpreted as 0o674, permissions: u=rw-, g=rwx, o=r-- +info: suggested value: 0o444, permissions: u=r--, g=r--, o=r-- 3 | import os 4 | from pathlib import Path 5 | @@ -33,6 +35,7 @@ RUF064 Non-octal mode 10 | os.chmod("foo", 99999) # Error | help: Replace with octal literal +info: current value 7777 will be interpreted as 0o141, permissions: u=--x, g=r--, o=--x RUF064 Non-octal mode --> RUF064.py:9:17 @@ -44,6 +47,7 @@ RUF064 Non-octal mode 10 | os.chmod("foo", 99999) # Error | help: Replace with octal literal +info: current value 10000 will be interpreted as 0o420, permissions: u=r--, g=-w-, o=--- RUF064 Non-octal mode --> RUF064.py:10:17 @@ -67,6 +71,8 @@ RUF064 [*] Non-octal mode 13 | os.umask(0o777) # OK | help: Replace with octal literal +info: current value 777 will be interpreted as 0o411, permissions: u=r--, g=--x, o=--x +info: suggested value: 0o777, permissions: u=rwx, g=rwx, o=rwx 9 | os.chmod("foo", 10000) # Error 10 | os.chmod("foo", 99999) # Error 11 | @@ -87,6 +93,8 @@ RUF064 [*] Non-octal mode 16 | os.fchmod(0, 0o400) # OK | help: Replace with octal literal +info: current value 400 will be interpreted as 0o620, permissions: u=rw-, g=-w-, o=--- +info: suggested value: 0o400, permissions: u=r--, g=---, o=--- 12 | os.umask(777) # Error 13 | os.umask(0o777) # OK 14 | @@ -107,6 +115,8 @@ RUF064 [*] Non-octal mode 19 | os.lchmod("foo", 0o755) # OK | help: Replace with octal literal +info: current value 755 will be interpreted as 0o363, permissions: u=-wx, g=rw-, o=-wx +info: suggested value: 0o755, permissions: u=rwx, g=r-x, o=r-x 15 | os.fchmod(0, 400) # Error 16 | os.fchmod(0, 0o400) # OK 17 | @@ -127,6 +137,8 @@ RUF064 [*] Non-octal mode 22 | os.mkdir("foo", 0o600) # OK | help: Replace with octal literal +info: current value 600 will be interpreted as 0o130, permissions: u=--x, g=-wx, o=--- +info: suggested value: 0o600, permissions: u=rw-, g=---, o=--- 18 | os.lchmod("foo", 755) # Error 19 | os.lchmod("foo", 0o755) # OK 20 | @@ -147,6 +159,8 @@ RUF064 [*] Non-octal mode 25 | os.makedirs("foo", 0o644) # OK | help: Replace with octal literal +info: current value 644 will be interpreted as 0o204, permissions: u=-w-, g=---, o=r-- +info: suggested value: 0o644, permissions: u=rw-, g=r--, o=r-- 21 | os.mkdir("foo", 600) # Error 22 | os.mkdir("foo", 0o600) # OK 23 | @@ -167,6 +181,8 @@ RUF064 [*] Non-octal mode 28 | os.mkfifo("foo", 0o640) # OK | help: Replace with octal literal +info: current value 640 will be interpreted as 0o200, permissions: u=-w-, g=---, o=--- +info: suggested value: 0o640, permissions: u=rw-, g=r--, o=--- 24 | os.makedirs("foo", 644) # Error 25 | os.makedirs("foo", 0o644) # OK 26 | @@ -187,6 +203,8 @@ RUF064 [*] Non-octal mode 31 | os.mknod("foo", 0o660) # OK | help: Replace with octal literal +info: current value 660 will be interpreted as 0o224, permissions: u=-w-, g=-w-, o=r-- +info: suggested value: 0o660, permissions: u=rw-, g=rw-, o=--- 27 | os.mkfifo("foo", 640) # Error 28 | os.mkfifo("foo", 0o640) # OK 29 | @@ -207,6 +225,8 @@ RUF064 [*] Non-octal mode 34 | os.open("foo", os.O_CREAT, 0o644) # OK | help: Replace with octal literal +info: current value 644 will be interpreted as 0o204, permissions: u=-w-, g=---, o=r-- +info: suggested value: 0o644, permissions: u=rw-, g=r--, o=r-- 30 | os.mknod("foo", 660) # Error 31 | os.mknod("foo", 0o660) # OK 32 | @@ -227,6 +247,8 @@ RUF064 [*] Non-octal mode 37 | Path("bar").chmod(0o755) # OK | help: Replace with octal literal +info: current value 755 will be interpreted as 0o363, permissions: u=-wx, g=rw-, o=-wx +info: suggested value: 0o755, permissions: u=rwx, g=r-x, o=r-x 33 | os.open("foo", os.O_CREAT, 644) # Error 34 | os.open("foo", os.O_CREAT, 0o644) # OK 35 | @@ -246,6 +268,8 @@ RUF064 [*] Non-octal mode 41 | path.chmod(0o755) # OK | help: Replace with octal literal +info: current value 755 will be interpreted as 0o363, permissions: u=-wx, g=rw-, o=-wx +info: suggested value: 0o755, permissions: u=rwx, g=r-x, o=r-x 37 | Path("bar").chmod(0o755) # OK 38 | 39 | path = Path("bar") @@ -266,6 +290,8 @@ RUF064 [*] Non-octal mode 44 | dbm.open("db", "r", 0o600) # OK | help: Replace with octal literal +info: current value 600 will be interpreted as 0o130, permissions: u=--x, g=-wx, o=--- +info: suggested value: 0o600, permissions: u=rw-, g=---, o=--- 40 | path.chmod(755) # Error 41 | path.chmod(0o755) # OK 42 | @@ -286,6 +312,8 @@ RUF064 [*] Non-octal mode 47 | dbm.gnu.open("db", "r", 0o600) # OK | help: Replace with octal literal +info: current value 600 will be interpreted as 0o130, permissions: u=--x, g=-wx, o=--- +info: suggested value: 0o600, permissions: u=rw-, g=---, o=--- 43 | dbm.open("db", "r", 600) # Error 44 | dbm.open("db", "r", 0o600) # OK 45 | @@ -306,6 +334,8 @@ RUF064 [*] Non-octal mode 50 | dbm.ndbm.open("db", "r", 0o600) # OK | help: Replace with octal literal +info: current value 600 will be interpreted as 0o130, permissions: u=--x, g=-wx, o=--- +info: suggested value: 0o600, permissions: u=rw-, g=---, o=--- 46 | dbm.gnu.open("db", "r", 600) # Error 47 | dbm.gnu.open("db", "r", 0o600) # OK 48 | @@ -326,6 +356,8 @@ RUF064 [*] Non-octal mode 53 | os.fchmod(0, 493) # 0o755 | help: Replace with octal literal +info: current value 256 will be interpreted as 0o400, permissions: u=r--, g=---, o=--- +info: suggested value: 0o400, permissions: u=r--, g=---, o=--- 49 | dbm.ndbm.open("db", "r", 600) # Error 50 | dbm.ndbm.open("db", "r", 0o600) # OK 51 | @@ -346,6 +378,8 @@ RUF064 [*] Non-octal mode 55 | # https://github.com/astral-sh/ruff/issues/19010 | help: Replace with octal literal +info: current value 493 will be interpreted as 0o755, permissions: u=rwx, g=r-x, o=r-x +info: suggested value: 0o755, permissions: u=rwx, g=r-x, o=r-x 50 | dbm.ndbm.open("db", "r", 0o600) # OK 51 | 52 | os.fchmod(0, 256) # 0o400 @@ -365,6 +399,7 @@ RUF064 [*] Non-octal mode 57 | os.chmod("foo", 0000) # Error | help: Replace with octal literal +info: current value 000 will be interpreted as 0o0, permissions: u=---, g=---, o=--- 53 | os.fchmod(0, 493) # 0o755 54 | 55 | # https://github.com/astral-sh/ruff/issues/19010 @@ -385,6 +420,7 @@ RUF064 [*] Non-octal mode 59 | os.chmod("foo", 0b0) # Error | help: Replace with octal literal +info: current value 0000 will be interpreted as 0o0, permissions: u=---, g=---, o=--- 54 | 55 | # https://github.com/astral-sh/ruff/issues/19010 56 | os.chmod("foo", 000) # Error @@ -405,6 +441,7 @@ RUF064 Non-octal mode 61 | os.chmod("foo", 0) # Ok | help: Replace with octal literal +info: current value 0b0 will be interpreted as 0o0, permissions: u=---, g=---, o=--- RUF064 Non-octal mode --> RUF064.py:60:17 @@ -415,3 +452,4 @@ RUF064 Non-octal mode 61 | os.chmod("foo", 0) # Ok | help: Replace with octal literal +info: current value 0x0 will be interpreted as 0o0, permissions: u=---, g=---, o=--- From ca0e6252903de228ea06f5b6a54e1d3567b0ee72 Mon Sep 17 00:00:00 2001 From: Bhuminjay Date: Fri, 30 Jan 2026 18:26:30 +0530 Subject: [PATCH 2/9] clippy fix Signed-off-by: Bhuminjay --- .../src/rules/ruff/rules/non_octal_permissions.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs index 3bc42c52a192b..b7ff229fcca07 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs @@ -128,12 +128,9 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { return; } - let mode = match int.as_u16() { - Some(m) => m, - None => { - checker.report_diagnostic(NonOctalPermissions, mode_arg.range()); - 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()); From 95a85338036fab8b4be4fa7607cd15282ca72d5a Mon Sep 17 00:00:00 2001 From: Bhuminjay Date: Sat, 31 Jan 2026 17:40:19 +0530 Subject: [PATCH 3/9] message nit Signed-off-by: Bhuminjay --- .../rules/ruff/rules/non_octal_permissions.rs | 40 +++++----- ..._rules__ruff__tests__RUF064_RUF064.py.snap | 76 +++++++++---------- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs index b7ff229fcca07..93fbe47d41e10 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs @@ -88,23 +88,6 @@ impl Violation for NonOctalPermissions { } } -fn get_permissions(mode: u16) -> String { - let perm = mode & 0o777; - let mut out = String::with_capacity(9); - let append_permission = |out: &mut String, bits: u16| { - out.push(if bits & 0o4 != 0 { 'r' } else { '-' }); - out.push(if bits & 0o2 != 0 { 'w' } else { '-' }); - out.push(if bits & 0o1 != 0 { 'x' } else { '-' }); - }; - out.push_str("u="); - append_permission(&mut out, (perm >> 6) & 0o7); - out.push_str(", g="); - append_permission(&mut out, (perm >> 3) & 0o7); - out.push_str(", o="); - append_permission(&mut out, perm & 0o7); - out -} - /// RUF064 pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { let mode_arg = find_func_mode_arg(call, checker.semantic()) @@ -136,8 +119,8 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { 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, + "Current value of mode {mode_literal} ({:#o}) sets permissions: {})", + mode & 0o7777, get_permissions(mode) )); // Don't suggest a fix for 0x or 0b literals. @@ -157,7 +140,7 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { }; let suggested_permissions = get_permissions(suggested); diagnostic.info(format!( - "suggested value: 0o{suggested:o}, permissions: {suggested_permissions}" + "Suggested value of {suggested:#0} sets permissions: {suggested_permissions}" )); let edit = Edit::range_replacement(format!("{suggested:#o}"), mode_arg.range()); diagnostic.set_fix(Fix::unsafe_edit(edit)); @@ -260,3 +243,20 @@ fn suggest_fix(mode: u16) -> Option { _ => None, } } + +fn get_permissions(mode: u16) -> String { + let perm = mode & 0o777; + let mut out = String::with_capacity(9); + let append_permission = |out: &mut String, bits: u16| { + out.push(if bits & 0o4 != 0 { 'r' } else { '-' }); + out.push(if bits & 0o2 != 0 { 'w' } else { '-' }); + out.push(if bits & 0o1 != 0 { 'x' } else { '-' }); + }; + out.push_str("u="); + append_permission(&mut out, (perm >> 6) & 0o7); + out.push_str(", g="); + append_permission(&mut out, (perm >> 3) & 0o7); + out.push_str(", o="); + append_permission(&mut out, perm & 0o7); + out +} diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap index b198ecfc4b9f5..2a9f96f5c58e4 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap @@ -12,8 +12,8 @@ RUF064 [*] Non-octal mode 8 | os.chmod("foo", 7777) # Error | help: Replace with octal literal -info: current value 444 will be interpreted as 0o674, permissions: u=rw-, g=rwx, o=r-- -info: suggested value: 0o444, permissions: u=r--, g=r--, o=r-- +info: Current value of mode 444 (0o674) sets permissions: u=rw-, g=rwx, o=r--) +info: Suggested value of 292 sets permissions: u=r--, g=r--, o=r-- 3 | import os 4 | from pathlib import Path 5 | @@ -35,7 +35,7 @@ RUF064 Non-octal mode 10 | os.chmod("foo", 99999) # Error | help: Replace with octal literal -info: current value 7777 will be interpreted as 0o141, permissions: u=--x, g=r--, o=--x +info: Current value of mode 7777 (0o7141) sets permissions: u=--x, g=r--, o=--x) RUF064 Non-octal mode --> RUF064.py:9:17 @@ -47,7 +47,7 @@ RUF064 Non-octal mode 10 | os.chmod("foo", 99999) # Error | help: Replace with octal literal -info: current value 10000 will be interpreted as 0o420, permissions: u=r--, g=-w-, o=--- +info: Current value of mode 10000 (0o3420) sets permissions: u=r--, g=-w-, o=---) RUF064 Non-octal mode --> RUF064.py:10:17 @@ -71,8 +71,8 @@ RUF064 [*] Non-octal mode 13 | os.umask(0o777) # OK | help: Replace with octal literal -info: current value 777 will be interpreted as 0o411, permissions: u=r--, g=--x, o=--x -info: suggested value: 0o777, permissions: u=rwx, g=rwx, o=rwx +info: Current value of mode 777 (0o1411) sets permissions: u=r--, g=--x, o=--x) +info: Suggested value of 511 sets permissions: u=rwx, g=rwx, o=rwx 9 | os.chmod("foo", 10000) # Error 10 | os.chmod("foo", 99999) # Error 11 | @@ -93,8 +93,8 @@ RUF064 [*] Non-octal mode 16 | os.fchmod(0, 0o400) # OK | help: Replace with octal literal -info: current value 400 will be interpreted as 0o620, permissions: u=rw-, g=-w-, o=--- -info: suggested value: 0o400, permissions: u=r--, g=---, o=--- +info: Current value of mode 400 (0o620) sets permissions: u=rw-, g=-w-, o=---) +info: Suggested value of 256 sets permissions: u=r--, g=---, o=--- 12 | os.umask(777) # Error 13 | os.umask(0o777) # OK 14 | @@ -115,8 +115,8 @@ RUF064 [*] Non-octal mode 19 | os.lchmod("foo", 0o755) # OK | help: Replace with octal literal -info: current value 755 will be interpreted as 0o363, permissions: u=-wx, g=rw-, o=-wx -info: suggested value: 0o755, permissions: u=rwx, g=r-x, o=r-x +info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx) +info: Suggested value of 493 sets permissions: u=rwx, g=r-x, o=r-x 15 | os.fchmod(0, 400) # Error 16 | os.fchmod(0, 0o400) # OK 17 | @@ -137,8 +137,8 @@ RUF064 [*] Non-octal mode 22 | os.mkdir("foo", 0o600) # OK | help: Replace with octal literal -info: current value 600 will be interpreted as 0o130, permissions: u=--x, g=-wx, o=--- -info: suggested value: 0o600, permissions: u=rw-, g=---, o=--- +info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=---) +info: Suggested value of 384 sets permissions: u=rw-, g=---, o=--- 18 | os.lchmod("foo", 755) # Error 19 | os.lchmod("foo", 0o755) # OK 20 | @@ -159,8 +159,8 @@ RUF064 [*] Non-octal mode 25 | os.makedirs("foo", 0o644) # OK | help: Replace with octal literal -info: current value 644 will be interpreted as 0o204, permissions: u=-w-, g=---, o=r-- -info: suggested value: 0o644, permissions: u=rw-, g=r--, o=r-- +info: Current value of mode 644 (0o1204) sets permissions: u=-w-, g=---, o=r--) +info: Suggested value of 420 sets permissions: u=rw-, g=r--, o=r-- 21 | os.mkdir("foo", 600) # Error 22 | os.mkdir("foo", 0o600) # OK 23 | @@ -181,8 +181,8 @@ RUF064 [*] Non-octal mode 28 | os.mkfifo("foo", 0o640) # OK | help: Replace with octal literal -info: current value 640 will be interpreted as 0o200, permissions: u=-w-, g=---, o=--- -info: suggested value: 0o640, permissions: u=rw-, g=r--, o=--- +info: Current value of mode 640 (0o1200) sets permissions: u=-w-, g=---, o=---) +info: Suggested value of 416 sets permissions: u=rw-, g=r--, o=--- 24 | os.makedirs("foo", 644) # Error 25 | os.makedirs("foo", 0o644) # OK 26 | @@ -203,8 +203,8 @@ RUF064 [*] Non-octal mode 31 | os.mknod("foo", 0o660) # OK | help: Replace with octal literal -info: current value 660 will be interpreted as 0o224, permissions: u=-w-, g=-w-, o=r-- -info: suggested value: 0o660, permissions: u=rw-, g=rw-, o=--- +info: Current value of mode 660 (0o1224) sets permissions: u=-w-, g=-w-, o=r--) +info: Suggested value of 432 sets permissions: u=rw-, g=rw-, o=--- 27 | os.mkfifo("foo", 640) # Error 28 | os.mkfifo("foo", 0o640) # OK 29 | @@ -225,8 +225,8 @@ RUF064 [*] Non-octal mode 34 | os.open("foo", os.O_CREAT, 0o644) # OK | help: Replace with octal literal -info: current value 644 will be interpreted as 0o204, permissions: u=-w-, g=---, o=r-- -info: suggested value: 0o644, permissions: u=rw-, g=r--, o=r-- +info: Current value of mode 644 (0o1204) sets permissions: u=-w-, g=---, o=r--) +info: Suggested value of 420 sets permissions: u=rw-, g=r--, o=r-- 30 | os.mknod("foo", 660) # Error 31 | os.mknod("foo", 0o660) # OK 32 | @@ -247,8 +247,8 @@ RUF064 [*] Non-octal mode 37 | Path("bar").chmod(0o755) # OK | help: Replace with octal literal -info: current value 755 will be interpreted as 0o363, permissions: u=-wx, g=rw-, o=-wx -info: suggested value: 0o755, permissions: u=rwx, g=r-x, o=r-x +info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx) +info: Suggested value of 493 sets permissions: u=rwx, g=r-x, o=r-x 33 | os.open("foo", os.O_CREAT, 644) # Error 34 | os.open("foo", os.O_CREAT, 0o644) # OK 35 | @@ -268,8 +268,8 @@ RUF064 [*] Non-octal mode 41 | path.chmod(0o755) # OK | help: Replace with octal literal -info: current value 755 will be interpreted as 0o363, permissions: u=-wx, g=rw-, o=-wx -info: suggested value: 0o755, permissions: u=rwx, g=r-x, o=r-x +info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx) +info: Suggested value of 493 sets permissions: u=rwx, g=r-x, o=r-x 37 | Path("bar").chmod(0o755) # OK 38 | 39 | path = Path("bar") @@ -290,8 +290,8 @@ RUF064 [*] Non-octal mode 44 | dbm.open("db", "r", 0o600) # OK | help: Replace with octal literal -info: current value 600 will be interpreted as 0o130, permissions: u=--x, g=-wx, o=--- -info: suggested value: 0o600, permissions: u=rw-, g=---, o=--- +info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=---) +info: Suggested value of 384 sets permissions: u=rw-, g=---, o=--- 40 | path.chmod(755) # Error 41 | path.chmod(0o755) # OK 42 | @@ -312,8 +312,8 @@ RUF064 [*] Non-octal mode 47 | dbm.gnu.open("db", "r", 0o600) # OK | help: Replace with octal literal -info: current value 600 will be interpreted as 0o130, permissions: u=--x, g=-wx, o=--- -info: suggested value: 0o600, permissions: u=rw-, g=---, o=--- +info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=---) +info: Suggested value of 384 sets permissions: u=rw-, g=---, o=--- 43 | dbm.open("db", "r", 600) # Error 44 | dbm.open("db", "r", 0o600) # OK 45 | @@ -334,8 +334,8 @@ RUF064 [*] Non-octal mode 50 | dbm.ndbm.open("db", "r", 0o600) # OK | help: Replace with octal literal -info: current value 600 will be interpreted as 0o130, permissions: u=--x, g=-wx, o=--- -info: suggested value: 0o600, permissions: u=rw-, g=---, o=--- +info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=---) +info: Suggested value of 384 sets permissions: u=rw-, g=---, o=--- 46 | dbm.gnu.open("db", "r", 600) # Error 47 | dbm.gnu.open("db", "r", 0o600) # OK 48 | @@ -356,8 +356,8 @@ RUF064 [*] Non-octal mode 53 | os.fchmod(0, 493) # 0o755 | help: Replace with octal literal -info: current value 256 will be interpreted as 0o400, permissions: u=r--, g=---, o=--- -info: suggested value: 0o400, permissions: u=r--, g=---, o=--- +info: Current value of mode 256 (0o400) sets permissions: u=r--, g=---, o=---) +info: Suggested value of 256 sets permissions: u=r--, g=---, o=--- 49 | dbm.ndbm.open("db", "r", 600) # Error 50 | dbm.ndbm.open("db", "r", 0o600) # OK 51 | @@ -378,8 +378,8 @@ RUF064 [*] Non-octal mode 55 | # https://github.com/astral-sh/ruff/issues/19010 | help: Replace with octal literal -info: current value 493 will be interpreted as 0o755, permissions: u=rwx, g=r-x, o=r-x -info: suggested value: 0o755, permissions: u=rwx, g=r-x, o=r-x +info: Current value of mode 493 (0o755) sets permissions: u=rwx, g=r-x, o=r-x) +info: Suggested value of 493 sets permissions: u=rwx, g=r-x, o=r-x 50 | dbm.ndbm.open("db", "r", 0o600) # OK 51 | 52 | os.fchmod(0, 256) # 0o400 @@ -399,7 +399,7 @@ RUF064 [*] Non-octal mode 57 | os.chmod("foo", 0000) # Error | help: Replace with octal literal -info: current value 000 will be interpreted as 0o0, permissions: u=---, g=---, o=--- +info: Current value of mode 000 (0o0) sets permissions: u=---, g=---, o=---) 53 | os.fchmod(0, 493) # 0o755 54 | 55 | # https://github.com/astral-sh/ruff/issues/19010 @@ -420,7 +420,7 @@ RUF064 [*] Non-octal mode 59 | os.chmod("foo", 0b0) # Error | help: Replace with octal literal -info: current value 0000 will be interpreted as 0o0, permissions: u=---, g=---, o=--- +info: Current value of mode 0000 (0o0) sets permissions: u=---, g=---, o=---) 54 | 55 | # https://github.com/astral-sh/ruff/issues/19010 56 | os.chmod("foo", 000) # Error @@ -441,7 +441,7 @@ RUF064 Non-octal mode 61 | os.chmod("foo", 0) # Ok | help: Replace with octal literal -info: current value 0b0 will be interpreted as 0o0, permissions: u=---, g=---, o=--- +info: Current value of mode 0b0 (0o0) sets permissions: u=---, g=---, o=---) RUF064 Non-octal mode --> RUF064.py:60:17 @@ -452,4 +452,4 @@ RUF064 Non-octal mode 61 | os.chmod("foo", 0) # Ok | help: Replace with octal literal -info: current value 0x0 will be interpreted as 0o0, permissions: u=---, g=---, o=--- +info: Current value of mode 0x0 (0o0) sets permissions: u=---, g=---, o=---) From 25f28a6dae19ebcf3df54883b7729a920006cd57 Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Mon, 2 Feb 2026 12:54:44 -0500 Subject: [PATCH 4/9] report_diagnostic once --- .../src/rules/ruff/rules/non_octal_permissions.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs index 93fbe47d41e10..e6e55d9a25925 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs @@ -111,13 +111,12 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { return; } + let mut diagnostic = checker.report_diagnostic(NonOctalPermissions, mode_arg.range()); + 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 of mode {mode_literal} ({:#o}) sets permissions: {})", mode & 0o7777, From c42520c5157e63a566dbd9f9e3f9c596ea66f37b Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Mon, 2 Feb 2026 12:55:57 -0500 Subject: [PATCH 5/9] extra paren --- .../rules/ruff/rules/non_octal_permissions.rs | 2 +- ..._rules__ruff__tests__RUF064_RUF064.py.snap | 44 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs index e6e55d9a25925..c1520e07293d4 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs @@ -118,7 +118,7 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { }; diagnostic.info(format!( - "Current value of mode {mode_literal} ({:#o}) sets permissions: {})", + "Current value of mode {mode_literal} ({:#o}) sets permissions: {}", mode & 0o7777, get_permissions(mode) )); diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap index 2a9f96f5c58e4..ffd3da5046492 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap @@ -12,7 +12,7 @@ RUF064 [*] Non-octal mode 8 | os.chmod("foo", 7777) # Error | help: Replace with octal literal -info: Current value of mode 444 (0o674) sets permissions: u=rw-, g=rwx, o=r--) +info: Current value of mode 444 (0o674) sets permissions: u=rw-, g=rwx, o=r-- info: Suggested value of 292 sets permissions: u=r--, g=r--, o=r-- 3 | import os 4 | from pathlib import Path @@ -35,7 +35,7 @@ RUF064 Non-octal mode 10 | os.chmod("foo", 99999) # Error | help: Replace with octal literal -info: Current value of mode 7777 (0o7141) sets permissions: u=--x, g=r--, o=--x) +info: Current value of mode 7777 (0o7141) sets permissions: u=--x, g=r--, o=--x RUF064 Non-octal mode --> RUF064.py:9:17 @@ -47,7 +47,7 @@ RUF064 Non-octal mode 10 | os.chmod("foo", 99999) # Error | help: Replace with octal literal -info: Current value of mode 10000 (0o3420) sets permissions: u=r--, g=-w-, o=---) +info: Current value of mode 10000 (0o3420) sets permissions: u=r--, g=-w-, o=--- RUF064 Non-octal mode --> RUF064.py:10:17 @@ -71,7 +71,7 @@ RUF064 [*] Non-octal mode 13 | os.umask(0o777) # OK | help: Replace with octal literal -info: Current value of mode 777 (0o1411) sets permissions: u=r--, g=--x, o=--x) +info: Current value of mode 777 (0o1411) sets permissions: u=r--, g=--x, o=--x info: Suggested value of 511 sets permissions: u=rwx, g=rwx, o=rwx 9 | os.chmod("foo", 10000) # Error 10 | os.chmod("foo", 99999) # Error @@ -93,7 +93,7 @@ RUF064 [*] Non-octal mode 16 | os.fchmod(0, 0o400) # OK | help: Replace with octal literal -info: Current value of mode 400 (0o620) sets permissions: u=rw-, g=-w-, o=---) +info: Current value of mode 400 (0o620) sets permissions: u=rw-, g=-w-, o=--- info: Suggested value of 256 sets permissions: u=r--, g=---, o=--- 12 | os.umask(777) # Error 13 | os.umask(0o777) # OK @@ -115,7 +115,7 @@ RUF064 [*] Non-octal mode 19 | os.lchmod("foo", 0o755) # OK | help: Replace with octal literal -info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx) +info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx info: Suggested value of 493 sets permissions: u=rwx, g=r-x, o=r-x 15 | os.fchmod(0, 400) # Error 16 | os.fchmod(0, 0o400) # OK @@ -137,7 +137,7 @@ RUF064 [*] Non-octal mode 22 | os.mkdir("foo", 0o600) # OK | help: Replace with octal literal -info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=---) +info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- info: Suggested value of 384 sets permissions: u=rw-, g=---, o=--- 18 | os.lchmod("foo", 755) # Error 19 | os.lchmod("foo", 0o755) # OK @@ -159,7 +159,7 @@ RUF064 [*] Non-octal mode 25 | os.makedirs("foo", 0o644) # OK | help: Replace with octal literal -info: Current value of mode 644 (0o1204) sets permissions: u=-w-, g=---, o=r--) +info: Current value of mode 644 (0o1204) sets permissions: u=-w-, g=---, o=r-- info: Suggested value of 420 sets permissions: u=rw-, g=r--, o=r-- 21 | os.mkdir("foo", 600) # Error 22 | os.mkdir("foo", 0o600) # OK @@ -181,7 +181,7 @@ RUF064 [*] Non-octal mode 28 | os.mkfifo("foo", 0o640) # OK | help: Replace with octal literal -info: Current value of mode 640 (0o1200) sets permissions: u=-w-, g=---, o=---) +info: Current value of mode 640 (0o1200) sets permissions: u=-w-, g=---, o=--- info: Suggested value of 416 sets permissions: u=rw-, g=r--, o=--- 24 | os.makedirs("foo", 644) # Error 25 | os.makedirs("foo", 0o644) # OK @@ -203,7 +203,7 @@ RUF064 [*] Non-octal mode 31 | os.mknod("foo", 0o660) # OK | help: Replace with octal literal -info: Current value of mode 660 (0o1224) sets permissions: u=-w-, g=-w-, o=r--) +info: Current value of mode 660 (0o1224) sets permissions: u=-w-, g=-w-, o=r-- info: Suggested value of 432 sets permissions: u=rw-, g=rw-, o=--- 27 | os.mkfifo("foo", 640) # Error 28 | os.mkfifo("foo", 0o640) # OK @@ -225,7 +225,7 @@ RUF064 [*] Non-octal mode 34 | os.open("foo", os.O_CREAT, 0o644) # OK | help: Replace with octal literal -info: Current value of mode 644 (0o1204) sets permissions: u=-w-, g=---, o=r--) +info: Current value of mode 644 (0o1204) sets permissions: u=-w-, g=---, o=r-- info: Suggested value of 420 sets permissions: u=rw-, g=r--, o=r-- 30 | os.mknod("foo", 660) # Error 31 | os.mknod("foo", 0o660) # OK @@ -247,7 +247,7 @@ RUF064 [*] Non-octal mode 37 | Path("bar").chmod(0o755) # OK | help: Replace with octal literal -info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx) +info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx info: Suggested value of 493 sets permissions: u=rwx, g=r-x, o=r-x 33 | os.open("foo", os.O_CREAT, 644) # Error 34 | os.open("foo", os.O_CREAT, 0o644) # OK @@ -268,7 +268,7 @@ RUF064 [*] Non-octal mode 41 | path.chmod(0o755) # OK | help: Replace with octal literal -info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx) +info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx info: Suggested value of 493 sets permissions: u=rwx, g=r-x, o=r-x 37 | Path("bar").chmod(0o755) # OK 38 | @@ -290,7 +290,7 @@ RUF064 [*] Non-octal mode 44 | dbm.open("db", "r", 0o600) # OK | help: Replace with octal literal -info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=---) +info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- info: Suggested value of 384 sets permissions: u=rw-, g=---, o=--- 40 | path.chmod(755) # Error 41 | path.chmod(0o755) # OK @@ -312,7 +312,7 @@ RUF064 [*] Non-octal mode 47 | dbm.gnu.open("db", "r", 0o600) # OK | help: Replace with octal literal -info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=---) +info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- info: Suggested value of 384 sets permissions: u=rw-, g=---, o=--- 43 | dbm.open("db", "r", 600) # Error 44 | dbm.open("db", "r", 0o600) # OK @@ -334,7 +334,7 @@ RUF064 [*] Non-octal mode 50 | dbm.ndbm.open("db", "r", 0o600) # OK | help: Replace with octal literal -info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=---) +info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- info: Suggested value of 384 sets permissions: u=rw-, g=---, o=--- 46 | dbm.gnu.open("db", "r", 600) # Error 47 | dbm.gnu.open("db", "r", 0o600) # OK @@ -356,7 +356,7 @@ RUF064 [*] Non-octal mode 53 | os.fchmod(0, 493) # 0o755 | help: Replace with octal literal -info: Current value of mode 256 (0o400) sets permissions: u=r--, g=---, o=---) +info: Current value of mode 256 (0o400) sets permissions: u=r--, g=---, o=--- info: Suggested value of 256 sets permissions: u=r--, g=---, o=--- 49 | dbm.ndbm.open("db", "r", 600) # Error 50 | dbm.ndbm.open("db", "r", 0o600) # OK @@ -378,7 +378,7 @@ RUF064 [*] Non-octal mode 55 | # https://github.com/astral-sh/ruff/issues/19010 | help: Replace with octal literal -info: Current value of mode 493 (0o755) sets permissions: u=rwx, g=r-x, o=r-x) +info: Current value of mode 493 (0o755) sets permissions: u=rwx, g=r-x, o=r-x info: Suggested value of 493 sets permissions: u=rwx, g=r-x, o=r-x 50 | dbm.ndbm.open("db", "r", 0o600) # OK 51 | @@ -399,7 +399,7 @@ RUF064 [*] Non-octal mode 57 | os.chmod("foo", 0000) # Error | help: Replace with octal literal -info: Current value of mode 000 (0o0) sets permissions: u=---, g=---, o=---) +info: Current value of mode 000 (0o0) sets permissions: u=---, g=---, o=--- 53 | os.fchmod(0, 493) # 0o755 54 | 55 | # https://github.com/astral-sh/ruff/issues/19010 @@ -420,7 +420,7 @@ RUF064 [*] Non-octal mode 59 | os.chmod("foo", 0b0) # Error | help: Replace with octal literal -info: Current value of mode 0000 (0o0) sets permissions: u=---, g=---, o=---) +info: Current value of mode 0000 (0o0) sets permissions: u=---, g=---, o=--- 54 | 55 | # https://github.com/astral-sh/ruff/issues/19010 56 | os.chmod("foo", 000) # Error @@ -441,7 +441,7 @@ RUF064 Non-octal mode 61 | os.chmod("foo", 0) # Ok | help: Replace with octal literal -info: Current value of mode 0b0 (0o0) sets permissions: u=---, g=---, o=---) +info: Current value of mode 0b0 (0o0) sets permissions: u=---, g=---, o=--- RUF064 Non-octal mode --> RUF064.py:60:17 @@ -452,4 +452,4 @@ RUF064 Non-octal mode 61 | os.chmod("foo", 0) # Ok | help: Replace with octal literal -info: Current value of mode 0x0 (0o0) sets permissions: u=---, g=---, o=---) +info: Current value of mode 0x0 (0o0) sets permissions: u=---, g=---, o=--- From 80e00c4fc4d459f09dfcafe44b321153c4de6d5a Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Mon, 2 Feb 2026 12:57:05 -0500 Subject: [PATCH 6/9] show suggestion as octal --- .../rules/ruff/rules/non_octal_permissions.rs | 2 +- ..._rules__ruff__tests__RUF064_RUF064.py.snap | 32 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs index c1520e07293d4..a055fb644f83c 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs @@ -139,7 +139,7 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { }; let suggested_permissions = get_permissions(suggested); diagnostic.info(format!( - "Suggested value of {suggested:#0} sets permissions: {suggested_permissions}" + "Suggested value of {suggested:#o} sets permissions: {suggested_permissions}" )); let edit = Edit::range_replacement(format!("{suggested:#o}"), mode_arg.range()); diagnostic.set_fix(Fix::unsafe_edit(edit)); diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap index ffd3da5046492..8f230b641e3a8 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap @@ -13,7 +13,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 444 (0o674) sets permissions: u=rw-, g=rwx, o=r-- -info: Suggested value of 292 sets permissions: u=r--, g=r--, o=r-- +info: Suggested value of 0o444 sets permissions: u=r--, g=r--, o=r-- 3 | import os 4 | from pathlib import Path 5 | @@ -72,7 +72,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 777 (0o1411) sets permissions: u=r--, g=--x, o=--x -info: Suggested value of 511 sets permissions: u=rwx, g=rwx, o=rwx +info: Suggested value of 0o777 sets permissions: u=rwx, g=rwx, o=rwx 9 | os.chmod("foo", 10000) # Error 10 | os.chmod("foo", 99999) # Error 11 | @@ -94,7 +94,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 400 (0o620) sets permissions: u=rw-, g=-w-, o=--- -info: Suggested value of 256 sets permissions: u=r--, g=---, o=--- +info: Suggested value of 0o400 sets permissions: u=r--, g=---, o=--- 12 | os.umask(777) # Error 13 | os.umask(0o777) # OK 14 | @@ -116,7 +116,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx -info: Suggested value of 493 sets permissions: u=rwx, g=r-x, o=r-x +info: Suggested value of 0o755 sets permissions: u=rwx, g=r-x, o=r-x 15 | os.fchmod(0, 400) # Error 16 | os.fchmod(0, 0o400) # OK 17 | @@ -138,7 +138,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- -info: Suggested value of 384 sets permissions: u=rw-, g=---, o=--- +info: Suggested value of 0o600 sets permissions: u=rw-, g=---, o=--- 18 | os.lchmod("foo", 755) # Error 19 | os.lchmod("foo", 0o755) # OK 20 | @@ -160,7 +160,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 644 (0o1204) sets permissions: u=-w-, g=---, o=r-- -info: Suggested value of 420 sets permissions: u=rw-, g=r--, o=r-- +info: Suggested value of 0o644 sets permissions: u=rw-, g=r--, o=r-- 21 | os.mkdir("foo", 600) # Error 22 | os.mkdir("foo", 0o600) # OK 23 | @@ -182,7 +182,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 640 (0o1200) sets permissions: u=-w-, g=---, o=--- -info: Suggested value of 416 sets permissions: u=rw-, g=r--, o=--- +info: Suggested value of 0o640 sets permissions: u=rw-, g=r--, o=--- 24 | os.makedirs("foo", 644) # Error 25 | os.makedirs("foo", 0o644) # OK 26 | @@ -204,7 +204,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 660 (0o1224) sets permissions: u=-w-, g=-w-, o=r-- -info: Suggested value of 432 sets permissions: u=rw-, g=rw-, o=--- +info: Suggested value of 0o660 sets permissions: u=rw-, g=rw-, o=--- 27 | os.mkfifo("foo", 640) # Error 28 | os.mkfifo("foo", 0o640) # OK 29 | @@ -226,7 +226,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 644 (0o1204) sets permissions: u=-w-, g=---, o=r-- -info: Suggested value of 420 sets permissions: u=rw-, g=r--, o=r-- +info: Suggested value of 0o644 sets permissions: u=rw-, g=r--, o=r-- 30 | os.mknod("foo", 660) # Error 31 | os.mknod("foo", 0o660) # OK 32 | @@ -248,7 +248,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx -info: Suggested value of 493 sets permissions: u=rwx, g=r-x, o=r-x +info: Suggested value of 0o755 sets permissions: u=rwx, g=r-x, o=r-x 33 | os.open("foo", os.O_CREAT, 644) # Error 34 | os.open("foo", os.O_CREAT, 0o644) # OK 35 | @@ -269,7 +269,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx -info: Suggested value of 493 sets permissions: u=rwx, g=r-x, o=r-x +info: Suggested value of 0o755 sets permissions: u=rwx, g=r-x, o=r-x 37 | Path("bar").chmod(0o755) # OK 38 | 39 | path = Path("bar") @@ -291,7 +291,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- -info: Suggested value of 384 sets permissions: u=rw-, g=---, o=--- +info: Suggested value of 0o600 sets permissions: u=rw-, g=---, o=--- 40 | path.chmod(755) # Error 41 | path.chmod(0o755) # OK 42 | @@ -313,7 +313,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- -info: Suggested value of 384 sets permissions: u=rw-, g=---, o=--- +info: Suggested value of 0o600 sets permissions: u=rw-, g=---, o=--- 43 | dbm.open("db", "r", 600) # Error 44 | dbm.open("db", "r", 0o600) # OK 45 | @@ -335,7 +335,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- -info: Suggested value of 384 sets permissions: u=rw-, g=---, o=--- +info: Suggested value of 0o600 sets permissions: u=rw-, g=---, o=--- 46 | dbm.gnu.open("db", "r", 600) # Error 47 | dbm.gnu.open("db", "r", 0o600) # OK 48 | @@ -357,7 +357,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 256 (0o400) sets permissions: u=r--, g=---, o=--- -info: Suggested value of 256 sets permissions: u=r--, g=---, o=--- +info: Suggested value of 0o400 sets permissions: u=r--, g=---, o=--- 49 | dbm.ndbm.open("db", "r", 600) # Error 50 | dbm.ndbm.open("db", "r", 0o600) # OK 51 | @@ -379,7 +379,7 @@ RUF064 [*] Non-octal mode | help: Replace with octal literal info: Current value of mode 493 (0o755) sets permissions: u=rwx, g=r-x, o=r-x -info: Suggested value of 493 sets permissions: u=rwx, g=r-x, o=r-x +info: Suggested value of 0o755 sets permissions: u=rwx, g=r-x, o=r-x 50 | dbm.ndbm.open("db", "r", 0o600) # OK 51 | 52 | os.fchmod(0, 256) # 0o400 From 07694d36b97a18c0f41cded7414a55adf1b152cd Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Mon, 2 Feb 2026 12:59:27 -0500 Subject: [PATCH 7/9] drop `mode` to parallel the suggestion message --- .../rules/ruff/rules/non_octal_permissions.rs | 2 +- ..._rules__ruff__tests__RUF064_RUF064.py.snap | 44 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs index a055fb644f83c..2d23c0ceeb8f9 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs @@ -118,7 +118,7 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { }; diagnostic.info(format!( - "Current value of mode {mode_literal} ({:#o}) sets permissions: {}", + "Current value of {mode_literal} ({:#o}) sets permissions: {}", mode & 0o7777, get_permissions(mode) )); diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap index 8f230b641e3a8..191c7e30f3978 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap @@ -12,7 +12,7 @@ RUF064 [*] Non-octal mode 8 | os.chmod("foo", 7777) # Error | help: Replace with octal literal -info: Current value of mode 444 (0o674) sets permissions: u=rw-, g=rwx, o=r-- +info: Current value of 444 (0o674) sets permissions: u=rw-, g=rwx, o=r-- info: Suggested value of 0o444 sets permissions: u=r--, g=r--, o=r-- 3 | import os 4 | from pathlib import Path @@ -35,7 +35,7 @@ RUF064 Non-octal mode 10 | os.chmod("foo", 99999) # Error | help: Replace with octal literal -info: Current value of mode 7777 (0o7141) sets permissions: u=--x, g=r--, o=--x +info: Current value of 7777 (0o7141) sets permissions: u=--x, g=r--, o=--x RUF064 Non-octal mode --> RUF064.py:9:17 @@ -47,7 +47,7 @@ RUF064 Non-octal mode 10 | os.chmod("foo", 99999) # Error | help: Replace with octal literal -info: Current value of mode 10000 (0o3420) sets permissions: u=r--, g=-w-, o=--- +info: Current value of 10000 (0o3420) sets permissions: u=r--, g=-w-, o=--- RUF064 Non-octal mode --> RUF064.py:10:17 @@ -71,7 +71,7 @@ RUF064 [*] Non-octal mode 13 | os.umask(0o777) # OK | help: Replace with octal literal -info: Current value of mode 777 (0o1411) sets permissions: u=r--, g=--x, o=--x +info: Current value of 777 (0o1411) sets permissions: u=r--, g=--x, o=--x info: Suggested value of 0o777 sets permissions: u=rwx, g=rwx, o=rwx 9 | os.chmod("foo", 10000) # Error 10 | os.chmod("foo", 99999) # Error @@ -93,7 +93,7 @@ RUF064 [*] Non-octal mode 16 | os.fchmod(0, 0o400) # OK | help: Replace with octal literal -info: Current value of mode 400 (0o620) sets permissions: u=rw-, g=-w-, o=--- +info: Current value of 400 (0o620) sets permissions: u=rw-, g=-w-, o=--- info: Suggested value of 0o400 sets permissions: u=r--, g=---, o=--- 12 | os.umask(777) # Error 13 | os.umask(0o777) # OK @@ -115,7 +115,7 @@ RUF064 [*] Non-octal mode 19 | os.lchmod("foo", 0o755) # OK | help: Replace with octal literal -info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx +info: Current value of 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx info: Suggested value of 0o755 sets permissions: u=rwx, g=r-x, o=r-x 15 | os.fchmod(0, 400) # Error 16 | os.fchmod(0, 0o400) # OK @@ -137,7 +137,7 @@ RUF064 [*] Non-octal mode 22 | os.mkdir("foo", 0o600) # OK | help: Replace with octal literal -info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- +info: Current value of 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- info: Suggested value of 0o600 sets permissions: u=rw-, g=---, o=--- 18 | os.lchmod("foo", 755) # Error 19 | os.lchmod("foo", 0o755) # OK @@ -159,7 +159,7 @@ RUF064 [*] Non-octal mode 25 | os.makedirs("foo", 0o644) # OK | help: Replace with octal literal -info: Current value of mode 644 (0o1204) sets permissions: u=-w-, g=---, o=r-- +info: Current value of 644 (0o1204) sets permissions: u=-w-, g=---, o=r-- info: Suggested value of 0o644 sets permissions: u=rw-, g=r--, o=r-- 21 | os.mkdir("foo", 600) # Error 22 | os.mkdir("foo", 0o600) # OK @@ -181,7 +181,7 @@ RUF064 [*] Non-octal mode 28 | os.mkfifo("foo", 0o640) # OK | help: Replace with octal literal -info: Current value of mode 640 (0o1200) sets permissions: u=-w-, g=---, o=--- +info: Current value of 640 (0o1200) sets permissions: u=-w-, g=---, o=--- info: Suggested value of 0o640 sets permissions: u=rw-, g=r--, o=--- 24 | os.makedirs("foo", 644) # Error 25 | os.makedirs("foo", 0o644) # OK @@ -203,7 +203,7 @@ RUF064 [*] Non-octal mode 31 | os.mknod("foo", 0o660) # OK | help: Replace with octal literal -info: Current value of mode 660 (0o1224) sets permissions: u=-w-, g=-w-, o=r-- +info: Current value of 660 (0o1224) sets permissions: u=-w-, g=-w-, o=r-- info: Suggested value of 0o660 sets permissions: u=rw-, g=rw-, o=--- 27 | os.mkfifo("foo", 640) # Error 28 | os.mkfifo("foo", 0o640) # OK @@ -225,7 +225,7 @@ RUF064 [*] Non-octal mode 34 | os.open("foo", os.O_CREAT, 0o644) # OK | help: Replace with octal literal -info: Current value of mode 644 (0o1204) sets permissions: u=-w-, g=---, o=r-- +info: Current value of 644 (0o1204) sets permissions: u=-w-, g=---, o=r-- info: Suggested value of 0o644 sets permissions: u=rw-, g=r--, o=r-- 30 | os.mknod("foo", 660) # Error 31 | os.mknod("foo", 0o660) # OK @@ -247,7 +247,7 @@ RUF064 [*] Non-octal mode 37 | Path("bar").chmod(0o755) # OK | help: Replace with octal literal -info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx +info: Current value of 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx info: Suggested value of 0o755 sets permissions: u=rwx, g=r-x, o=r-x 33 | os.open("foo", os.O_CREAT, 644) # Error 34 | os.open("foo", os.O_CREAT, 0o644) # OK @@ -268,7 +268,7 @@ RUF064 [*] Non-octal mode 41 | path.chmod(0o755) # OK | help: Replace with octal literal -info: Current value of mode 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx +info: Current value of 755 (0o1363) sets permissions: u=-wx, g=rw-, o=-wx info: Suggested value of 0o755 sets permissions: u=rwx, g=r-x, o=r-x 37 | Path("bar").chmod(0o755) # OK 38 | @@ -290,7 +290,7 @@ RUF064 [*] Non-octal mode 44 | dbm.open("db", "r", 0o600) # OK | help: Replace with octal literal -info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- +info: Current value of 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- info: Suggested value of 0o600 sets permissions: u=rw-, g=---, o=--- 40 | path.chmod(755) # Error 41 | path.chmod(0o755) # OK @@ -312,7 +312,7 @@ RUF064 [*] Non-octal mode 47 | dbm.gnu.open("db", "r", 0o600) # OK | help: Replace with octal literal -info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- +info: Current value of 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- info: Suggested value of 0o600 sets permissions: u=rw-, g=---, o=--- 43 | dbm.open("db", "r", 600) # Error 44 | dbm.open("db", "r", 0o600) # OK @@ -334,7 +334,7 @@ RUF064 [*] Non-octal mode 50 | dbm.ndbm.open("db", "r", 0o600) # OK | help: Replace with octal literal -info: Current value of mode 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- +info: Current value of 600 (0o1130) sets permissions: u=--x, g=-wx, o=--- info: Suggested value of 0o600 sets permissions: u=rw-, g=---, o=--- 46 | dbm.gnu.open("db", "r", 600) # Error 47 | dbm.gnu.open("db", "r", 0o600) # OK @@ -356,7 +356,7 @@ RUF064 [*] Non-octal mode 53 | os.fchmod(0, 493) # 0o755 | help: Replace with octal literal -info: Current value of mode 256 (0o400) sets permissions: u=r--, g=---, o=--- +info: Current value of 256 (0o400) sets permissions: u=r--, g=---, o=--- info: Suggested value of 0o400 sets permissions: u=r--, g=---, o=--- 49 | dbm.ndbm.open("db", "r", 600) # Error 50 | dbm.ndbm.open("db", "r", 0o600) # OK @@ -378,7 +378,7 @@ RUF064 [*] Non-octal mode 55 | # https://github.com/astral-sh/ruff/issues/19010 | help: Replace with octal literal -info: Current value of mode 493 (0o755) sets permissions: u=rwx, g=r-x, o=r-x +info: Current value of 493 (0o755) sets permissions: u=rwx, g=r-x, o=r-x info: Suggested value of 0o755 sets permissions: u=rwx, g=r-x, o=r-x 50 | dbm.ndbm.open("db", "r", 0o600) # OK 51 | @@ -399,7 +399,7 @@ RUF064 [*] Non-octal mode 57 | os.chmod("foo", 0000) # Error | help: Replace with octal literal -info: Current value of mode 000 (0o0) sets permissions: u=---, g=---, o=--- +info: Current value of 000 (0o0) sets permissions: u=---, g=---, o=--- 53 | os.fchmod(0, 493) # 0o755 54 | 55 | # https://github.com/astral-sh/ruff/issues/19010 @@ -420,7 +420,7 @@ RUF064 [*] Non-octal mode 59 | os.chmod("foo", 0b0) # Error | help: Replace with octal literal -info: Current value of mode 0000 (0o0) sets permissions: u=---, g=---, o=--- +info: Current value of 0000 (0o0) sets permissions: u=---, g=---, o=--- 54 | 55 | # https://github.com/astral-sh/ruff/issues/19010 56 | os.chmod("foo", 000) # Error @@ -441,7 +441,7 @@ RUF064 Non-octal mode 61 | os.chmod("foo", 0) # Ok | help: Replace with octal literal -info: Current value of mode 0b0 (0o0) sets permissions: u=---, g=---, o=--- +info: Current value of 0b0 (0o0) sets permissions: u=---, g=---, o=--- RUF064 Non-octal mode --> RUF064.py:60:17 @@ -452,4 +452,4 @@ RUF064 Non-octal mode 61 | os.chmod("foo", 0) # Ok | help: Replace with octal literal -info: Current value of mode 0x0 (0o0) sets permissions: u=---, g=---, o=--- +info: Current value of 0x0 (0o0) sets permissions: u=---, g=---, o=--- From 27047ad42874d491653c996e3e01208bf85f861c Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Mon, 2 Feb 2026 13:04:49 -0500 Subject: [PATCH 8/9] pad to at least 3 octal digits --- .../src/rules/ruff/rules/non_octal_permissions.rs | 4 ++-- ...ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs index 2d23c0ceeb8f9..fc8862f8d94ea 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs @@ -118,7 +118,7 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { }; diagnostic.info(format!( - "Current value of {mode_literal} ({:#o}) sets permissions: {}", + "Current value of {mode_literal} ({:#05o}) sets permissions: {}", mode & 0o7777, get_permissions(mode) )); @@ -139,7 +139,7 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { }; let suggested_permissions = get_permissions(suggested); diagnostic.info(format!( - "Suggested value of {suggested:#o} sets permissions: {suggested_permissions}" + "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)); diff --git a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap index 191c7e30f3978..7d5a58f758412 100644 --- a/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap +++ b/crates/ruff_linter/src/rules/ruff/snapshots/ruff_linter__rules__ruff__tests__RUF064_RUF064.py.snap @@ -399,7 +399,7 @@ RUF064 [*] Non-octal mode 57 | os.chmod("foo", 0000) # Error | help: Replace with octal literal -info: Current value of 000 (0o0) sets permissions: u=---, g=---, o=--- +info: Current value of 000 (0o000) sets permissions: u=---, g=---, o=--- 53 | os.fchmod(0, 493) # 0o755 54 | 55 | # https://github.com/astral-sh/ruff/issues/19010 @@ -420,7 +420,7 @@ RUF064 [*] Non-octal mode 59 | os.chmod("foo", 0b0) # Error | help: Replace with octal literal -info: Current value of 0000 (0o0) sets permissions: u=---, g=---, o=--- +info: Current value of 0000 (0o000) sets permissions: u=---, g=---, o=--- 54 | 55 | # https://github.com/astral-sh/ruff/issues/19010 56 | os.chmod("foo", 000) # Error @@ -441,7 +441,7 @@ RUF064 Non-octal mode 61 | os.chmod("foo", 0) # Ok | help: Replace with octal literal -info: Current value of 0b0 (0o0) sets permissions: u=---, g=---, o=--- +info: Current value of 0b0 (0o000) sets permissions: u=---, g=---, o=--- RUF064 Non-octal mode --> RUF064.py:60:17 @@ -452,4 +452,4 @@ RUF064 Non-octal mode 61 | os.chmod("foo", 0) # Ok | help: Replace with octal literal -info: Current value of 0x0 (0o0) sets permissions: u=---, g=---, o=--- +info: Current value of 0x0 (0o000) sets permissions: u=---, g=---, o=--- From 7adcc5b7eb97ad7b63d35a27993b6e8533933a1f Mon Sep 17 00:00:00 2001 From: Brent Westbrook Date: Mon, 2 Feb 2026 13:17:42 -0500 Subject: [PATCH 9/9] format -> format_args --- .../ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs index fc8862f8d94ea..fdfda6071423a 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/non_octal_permissions.rs @@ -117,7 +117,7 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { return; }; - diagnostic.info(format!( + diagnostic.info(format_args!( "Current value of {mode_literal} ({:#05o}) sets permissions: {}", mode & 0o7777, get_permissions(mode) @@ -138,7 +138,7 @@ pub(crate) fn non_octal_permissions(checker: &Checker, call: &ExprCall) { return; }; let suggested_permissions = get_permissions(suggested); - diagnostic.info(format!( + diagnostic.info(format_args!( "Suggested value of {suggested:#05o} sets permissions: {suggested_permissions}" )); let edit = Edit::range_replacement(format!("{suggested:#o}"), mode_arg.range());