Skip to content

Eng 12002 cli push time metadata flags#290

Closed
BartoszBlizniak wants to merge 14 commits into
masterfrom
eng-12002-cli-push-time-metadata-flags
Closed

Eng 12002 cli push time metadata flags#290
BartoszBlizniak wants to merge 14 commits into
masterfrom
eng-12002-cli-push-time-metadata-flags

Conversation

@BartoszBlizniak
Copy link
Copy Markdown
Member

@BartoszBlizniak BartoszBlizniak commented May 11, 2026

Description

Adds push-time metadata flags to cloudsmith push <format> so SBOM / BuildInfo / generic JSON can be attached in a single command instead of a separate cloudsmith metadata add follow-up.

New flags on every push subcommand:

  • --metadata-content-file PATH (or - for stdin)
  • --metadata-content JSON
  • --metadata-content-type MIME
  • --metadata-source-identity TEXT

Flow:

  1. Resolve + JSON-object validation locally (once per push, even for multi-file uploads / stdin).
  2. Pre-validate payload via POST /v2/metadata/validate/ before any S3 upload — malformed metadata can no longer leave orphan packages.
  3. After create_package, attach metadata via POST /v2/metadata/.
  4. Failures are fatal by default (CI surfaces broken SBOMs). Opt out per push with CLOUDSMITH_METADATA_FAILURE_MODE=warn (or 0) to downgrade to a warning + copy-paste retry hint.
  5. Result is surfaced under metadata_attachment in JSON output (success and error envelopes).

Also extracts shared metadata helpers into cli/metadata_common.py so the standalone cloudsmith metadata add/update paths and the new push path share content resolution / JSON-object enforcement / default source
identity.

Ships examples/metadata_demo/ with copy-paste-ready CRUD + push commands, sample payload, valid CycloneDX / BuildInfo, and a broken BuildInfo for exercising the failure paths.

Type of Change

  • New feature
  • Refactoring (shared metadata_common.py)
  • Bug fix
  • Breaking change
  • Documentation update
  • Other

Additional Notes

  • Default mode aborts the push on validation/attach failure with the HTTP status as the exit code. Wrappers that need legacy "best-effort" behaviour must set $CLOUDSMITH_METADATA_FAILURE_MODE=warn.

Examples:

Push:

cloudsmith push raw ${ORG}/${REPO} examples/metadata_demo/payload.txt \
    --name metadata-demo \
    --version 1.0.0 \
    --republish \
    --metadata-content '{"build_id": "demo-inline", "git_sha": "abc123"}' \
    --metadata-content-type application/json

Checking raw package upload parameters ... OK
Validating metadata content from inline ... OK
Checking payload.txt file upload parameters ... OK
Requesting file upload for payload.txt ... OK
Uploading payload.txt:  [####################################]  100%
Creating a new raw package ... OK
Created: bart-demo-org/821/payloadtxt-wu4u (bONvPYh5LfhH)
Attaching metadata to package bONvPYh5LfhH ... OK
Metadata attached: bart-demo-org/821/payloadtxt-wu4u/ATkdRL03Uwk6

Synchronising payloadtxt-wu4u:  [####################################]  100%  Completed / Fully Synchronised                      

Package synchronised successfully in 16.006934 second(s)!

Push with invalid metadata:

cloudsmith push raw ${ORG}/${REPO} examples/metadata_demo/payload.txt \
    --name metadata-demo \
    --version 1.0.0 \
    --republish \
    --metadata-content-file examples/metadata_demo/buildinfo-broken.json \
    --metadata-content-type application/vnd.jfrog.buildinfo+json

Checking raw package upload parameters ... OK
Validating metadata content from buildinfo-broken.json ... FAILED
ERROR
Metadata content failed validation (HTTP 422): Invalid input. (status: 422 - Unprocessable Entity)

Detail: Invalid input.
Content Field: Content does not conform to the schema for content type 'application/vnd.jfrog.buildinfo+json'.

Push with invalid metadata and $CLOUDSMITH_METADATA_FAILURE_MODE set to warn:

CLOUDSMITH_METADATA_FAILURE_MODE=warn \
cloudsmith push raw ${ORG}/${REPO} examples/metadata_demo/payload.txt \
    --name metadata-demo \
    --version 1.0.0 \
    --republish \
    --metadata-content-file examples/metadata_demo/buildinfo-broken.json \
    --metadata-content-type application/vnd.jfrog.buildinfo+json

Checking raw package upload parameters ... OK
Validating metadata content from buildinfo-broken.json ... FAILED
Metadata content failed validation (HTTP 422): Invalid input.
Package upload will continue without metadata. Unset $CLOUDSMITH_METADATA_FAILURE_MODE (or set it to ``error``) to fail the push instead.
Checking payload.txt file upload parameters ... OK
Requesting file upload for payload.txt ... OK
Uploading payload.txt:  [####################################]  100%
Creating a new raw package ... OK
Created: bart-demo-org/821/payloadtxt-6mm2 (H4Q1EDW8Gm2E)

Fix the metadata content, then run:
cloudsmith metadata add bart-demo-org/821/payloadtxt-6mm2 \
    --file /Users/bblizniak/github/cloudsmith-cli/examples/metadata_demo/buildinfo-broken.json \
    --content-type application/vnd.jfrog.buildinfo+json

Synchronising payloadtxt-6mm2:  [####################################]  100%  Completed / Fully Synchronised

Package synchronised successfully in 6.121764 second(s)!

@BartoszBlizniak BartoszBlizniak marked this pull request as ready for review May 11, 2026 14:44
@BartoszBlizniak BartoszBlizniak requested a review from a team as a code owner May 11, 2026 14:44
Copilot AI review requested due to automatic review settings May 11, 2026 14:44
@BartoszBlizniak
Copy link
Copy Markdown
Member Author

Gonan take this apart

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds “push-time” metadata attachment to cloudsmith push <format> so SBOM/BuildInfo/generic JSON can be validated and attached in the same command (with shared helpers extracted for reuse).

Changes:

  • Add --metadata-* flags to all push subcommands, with local JSON-object validation, server-side pre-validation, and post-create attachment (with configurable warn vs error behavior).
  • Refactor shared metadata option/content handling into cli/metadata_common.py, and update cloudsmith metadata add/update to use the shared logic (including JSON-object enforcement).
  • Expand test coverage for push-time metadata flows and help-text examples; modernize typing annotations across several modules and update pre-commit pyupgrade.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
cloudsmith_cli/core/pagination.py Modernize typing annotations (builtin generics / PEP 604).
cloudsmith_cli/core/mcp/server.py Modernize typing annotations for MCP server helpers.
cloudsmith_cli/core/mcp/data.py Update dataclass typing to builtin generics / PEP 604.
cloudsmith_cli/core/download.py Modernize typing annotations for download helpers.
cloudsmith_cli/core/api/metadata.py Modernize typing annotations for metadata API wrapper functions.
cloudsmith_cli/core/api/init.py Modernize typing annotations (type[T]).
cloudsmith_cli/cli/commands/push.py Implement push-time metadata flag resolution, pre-validation, attachment, retry hints, and JSON surfacing.
cloudsmith_cli/cli/metadata_common.py New shared helpers for resolving/validating metadata content and defaults.
cloudsmith_cli/cli/commands/metadata.py Refactor metadata add/update to use shared resolution logic + enforce JSON-object payloads.
cloudsmith_cli/cli/exceptions.py Include push-time metadata context in JSON error envelopes.
cloudsmith_cli/cli/tests/test_push.py Add comprehensive tests for push-time metadata behavior, warn/error modes, and JSON envelopes/hints.
cloudsmith_cli/cli/tests/test_metadata_common.py New tests for shared metadata resolution/helpers.
cloudsmith_cli/cli/tests/commands/test_metadata.py Update help-text expectations + add tests for rejecting non-object content.
cloudsmith_cli/cli/saml.py Minor string formatting cleanup.
cloudsmith_cli/cli/commands/mcp.py Modernize typing annotations for MCP CLI printing helpers.
.pre-commit-config.yaml Update pyupgrade hook version and enforce --py310-plus.
.github/.platforms/generate_platforms.py Modernize typing import (Callable from collections.abc).
Comments suppressed due to low confidence (1)

cloudsmith_cli/cli/metadata_common.py:170

  • validate_metadata_payload_api() appears unused (no references in the codebase). If it’s not intended for near-term use, consider removing it (and the corresponding api_validate_metadata/exception-handling imports) to avoid dead code; otherwise, update callers to use it so validation behavior stays centralized.
def validate_metadata_payload_api(
    *,
    ctx,
    opts,
    content: dict[str, Any],
    content_type: str,
    context_msg: str,
    reraise_on_error: bool = False,
) -> None:
    """Validate metadata content through the metadata validation endpoint."""
    with handle_api_exceptions(
        ctx,
        opts=opts,
        context_msg=context_msg,
        reraise_on_error=reraise_on_error,
    ):
        with maybe_spinner(opts):
            api_validate_metadata(content=content, content_type=content_type)


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +117 to +123
if not metadata_provided:
if metadata_content_type or metadata_source_identity:
raise click.UsageError(
"Add --metadata-content-file or --metadata-content when using "
"--metadata-content-type or --metadata-source-identity."
)
return ResolvedMetadata(provided=False, content=None), None
# N times) is almost never what the user wants. Force them to
# push files individually with metadata, or drop the flags.
metadata_flags_set = any(
metadata_kwargs.get(k) for k in METADATA_KWARG_NAMES
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants