Skip to content
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

Add length check for Docker Registry authentication strings #480

Merged
merged 5 commits into from
Feb 8, 2024

Conversation

nmgaston
Copy link
Contributor

@nmgaston nmgaston commented Feb 7, 2024

The PR review is to check for sustainability and correctness. Sustainability is actually more business critical as correctness is largely tested into the code over time. Its useful to keep in mind that SW often outlives the HW it was written for and engineers move from job to job so it is critical that code developed for Intel be supportable across many years. It is up to the submitter and reviewer to look at the code from a perspective of what if we have to debug this 3 years from now after the author is no longer available and defect databases have been lost. Yes, that happens all the time when we are working with time scales of more than 2 years. When reviewing your code it is important to look at it from this perspective.

Author Mandatory (to be filled by PR Author/Submitter)

  • Developer who submits the Pull Request for merge is required to mark the checklist below as applicable for the PR changes submitted.
  • Those checklist items which are not marked are considered as not applicable for the PR change.
  • Items marked with an asterisk suffix are mandatory items to check and if not marked will be treated as non-compliant pull requests by the developers for Inner Source Development Model (ISDM) compliance

PULL DESCRIPTION

Provide a 1-2 line brief overview of the changes submitted through the Pull Request...

REFERENCES

Reference URL for issue tracking (JIRA/HSD/Github): <URL to be filled>

  • Added label to the Pull Request following the template: ISDM_<Complexity>*
    Note-1: Depending on complexity of code changes, use the suitable word for complexity: Low/Medium/High
    Example: PR for Slim boot loader project with medium complexity can have the label as: ISDM_Medium
  • Added label to the Pull Request for easier discoverability and search
  • RTC or HSD number will be included in final merge. HSD must always be included if available.
  • Changelogs are updated (or N/A if not customer visible)
  • inbm/log_changes.txt and inbm-vision/log_changes.txt are updated for potentially Validation-breaking log changes (or N/A if none)

CODE MAINTAINABILITY

  • Commit Message meets guidelines as indicated in the URL*
  • Every commit is a single defect fix and does not mix feature addition or changes*
  • Added required new tests relevant to the changes
    • PR contains URL links to functional tests executed with the new tests
  • Updated Documentation as relevant to the changes
  • Updated Build steps/commands changes as relevant
  • PR change contains code related to security
  • PR introduces changes that breaks compatibility with other modules (If YES, please provide description)
  • Specific instructions or information for code reviewers (If any):
  • Run 'go fmt' or format-python.sh as applicable.
  • New/modified methods and functions should have type annotations on signatures as applicable
  • New/modified methods must have appropriate doc strings (language dependent)

APPLICATION SPECIFIC

  • Does PR change default config files under /etc? If so, will application still work after an upgrade that leaves /etc alone, like a Mender upgrade?
  • Is cloud UI changed? If so, are cloud definition files updated?

Maintainer Mandatory (to be filled by PR Reviewer/Approving Maintainer)

  • Maintainer who approves the Pull Request for merge is required to mark the checklist below as appropriate for the PR change reviewed as key proof of attestation indicating reasons for merge.
  • Those checklist items which are not marked are considered as not applicable for the PR change.
  • Items marked with an asterisk suffix are mandatory items to check and if not marked will be treated as non-compliant pull requests by the maintainers for ISDM compliance.

QUALITY CHECKS

  • Architectural and Design Fit
  • Quality of code (At least one should be checked as applicable)*
    • Commit Message meets guidelines
    • PR changes adhere to industry practices and standards
    • Error and exception code paths implemented correctly
    • Code reviewed for domain or language specific anti-patterns
    • Code is adequately commented
    • Code copyright is correct
    • Confusing logic is explained in comments
    • Commit comment can be used to design a new test case for the changes
  • Test coverage shows adequate coverage with required CI functional tests pass on all supported platforms*
  • Static code scan report shows zero critical issues*
  • Integration tests are passing

CODE REVIEW IMPACT

  • Summary of Defects Detected in Code Review: <%P1xx,P2xx,P3xx,P4xx%>
    Note P1/P2/P3/P4 denotes severity of defects found (Showstopper/High/Medium/Low) and xx denotes number of defects found

SECURITY CHECKS

Please check if your PR fulfills the following requirements:

  • Follow best practices when handling primitive data types
  • Configure minimal permissions when opening pipes and ports
  • Check contents within input structures are valid before use
  • All forms of input validated
  • Avoid inter-process race conditions
  • Error and exception handling implemented
  • Defend against Canonical Representation Issues - Any paths utilized?
  • Follow 'secure by default' - Any configuration values added
  • Fail safe - Any failure scenarios?
  • Clean up temporary files - Any temporary files being used?

Code must act as a teacher for future developers

@nmgaston nmgaston merged commit db01667 into develop Feb 8, 2024
7 checks passed
@nmgaston nmgaston deleted the AddLengthCheckForStrings branch February 8, 2024 02:49
@gblewis1
Copy link
Contributor

/review

@nex-maximus
Copy link
Collaborator

$\color{#FFA500}CODE \space REVIEW \space STARTED$

@nex-maximus
Copy link
Collaborator

Preparing review...

@nex-maximus
Copy link
Collaborator

Code Review Analysis

  • PR summary: This PR introduces length checks and character validation for Docker Registry authentication strings, specifically for usernames and server names. It aims to enhance security and ensure that the credentials used for Docker Registry authentication adhere to Docker's defined standards for length and character composition.
  • PR Category: Enhancement

Code Review Feedback

General suggestions: The PR effectively addresses the need for validating Docker Registry authentication strings, which is crucial for maintaining security and adherence to Docker's standards. It's important to ensure that error messages are clear and actionable, providing users with a clear understanding of the constraints. Additionally, considering the future maintainability of the code, it might be beneficial to externalize string length limits and regex patterns to a configuration file or constants, making it easier to update these values if Docker's requirements change.

  • Security concerns: No
User guidelines:

Tag me in a comment '@nex-maximus' and add one of the following commands:
/review [-all]: Request a review of your Pull Request. By default, the agent considers changes since the last review For including all the files in PR, which only include the '-all' option.
/describe: Modify the PR title and description based on the contents of the PR.
For example: /review --pr_reviewer.extra_instructions="focus on the file: ..."

@@ -28,6 +28,10 @@ var composeImagesRemoveAll = dockercompose.ImageRemoveAll
var composePull = dockercompose.Pull
var composePullWithFile = dockercompose.PullWithFile

// Maximum lengths as defined by Docker
var dockerRegistryUserNameLengthLimit = 30
Copy link
Collaborator

Choose a reason for hiding this comment

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

$\color{#FFA500}Improvements: Code Maintainability$

Consider externalizing dockerRegistryUserNameLengthLimit and dockerRegistryServerNameLengthLimit to a configuration file or at least to a more central location within the codebase. This would make it easier to update these values without having to dive deep into the business logic code.

func is_username_registry_safe(username string, serverName string) bool {
func isRegistryCredentialsSafe(username string, serverName string) error {
if len(username) > dockerRegistryUserNameLengthLimit {
return fmt.Errorf("error: docker registry username can not exceed %d characters", dockerRegistryUserNameLengthLimit)
Copy link
Collaborator

Choose a reason for hiding this comment

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

$\color{#FFA500}Improvements: Code Maintainability$

The error messages returned from isRegistryCredentialsSafe could be more descriptive by including the invalid input value. This would help users quickly identify and correct the issue.

func TestReturnErrorUserNameTooLong(t *testing.T) {
expected := errors.New("error: docker registry username can not exceed 30 characters")
actual := isRegistryCredentialsSafe("usernameusernameusernameusername", "servername")
if actual.Error() != expected.Error() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

$\color{#FFA500}Improvements: Code Maintainability$

In your tests, instead of comparing error strings, consider using errors.Is for a more robust error comparison. This approach is less fragile and more idiomatic.

func TestReturnNilRegistrySafe(t *testing.T) {
assert.Equal(t, isRegistryCredentialsSafe("username", "servername"), nil)}

func TestReturnErrorUserNameTooLong(t *testing.T) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

$\color{#FFD700}Coding Style$

The test function names could be more descriptive to reflect the specific scenario being tested, such as TestRegistryCredentialsSafe_UserNameTooLong instead of TestReturnErrorUserNameTooLong. This provides clearer intent and readability.

func (compose *ComposeInfo) List(instanceName string) {
if err := composeList(util.ExecCommandWrap{}, instanceName); err != nil {
osExit(1)
}
}

// Check if docker username or docker registry strings are safe with good characters
func is_username_registry_safe(username string, serverName string) bool {
func isRegistryCredentialsSafe(username string, serverName string) error {
Copy link
Collaborator

Choose a reason for hiding this comment

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

$\color{#FFA500}Improvements: Code Robustness$

For the isRegistryCredentialsSafe function, consider returning a custom error type that includes fields for the specific validation failure (e.g., ErrLengthExceeded, ErrInvalidCharacters). This would allow for more nuanced error handling and user feedback.

if !is_username_registry_safe(username, serverName) {
fmt.Fprintf(os.Stderr, "Error: No special characters allowed in username/registry. List of good characters include: [a-z], [A-Z], [0-9], . , - , _, :")
if err := isRegistryCredentialsSafe(username, serverName); err != nil {
fmt.Fprintf(os.Stderr, err.Error())
Copy link
Collaborator

Choose a reason for hiding this comment

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

$\color{#FFA500}Improvements: Code Refactoring$

The fmt.Fprintf(os.Stderr, err.Error()) pattern is used multiple times. Consider creating a utility function for error reporting to standardize error handling and make the code cleaner.

@nex-maximus
Copy link
Collaborator

Preparing code suggestions...

Comment on lines 46 to 48
}
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

$\color{#FFA500}Improvements: Code Robustness$


Suggestion: Refactor the error handling to return errors instead of exiting the process directly. This allows for more granular error handling and recovery by the caller.
NOTE: Ensure that the suggested code is comprehensive. This serves as an example of the code you could use. The user should verify it after accepting the suggestion.

Suggested change
}
}
if err := composeDown(util.ExecCommandWrap{}, instanceName); err != nil {
return err
}
return nil

Comment on lines 51 to 54
func (compose *ComposeInfo) DownWithFile(instanceName string, fileName string) {
if err := composeDownWithFile(util.ExecCommandWrap{}, instanceName, fileName); err != nil {
osExit(1)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

$\color{#FFA500}Improvements: Code Robustness$


Suggestion: Validate the instanceName and fileName parameters to ensure they are not empty before proceeding with operations, enhancing error handling and user feedback.
NOTE: Ensure that the suggested code is comprehensive. This serves as an example of the code you could use. The user should verify it after accepting the suggestion.

Suggested change
func (compose *ComposeInfo) DownWithFile(instanceName string, fileName string) {
if err := composeDownWithFile(util.ExecCommandWrap{}, instanceName, fileName); err != nil {
osExit(1)
}
func (compose *ComposeInfo) DownWithFile(instanceName string, fileName string) {
if instanceName == "" || fileName == "" {
return fmt.Errorf("instanceName and fileName cannot be empty")
}
if err := composeDownWithFile(util.ExecCommandWrap{}, instanceName, fileName); err != nil {
return err
}
return nil
}

Comment on lines +20 to +22
if actual.Error() != expected.Error() {
t.Errorf("wrong error: %v", actual)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

$\color{#FFA500}Improvements: Code Robustness$


Suggestion: Replace direct string comparison for errors with type assertions or specific error type checks where possible.
NOTE: Ensure that the suggested code is comprehensive. This serves as an example of the code you could use. The user should verify it after accepting the suggestion.

Suggested change
if actual.Error() != expected.Error() {
t.Errorf("wrong error: %v", actual)
}
var err *MyCustomError
if errors.As(actual, &err) {
assert.Equal(t, expected.Error(), err.Error())
} else {
t.Errorf("expected error of type MyCustomError, got %T", actual)
}

Comment on lines +18 to +26
expected := errors.New("error: docker registry username can not exceed 30 characters")
actual := isRegistryCredentialsSafe("usernameusernameusernameusername", "servername")
if actual.Error() != expected.Error() {
t.Errorf("wrong error: %v", actual)
}
}

func Test_is_username_registry_safe_fail(t *testing.T) {
result :=is_username_registry_safe("username*", "servername")
assert.Equal(t, false, result)

func TestReturnErrorServerNameTooLong(t *testing.T) {
expected := errors.New("error: docker registry servername can not exceed 253 characters")
Copy link
Collaborator

Choose a reason for hiding this comment

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

$\color{#FFA500}Improvements: Code Maintainability$


Suggestion: Avoid using magic numbers directly in tests by defining them as constants or using descriptive variables.
NOTE: Ensure that the suggested code is comprehensive. This serves as an example of the code you could use. The user should verify it after accepting the suggestion.

Suggested change
expected := errors.New("error: docker registry username can not exceed 30 characters")
actual := isRegistryCredentialsSafe("usernameusernameusernameusername", "servername")
if actual.Error() != expected.Error() {
t.Errorf("wrong error: %v", actual)
}
}
func Test_is_username_registry_safe_fail(t *testing.T) {
result :=is_username_registry_safe("username*", "servername")
assert.Equal(t, false, result)
func TestReturnErrorServerNameTooLong(t *testing.T) {
expected := errors.New("error: docker registry servername can not exceed 253 characters")
const maxUsernameLength = 30
const maxServerNameLength = 253
expectedUsernameError := fmt.Errorf("error: docker registry username can not exceed %d characters", maxUsernameLength)
expectedServernameError := fmt.Errorf("error: docker registry servername can not exceed %d characters", maxServerNameLength)

assert.Equal(t, isRegistryCredentialsSafe("username", "servername"), nil)}

func TestReturnErrorUserNameTooLong(t *testing.T) {
expected := errors.New("error: docker registry username can not exceed 30 characters")
Copy link
Collaborator

Choose a reason for hiding this comment

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

$\color{#FFD700}Coding Style$


Suggestion: Ensure consistent use of error messages, specifically regarding the character limit error message.
NOTE: Ensure that the suggested code is comprehensive. This serves as an example of the code you could use. The user should verify it after accepting the suggestion.

Suggested change
expected := errors.New("error: docker registry username can not exceed 30 characters")
expected := errors.New("error: docker registry username cannot exceed 30 characters")

Comment on lines +27 to +28
actual := isRegistryCredentialsSafe("username",
"servernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservername")
Copy link
Collaborator

Choose a reason for hiding this comment

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

$\color{#FFA500}Improvements: Code Maintainability$


Suggestion: Implement a helper function for creating long strings to avoid hardcoding long strings directly in test cases.
NOTE: Ensure that the suggested code is comprehensive. This serves as an example of the code you could use. The user should verify it after accepting the suggestion.

Suggested change
actual := isRegistryCredentialsSafe("username",
"servernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservernameservername")
longServerName := strings.Repeat("servername", 26) // Creates a long server name for testing
actual := isRegistryCredentialsSafe("username", longServerName)

Comment on lines +20 to +22
if actual.Error() != expected.Error() {
t.Errorf("wrong error: %v", actual)
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

$\color{#FFA500}Improvements: Code Refactoring$


Suggestion: Refactor error comparison in tests to use assert.Error for consistency and clarity.
NOTE: Ensure that the suggested code is comprehensive. This serves as an example of the code you could use. The user should verify it after accepting the suggestion.

Suggested change
if actual.Error() != expected.Error() {
t.Errorf("wrong error: %v", actual)
}
assert.Error(t, actual, expected.Error())

@nex-maximus
Copy link
Collaborator

$\color{#FFA500}CODE \space REVIEW \space ENDED$

If you wish to include any dependent files which are not in the PR, add the details in:
1. .github/dependent_files.json
(or)
2. pass it via the comment in this format -> /review -all --dependent_files=file1.py, scr2/file2.py

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.

3 participants