Skip to content

admission: uv global options can hide indirect requirement-source evidence #428

Description

@seonghobae

Security/evidence defect

Fresh review of canonical Agent Artifact Admission child #427@fd19ac126a0e90a60164f8f9a24a47ea29490336 found a distinct parser/evidence asymmetry that must be serialized after #426/#427, not folded into that queued exact head.

validate_artifact_operands() and is_install_root_selector_value() now locate the active uv ... pip install command via uv_active_command_index(), so reviewed parser-valid global uv options no longer hide direct artifact operands. requests_indirect_artifact_source() still uses the old fixed-position guard:

"uv" if arguments.first().is_some_and(|argument| argument == "pip")
    && arguments.get(1).is_some_and(|argument| argument == "install") => { ... }

That means a parser-valid global option before pip install can suppress the -r/--requirement, -e/--editable, --group, or --project indirect-source classification while the operand validator has already moved to active-command parsing.

Astral's current uv CLI reference documents both the global --color <auto|always|never> option and uv pip install [OPTIONS] <PACKAGE|--requirements <REQUIREMENTS>|...>, with -r/--requirement/--requirements meaning “install the packages listed in the given files”: https://docs.astral.sh/uv/reference/cli/

Hostile realistic RED

Use a value that intentionally collides with an already approved direct artifact token:

uv --color never pip install -r cwl-example==1.2.3 --require-hashes --no-deps --no-python-downloads

with declared/approved artifact_argument = "cwl-example==1.2.3".

CLI meaning: cwl-example==1.2.3 is the requirements-file operand of -r, not a direct package operand. On the reviewed exact head, active-command operand validation can count that token as the approved artifact while requests_indirect_artifact_source() misses the indirect source because arguments[0..2] are --color never rather than pip install.

Expected RED assertion on the successor test-only head:

  • decision remains Block because the global-option form is intentionally outside supported_install_command();
  • evidence must include ForbiddenCommand and ArtifactNotApproved for the unapproved indirect source;
  • command hash remains exact/deterministic;
  • ordinary uv pip install cwl-example==1.2.3 --require-hashes --no-deps --no-python-downloads remains the control and must not regress;
  • non-install siblings such as uv --color never pip sync -r ... must not inherit install-only indirect-source semantics.

Also cover attached parser-valid forms where applicable (for example --color=never) and verify a consumed selector value cannot masquerade as an approved direct artifact.

Minimum causal repair

After #427 is exact-head GREEN and normally integrated into canonical #129, create a successor child from the then-current #129 head:

  1. RED-only commit first.
  2. Make requests_indirect_artifact_source() locate the active uv command with the existing uv_active_command_index() and inspect indirect selectors only when the active slice is exactly pip install.
  3. Do not widen supported_install_command(); global-option uv commands remain fail-closed/forbidden until separately authorized.
  4. Do not copy uv parsing logic; reuse the single parser helper already introduced in the canonical admission domain.
  5. Run exact-head fmt/tests/clippy plus the focused hostile contract, then normal integration into feat(security): gate AI-agent artifact installation #129 only after GREEN.

Ownership / dependency

Wardnet owns this admission evidence semantics. No quarantine runtime, EgressWeave, contextual-orchestrator, appguardrail, CGC, EA, or central workflow logic is duplicated. This issue is deliberately serialized behind #426/#427 so the existing single-writer lane and queued evidence are preserved.

Activity

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions