Skip to content

πŸ§ͺ Test gap analysis β€” 6 gaps found in compile/standalone.rs validation functionsΒ #176

@github-actions

Description

@github-actions

Test Gap Analysis

Test suite snapshot: 679 unit tests, 44 integration tests, 8 MCP HTTP tests, 9 proxy tests (740 total) β€” all passing.

Note: All gaps identified in the previous run (2026-04-13) have been fixed. This report covers new gaps discovered in the current cycle.

Priority Gaps

Module Function Why It Matters Suggested Test
compile/standalone.rs validate_docker_args Security-critical: detects --privileged, --entrypoint bypass, -v/--volume flag injection through args: field Test each dangerous flag triggers warning; -v docker.sock calls validate_mount_source
compile/standalone.rs validate_mount_source Security-critical: detects Docker socket exposure (container escape) and sensitive host paths Test docker.sock, /etc/shadow, /proc, case-insensitive /ETC/, path boundary /etc-configs
compile/standalone.rs validate_container_image Prevents confused-deputy attacks via malformed image names Test empty string and image with shell metacharacters
compile/standalone.rs warn_potential_secrets Security hygiene: warns when env vars or headers may contain inline credentials Test API_TOKEN="abc123" triggers warning; API_TOKEN="" passthrough does NOT; Authorization header triggers
compile/standalone.rs generate_allowed_domains Correctness of AWF network allowlist β€” blocked must take precedence over allow Test that network.blocked removes a host even when it appears in network.allow; host.docker.internal always present
compile/standalone.rs generate_prepare_steps with has_memory: true Memory download/prompt steps are prepended only when cache-memory enabled β€” untested in isolation Test both has_memory=true (steps contain memory preamble) and has_memory=false (no memory steps)

Suggested Test Cases

1. validate_docker_args β€” dangerous flag detection

#[test]
fn test_validate_docker_args_privileged_flag() {
    // Should emit a warning to stderr (capture with a wrapper or just verify it doesn't panic)
    validate_docker_args(&["--privileged".to_string()], "my-mcp");
}

#[test]
fn test_validate_docker_args_entrypoint_in_args_warns() {
    // --entrypoint in args bypasses the dedicated `entrypoint:` field
    validate_docker_args(&["--entrypoint".to_string(), "/bin/sh".to_string()], "my-mcp");
}

#[test]
fn test_validate_docker_args_volume_flag_calls_mount_validation() {
    // -v docker.sock in args bypasses `mounts:` validation
    validate_docker_args(
        &["-v".to_string(), "/var/run/docker.sock:/var/run/docker.sock".to_string()],
        "my-mcp",
    );
}

#[test]
fn test_validate_docker_args_safe_args_no_warning() {
    // A legitimate arg like --read-only should not warn
    validate_docker_args(&["--read-only".to_string()], "my-mcp");
}

2. validate_mount_source β€” sensitive path and Docker socket detection

#[test]
fn test_validate_mount_source_docker_sock() {
    // Docker socket exposure must warn (container escape risk)
    validate_mount_source("/var/run/docker.sock:/var/run/docker.sock:rw", "my-mcp");
}

#[test]
fn test_validate_mount_source_sensitive_path_etc() {
    validate_mount_source("/etc/passwd:/data/passwd:ro", "my-mcp");
}

#[test]
fn test_validate_mount_source_case_insensitive() {
    // /ETC/shadow should match sensitive /etc prefix
    validate_mount_source("/ETC/shadow:/data/shadow:ro", "my-mcp");
}

#[test]
fn test_validate_mount_source_no_false_positive_on_etc_configs() {
    // /etc-configs should NOT match the /etc prefix
    // (this test verifies the path-boundary logic)
    validate_mount_source("/etc-configs:/app/config:ro", "my-mcp");
}

#[test]
fn test_validate_mount_source_safe_path_no_warning() {
    // /app/data is not sensitive
    validate_mount_source("/app/(redacted) "my-mcp");
}

3. warn_potential_secrets β€” inline credential detection

#[test]
fn test_warn_potential_secrets_token_env_var_triggers() {
    let env = HashMap::from([("API_TOKEN".to_string(), "secret123".to_string())]);
    let headers = HashMap::new();
    warn_potential_secrets("my-mcp", &env, &headers);
    // Should emit a warning (non-empty value with sensitive key name)
}

#[test]
fn test_warn_potential_secrets_empty_passthrough_no_warning() {
    // Empty string = passthrough; must NOT trigger warning
    let env = HashMap::from([("API_TOKEN".to_string(), "".to_string())]);
    let headers = HashMap::new();
    warn_potential_secrets("my-mcp", &env, &headers);
}

#[test]
fn test_warn_potential_secrets_authorization_header_triggers() {
    let env = HashMap::new();
    let headers = HashMap::from([("Authorization".to_string(), "Bearer abc".to_string())]);
    warn_potential_secrets("my-mcp", &env, &headers);
}

4. generate_allowed_domains β€” network policy

#[test]
fn test_generate_allowed_domains_blocked_takes_precedence_over_allow() {
    let mut front_matter = minimal_front_matter();
    front_matter.network = Some(NetworkConfig {
        allow: vec!["evil.example.com".to_string()],
        blocked: vec!["evil.example.com".to_string()],
    });
    let domains = generate_allowed_domains(&front_matter);
    assert!(
        !domains.contains("evil.example.com"),
        "blocked host must be excluded even if also in allow"
    );
}

#[test]
fn test_generate_allowed_domains_host_docker_internal_always_present() {
    let front_matter = minimal_front_matter();
    let domains = generate_allowed_domains(&front_matter);
    assert!(domains.contains("host.docker.internal"));
}

#[test]
fn test_generate_allowed_domains_user_allow_host_included() {
    let mut front_matter = minimal_front_matter();
    front_matter.network = Some(NetworkConfig {
        allow: vec!["api.mycompany.com".to_string()],
        blocked: vec![],
    });
    let domains = generate_allowed_domains(&front_matter);
    assert!(domains.contains("api.mycompany.com"));
}

5. generate_prepare_steps β€” memory path

#[test]
fn test_generate_prepare_steps_with_memory_includes_memory_preamble() {
    let result = generate_prepare_steps(&[], true);
    // Should include the memory download step content
    assert!(!result.is_empty(), "memory steps must be emitted when has_memory=true");
    assert!(result.contains("agent_memory"), "should reference memory directory");
}

#[test]
fn test_generate_prepare_steps_without_memory_and_no_steps_is_empty() {
    let result = generate_prepare_steps(&[], false);
    assert!(result.is_empty());
}

Coverage Summary

Module Total Fns Tested Coverage Estimate
compile/standalone.rs ~20 ~14 ~70%
compile/onees.rs ~7 ~7 ~100% βœ…
compile/common.rs ~25 ~25 ~100% βœ…
fuzzy_schedule.rs ~12 ~12 ~100% βœ…
sanitize.rs ~8 ~8 ~100% βœ…
safeoutputs/* ~50 ~50 ~100% βœ…

This issue was created by the automated test gap finder. Previous run: 2026-04-13. Modules audited this cycle: compile/standalone.rs, compile/onees.rs (all modules now complete). All 6 gaps identified in the previous run have been fixed.

Generated by Test Gap Finder Β· ● 1.2M Β· β—·

Metadata

Metadata

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions