Skip to content

feat(cli): add catalog versions kind and use it in the copilot-cli workflow#1471

Merged
jamesadevine merged 1 commit into
mainfrom
feat/catalog-versions-kind
Jul 11, 2026
Merged

feat(cli): add catalog versions kind and use it in the copilot-cli workflow#1471
jamesadevine merged 1 commit into
mainfrom
feat/catalog-versions-kind

Conversation

@jamesadevine

Copy link
Copy Markdown
Collaborator

Problem

The Copilot CLI SafeOutputs Contract workflow failed at the Resolve compiler-pinned Copilot CLI version step (run 29150669094):

here-document at line 3 delimited by end-of-file (wanted `PY')
unexpected EOF while looking for matching `)'
Process completed with exit code 2.

Root cause: the step scraped COPILOT_CLI_VERSION from src/engine.rs using an indented python3 - <<'PY' heredoc nested inside a $( … ) command substitution. YAML run: | preserves the indentation, but an unquoted heredoc (<<'PY', not <<-) requires the closing PY at column 0, so bash never finds the terminator. Regex-scraping Rust source from CI is also brittle.

Fix — the compiler is the single source of truth

  • src/inspect/catalog.rs: new versions kind for ado-aw catalog exposing only genuine semver version constants:

    field source value
    copilot_cli engine::COPILOT_CLI_VERSION 1.0.69
    awf common::AWF_VERSION 0.27.28
    mcpg common::MCPG_VERSION 0.4.1

    Container image references and the default model name are intentionally excluded.

  • .github/workflows/copilot-cli-safeoutputs.yml: the step now runs
    cargo run --quiet -- catalog --kind versions --json | jq -r '.versions.copilot_cli'
    with a null/empty guard. No heredoc, no source scraping. The build is cached and reused by the later cargo test step.

  • Docs + help text updated (docs/cli.md, site/.../setup/cli.mdx, README.md, clap help, mcp-author descriptions). The mcp-author catalog tool routes through catalog_kind, so versions works there automatically.

Why not override --version

clap's --version prints the crate version and is consumed by update_check.rs; catalog is the existing JSON introspection surface (--kind, --json), so a new kind is the idiomatic, low-risk fit.

Validation

  • cargo clippy --all-targets --all-features — clean
  • catalog + mcp_author unit tests pass (incl. 3 new tests)
  • ado-aw catalog --kind versions --json emits { "versions": { "copilot_cli": "1.0.69", "awf": "0.27.28", "mcpg": "0.4.1" } }

…rkflow

Replace the fragile indented python heredoc in the Copilot CLI SafeOutputs Contract workflow (which failed with an unquoted-heredoc EOF error) with a deterministic query against the compiler.

Add a 'versions' kind to 'ado-aw catalog' that surfaces the pinned semver constants (copilot_cli, awf, mcpg) as the single source of truth, and have the workflow read it via 'cargo run -- catalog --kind versions --json | jq -r .versions.copilot_cli'.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8acc4e17-2dc8-4db5-a250-f8469d7c1b7c
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Rust PR Review

Summary: Looks good — clean, minimal fix for a real CI breakage with no correctness or security concerns.

Findings

✅ What Looks Good

  • Root-cause fix is correct: The heredoc-in-$() bash pattern fails because <<'PY' requires the terminator at column 0, but YAML run: | preserves leading whitespace. Replacing it with cargo run -- catalog --kind versions --json | jq -r '.versions.copilot_cli' is the right approach.
  • Null guard is appropriate: test -n "$version" && test "$version" != "null" catches both an empty result and jq's literal "null" string when the key is missing — fail-fast before echo "version=${version}" propagates a bad value.
  • Option<VersionCatalog> is the right shape: VersionCatalog has no natural "empty" state (all fields are non-empty &'static str constants), so Option with skip_serializing_if = "Option::is_none" is cleaner than a sentinel. Consistent with how other kind-filtered queries return partial catalogs via ..Catalog::default().
  • render_text trailing newline: The extra out.push('\n') after the models loop is correctly scoped inside if !catalog.models.is_empty(), so --kind versions alone doesn't produce a stray blank line, and out.trim_end() handles any residual whitespace.
  • Tests cover the key invariants: the three new tests verify kind-routing, full-catalog inclusion, and JSON serialization — adequate coverage for a straight-through data plumbing change.
  • No unsafe, no unwraps on user-facing paths, no YAML injection surface introduced by this change.

Generated by Rust PR Reviewer for #1471 · 22.7 AIC · ⌖ 5.66 AIC · ⊞ 6.2K ·

@jamesadevine jamesadevine merged commit 8009dd0 into main Jul 11, 2026
21 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant