OpenViSTAI · Agents · Blockchain · Crypto
Menu
OPENVIST RECIPES

Audit required configuration keys without exposing values with Rust

Rust

Report missing and empty required names, duplicate assignment positions and unknown keys under one literal assignment contract.

Rust code excerpt: Audit required configuration keys without exposing values with Rust. Version 0.1.0. Read the full recipe for code, sources and recorded test scope.

Report missing and empty required names, duplicate assignment positions and unknown keys under one literal assignment contract. Uses saved stdin text; never reads the real process environment.

Before you start

  • Save the code as recipe.rs. Compile with Rust 1.99.0 using: rustc --edition=2021 recipe.rs -o recipe
  • Run recipe without arguments and supply the protocol through stdin. The executable reads no files, environment variables, or host configuration.
  • Provide unique required-key selectors, one exact --- separator line, then literal KEY=value assignments. Exactly empty lines and lines starting with # are ignored in both sections. Whitespace is never trimmed.
  • Keys must match ASCII [A-Za-z_][A-Za-z0-9_]{0,63}. Assignments split at the first equals sign; their values are not interpreted.
  • Successful execution emits exactly one JSON object followed by LF, exits 0, and leaves stderr empty. All input is validated before stdout is written.
  • Missing, empty, and unknown key arrays use ASCII ordering. Duplicate objects use key order and include every one-based assignment-record position, including duplicates of unknown keys.
  • Required keys are reported as empty if any assignment has an exactly empty value. Values are never included in output or diagnostics.
  • Invalid arguments or input, invalid UTF-8, and stdin read failures produce only error: invalid input followed by LF on stderr, with empty stdout and exit status 2.
  • Example stdin: A\nB\n---\nA=\nA=example\nC=literal=value\n. Expected stdout: {"missing":["B"],"empty":["A"],"duplicates":[{"key":"A","positions":[1,2]}],"unknown":["C"]} followed by LF.

Build and check

  1. Save the example as recipe.rs.
  2. Prepare input.txt with selectors, a --- separator and literal assignments; use synthetic values while learning.
  3. Run the documented command and inspect the JSON output.
  4. Exit 2 indicates rejected input; no successful JSON result is emitted.

Limits to understand

  • Input is at most 65536 bytes; the bounded stdin read requests at most 65537 bytes to detect oversize input.
  • Input must be strict UTF-8 without a leading BOM. ASCII controls other than LF, including CR, NUL, and DEL, are rejected everywhere, including comments.
  • At most 100 selector records and 100 assignment records are accepted. Assignment records are counted before deduplication. A final LF does not add a record.
  • The combined UTF-8 byte length of all assignment values, including duplicates and unknown keys, must not exceed 1024.
  • Exactly one separator is required; either section may otherwise be empty.
  • This is a literal protocol, not general dotenv syntax: no quoting rules, interpolation, shell expansion, export prefixes, inline comments, or multiline values.
  • Other Unicode scalar values are allowed in values and comments. The JSON string encoder preserves Unicode and escapes quotes, backslashes, and U+0000 through U+001F.
  • Allocation and output-write failures are outside the input-error guarantee. Output-write failures result in exit status 2 and may leave partial stdout.
  • Literal assignment subset only; no quoting rules, export syntax, interpolation, multiline values or general dotenv compatibility.
  • Key names can themselves be sensitive.
  • stdin may block until EOF; input is bounded to 65536 bytes and 100 selector / 100 assignment records. Total assignment-value bytes are limited to 1024.

Run it

rustc --edition=2021 recipe.rs -o recipe
./recipe < input.txt

Example input

API_KEY
HOST
PORT
---
HOST=
API_KEY=first
API_KEY=second
EXTRA=x

Expected output

{"missing":["PORT"],"empty":["HOST"],"duplicates":[{"key":"API_KEY","positions":[2,3]}],"unknown":["EXTRA"]}
INSPECT THE SCRIPT

Inspect, copy and run the documented checks.

This browser preview builds code locally. It does not contact an API or run the code.

Default example ready.

Rust example
use std::collections::{BTreeMap, BTreeSet};
use std::io::{self, Read, Write};

struct AssignmentInfo {
    positions: Vec<usize>,
    has_empty: bool,
}

fn valid_key(key: &str) -> bool {
    let bytes = key.as_bytes();
    if bytes.is_empty() || bytes.len() > 64 {
        return false;
    }
    let first = bytes[0];
    if !(first.is_ascii_alphabetic() || first == b'_') {
        return false;
    }
    bytes[1..]
        .iter()
        .all(|&b| b.is_ascii_alphanumeric() || b == b'_')
}

fn json_string(out: &mut String, text: &str) {
    const HEX: &[u8; 16] = b"0123456789abcdef";
    out.push('"');
    for ch in text.chars() {
        match ch {
            '"' => out.push_str("\\\""),
            '\\' => out.push_str("\\\\"),
            '\u{0000}'..='\u{001f}' => {
                let n = ch as usize;
                out.push_str("\\u00");
                out.push(HEX[n >> 4] as char);
                out.push(HEX[n & 15] as char);
            }
            _ => out.push(ch),
        }
    }
    out.push('"');
}

fn json_names(out: &mut String, names: &[&str]) {
    out.push('[');
    for (index, name) in names.iter().enumerate() {
        if index != 0 {
            out.push(',');
        }
        json_string(out, name);
    }
    out.push(']');
}

fn audit() -> Result<String, ()> {
    let mut bytes = Vec::new();
    {
        let stdin = io::stdin();
        let mut bounded = stdin.lock().take(65537);
        bounded.read_to_end(&mut bytes).map_err(|_| ())?;
    }
    if bytes.len() > 65536 {
        return Err(());
    }
    let text = std::str::from_utf8(&bytes).map_err(|_| ())?;
    if text.starts_with('\u{feff}') {
        return Err(());
    }
    if bytes.iter().any(|&b| (b < 32 && b != b'\n') || b == 127) {
        return Err(());
    }

    let mut selectors: BTreeSet<String> = BTreeSet::new();
    let mut assignments: BTreeMap<String, AssignmentInfo> = BTreeMap::new();
    let mut in_assignments = false;
    let mut record_count = 0usize;
    let mut value_bytes = 0usize;

    for line in text.split('\n') {
        if line.is_empty() || line.starts_with('#') {
            continue;
        }
        if line == "---" {
            if in_assignments {
                return Err(());
            }
            in_assignments = true;
            continue;
        }
        if !in_assignments {
            if !valid_key(line) || selectors.len() >= 100 {
                return Err(());
            }
            if !selectors.insert(line.to_owned()) {
                return Err(());
            }
        } else {
            record_count += 1;
            if record_count > 100 {
                return Err(());
            }
            let (key, value) = line.split_once('=').ok_or(())?;
            if !valid_key(key) {
                return Err(());
            }
            value_bytes += value.len();
            if value_bytes > 1024 {
                return Err(());
            }
            let info = assignments.entry(key.to_owned()).or_insert_with(|| {
                AssignmentInfo {
                    positions: Vec::new(),
                    has_empty: false,
                }
            });
            info.positions.push(record_count);
            info.has_empty |= value.is_empty();
        }
    }
    if !in_assignments {
        return Err(());
    }

    let mut missing: Vec<&str> = Vec::new();
    let mut empty: Vec<&str> = Vec::new();
    let mut unknown: Vec<&str> = Vec::new();
    for key in &selectors {
        match assignments.get(key) {
            None => missing.push(key.as_str()),
            Some(info) if info.has_empty => empty.push(key.as_str()),
            Some(_) => {}
        }
    }
    for key in assignments.keys() {
        if !selectors.contains(key) {
            unknown.push(key.as_str());
        }
    }

    let mut out = String::new();
    out.push_str("{\"missing\":");
    json_names(&mut out, &missing);
    out.push_str(",\"empty\":");
    json_names(&mut out, &empty);
    out.push_str(",\"duplicates\":[");
    let mut first_duplicate = true;
    for (key, info) in &assignments {
        if info.positions.len() < 2 {
            continue;
        }
        if !first_duplicate {
            out.push(',');
        }
        first_duplicate = false;
        out.push_str("{\"key\":");
        json_string(&mut out, key);
        out.push_str(",\"positions\":[");
        for (index, position) in info.positions.iter().enumerate() {
            if index != 0 {
                out.push(',');
            }
            out.push_str(&position.to_string());
        }
        out.push_str("]}");
    }
    out.push_str("],\"unknown\":");
    json_names(&mut out, &unknown);
    out.push_str("}\n");
    Ok(out)
}

fn invalid_input() -> ! {
    let stderr = io::stderr();
    let _ = stderr.lock().write_all(b"error: invalid input\n");
    std::process::exit(2)
}

fn main() {
    if std::env::args_os().skip(1).next().is_some() {
        invalid_input();
    }
    let output = match audit() {
        Ok(output) => output,
        Err(()) => invalid_input(),
    };
    let stdout = io::stdout();
    let mut writer = stdout.lock();
    if writer.write_all(output.as_bytes()).is_err() {
        std::process::exit(2);
    }
    if writer.flush().is_err() {
        std::process::exit(2);
    }
}
What to verify after running
  • Check the supplied example against its expected output.
  • Inspect missing, empty, duplicate and unknown key findings.
  • Confirm invalid syntax and extra arguments fail without input values in diagnostics.

Request or format preview

Illustrative preview. No provider response, price or balance is fetched.

Change a setting to inspect the preview.

Official sources and related profiles

    Code license: MIT. Keep the license notice with your copy.

    Example version 0.1.0 · Documentation reviewed 2026-10-16.

    The release gate requires six primary fixtures and 29 supplementary checks in the pinned offline runtime. Review the bound test evidence for the actual release; these checks do not prove exhaustive correctness or compatibility with other versions.