Skip to content

bug: stdout output accepts input-only formats like cri/raw/auto during validation #1060

Closed

Description

@strawgate

Summary

output.type: stdout currently accepts input-side formats such as cri, raw, and auto during --validate, even though the stdout sink only meaningfully supports json and console.

Reproduction

This config validates successfully:

input:
  type: file
  path: /dev/null
output:
  type: stdout
  format: cri

So does the same config with format: raw or format: auto.

Run:

git fetch origin
git switch --detach origin/master
cargo build -p logfwd
./target/debug/logfwd --config config.yaml --validate

Actual behavior

Validation succeeds:

ready: default
config ok: 1 pipeline(s)

Expected behavior

stdout output validation should reject input-only formats and only accept the formats that the stdout sink actually supports.

Why this matters

A config typo or copy/paste from an input stanza looks valid but changes stdout behavior implicitly instead of failing fast.

Affected commit

Observed on origin/master at df59f6bd143bc737a2d198c8b381bd3321114a28.

Activity

  1. github-actions commented on Apr 5, 2026

    @github-actions
    Contributor

    tl;dr: Issue #1060 is valid and reproducible — stdout output currently accepts input-only formats (cri/raw/auto) during --validate because output-format compatibility is not checked, and unsupported stdout formats silently fall back to text output.

    Recommendation

    Add explicit stdout-format validation in config validation and remove the silent fallback path in sink construction so invalid stdout.format values fail fast at validation time.

    Findings
    1. Shared format enum allows input-only variants on outputs

      • crates/logfwd-config/src/lib.rs:201-210 defines Format with Cri, Raw, Auto, etc.
      • crates/logfwd-config/src/lib.rs:250-260 uses OutputConfig.format: Option(Format).
    2. Config validation does not constrain stdout format

      • crates/logfwd-config/src/lib.rs:748 has OutputType::Stdout | OutputType::Null => {} (no format checks).
    3. Runtime silently coerces unsupported stdout formats to text

      • crates/logfwd-output/src/lib.rs:770-774:
        • json -> StdoutFormat::Json
        • console -> StdoutFormat::Console
        • _ -> StdoutFormat::Text (silent fallback)
    4. Coverage gap exists in current tests

      • crates/logfwd-config/src/lib.rs:1204-1222 tests unimplemented input formats only.
      • crates/logfwd-config/src/lib.rs:1236-1250 tests output types, but no stdout format validity matrix.
    Verification

    I reproduced the behavior locally with the built binary:

    for fmt in cri raw auto; do
      ./target/debug/logfwd --config /tmp/gh-aw/agent/config-1060-${fmt}.yaml --validate
    done

    Observed output:

    === format: cri ===
      ready: default
    config ok: 1 pipeline(s)
    === format: raw ===
      ready: default
    config ok: 1 pipeline(s)
    === format: auto ===
      ready: default
    config ok: 1 pipeline(s)
    

    Relevant existing tests pass but do not cover this case:

    cargo test -q -p logfwd-config validation_unimplemented_input_format
    cargo test -q -p logfwd-config all_output_types
    running 1 test
    .
    test result: ok. 1 passed; 0 failed; ...
    
    running 1 test
    .
    test result: ok. 1 passed; 0 failed; ...
    
    Detailed Action Plan
    1. Add stdout format guard in config validation

      • File: crates/logfwd-config/src/lib.rs (inside output loop near OutputType::Stdout | OutputType::Null branch).
      • For OutputType::Stdout, allow only supported values (json, console, and whichever default behavior is intended when format is unset).
      • Reject cri/raw/auto/logfmt/syslog with a clear error message: pipeline name, output label, and allowed values.
    2. Fail closed in sink factory

      • File: crates/logfwd-output/src/lib.rs:769-775.
      • Replace _ => StdoutFormat::Text with explicit accepted mappings and return Err(...) for unsupported values.
      • This prevents runtime behavior drift if validation is bypassed.
    3. Add regression tests in config crate

      • File: crates/logfwd-config/src/lib.rs tests section.
      • Add tests that assert Config::load_str(...) fails for output.type: stdout with format: cri/raw/auto (and optionally logfmt/syslog).
      • Add/clarify valid stdout format tests (json, console, unset/default).
    4. Add CLI-level validation regression test

      • Add an integration test in existing CLI/integration test location to assert --validate exits with config error for invalid stdout.format.
    5. Docs alignment

      • Update stdout format docs in README.md / book/src/config/reference.md (or current source of truth) to list only supported stdout formats and default behavior.
    Related Items
    Type Link Relevance
    Issue #1060 Current bug report
    Issue #499 Prior format-validation gap (input-side silent fallthrough)
    Issue #158 Startup validation umbrella work; this fits that theme
    Issue #573 Earlier format-handling refactor context
    File crates/logfwd-config/src/lib.rs Config schema + validation gap
    File crates/logfwd-output/src/lib.rs Stdout fallback behavior

    Note

    🔒 Integrity filtering filtered 3 items

    Integrity filtering activated and filtered the following items during workflow execution.
    This happens when a tool call accesses a resource that does not meet the required integrity or secrecy level of the workflow.


    What is this? | From workflow: Issue Triage

    Give us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.

  2. strawgate commented on Apr 5, 2026

    @strawgate
    OwnerAuthor

    Validation: CONFIRMED — shared root cause with all silent-ignore config issues

    Both InputConfig and OutputConfig are single flat structs (#[serde(deny_unknown_fields)]) with fields shared across all input/output types. Config::validate() checks that required fields are present for each type but does not reject extraneous optional fields that have no meaning for the selected type.

    This bug is one of ~12 confirmed instances of the same pattern (see also #1057, #1058, #1060, #1064, #1065, #1066, #1070, #1071, #1072, #1073, #1075, #1077, #1078).

    Root cause confirmed:

    • crates/logfwd-output/src/lib.rs: runtime builders use match cfg.output_type and silently ignore fields not consumed by the selected arm.
    • crates/logfwd-config/src/lib.rs Config::validate(): validates required fields per type but has no reject-if-present checks for inapplicable optional fields.

    Unified fix — add per-type field rejection to Config::validate():

    // Example for OutputConfig:
    match output.output_type {
        OutputType::Stdout | OutputType::Null => {
            if output.endpoint.is_some() { warn_or_err("endpoint not used by this output type"); }
            if output.index.is_some() { warn_or_err("index not used by this output type"); }
            if output.compression.is_some() { warn_or_err("compression not used by this output type"); }
            if output.auth.is_some() { warn_or_err("auth not used by this output type"); }
            // etc.
        }
        OutputType::Elasticsearch => {
            if output.protocol.is_some() { warn_or_err("protocol not used by elasticsearch"); }
            // etc.
        }
        // ...
    }

    A single pass over all output types covering all optional fields fixes all 12 related issues at once.

  3. strawgate commented on Apr 5, 2026

    @strawgate
    OwnerAuthor

    Fixed on master in PR #1153 (a20b1ac0abc635914ee267103d466926401c3fb4).

    I rechecked origin/master; stdout validation/default behavior now matches this issue, so this looks stale and safe to close.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions