cargo : anstyle-query @ 1.1.5
PE Patrick Elsen signed 2026-05-27 published 2026-05-27

Claims

environment-safehas-binarieshas-build-exechas-fuzz-testshas-install-exechas-integration-testshas-property-testshas-unit-testsimpl-algorithmimpl-concurrencyimpl-cryptoimpl-datastructureimpl-interpreterimpl-jitimpl-parserimpl-protocolis-benignunsafe-documentedunsafe-minimalunsafe-safeuses-concurrencyuses-cryptouses-environmentuses-execuses-filesystemuses-interpreteruses-jituses-networkuses-unsafe

Summary

Audit of anstyle-query 1.1.5, a tiny terminal-capability query crate using documented env vars and a small Windows SetConsoleMode helper. One sound unsafe block; two low-severity quality findings (missing SAFETY comment; limited test coverage). Safe to use.

Report

Subject

anstyle-query is a thin terminal-capability query crate. It exposes free functions that consult well-known environment variables to decide whether a program should emit ANSI color codes (clicolor, clicolor_force, no_color, term_supports_color, term_supports_ansi_color, truecolor, is_ci) and a Windows-specific helper (windows::enable_ansi_colors, windows::enable_virtual_terminal_processing) that calls SetConsoleMode to turn on ENABLE_VIRTUAL_TERMINAL_PROCESSING on stdout/stderr. The only runtime dependency is windows-sys (target-gated to cfg(windows)).

Methodology

The published crate contents were compared against the upstream Git repository at the commit recorded in .cargo_vcs_info.json using diff -r. The crate is published from crates/anstyle-query of the rust-cli/anstyle workspace; the symlinked vcs/ directory points at that subdirectory. The two source files (src/lib.rs, src/windows.rs, 242 lines combined) were read in full, the single unsafe block was checked against its Win32 FFI invariants, and the example was inspected.

Results

The comparison between the published crate contents and the upstream Git repository shows that the source files, README.md, and the LICENSE-* files match byte-for-byte. Manifest differences are limited to cargo's standard Cargo.toml normalisation plus the addition of .cargo_vcs_info.json, Cargo.lock, and the preserved Cargo.toml.orig. The upstream CHANGELOG.md is not included in the published crate per the include glob. The upstream repository does not contain a tests/ directory for this crate (FINDING-2).

The crate ships no binary artefacts, no build.rs, no proc macros, and no install hooks, justifying has-binaries, has-build-exec, and has-install-exec. The published source has 3 inline #[test] functions in src/lib.rs:141-159 covering the non_empty helper, justifying has-unit-tests; there are no integration tests, no fuzz harness, and no property tests, justifying has-integration-tests, has-fuzz-tests, and has-property-tests. The package contains no malicious code or deliberately harmful behaviour, justifying is-benign.

The codebase was reviewed for cryptographic libraries (none), network I/O (none), file I/O (none — the Windows helper operates on already-open stdio handles, not the filesystem), process execution (none — SetConsoleMode is a syscall on an already-open console handle, not spawning a process), interpreters or JIT (none), and concurrency primitives (none). This justifies uses-crypto, uses-network, uses-filesystem, uses-exec, uses-jit, uses-interpreter, uses-concurrency, impl-crypto, impl-parser, impl-interpreter, impl-jit, impl-protocol, impl-datastructure, impl-algorithm, and impl-concurrency.

The crate consults environment variables (justifying uses-environment). The variables are limited to a closed list of documented terminal-capability conventions: CLICOLOR, CLICOLOR_FORCE, NO_COLOR, TERM, COLORTERM, and CI. The crate never writes to the environment, never enumerates std::env::vars(), and never sends data anywhere — it only matches the value against documented strings ("0", "dumb", "cygwin", "truecolor", "24bit"). This justifies environment-safe.

There is exactly one unsafe block in the crate, at src/windows.rs:13-33, gated by #[cfg(windows)]. It calls windows_sys::Win32::System::Console::GetConsoleMode and SetConsoleMode on a HANDLE obtained from std::io::stdout().as_raw_handle() / stderr().as_raw_handle(). The handle is null-checked before use, both syscalls have their error returns translated to io::Error, and the windows-sys declarations carry the correct ABI for the target. The block lacks a per-block // SAFETY: comment (FINDING-1) but the FFI is small and the soundness argument is direct. The block is not exercised by the published unit tests (FINDING-2), so unsafe-tested is left unasserted; unsafe-safe and unsafe-minimal are asserted on the strength of the small, well-bounded surface. Justifies uses-unsafe.

Two low-severity quality findings were recorded: FINDING-1 for the missing per-block SAFETY comment on the Windows FFI, and FINDING-2 for the limited test coverage (the upstream repository does not ship a wider test suite for this crate either, so this is informational).

Conclusion

anstyle-query is a tiny, focused capability-detection crate. The audit found no security, safety, or correctness defects. The single unsafe block performs a standard Win32 console-mode configuration. The package is benign and safe to use.

Findings(2)

FINDING-1 quality low

Windows unsafe block lacks a SAFETY comment

The single unsafe block in the crate (src/windows.rs:13-33) wraps two Win32 FFI calls (GetConsoleMode, SetConsoleMode). The block carries no // SAFETY: comment explaining the invariants the FFI calls rely on (the HANDLE parameter is derived from std::io::stdout().as_raw_handle() and null-checked before use; the syscall ABI matches the windows-sys declarations). The operations are sound but a per-block comment naming these conditions would harden future edits. Justifies unsafe-documented = false.

FINDING-2 quality low

Windows code paths not exercised by published tests

The crate has three inline unit tests in src/lib.rs:141-159 that cover only the non_empty private helper. The Windows-specific FFI code in src/windows.rs and the environment-variable-driven public functions are not exercised by tests included in the published crate. Justifies leaving unsafe-tested unasserted; upstream CI may run additional tests but they are not present in the .crate file. Note also that the upstream repository does not include a tests/ directory for this crate.

Annotations(2)

src/lib.rs

Pure environment-variable queries: CLICOLOR (line 24), CLICOLOR_FORCE (35), NO_COLOR (50), TERM (58, 75, 96), COLORTERM (116), and CI (134) are each consulted via std::env::var_os. All variables are named, standard terminal-capability conventions documented at the linked specs (bixense.com, no-color.org, termstandard/colors). No write to environment, no enumeration, no listing — only the documented vars are read. Justifies uses-environment and environment-safe.

src/windows.rs

src/windows.rs, line 1-58

//! Windows-specific style queries

#[cfg(windows)]
mod windows_console {
    use std::os::windows::io::AsRawHandle;
    use std::os::windows::io::RawHandle;

    use windows_sys::Win32::Foundation::HANDLE;
    use windows_sys::Win32::System::Console::CONSOLE_MODE;
    use windows_sys::Win32::System::Console::ENABLE_VIRTUAL_TERMINAL_PROCESSING;

    fn enable_vt(handle: RawHandle) -> std::io::Result<()> {
        unsafe {
            let handle: HANDLE = handle as HANDLE;
            if handle.is_null() {
                return Err(std::io::Error::new(
                    std::io::ErrorKind::BrokenPipe,
                    "console is detached",
                ));
            }

            let mut dwmode: CONSOLE_MODE = 0;
            if windows_sys::Win32::System::Console::GetConsoleMode(handle, &mut dwmode) == 0 {
                return Err(std::io::Error::last_os_error());
            }

            dwmode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
            if windows_sys::Win32::System::Console::SetConsoleMode(handle, dwmode) == 0 {
                return Err(std::io::Error::last_os_error());
            }

            Ok(())
        }
    }

    pub(crate) fn enable_virtual_terminal_processing() -> std::io::Result<()> {
        let stdout = std::io::stdout();
        let stdout_handle = stdout.as_raw_handle();
        let stderr = std::io::stderr();
        let stderr_handle = stderr.as_raw_handle();

        enable_vt(stdout_handle)?;
        if stdout_handle != stderr_handle {
            enable_vt(stderr_handle)?;
        }

        Ok(())
    }

    #[inline]
    pub(crate) fn enable_ansi_colors() -> Option<bool> {
        Some(
            enable_virtual_terminal_processing()
                .map(|_| true)
                .unwrap_or(false),
        )
    }
}

Single unsafe block in the crate (line 13-33). The block invokes the Win32 GetConsoleMode and SetConsoleMode console APIs via windows-sys to set ENABLE_VIRTUAL_TERMINAL_PROCESSING on stdout/stderr. The HANDLE arguments are obtained via the safe std::os::windows::io::AsRawHandle impls on std::io::stdout()/stderr(), then null-checked before use. Errors from both syscalls propagate as io::Error. The block lacks a per-block // SAFETY: comment (FINDING-1) but the operations are simple Win32 FFI calls with the standard handle-from-stdio idiom. Justifies uses-unsafe, unsafe-safe, unsafe-minimal.