New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OCPBUGS-22739: Properly handle rewrite-target annotation #534
OCPBUGS-22739: Properly handle rewrite-target annotation #534
Conversation
@gcs278: This pull request references Jira Issue OCPBUGS-22739, which is invalid:
Comment The bug has been updated to refer to the pull request using the external bug tracker. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
// leave double %% as is, so that existing users who manually addressed the issue are not broken. Furthermore, even | ||
// sequences, such as %%%% or %%%%%% were valid and should be left untouched, while odd sequences such as %%% or | ||
// %%%%% were invalid, and should be doubled to ensure every % is escaped. | ||
re := regexp.MustCompile(`%+`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this function will be called frequently then we should be somewhat wary of the time and cost to compile the RE. See: #268
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch. Might as well optimize it. Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using cachedRegexpCompile
makes sense where the pattern is built at run-time, but in this case, you can just use a package variable to avoid the map lookup and error checking:
var (
// oneOrMorePercentSigns matches one or more literal percent signs.
oneOrMorePercentSigns = regexp.MustCompile(`%+`)
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see the intention of cachedRegexpComplie
now. Done.
5e9d232
to
0a5016f
Compare
8651281
to
4933f71
Compare
The changes LGTM but I think somebody else should also review otherwise I'd just be rubber-stamping my own suggestions. |
/jira refresh |
@gcs278: This pull request references Jira Issue OCPBUGS-22739, which is valid. The bug has been moved to the POST state. 3 validation(s) were run on this bug
Requesting review from QA contact: In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Image build failed again. |
testplatform refreshed the RPM repo: |
tested it with 4.15.0-0.ci.test-2023-11-14-012251-ci-ln-8wxgkwb-latest % oc -n openshift-ingress rsh router-default-9d6f95d4c-9tmc % oc annotate route/service-unsecure haproxy.router.openshift.io/rewrite-target="/t t$%&*(){}[].,z#:`_-|" --overwrite % oc get route service-unsecure -o=jsonpath="{.metadata.annotations.haproxy.router.openshift.io/rewrite-target}" |
/label qe-approved |
@gcs278: This pull request references Jira Issue OCPBUGS-22739, which is valid. 3 validation(s) were run on this bug
Requesting review from QA contact: In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
I've asked @alebedev87 to take a look to help move this PR along (since Andy has a conflict of interest) /assign @alebedev87 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, looks fine to me, just some small comments and questions.
|
||
// processDoubleQuotes is a processFunc that processes double quote | ||
// characters. It skips the double quote if it's not escaped. | ||
var processDoubleQuotes = func(char rune, escaped bool) runeResult { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any particular reason this is not just:
var processDoubleQuotes = func(char rune, escaped bool) runeResult { | |
func processDoubleQuotes(char rune, escaped bool) runeResult { |
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea I don't see any reason these need to be a var, I'll change.
// string. It returns a processFunc which will set | ||
// encounteredCommentMarker to true and stop processing if it | ||
// encounters a '#' that is not escaped. | ||
func processHashCreator(encounteredCommentMarker *bool) processFunc { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
func processHashCreator(encounteredCommentMarker *bool) processFunc { | |
func newProcessHashCreator(encounteredCommentMarker *bool) processFunc { |
wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea that's fair. Done.
package rewritetarget_test | ||
|
||
import ( | ||
"github.com/openshift/router/pkg/router/template/util/rewritetarget" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SanitizeInput
is in the same package, no need to import it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not the same package. This is a deliberate decision. Placing tests in a separate package, package rewritetarget_test
, enforces black-box testing principles. For me, key reasons to use black-box testing:
-
Encapsulation: It guarantees tests can only access exported package members, mirroring how external packages interact with
rewritetarget
. This approach reinforces the integrity of the package's encapsulation. -
API Design: Black-box testing inherently leads to clearer and more stable APIs by focusing on the package's usability rather than its internals.
-
Resilience: Tests are less prone to break due to internal changes, as they're tied to the public API. This helps to reduce maintenance.
-
User Perspective: It provides insights into how the package is used, highlighting potential areas for improvement from the end-user’s standpoint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, right, I was looking at the directories. So, what's the idea behind? To test without the access to any private variables? Like if it was the user of the package?
I see this pattern is not quite uniformly implemented in util
package (e.g. haproxy).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Encapsulation: It guarantees tests can only access exported package members, mirroring how external packages interact with rewritetarget. This approach reinforces the integrity of the package's encapsulation. API Design: Black-box testing inherently leads to clearer and more stable APIs by focusing on the package's usability rather than its internals. Resilience: Tests are less prone to break due to internal changes, as they're tied to the public API. This helps to reduce maintenance. User Perspective: It provides insights into how the package is used, highlighting potential areas for improvement from the end-user’s standpoint.
I see. Yes, I think it makes sense for SanitizeInput
function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, Andy and I had this discussion in slack. It's an interesting perspective we should consider when writing unit tests.
}, | ||
{ | ||
name: "triple percent should be doubled entirely", | ||
input: `%%%foo`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So here we think that the user put "3 percent signs without escaping" and not "1 escaped percent sign plus one unescaped", right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly. This case is currently a syntax error, which means we don't have to maintain any sort of compatibility. with users using %%%
today.
The most logical thing to do here is assume the user isn't escaping any of them and double them (to escape them).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another interpretation of %%%
input could be as a combination of %%
+ %
inputs. Therefore, by default, we assume the user's intent is to do the right escaping (like in case of %%
input) and we do the minimum necessary to ensure the correct syntax(== %%%%
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes it's all coming back to me now. You are correct, we could assume mixed intention for escaped & unescaped, taking each %
by itself. However, the doubling %%%
to %%%%%%
then gets interpreted back to %%%
again, which is exactly what the author specified in the first place, keeping some consistency.
val = convertDoubleBackslashes(val) | ||
|
||
if !encounteredCommentMarker { | ||
// Add the capture group. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be a little more info of why we are adding the capture group.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// The literal `\1` is appended to annotations without
// comments to comply with HAProxy rewrite rule
// expectations, which necessitate a capture group
// reference (i.e., `\1`) for dynamic substitutions.
Any better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Thanks Andy, you are making this too easy for me 😄
Process the `haproxy.router.openshift.io/rewrite-target` annotation value to prevent HaProxy configuration issues while maintaining API compatibility. Properly handle values with spaces, backslashes, and other special characters. Add a new package, rewritetarget, to organize the functions that process the rewrite target annotation. Add a separate unit test package, rewritetarget_test, to enforce black-box testing principles.
4933f71
to
e298bb0
Compare
@alebedev87 @frobware Code review changes from Andrey's comments. I also revised the git commit message. |
@gcs278: This pull request references Jira Issue OCPBUGS-22739, which is valid. 3 validation(s) were run on this bug
Requesting review from QA contact: In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
/lgtm |
/retest |
tested it with 4.15.0-0.ci.test-2024-03-14-121356-ci-ln-1wy2cjb-latest % oc get clusterversion % oc -n openshift-ingress rsh router-default-567f677657-7gr4q % oc annotate route/service-unsecure haproxy.router.openshift.io/rewrite-target="/t t$%&*(){}[].,z#:`_-|" --overwrite % oc get route service-unsecure -o=jsonpath="{.metadata.annotations.haproxy.router.openshift.io/rewrite-target}" |
/label qe-approved |
@gcs278: all tests passed! Full PR test history. Your PR dashboard. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
/approve |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: alebedev87 The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/hold I want to give @Miciah a chance to look at this, as he helped me with the solution. We are in I'll unhold after shift week if I don't hear any issues. |
Moving forward with this fix. I'm going to look into getting docs to help me with a doc update. /unhold |
@gcs278: Jira Issue OCPBUGS-22739: All pull requests linked via external trackers have merged: Jira Issue OCPBUGS-22739 has been moved to the MODIFIED state. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
[ART PR BUILD NOTIFIER] This PR has been included in build ose-haproxy-router-base-container-v4.16.0-202403251813.p0.g526f832.assembly.stream.el9 for distgit ose-haproxy-router-base. |
/cherry-pick release-4.15 |
@gcs278: new pull request created: #569 In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
/cherry-pick release-4.14 |
@gcs278: #534 failed to apply on top of branch "release-4.14":
In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Process the
haproxy.router.openshift.io/rewrite-target
annotation value to prevent HaProxy configuration issues while maintaining API compatibility. Properly handle values with spaces, backslashes, and other special characters.Add a new package, rewritetarget, to organize the functions that process the rewrite target annotation. Add a separate unit test package, rewritetarget_test, to enforce black-box testing principles.
images/router/haproxy/conf/haproxy-config.template
: Call processRewriteTarget function in template.pkg/router/template/rewritetarget/rewritetarget.go
: New package with functions to process the rewrite target annotation.pkg/router/template/rewritetarget/rewritetarget_test.go
: Unit test SanitizeInput function.pkg/router/template/template_helper.go
: Expose SanitizeInput to as a Go Template function.