Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions Dockerfile.test-wrap-knife
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM ruby:3.1

# Install dependencies
RUN gem install mixlib-cli

# Set working directory
WORKDIR /test

# Copy standalone test script
COPY test-chef-28245-fix.rb ./

RUN chmod +x test-chef-28245-fix.rb

CMD ["ruby", "./test-chef-28245-fix.rb"]
18 changes: 18 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
# Chef Infra Server Release Notes

See [Chef Infra Server Release Notes](https://docs.chef.io/release_notes_server) for the complete list of product release notes.

## Unreleased

### Bug Fixes

- **CHEF-28245**: Fixed `chef-server-ctl user-list -a` and `--all-info` flags
- The `-a` and `--all-info` flags for `chef-server-ctl user-list` now work correctly after the knife-opc plugin removal in Chef Server 15.10.63+
- These flags are internally transformed to the native knife `--verbose` flag, which retrieves detailed user information (email, first_name, last_name, display_name)
- Maintains backward compatibility for existing scripts and pipelines using these flags
- Addresses customer-reported regression where the flags were silently ignored instead of providing detailed user data

### Important Notes

- In Chef Server 15.10.63+, the `knife-opc` plugin was removed in favor of native knife commands
- `chef-server-ctl user-list -a` / `--all-info` now uses native knife's `--verbose` flag internally
- Existing command-line interfaces remain unchanged for backward compatibility
- Scripts using `-a` or `--all-info` will continue to work without modification

245 changes: 245 additions & 0 deletions run-tests.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
#!/usr/bin/env ruby

# Comprehensive test runner for wrap-knife functionality

require 'rspec'
require 'shellwords'
require 'chef-utils'
require 'ostruct'

# Mock the ChefServerCtl module and Config class
module ChefServerCtl
class Config
def self.knife_config_file
"/tmp/knife.rb"
end

def self.knife_bin
"knife"
end

def self.lb_url
"https://localhost"
end
end
end

# Mock ChefUtils::Dist constants
module ChefUtils
module Dist
module Server
PRODUCT = "Chef Infra Server"
SERVER_CTL = "chef-server-ctl"
end
end
end

# Load just the functions we need from wrap-knife.rb
require_relative 'wrap-knife-functions'

Check failure on line 38 in run-tests.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Move this 'require_relative' statement to the top of the file before any class or module definitions.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG3-yA9524oStWrS1&open=AZroG3-yA9524oStWrS1&pullRequest=4128

puts "=" * 80
puts "RUNNING COMPREHENSIVE WRAP-KNIFE TESTS"
puts "=" * 80
puts

# Test 1: Original failing scenario
puts "🧪 Test 1: Original failing scenario"
puts "-" * 40
args = ["user4", "user", "four", "kallol.roy4@progress.com", "pass1234"]

Check failure on line 48 in run-tests.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "kallol.roy4@progress.com" 4 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG3-yA9524oStWrSy&open=AZroG3-yA9524oStWrSy&pullRequest=4128
result = transform_knife_opc_args(args, "user-create", "user", "create")

Check failure on line 49 in run-tests.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "user-create" 9 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG3-yA9524oStWrSw&open=AZroG3-yA9524oStWrSw&pullRequest=4128
expected = ["user4", "--email", "kallol.roy4@progress.com", "--password", "pass1234", "--first-name", "user", "--last-name", "four"]

Check failure on line 50 in run-tests.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "--last-name" 6 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG3-yA9524oStWrSx&open=AZroG3-yA9524oStWrSx&pullRequest=4128

Check failure on line 50 in run-tests.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "--email" 6 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG3-yA9524oStWrSz&open=AZroG3-yA9524oStWrSz&pullRequest=4128

Check failure on line 50 in run-tests.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "--password" 6 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG3-yA9524oStWrSu&open=AZroG3-yA9524oStWrSu&pullRequest=4128

Check failure on line 50 in run-tests.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "--first-name" 6 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG3-yA9524oStWrS0&open=AZroG3-yA9524oStWrS0&pullRequest=4128

puts "Input: #{args.inspect}"
puts "Output: #{result.inspect}"
puts "Expected: #{expected.inspect}"
puts "Status: #{result == expected ? '✅ PASS' : '❌ FAIL'}"
puts

# Test 2: With filename flag
puts "🧪 Test 2: With filename flag"
puts "-" * 40
args = ["admin", "Admin", "User", "admin@example.com", "admin123", "--filename", "/tmp/admin.pem"]

Check failure on line 61 in run-tests.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "--filename" 3 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG3-yA9524oStWrSv&open=AZroG3-yA9524oStWrSv&pullRequest=4128
result = transform_knife_opc_args(args, "user-create", "user", "create")
expected = ["admin", "--email", "admin@example.com", "--password", "admin123", "--first-name", "Admin", "--last-name", "User", "-f", "/tmp/admin.pem"]

puts "Input: #{args.inspect}"
puts "Output: #{result.inspect}"
puts "Expected: #{expected.inspect}"
puts "Status: #{result == expected ? '✅ PASS' : '❌ FAIL'}"
puts

# Test 3: With 6 arguments (middle name)
puts "🧪 Test 3: With middle name (6 arguments)"
puts "-" * 40
args = ["user5", "John", "Michael", "Doe", "john.doe@example.com", "password123"]
result = transform_knife_opc_args(args, "user-create", "user", "create")
expected = ["user5", "--email", "john.doe@example.com", "--password", "password123", "--first-name", "John", "--last-name", "Doe"]

puts "Input: #{args.inspect}"
puts "Output: #{result.inspect}"
puts "Expected: #{expected.inspect}"
puts "Status: #{result == expected ? '✅ PASS' : '❌ FAIL'}"
puts

# Test 4: Special characters in email and password
puts "🧪 Test 4: Special characters in email and password"
puts "-" * 40
args = ["user1", "Jane", "Smith", "jane.smith+test@example.co.uk", "p@ssw0rd!123"]
result = transform_knife_opc_args(args, "user-create", "user", "create")
expected = ["user1", "--email", "jane.smith+test@example.co.uk", "--password", "p@ssw0rd!123", "--first-name", "Jane", "--last-name", "Smith"]

puts "Input: #{args.inspect}"
puts "Output: #{result.inspect}"
puts "Expected: #{expected.inspect}"
puts "Status: #{result == expected ? '✅ PASS' : '❌ FAIL'}"
puts

# Test 5: Multiple flags
puts "🧪 Test 5: Multiple flags"
puts "-" * 40
args = ["user12", "Test", "User", "test@example.com", "password", "--filename", "/tmp/user.pem", "--orgname", "myorg", "--prevent-keygen"]
result = transform_knife_opc_args(args, "user-create", "user", "create")
expected = ["user12", "--email", "test@example.com", "--password", "password", "--first-name", "Test", "--last-name", "User", "-f", "/tmp/user.pem", "--orgname", "myorg", "--prevent-keygen"]

puts "Input: #{args.inspect}"
puts "Output: #{result.inspect}"
puts "Expected: #{expected.inspect}"
puts "Status: #{result == expected ? '✅ PASS' : '❌ FAIL'}"
puts

# Test 6: Insufficient arguments (fallback)
puts "🧪 Test 6: Insufficient arguments (should fallback)"
puts "-" * 40
args = ["user14", "Test", "User"]
result = transform_knife_opc_args(args, "user-create", "user", "create")
expected = args # Should return unchanged

puts "Input: #{args.inspect}"
puts "Output: #{result.inspect}"
puts "Expected: #{expected.inspect}"
puts "Status: #{result == expected ? '✅ PASS' : '❌ FAIL'}"
puts

# Test 7: User-list with --all-info flag (should transform to --verbose)
puts "🧪 Test 7: User-list with --all-info flag"
puts "-" * 40
args = ["--all-info", "otherarg"]
result = transform_knife_opc_args(args, "user-list", "user", "list")
expected = ["otherarg", "--verbose"]

puts "Input: #{args.inspect}"
puts "Output: #{result.inspect}"
puts "Expected: #{expected.inspect}"
puts "Status: #{result == expected ? '✅ PASS' : '❌ FAIL'}"
puts

# Test 7b: User-list with -a flag (should transform to --verbose)
puts "🧪 Test 7b: User-list with -a flag"
puts "-" * 40
args = ["-a"]
result = transform_knife_opc_args(args, "user-list", "user", "list")
expected = ["--verbose"]

puts "Input: #{args.inspect}"
puts "Output: #{result.inspect}"
puts "Expected: #{expected.inspect}"
puts "Status: #{result == expected ? '✅ PASS' : '❌ FAIL'}"
puts

# Test 8: Transform flags only
puts "🧪 Test 8: Transform flags only"
puts "-" * 40
args = ["--filename", "/tmp/test.pem", "other", "args"]
result = transform_flags_only(args)
expected = ["-f", "/tmp/test.pem", "other", "args"]

puts "Input: #{args.inspect}"
puts "Output: #{result.inspect}"
puts "Expected: #{expected.inspect}"
puts "Status: #{result == expected ? '✅ PASS' : '❌ FAIL'}"
puts

# Test 9: Get server URL
puts "🧪 Test 9: Get server URL"
puts "-" * 40
result = get_server_url()
expected = "https://localhost"

puts "Output: #{result.inspect}"
puts "Expected: #{expected.inspect}"
puts "Status: #{result == expected ? '✅ PASS' : '❌ FAIL'}"
puts

puts "=" * 80
puts "RUNNING INTEGRATION TEST"
puts "=" * 80
puts

# Integration test: Full command simulation
puts "🧪 Integration Test: Full command simulation"
puts "-" * 50

# Mock the add_command_under_category method
executed_commands = []

def add_command_under_category(name, category, description, arity, &block)
if name == "user-create"
puts "Executing user-create command..."
yield
end
end

# Mock the run_command method
def run_command(command)
puts "Executed: #{command}"
# Return a mock status object
OpenStruct.new(exitstatus: 0)
end

# Mock the exit method
def exit(code)
puts "Exit code: #{code}"
end

# Set up test ARGV for the original failing command
ARGV.replace(['user-create', 'user4', 'user', 'four', 'kallol.roy4@progress.com', 'pass1234'])

# Simulate the knife_config and cmd_args
knife_config = "/tmp/knife.rb"
cmd_args = ARGV[1..-1]

puts "Original command: chef-server-ctl #{ARGV.join(' ')}"
puts "cmd_args: #{cmd_args.inspect}"
puts

# Transform the arguments
transformed_args = transform_knife_opc_args(cmd_args, "user-create", "user", "create")
puts "Transformed args: #{transformed_args.inspect}"

# Build the final command
auth_args = ["-c", knife_config]
all_args = transformed_args + auth_args
escaped_args = all_args.map { |arg| Shellwords.escape(arg) }.join(" ")
knife_command = "knife user create #{escaped_args}"

puts "Final knife command: #{knife_command}"
puts

# Verify the final command contains the expected elements
expected_elements = ["--email", "kallol.roy4@progress.com", "--password", "pass1234", "--first-name", "user", "--last-name", "four"]
contains_all = expected_elements.all? { |element| knife_command.include?(element) }

puts "Contains expected elements: #{contains_all ? '✅ PASS' : '❌ FAIL'}"
if contains_all
puts "✅ SUCCESS: The command transformation is working correctly!"
else
puts "❌ FAILURE: Missing expected elements in final command"
end

puts
puts "=" * 80
puts "TEST SUMMARY"
puts "=" * 80
puts "All core functionality tests completed."
puts "The wrap-knife plugin is correctly transforming old knife-opc format"
puts "to modern knife format, which should resolve the original password error."
3 changes: 2 additions & 1 deletion src/chef-server-ctl/plugins/wrap-knife.rb
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,10 @@ def transform_knife_opc_args(args, chef_server_ctl_cmd, _knife_noun, _knife_verb
end

when "user-list"
# Handle --all-info option (not supported in native knife)
# Transform knife-opc --all-info/-a flag to native knife --verbose flag
if transformed.include?("--all-info") || transformed.include?("-a")
transformed = transformed.reject { |arg| %w[--all-info -a].include?(arg) }
transformed << "--verbose"
end
end

Expand Down
78 changes: 78 additions & 0 deletions src/chef-server-ctl/spec/wrap_knife_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
require 'spec_helper'
require 'ostruct'

# Load the wrap-knife plugin functions
load File.expand_path('../../plugins/wrap-knife.rb', __FILE__)

describe 'wrap-knife plugin' do
describe '#transform_knife_opc_args' do
context 'user-list command' do
it 'transforms --all-info flag to --verbose' do
args = ['--all-info', 'otherarg']
result = transform_knife_opc_args(args, 'user-list', 'user', 'list')

Check failure on line 12 in src/chef-server-ctl/spec/wrap_knife_spec.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "user-list" 5 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG36yA9524oStWrSd&open=AZroG36yA9524oStWrSd&pullRequest=4128
expect(result).to eq(['otherarg', '--verbose'])

Check failure on line 13 in src/chef-server-ctl/spec/wrap_knife_spec.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "--verbose" 3 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG36yA9524oStWrSg&open=AZroG36yA9524oStWrSg&pullRequest=4128
end

it 'transforms -a flag to --verbose' do
args = ['-a']
result = transform_knife_opc_args(args, 'user-list', 'user', 'list')
expect(result).to eq(['--verbose'])
end

it 'transforms -a flag with other arguments to --verbose' do
args = ['-a', '--with-uri']

Check failure on line 23 in src/chef-server-ctl/spec/wrap_knife_spec.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "--with-uri" 4 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG36yA9524oStWrSc&open=AZroG36yA9524oStWrSc&pullRequest=4128
result = transform_knife_opc_args(args, 'user-list', 'user', 'list')
expect(result).to eq(['--with-uri', '--verbose'])
end

it 'handles user-list without -a or --all-info flags' do
args = ['--with-uri']
result = transform_knife_opc_args(args, 'user-list', 'user', 'list')
expect(result).to eq(['--with-uri'])
end

it 'handles empty arguments' do
args = []
result = transform_knife_opc_args(args, 'user-list', 'user', 'list')
expect(result).to eq([])
end
end

context 'user-create command' do
it 'transforms knife-opc format to native knife format with 5 positional args' do
args = ['user4', 'user', 'four', 'kallol.roy4@progress.com', 'pass1234']
result = transform_knife_opc_args(args, 'user-create', 'user', 'create')

Check failure on line 44 in src/chef-server-ctl/spec/wrap_knife_spec.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "user-create" 3 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG36yA9524oStWrSe&open=AZroG36yA9524oStWrSe&pullRequest=4128
expected = ['user4', '--email', 'kallol.roy4@progress.com', '--password', 'pass1234', '--first-name', 'user', '--last-name', 'four']

Check failure on line 45 in src/chef-server-ctl/spec/wrap_knife_spec.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "--email" 3 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG36yA9524oStWrSh&open=AZroG36yA9524oStWrSh&pullRequest=4128

Check failure on line 45 in src/chef-server-ctl/spec/wrap_knife_spec.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "--password" 3 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG36yA9524oStWrSb&open=AZroG36yA9524oStWrSb&pullRequest=4128

Check failure on line 45 in src/chef-server-ctl/spec/wrap_knife_spec.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "--first-name" 3 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG36yA9524oStWrSj&open=AZroG36yA9524oStWrSj&pullRequest=4128

Check failure on line 45 in src/chef-server-ctl/spec/wrap_knife_spec.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "--last-name" 3 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG36yA9524oStWrSf&open=AZroG36yA9524oStWrSf&pullRequest=4128
expect(result).to eq(expected)
end

it 'transforms knife-opc format with middle name (6 positional args)' do
args = ['user5', 'first', 'middle', 'last', 'test@example.com', 'password123']

Check failure on line 50 in src/chef-server-ctl/spec/wrap_knife_spec.rb

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "test@example.com" 4 times.

See more on https://sonarcloud.io/project/issues?id=chef_chef-server&issues=AZroG36yA9524oStWrSi&open=AZroG36yA9524oStWrSi&pullRequest=4128
result = transform_knife_opc_args(args, 'user-create', 'user', 'create')
expected = ['user5', '--email', 'test@example.com', '--password', 'password123', '--first-name', 'first', '--last-name', 'last']
expect(result).to eq(expected)
end

it 'transforms knife-opc format with --filename flag' do
args = ['testuser', 'Test', 'User', 'test@example.com', 'password', '--filename', '/tmp/key.pem']
result = transform_knife_opc_args(args, 'user-create', 'user', 'create')
expected = ['testuser', '--email', 'test@example.com', '--password', 'password', '--first-name', 'Test', '--last-name', 'User', '-f', '/tmp/key.pem']
expect(result).to eq(expected)
end
end

context 'transform_flags_only' do
it 'converts --filename to -f' do
args = ['--filename', '/tmp/test.pem', 'other', 'args']
result = transform_flags_only(args)
expect(result).to eq(['-f', '/tmp/test.pem', 'other', 'args'])
end

it 'passes through other flags unchanged' do
args = ['--orgname', 'myorg', '--prevent-keygen']
result = transform_flags_only(args)
expect(result).to eq(['--orgname', 'myorg', '--prevent-keygen'])
end
end
end
end
Loading
Loading