Skip to content

πŸ§ͺ Test gap analysis β€” 3 gaps found in validate.rs and ado_script path consistencyΒ #676

@github-actions

Description

@github-actions

Test Gap Analysis

Test suite snapshot: 1,814 total tests β€” all pass βœ…
Previous open issues still active: #376 (lean runtime, logging, MCP tools list), #647 (stage/job header repos branch, update_check parse_version), #664 (azure-devops tool validation, missing-data executor).

This issue tracks three new gaps discovered in the 2026-05-21 cycle, with the first being particularly relevant after the #671 "flatten bundled artifact paths" refactoring.


Priority Gaps

Module Function/Path Why It Matters Suggested Test
compile/extensions/ado_script.rs GATE_EVAL_PATH/IMPORT_EVAL_PATH vs unzip -d destination After #671 flatten refactoring, path constants and download step must stay in sync; no regression test guards this Assert GATE_EVAL_PATH starts with the unzip -d target and the suffix matches the zip's internal path prefix
validate.rs reject_ado_expressions_in_value() β€” Sequence branch Security-critical: a default: [...] list with an ADO expression injection is never tested; only the String default path is exercised Pass a serde_yaml::Value::Sequence containing "$(secretVar)" directly to the function
validate.rs is_valid_artifact_name() Only tested indirectly through upload_pipeline_artifact.rs; the character allowlist ([A-Za-z0-9._-]) has no standalone unit test that catches a regression (e.g. spaces, $, / should be rejected) Add direct unit test with valid and invalid names

Suggested Test Cases

1. ado_script.rs β€” path constant consistency with download step

#[test]
fn gate_and_import_eval_paths_consistent_with_download_step() {
    // The download step does: unzip -o ado-script.zip -d /tmp/ado-aw-scripts/
    // The zip is built with: cd scripts && zip ... ado-script/gate.js ado-script/import.js
    // So extracted paths are /tmp/ado-aw-scripts/ado-script/{gate,import}.js.
    // This test guards against the constants drifting from the download destination.
    let extract_dir = "/tmp/ado-aw-scripts/";
    assert!(
        GATE_EVAL_PATH.starts_with(extract_dir),
        "GATE_EVAL_PATH must be under the unzip -d destination"
    );
    assert!(
        IMPORT_EVAL_PATH.starts_with(extract_dir),
        "IMPORT_EVAL_PATH must be under the unzip -d destination"
    );
    let zip_prefix = "ado-script/";
    assert!(
        GATE_EVAL_PATH.strip_prefix(extract_dir).unwrap().starts_with(zip_prefix),
        "GATE_EVAL_PATH suffix must match zip internal path prefix used in release.yml"
    );
    assert!(
        IMPORT_EVAL_PATH.strip_prefix(extract_dir).unwrap().starts_with(zip_prefix),
        "IMPORT_EVAL_PATH suffix must match zip internal path prefix used in release.yml"
    );
    // Also verify the download step bash script references the extract dir.
    let steps = install_and_download_steps();
    let download = &steps[1];
    assert!(
        download.contains("-d /tmp/ado-aw-scripts/"),
        "download step must unzip to /tmp/ado-aw-scripts/"
    );
}

2. validate.rs β€” reject_ado_expressions_in_value Sequence branch

#[test]
fn reject_ado_expressions_in_value_catches_injection_in_sequence() {
    // When `default:` is a YAML list, the Sequence branch of
    // reject_ado_expressions_in_value must recurse into each element.
    let seq = serde_yaml::Value::Sequence(vec![
        serde_yaml::Value::String("safe".to_string()),
        serde_yaml::Value::String("$(secretVar)".to_string()),
    ]);
    let result = reject_ado_expressions_in_value(&seq, "myParam", "default");
    assert!(result.is_err(), "Sequence with ADO expression must be rejected");
}

#[test]
fn reject_ado_expressions_in_value_allows_safe_sequence() {
    let seq = serde_yaml::Value::Sequence(vec![
        serde_yaml::Value::String("us-east".to_string()),
        serde_yaml::Value::String("eu-west".to_string()),
    ]);
    assert!(reject_ado_expressions_in_value(&seq, "region", "default").is_ok());
}

3. validate.rs β€” is_valid_artifact_name direct unit test

#[test]
fn test_is_valid_artifact_name() {
    // Valid: alphanumeric, dots, underscores, hyphens
    assert!(is_valid_artifact_name("my-artifact_v1.0"));
    assert!(is_valid_artifact_name("drop"));
    // Invalid: empty
    assert!(!is_valid_artifact_name(""));
    // Invalid: spaces
    assert!(!is_valid_artifact_name("my artifact"));
    // Invalid: ADO variable injection
    assert!(!is_valid_artifact_name("$(secretVar)"));
    // Invalid: path traversal
    assert!(!is_valid_artifact_name("../../etc/passwd"));
    // Invalid: template marker
    assert!(!is_valid_artifact_name("{{inject}}"));
}

Coverage Summary

Module Public Fns Tests Notes
compile/extensions/ado_script.rs 1 pub fn + constants 23 No path-consistency assertion between constants and download step
validate.rs 18 26 reject_ado_expressions_in_value Sequence branch untested; is_valid_artifact_name lacks direct test

This issue was created by the automated test gap finder. Previous run: 2026-05-20. Modules audited this cycle: all (full coverage audit). Open prior issues: #376, #647, #664.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • dev.azure.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "dev.azure.com"

See Network Configuration for more information.

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

Metadata

Metadata

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