Skip to content

Conversation

@brooke-hamilton
Copy link
Member

Description

When users provide invalid OCI repository names in rad bicep publish --target, the error from oras-go (invalid reference: invalid repository "...") doesn't explain OCI naming rules or how to fix the issue.

Changes

  • Added enhanceOCIError() function that wraps oras-go validation errors with detailed messages explaining:
    • Which component is invalid (registry, repository, or tag)
    • Specific OCI naming requirements for that component
    • Valid examples
    • Link to OCI specification
  • Updated extractDestination() to use enhanced error handling
  • Added test suite covering uppercase repository names, invalid tags, and missing components

Example

Before:

Error: invalid reference: invalid repository "myregistry/Data/mySqlDatabases"

After:

Invalid OCI repository name in target "localhost:5000/myregistry/Data/mySqlDatabases:latest".

OCI repository names must:
  - Contain only lowercase letters (a-z), digits (0-9), periods (.), underscores (_), and hyphens (-)
  - Start with a lowercase letter or digit
  - Separate path components with forward slashes (/)
  - Not contain consecutive special characters except double underscores (__)

Example: 'br:localhost:5000/myregistry/data/mysqldatabases:latest'

For more information on OCI naming conventions, see:
https://github.com/opencontainers/distribution-spec/blob/main/spec.md

Cause: invalid reference: invalid repository "myregistry/Data/mySqlDatabases"

Type of change

  • This pull request fixes a bug in Radius and has an approved issue (issue link required).

Fixes: #10517

Contributor checklist

Please verify that the PR meets the following requirements, where applicable:

  • An overview of proposed schema changes is included in a linked GitHub issue.
    • Yes
    • Not applicable
  • A design document PR is created in the design-notes repository, if new APIs are being introduced.
    • Yes
    • Not applicable
  • The design document has been reviewed and approved by Radius maintainers/approvers.
    • Yes
    • Not applicable
  • A PR for the samples repository is created, if existing samples are affected by the changes in this PR.
    • Yes
    • Not applicable
  • A PR for the documentation repository is created, if the changes in this PR affect the documentation or any user facing updates are made.
    • Yes
    • Not applicable
  • A PR for the recipes repository is created, if existing recipes are affected by the changes in this PR.
    • Yes
    • Not applicable
Original prompt

This section details on the original issue you should resolve

<issue_title>Improve error message for invalid OCI repository name in rad bicep publish --target argument</issue_title>
<issue_description>### Overview of feature request

When running the rad bicep publish command, the --target argument must comply with OCI registry naming rules for specifying the registry, repository, and tag. If the argument fails validation, the error message from the oras.land/oras-go/v2/registry.ParseReference(string) command is returned. The problem is that the message is not descriptive enough to inform the user that the name is invalid. For example, the command below attempts to run rad bicep publish with uppercase characters in the --target argument, which is invalid according to OCI naming rules.

$ rad bicep publish --file kubernetes-mysql.bicep --target "br:localhost:5000/myregistry/Data/mySqlDatabases/kubernetes/kubernetesmysql:latest" --plain-http
Building bicep/kubernetes-mysql.bicep...
Error: invalid reference: invalid repository "myregistry/Data/mySqlDatabases/kubernetes/kubernetesmysql"

The desired behavior is that the error message would explain that OCI naming rules are being enforced, and give the user some idea about how to discover what those rules are, or give the user a summary of the rules.

Acceptance criteria

acceptance-criteria:

  • The error message for invalid --target arguments during rad bicep publish must explicitly state that OCI naming rules are being enforced.
  • The error message must indicate which part of the --target argument is invalid (registry, repository, or tag).
  • The error message must include a brief summary of OCI naming rules or provide a link to documentation for those rules.
  • The error message must guide users to correct their argument, such as suggesting lowercase characters for repository names.
  • The error message must help users understand why their input failed validation and how to resolve the issue.
  • Validation logic should be consistent with the rules implemented in reference.go.

Additional context

The library that Radius uses to parse the name is here: https://github.com/oras-project/oras-go/blob/main/registry/reference.go#L119-L120
Link to the Radius code: https://github.com/radius-project/radius/blob/main/pkg/cli/cmd/bicep/publish/publish.go#L298

Would you like to support us?

  • Yes, I would like to support you

AB#17295</issue_description>

Comments on the Issue (you are @copilot in this section)

Copy link
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

This PR enhances error messages when users provide invalid OCI repository names in the rad bicep publish --target argument. The changes wrap low-level oras-go validation errors with detailed, user-friendly messages that explain OCI naming rules and provide concrete examples.

Key changes:

  • Added enhanceOCIError() function to detect and enhance different types of OCI validation errors (repository, registry, tag, and format errors)
  • Updated extractDestination() to call the new error enhancement function
  • Added comprehensive test suite covering uppercase repository names, invalid tags, missing components, and valid inputs

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
pkg/cli/cmd/bicep/publish/publish.go Implements enhanceOCIError() function that wraps oras-go errors with detailed OCI naming guidance and examples
pkg/cli/cmd/bicep/publish/publish_test.go Adds TestRunner_extractDestination_EnhancedErrors test suite with 6 test cases validating error message content for various invalid and valid OCI targets

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

@codecov
Copy link

codecov bot commented Nov 14, 2025

Codecov Report

❌ Patch coverage is 88.88889% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 50.45%. Comparing base (a45fc2f) to head (8cab0ab).

Files with missing lines Patch % Lines
pkg/cli/cmd/bicep/publish/publish.go 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #10816      +/-   ##
==========================================
+ Coverage   50.43%   50.45%   +0.01%     
==========================================
  Files         672      672              
  Lines       42057    42065       +8     
==========================================
+ Hits        21213    21222       +9     
  Misses      18788    18788              
+ Partials     2056     2055       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@brooke-hamilton brooke-hamilton marked this pull request as draft November 14, 2025 15:37
@brooke-hamilton
Copy link
Member Author

@zachcasper please review the error messages.

@zachcasper
Copy link
Contributor

zachcasper commented Nov 17, 2025

Two thoughts:

  1. The OCI spec has a registry and a repository. localhost:5000 is the registry and myregistry/Data is the repository name in your example. The combination is typically referred to as an "OCI reference".
  2. You do not explain what br is.

My suggestion would be to change the message to:

Invalid OCI reference name in target '<user-provided-value>'.

The target must be a valid Bicep OCI registry in the form 'br:<OCI-registry-hostname>/<module-path>:<tag>'.

Cause: invalid reference: invalid repository "myregistry/Data/mySqlDatabases"

I think be saying the value must be a hostname is clear enough and the naming rules are not needed.

@brooke-hamilton
Copy link
Member Author

brooke-hamilton commented Nov 26, 2025

Two thoughts:

  1. The OCI spec has a registry and a repository. localhost:5000 is the registry and myregistry/Data is the repository name in your example. The combination is typically referred to as an "OCI reference".
  2. You do not explain what br is.

My suggestion would be to change the message to:

Invalid OCI reference name in target '<user-provided-value>'.

The target must be a valid Bicep OCI registry in the form 'br:<OCI-registry-hostname>/<module-path>:<tag>'.

Cause: invalid reference: invalid repository "myregistry/Data/mySqlDatabases"

I think be saying the value must be a hostname is clear enough and the naming rules are not needed.

@zachcasper these issues are addressed now. You can run the script below to see the error messages. Below the script is a sample of the output, which shows the error messages in each case. Please review the messages and provide feedback--I'm happy to make more revisions.

NOTE: The br: prefix is required by the rad bicep publish command.

Test Script

#!/bin/bash

# ============================================================================
# Test Script for Enhanced OCI Error Messages in rad bicep publish
# ============================================================================
# This script tests the improved error messages for invalid OCI references
# in the 'rad bicep publish' command.
#
# Prerequisites:
# - rad CLI built from the copilot/improve-oci-error-message branch
# - A simple Bicep file to publish
# ============================================================================

set -euo pipefail

echo "============================================================================"
echo "Testing Enhanced OCI Error Messages for 'rad bicep publish'"
echo "============================================================================"
echo ""

# Create a simple test Bicep file
TEST_BICEP_FILE="/tmp/test-oci-errors.bicep"
cat > "$TEST_BICEP_FILE" << 'EOF'
// Simple test Bicep file
metadata description = 'Test file for OCI error message testing'

@description('Test parameter')
param testParam string = 'default'

output result string = testParam
EOF

echo "Created test Bicep file: $TEST_BICEP_FILE"
echo ""

# Path to rad CLI - adjust if needed
RAD_CLI="./dist/linux_amd64/release/rad"

# Check if rad CLI exists
if [[ ! -f "$RAD_CLI" ]]; then
    echo "rad CLI not found at $RAD_CLI"
    echo "Building rad CLI..."
    make build
fi

echo "============================================================================"
echo "Test 1: Missing 'br:' prefix"
echo "============================================================================"
echo "Command: $RAD_CLI bicep publish --file $TEST_BICEP_FILE --target localhost:5000/test/module:v1"
echo ""
$RAD_CLI bicep publish --file "$TEST_BICEP_FILE" --target "localhost:5000/test/module:v1" 2>&1 || true
echo ""

echo "============================================================================"
echo "Test 2: Uppercase letters in repository name (invalid)"
echo "============================================================================"
echo "Command: $RAD_CLI bicep publish --file $TEST_BICEP_FILE --target br:localhost:5000/MyRegistry/Data/mySqlDatabases:latest"
echo ""
$RAD_CLI bicep publish --file "$TEST_BICEP_FILE" --target "br:localhost:5000/MyRegistry/Data/mySqlDatabases:latest" 2>&1 || true
echo ""

echo "============================================================================"
echo "Test 3: Uppercase at start of repository path"
echo "============================================================================"
echo "Command: $RAD_CLI bicep publish --file $TEST_BICEP_FILE --target br:localhost:5000/TestRepo/module:v1"
echo ""
$RAD_CLI bicep publish --file "$TEST_BICEP_FILE" --target "br:localhost:5000/TestRepo/module:v1" 2>&1 || true
echo ""

echo "============================================================================"
echo "Test 4: Invalid tag starting with hyphen"
echo "============================================================================"
echo "Command: $RAD_CLI bicep publish --file $TEST_BICEP_FILE --target br:localhost:5000/myregistry/data:-invalid"
echo ""
$RAD_CLI bicep publish --file "$TEST_BICEP_FILE" --target "br:localhost:5000/myregistry/data:-invalid" 2>&1 || true
echo ""

echo "============================================================================"
echo "Test 5: Missing repository (only registry)"
echo "============================================================================"
echo "Command: $RAD_CLI bicep publish --file $TEST_BICEP_FILE --target br:localhost:5000"
echo ""
$RAD_CLI bicep publish --file "$TEST_BICEP_FILE" --target "br:localhost:5000" 2>&1 || true
echo ""

echo "============================================================================"
echo "Test 6: Valid format (will fail at registry connection, but should pass validation)"
echo "============================================================================"
echo "Command: $RAD_CLI bicep publish --file $TEST_BICEP_FILE --target br:localhost:5000/myregistry/data/module:latest --plain-http"
echo ""
$RAD_CLI bicep publish --file "$TEST_BICEP_FILE" --target "br:localhost:5000/myregistry/data/module:latest" --plain-http 2>&1 || true
echo ""

echo "============================================================================"
echo "Test Complete"
echo "============================================================================"
echo ""
echo "Expected behavior:"
echo "- Tests 1-5 should show enhanced error messages with:"
echo "  - The invalid target displayed WITH the 'br:' prefix"
echo "  - Help text: \"The target must be a valid Bicep OCI registry reference in the form 'br:<OCI-registry-hostname>/<module-path>:<tag>'.\""
echo "  - The underlying cause from oras-go"
echo ""
echo "- Test 6 should fail with a connection error (no registry running),"
echo "  NOT a validation error, proving the valid format passes validation."
echo ""

# Cleanup
rm -f "$TEST_BICEP_FILE"
echo "Cleaned up test file."

Script Output

============================================================================
Testing Enhanced OCI Error Messages for 'rad bicep publish'
============================================================================

Created test Bicep file: /tmp/test-oci-errors.bicep

============================================================================
Test 1: Missing 'br:' prefix
============================================================================
Command: ./dist/linux_amd64/release/rad bicep publish --file /tmp/test-oci-errors.bicep --target localhost:5000/test/module:v1

Invalid target "localhost:5000/test/module:v1". The target must be in the format 'br:HOST/PATH:TAG'.


============================================================================
Test 2: Uppercase letters in repository name (invalid)
============================================================================
Command: ./dist/linux_amd64/release/rad bicep publish --file /tmp/test-oci-errors.bicep --target br:localhost:5000/MyRegistry/Data/mySqlDatabases:latest

Building /tmp/test-oci-errors.bicep...
Invalid OCI reference in target "br:localhost:5000/MyRegistry/Data/mySqlDatabases:latest".

The target must be a valid Bicep OCI registry reference in the form 'br:<OCI-registry-hostname>/<module-path>:<tag>'. Cause: invalid reference: invalid repository "MyRegistry/Data/mySqlDatabases".


============================================================================
Test 3: Uppercase at start of repository path
============================================================================
Command: ./dist/linux_amd64/release/rad bicep publish --file /tmp/test-oci-errors.bicep --target br:localhost:5000/TestRepo/module:v1

Building /tmp/test-oci-errors.bicep...
Invalid OCI reference in target "br:localhost:5000/TestRepo/module:v1".

The target must be a valid Bicep OCI registry reference in the form 'br:<OCI-registry-hostname>/<module-path>:<tag>'. Cause: invalid reference: invalid repository "TestRepo/module".


============================================================================
Test 4: Invalid tag starting with hyphen
============================================================================
Command: ./dist/linux_amd64/release/rad bicep publish --file /tmp/test-oci-errors.bicep --target br:localhost:5000/myregistry/data:-invalid

Building /tmp/test-oci-errors.bicep...
Invalid OCI reference in target "br:localhost:5000/myregistry/data:-invalid".

The target must be a valid Bicep OCI registry reference in the form 'br:<OCI-registry-hostname>/<module-path>:<tag>'. Cause: invalid reference: invalid tag "-invalid".


============================================================================
Test 5: Missing repository (only registry)
============================================================================
Command: ./dist/linux_amd64/release/rad bicep publish --file /tmp/test-oci-errors.bicep --target br:localhost:5000

Building /tmp/test-oci-errors.bicep...
Invalid OCI reference in target "br:localhost:5000".

The target must be a valid Bicep OCI registry reference in the form 'br:<OCI-registry-hostname>/<module-path>:<tag>'. Cause: invalid reference: missing registry or repository.


============================================================================
Test 6: Valid format (will fail at registry connection, but should pass validation)
============================================================================
Command: ./dist/linux_amd64/release/rad bicep publish --file /tmp/test-oci-errors.bicep --target br:localhost:5000/myregistry/data/module:latest --plain-http

Building /tmp/test-oci-errors.bicep...
Failed to publish Bicep file "/tmp/test-oci-errors.bicep" to "localhost:5000/myregistry/data/module:latest" Cause: failed to perform "Exists" on destination: Head "http://localhost:5000/v2/myregistry/data/module/manifests/sha256:71591f25f013425f1ee504cd37d18ba70a7fc6efc44093d0c679ba0eb2e9e9c4": dial tcp 127.0.0.1:5000: connect: connection refused.


============================================================================
Test Complete
============================================================================

Expected behavior:
- Tests 1-5 should show enhanced error messages with:
  - The invalid target displayed WITH the 'br:' prefix
  - Help text: "The target must be a valid Bicep OCI registry reference in the form 'br:<OCI-registry-hostname>/<module-path>:<tag>'."
  - The underlying cause from oras-go

- Test 6 should fail with a connection error (no registry running),
  NOT a validation error, proving the valid format passes validation.

Cleaned up test file.

@brooke-hamilton brooke-hamilton marked this pull request as ready for review November 26, 2025 21:43
Copy link
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

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

@zachcasper
Copy link
Contributor

@zachcasper these issues are addressed now. You can run the script below to see the error messages. Below the script is a sample of the output, which shows the error messages in each case. Please review the messages and provide feedback--I'm happy to make more revisions.

LGTM except test 1 seems to be an outlier compared to the others. It's accurate but test 2-5 are better.

Co-authored-by: Copilot <[email protected]>
Signed-off-by: Brooke Hamilton <[email protected]>
@radius-functional-tests
Copy link

radius-functional-tests bot commented Dec 10, 2025

Radius functional test overview

🔍 Go to test action run

Click here to see the test run details
Name Value
Repository brooke-hamilton/radius
Commit ref 8cab0ab
Unique ID func9b2d10caa1
Image tag pr-func9b2d10caa1
  • gotestsum 1.13.0
  • KinD: v0.29.0
  • Dapr: 1.14.4
  • Azure KeyVault CSI driver: 1.4.2
  • Azure Workload identity webhook: 1.3.0
  • Bicep recipe location ghcr.io/radius-project/dev/test/testrecipes/test-bicep-recipes/<name>:pr-func9b2d10caa1
  • Terraform recipe location http://tf-module-server.radius-test-tf-module-server.svc.cluster.local/<name>.zip (in cluster)
  • applications-rp test image location: ghcr.io/radius-project/dev/applications-rp:pr-func9b2d10caa1
  • dynamic-rp test image location: ghcr.io/radius-project/dev/dynamic-rp:pr-func9b2d10caa1
  • controller test image location: ghcr.io/radius-project/dev/controller:pr-func9b2d10caa1
  • ucp test image location: ghcr.io/radius-project/dev/ucpd:pr-func9b2d10caa1
  • deployment-engine test image location: ghcr.io/radius-project/deployment-engine:latest

Test Status

⌛ Building Radius and pushing container images for functional tests...
✅ Container images build succeeded
⌛ Publishing Bicep Recipes for functional tests...
✅ Recipe publishing succeeded
⌛ Starting ucp-cloud functional tests...
⌛ Starting corerp-cloud functional tests...
✅ ucp-cloud functional tests succeeded
✅ corerp-cloud functional tests succeeded

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.

Improve error message for invalid OCI repository name in rad bicep publish --target argument

3 participants