Skip to content

IPv6 validation for Ruby apps - #1587

Closed
Milena-Encheva wants to merge 3 commits into
cloudfoundry:developfrom
sap-contributions:CFDEPLOY-221-ipv6-validation-ruby
Closed

IPv6 validation for Ruby apps#1587
Milena-Encheva wants to merge 3 commits into
cloudfoundry:developfrom
sap-contributions:CFDEPLOY-221-ipv6-validation-ruby

Conversation

@Milena-Encheva

Copy link
Copy Markdown
Contributor

Are you submitting this PR against the develop branch?

Yes.

What is this change about?

The change is part of the IPv6 egress validation cycle. We progressively extend all of the exciting buildpacks relevant to our ecosystem. In this PR we provide additional endpoints in the ruby application for testing IPv6 support. In case ipv6 validation is enabled, we verify that egress IPv6 calls are possible with ruby applications.

Please provide contextual information.

https://github.com/cloudfoundry/community/blob/main/toc/rfc/rfc-0038-ipv6-dual-stack-for-cf.md

What version of cf-deployment have you run this cf-acceptance-test change against?

v48.9.0

Please check all that apply for this PR:

  • introduces a new test --- Are you sure everyone should be running this test?
  • changes an existing test
  • requires an update to a CATs integration-config

Did you update the README as appropriate for this change?

  • YES
  • N/A

If you are introducing a new acceptance test, what is your rationale for including it CATs rather than your own acceptance test suite?

_CATs should validate IPv6 egress calls with Ruby application. We add changes regarding to this buildpack only. The test group for ipv6 was already created.

How many more (or fewer) seconds of runtime will this change introduce to CATs?

Around 90 seconds per test.

What is the level of urgency for publishing this change?

  • Urgent - unblocks current or future work
  • Slightly Less than Urgent

Tag your pair, your PM, and/or team!

@oliver-heinrich @iaftab-alam

@iaftab-alam
iaftab-alam requested review from a team June 2, 2025 11:38
@philippthun

Copy link
Copy Markdown
Member

Here are some suggestions (from Copilot) for improvement in this PR based on the diff provided:

1. Error Message Handling in Sinatra Route

In the new Ruby code, the response always includes Error message: #{result[:error]} even when there is no error. This will print Error message: with a nil value for successful requests, which can be confusing to clients and test logs.

Suggestion:
Only include the error message if there is an error.

# Before:
"#{validation_name} validation resulted in #{result[:success] ? 'success' : 'failure'}. Detected IP type is #{result[:ip_type]}. Error message: #{result[:error]}"

# After:
message = "#{validation_name} validation resulted in #{result[:success] ? 'success' : 'failure'}. Detected IP type is #{result[:ip_type]}."
message += " Error message: #{result[:error]}" if result[:error]
message

2. Potential Hardcoding & DRY Principle

The IPTester class only ever receives a single endpoint, but is initialized with an array (endpoints). The array is not used elsewhere, so this could be simplified.

Suggestion:
Refactor to remove the unused @endpoints unless you plan to expand this later.


3. Error Logging Granularity

Currently, in test_endpoint, any exception results in a log message with just the exception object (#{e}). It could be more useful to include the full backtrace for debugging.

Suggestion:
Log the full backtrace for exceptions, or at least the class and message.

logger.error("Failed to reach #{endpoint}: #{e.class} - #{e.message}\n#{e.backtrace.join("\n")}")

4. IP Type Detection

The determine_ip_type method returns 'IPv6' for anything that’s not IPv4. Consider explicitly checking for both types and handling unexpected cases.

Suggestion:
Return 'Unknown' when the type is neither IPv4 nor IPv6.

def determine_ip_type(ip_string)
  ip = IPAddr.new(ip_string)
  return 'IPv4' if ip.ipv4?
  return 'IPv6' if ip.ipv6?
  'Unknown'
rescue IPAddr::InvalidAddressError
  'Invalid IP'
end

5. Test Coverage

While the Go test adds a Ruby test case, it only checks for a "Healthy" response. It would be better to actually validate the IPv6 functionality and the endpoints being exercised, perhaps by hitting the new /ipv6-test endpoint and asserting on the result.

Suggestion:
Expand the Go test to exercise the new Ruby endpoints and check for expected behavior, not just "Healthy".


6. Code Formatting

There are some double blank lines in the Ruby file that could be reduced to keep the code tidy.

@Milena-Encheva

Copy link
Copy Markdown
Contributor Author

Here are some suggestions (from Copilot) for improvement in this PR based on the diff provided:

1. Error Message Handling in Sinatra Route

In the new Ruby code, the response always includes Error message: #{result[:error]} even when there is no error. This will print Error message: with a nil value for successful requests, which can be confusing to clients and test logs.

Suggestion: Only include the error message if there is an error.

# Before:
"#{validation_name} validation resulted in #{result[:success] ? 'success' : 'failure'}. Detected IP type is #{result[:ip_type]}. Error message: #{result[:error]}"

# After:
message = "#{validation_name} validation resulted in #{result[:success] ? 'success' : 'failure'}. Detected IP type is #{result[:ip_type]}."
message += " Error message: #{result[:error]}" if result[:error]
message

2. Potential Hardcoding & DRY Principle

The IPTester class only ever receives a single endpoint, but is initialized with an array (endpoints). The array is not used elsewhere, so this could be simplified.

Suggestion: Refactor to remove the unused @endpoints unless you plan to expand this later.

3. Error Logging Granularity

Currently, in test_endpoint, any exception results in a log message with just the exception object (#{e}). It could be more useful to include the full backtrace for debugging.

Suggestion: Log the full backtrace for exceptions, or at least the class and message.

logger.error("Failed to reach #{endpoint}: #{e.class} - #{e.message}\n#{e.backtrace.join("\n")}")

4. IP Type Detection

The determine_ip_type method returns 'IPv6' for anything that’s not IPv4. Consider explicitly checking for both types and handling unexpected cases.

Suggestion: Return 'Unknown' when the type is neither IPv4 nor IPv6.

def determine_ip_type(ip_string)
  ip = IPAddr.new(ip_string)
  return 'IPv4' if ip.ipv4?
  return 'IPv6' if ip.ipv6?
  'Unknown'
rescue IPAddr::InvalidAddressError
  'Invalid IP'
end

5. Test Coverage

While the Go test adds a Ruby test case, it only checks for a "Healthy" response. It would be better to actually validate the IPv6 functionality and the endpoints being exercised, perhaps by hitting the new /ipv6-test endpoint and asserting on the result.

Suggestion: Expand the Go test to exercise the new Ruby endpoints and check for expected behavior, not just "Healthy".

6. Code Formatting

There are some double blank lines in the Ruby file that could be reduced to keep the code tidy.

Applied all change, except 5.Test Coverage: We use endpoint mapper in the app to go through all of the endpoints. The Go tests are checking each of them ( /ipv4-test, /ipv6-test and /dual-stack-test) for the correct output.

In ruby's case we are checking explicitly for "Healthy" when the default path is hit. For most of the buildpacks - the default is "Hello". For ruby it needed special handling.

@philippthun philippthun left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

👍

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.

2 participants