Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2e5430f
fix: tighten validation and interactive-prompt gaps
Phil-Browne Jul 10, 2026
8f6b2bb
test: cover name-too-long branch in port and MVE buy/LAG validators
Phil-Browne Jul 10, 2026
297c275
fix: correct int-width bound in GetIntFromInterface, address review nits
Phil-Browne Jul 10, 2026
728ad00
fix(mcr): validate address family in prefix filter list update path
Phil-Browne Jul 10, 2026
bf06ee1
fix(vxc,wasm): friendlier VLAN parse error, align WASM tag removal wi…
Phil-Browne Jul 10, 2026
85067ad
fix(vxc): require AWS connection name in shared validator
Phil-Browne Jul 10, 2026
014f9d8
fix(mcr): use consistent error shape for empty prefix filter entries
Phil-Browne Jul 10, 2026
663b779
fix(vxc): require IBM connection name in shared validator
Phil-Browne Jul 11, 2026
5809ba3
fix(vxc): add missing Transit case to partner config validator
Phil-Browne Jul 11, 2026
ab3d173
fix(vxc): reject empty AWS ASN immediately, align Azure VLAN field name
Phil-Browne Jul 11, 2026
f132135
fix(vxc): reject nil or mistyped Transit partner config
Phil-Browne Jul 11, 2026
38a73b3
fix(validation): guard against nil partner configs and nil prefix ent…
Phil-Browne Jul 11, 2026
e704b66
fix(vxc): nil-guard Google/Oracle partner configs, fix IBM ASN prompt
Phil-Browne Jul 11, 2026
940494a
fix(vxc): make IBM connection name optional to match the API contract
Phil-Browne Jul 11, 2026
622a557
fix(validation): close round-3 review gaps in prompts and validators
Phil-Browne Jul 11, 2026
1630b87
chore: extract conversion + tag-editing fixes to separate PRs
Phil-Browne Jul 11, 2026
a4f570a
fix(vxc): make AWS connection name optional to match the API contract
Phil-Browne Jul 13, 2026
9eb5605
Merge remote-tracking branch 'origin/main' into esd-1648-validation-p…
Phil-Browne Jul 15, 2026
c597636
Merge remote-tracking branch 'origin/main' into esd-1648-validation-p…
Phil-Browne Jul 15, 2026
f9a3ebd
ESD-1648: Reject unknown address family in prefix filter entry valida…
Phil-Browne Jul 22, 2026
6778eee
Merge branch 'main' into esd-1648-validation-prompt-gaps
Phil-Browne Jul 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions internal/commands/mcr/mcr_prompts.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,10 @@ func promptForPrefixFilterListDetails(mcrUID string, noColor bool) (*megaport.Cr
},
}

if err := validation.ValidatePrefixFilterListRequest(req); err != nil {
return nil, err
}

return req, nil
}

Expand Down
32 changes: 32 additions & 0 deletions internal/commands/mcr/mcr_prompts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,38 @@ func TestPromptForPrefixFilterListDetails_NoEntries(t *testing.T) {
assert.Contains(t, err.Error(), "at least one entry is required")
}

func TestPromptForPrefixFilterListDetails_InvalidPrefix(t *testing.T) {
originalPrompt := utils.GetResourcePrompt()
defer func() { utils.SetResourcePrompt(originalPrompt) }()

// Prefix that isn't a CIDR passes the entry prompt but must fail
// request-level validation before anything reaches the API.
utils.SetResourcePrompt(mockPromptSequence([]string{
"My PFL", "IPv4",
"banana", "permit", "", "",
"", // stop adding entries
}))

_, err := promptForPrefixFilterListDetails("mcr-123", true)
assert.Error(t, err)
assert.Contains(t, err.Error(), "must be a valid IPv4 CIDR notation")
}

func TestPromptForPrefixFilterListDetails_WrongFamilyPrefix(t *testing.T) {
originalPrompt := utils.GetResourcePrompt()
defer func() { utils.SetResourcePrompt(originalPrompt) }()

utils.SetResourcePrompt(mockPromptSequence([]string{
"My PFL", "IPv6",
"10.0.0.0/8", "permit", "", "",
"", // stop adding entries
}))

_, err := promptForPrefixFilterListDetails("mcr-123", true)
assert.Error(t, err)
assert.Contains(t, err.Error(), "must be a valid IPv6 CIDR notation")
}

func TestPromptForIPSecTunnelCount(t *testing.T) {
tests := []struct {
name string
Expand Down
3 changes: 3 additions & 0 deletions internal/commands/mve/mve_prompts.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,9 @@ func promptMVEVnics(noColor bool) ([]megaport.MVENetworkInterface, error) {
if err != nil {
return nil, err
}
if err := validation.ValidateVLAN(vlan); err != nil {
return nil, err
}
}

vnics = append(vnics, megaport.MVENetworkInterface{
Expand Down
11 changes: 11 additions & 0 deletions internal/commands/mve/mve_prompts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,17 @@ func TestPromptMVEVnics_InvalidVLAN(t *testing.T) {
assert.Contains(t, err.Error(), "invalid VLAN ID")
}

func TestPromptMVEVnics_OutOfRangeVLAN(t *testing.T) {
original := utils.GetResourcePrompt()
defer func() { utils.SetResourcePrompt(original) }()

utils.SetResourcePrompt(mockPromptSequence([]string{"eth0", "4100"}))

_, err := promptMVEVnics(true)
assert.Error(t, err)
assert.Contains(t, err.Error(), "VLAN ID")
}

// promptMVEVendorConfig tests — cisco/palo_alto admin password handling

func TestPromptMVEVendorConfig_Cisco_WithAdminPassword(t *testing.T) {
Expand Down
58 changes: 38 additions & 20 deletions internal/commands/vxc/vxc_prompts_partner.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package vxc
import (
"context"
"fmt"
"strconv"
"strings"

"github.com/megaport/megaport-cli/internal/utils"
Expand Down Expand Up @@ -98,8 +97,11 @@ func promptAWSConfig(noColor bool) (*megaport.VXCPartnerConfigAWS, error) {
if err != nil {
return nil, err
}
if ownerAccount == "" {
return nil, fmt.Errorf("owner account ID is required")
}

connectionName, err := utils.ResourcePrompt("vxc", "Enter connection name (required): ", noColor)
connectionName, err := utils.ResourcePrompt("vxc", "Enter connection name (optional, defaults to MEGAPORT): ", noColor)
if err != nil {
return nil, err
}
Expand All @@ -108,12 +110,12 @@ func promptAWSConfig(noColor bool) (*megaport.VXCPartnerConfigAWS, error) {
if err != nil {
return nil, err
}
var asn int
if asnStr != "" {
asn, err = validation.ParseInt("ASN", asnStr)
if err != nil {
return nil, err
}
if asnStr == "" {
return nil, fmt.Errorf("ASN is required")
}
asn, err := validation.ParseInt("ASN", asnStr)
if err != nil {
return nil, err
}

amazonASNStr, err := utils.ResourcePrompt("vxc", "Enter Amazon ASN (optional): ", noColor)
Expand Down Expand Up @@ -177,6 +179,9 @@ func promptAzureConfig(ctx context.Context, svc megaport.VXCService, noColor boo
if err != nil {
return nil, "", err
}
if serviceKey == "" {
return nil, "", fmt.Errorf("service key is required")
}

portChoice, err := utils.ResourcePrompt("vxc", "Enter port choice (primary/secondary, optional, default value is primary): ", noColor)
if err != nil {
Expand Down Expand Up @@ -268,9 +273,15 @@ func promptAzurePeeringConfig(noColor bool) (megaport.PartnerOrderAzurePeeringCo
if err != nil {
return megaport.PartnerOrderAzurePeeringConfig{}, err
}
vlan, err := strconv.Atoi(vlanStr)
if err != nil {
vlan = 0
var vlan int
if vlanStr != "" {
vlan, err = validation.ParseInt("VLAN ID", vlanStr)
if err != nil {
return megaport.PartnerOrderAzurePeeringConfig{}, err
}
if err := validation.ValidateVLAN(vlan); err != nil {
return megaport.PartnerOrderAzurePeeringConfig{}, err
}
}

return megaport.PartnerOrderAzurePeeringConfig{
Expand All @@ -289,6 +300,9 @@ func promptGoogleConfig(ctx context.Context, svc megaport.VXCService, noColor bo
if err != nil {
return nil, "", err
}
if pairingKey == "" {
return nil, "", fmt.Errorf("pairing key is required")
}

uid, err := getPartnerPortUID(ctx, svc, pairingKey, "GOOGLE")
if err != nil {
Expand All @@ -306,6 +320,9 @@ func promptOracleConfig(ctx context.Context, svc megaport.VXCService, noColor bo
if err != nil {
return nil, "", err
}
if virtualCircuitId == "" {
return nil, "", fmt.Errorf("virtual circuit ID is required")
}

uid, err := getPartnerPortUID(ctx, svc, virtualCircuitId, "ORACLE")
if err != nil {
Expand All @@ -323,24 +340,25 @@ func promptIBMConfig(noColor bool) (*megaport.VXCPartnerConfigIBM, error) {
if err != nil {
return nil, err
}
if accountID == "" {
return nil, fmt.Errorf("account ID is required")
}

name, err := utils.ResourcePrompt("vxc", "Enter name (required): ", noColor)
name, err := utils.ResourcePrompt("vxc", "Enter name (optional, defaults to MEGAPORT): ", noColor)
if err != nil {
return nil, err
}
if name == "" {
return nil, fmt.Errorf("name is required")
}

var customerASN int

customerASNStr, err := utils.ResourcePrompt("vxc", "Enter customer ASN (required if opposite end is not an MCR): ", noColor)
if err != nil {
return nil, err
}
customerASN, err = validation.ParseInt("customer ASN", customerASNStr)
if err != nil {
return nil, err
var customerASN int
if customerASNStr != "" {
customerASN, err = validation.ParseInt("customer ASN", customerASNStr)
if err != nil {
return nil, err
}
}

customerIPAddress, err := utils.ResourcePrompt("vxc", "Enter customer IP address (optional): ", noColor)
Expand Down
Loading
Loading