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

Security: switch to using image's digest sha256 value on promotion #249

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

zzaakiirr
Copy link
Contributor

@zzaakiirr zzaakiirr commented Dec 13, 2024

What does this PR do?

This PR:

  1. Adds new --use-digest-ref option to cpflow deploy image command. If it's true then docker image's reference will include image's digest (SHA256 value)
  2. Passes --use-digest-ref option to cpflow deploy image command by default for cpflow promote-app-from-upstream command

Issue

#232

Tests

RSpec specific pipeline - https://github.com/shakacode/control-plane-flow/actions/runs/12348992443/job/34458894605

image

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added support for using image digests during image promotion and deployment.
    • Introduced new configuration options for use_digest_image_ref in deployment commands.
    • Enhanced command options for improved configurability, including the --docker-context option.
  • Bug Fixes

    • Resolved issues with command execution failures and image deletion.
  • Documentation

    • Updated documentation to reflect new command options and pre-deletion hook functionality.
  • Tests

    • Introduced new test cases to validate the functionality of the --use-digest-image-ref option.
    • Enhanced assertions for deployment logging in various scenarios.

@zzaakiirr zzaakiirr self-assigned this Dec 13, 2024
Copy link

coderabbitai bot commented Dec 13, 2024

Walkthrough

The pull request introduces several modifications across multiple files, primarily enhancing command functionalities related to image deployment. Key changes include the addition of a method to utilize Docker image digests in command options, updates to the deployment logic to incorporate these digests, and refinements in error handling. Test cases have also been expanded to ensure the new features are adequately verified. The CHANGELOG.md has been updated to reflect these changes, including fixed issues and new features.

Changes

File Change Summary
CHANGELOG.md Updated with new entries under Unreleased for fixed issues and a new entry under Added for image digest.
lib/command/base.rb Added method use_digest_image_ref_option to generate an option for using Docker image digests.
lib/command/deploy_image.rb Added use_digest_image_ref_option to OPTIONS, updated call method to handle digest references, and refined error handling.
lib/command/promote_app_from_upstream.rb Updated deploy_image method to include --use-digest-image-ref in the command execution.
spec/command/deploy_image_spec.rb Introduced new context and test case for --use-digest-image-ref option in deploy-image command.
spec/command/promote_app_from_upstream_spec.rb Enhanced assertions in tests for deployment process related to release script handling.
README.md Added configuration option use_digest_image_ref: true in controlplane.yml section for my-app-production.
docs/commands.md Updated documentation for deploy-image and promote-app-from-upstream commands to include digest image references.
lib/core/config.rb Added method use_digest_image_ref? to retrieve the configuration value for digest references.
spec/dummy/.controlplane/controlplane.yml Added new application configuration dummy-test-use-digest-image-ref-{GLOBAL_IDENTIFIER} with digest reference enabled.

Possibly related issues

Possibly related PRs

Suggested reviewers

  • justin808

Poem

🐇 In the world of code, we hop and play,
With digest references, we pave the way.
Commands now clearer, errors refined,
In our rabbit hole, new features aligned.
So let’s celebrate, with a joyful cheer,
For every change brings us closer, my dear! 🥕

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@@ -32,7 +32,7 @@ def copy_image_from_upstream
def deploy_image
args = []
args.push("--run-release-phase") if config.current[:release_script]
run_cpflow_command("deploy-image", "-a", config.app, *args)
run_cpflow_command("deploy-image", "-a", config.app, "--use-digest-ref", *args)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe we should provide use_digest_ref option for promote-app-from-upstream command too - user may not want this behaviour enabled by default

raise "Image '#{image}' does not exist in the Docker repository on Control Plane " \
"(see https://console.cpln.io/console/org/#{config.org}/repository/#{config.app}). " \
"Use `cpflow build-image` first."
end

image = "#{image_details['name']}@#{image_details['digest']}" if config.options[:use_digest_ref]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

image_details["name"] contains image name and tag and we can keep the tag - it will be ignored due to existence of the digest value

@zzaakiirr
Copy link
Contributor Author

@coderabbitai review

Copy link

coderabbitai bot commented Dec 13, 2024

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
lib/command/deploy_image.rb (1)

37-37: Consider strengthening image name validation

The regex pattern could be more strict to prevent potential path traversal or malformed image names.

-          next unless container["image"].match?(%r{^/org/#{config.org}/image/#{config.app}})
+          next unless container["image"].match?(%r{^/org/#{Regexp.escape(config.org)}/image/#{Regexp.escape(config.app)}$})
spec/command/deploy_image_spec.rb (1)

53-58: Enhance digest reference testing

While the basic functionality is tested, consider adding tests for:

  1. Invalid digest formats
  2. Edge cases with special characters in image names
  3. Integration with release phase

Example test cases to add:

it "validates digest format" do
  # Mock invalid digest
  allow(cp).to receive(:fetch_image_details)
    .and_return({'name' => app, 'digest' => 'invalid-digest'})
    
  result = run_cpflow_command("deploy-image", "-a", app, "--use-digest-ref")
  
  expect(result[:status]).not_to eq(0)
  expect(result[:stderr]).to include("Invalid digest format")
end

it "handles special characters in image names" do
  special_app = "app-with.special_chars"
  # Test setup...
end

it "works with release phase", :slow do
  result = run_cpflow_command("deploy-image", "-a", app, 
    "--use-digest-ref", "--run-release-phase")
  
  expect(result[:status]).to eq(0)
  expect(result[:stderr]).to include("Finished running release script")
  expect(result[:stderr]).to match(/sha256:[a-fA-F0-9]{64}/)
end
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f8b544d and fc4d4a6.

📒 Files selected for processing (6)
  • CHANGELOG.md (1 hunks)
  • lib/command/base.rb (1 hunks)
  • lib/command/deploy_image.rb (2 hunks)
  • lib/command/promote_app_from_upstream.rb (1 hunks)
  • spec/command/deploy_image_spec.rb (1 hunks)
  • spec/command/promote_app_from_upstream_spec.rb (3 hunks)
🔇 Additional comments (9)
lib/command/deploy_image.rb (3)

8-9: LGTM: Option addition is clean and follows existing pattern

The use_digest_ref_option is properly added to the OPTIONS array, maintaining consistency with existing options.


25-30: Improved error handling for missing images

The error handling has been enhanced with:

  • Clear error message with specific image details
  • Helpful link to the console
  • Actionable suggestion for resolution

32-32: Verify digest reference construction

The image reference construction looks correct but should be tested with various image name formats.

✅ Verification successful

Image digest reference construction verified

The implementation is correct and well-tested:

  • The digest reference format name@digest is consistently used across the codebase
  • Test files verify the pattern with proper SHA256 digest format (sha256:[a-fA-F0-9]{64})
  • The feature is properly integrated with a --use-digest-ref CLI option
  • The functionality is tested in both direct deployment (deploy-image) and promotion (promote-app-from-upstream) scenarios
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for different image reference patterns in tests
rg -g '*.rb' 'image.*@sha256:[a-fA-F0-9]{64}'

Length of output: 47


Script:

#!/bin/bash
# Let's search for test files that might contain image digest references
fd -e rb -e spec test spec

# Then search for any image reference patterns in the test files
rg -g '*.rb' -g '*.spec' 'image.*@' 

# Also search for test examples or fixtures with digest references
rg -g '*.rb' -g '*.yml' -g '*.yaml' 'digest'

# Look for actual implementation of digest reference handling
ast-grep --pattern 'use_digest_ref'

Length of output: 3564

lib/command/promote_app_from_upstream.rb (1)

35-35: Consider making digest reference configurable

While using digest references by default is good for security, some users might need to opt-out. Consider adding a configuration option or command flag to disable this behavior.

spec/command/promote_app_from_upstream_spec.rb (3)

33-33: LGTM: Proper verification of SHA256 digest in deployment message.

The test correctly verifies that the deployment message includes the image reference with SHA256 digest format.


68-68: LGTM: Proper negative test for deployment failure.

The test correctly verifies that no deployment message is shown when the release script fails.


103-103: LGTM: Comprehensive test coverage for successful deployment.

The test properly verifies the deployment message with SHA256 digest in the successful case, maintaining consistency with other test cases.

lib/command/base.rb (1)

446-455: LGTM: Well-structured option method for digest reference.

The implementation follows the established pattern for option methods and provides clear documentation.

CHANGELOG.md (1)

25-28: LGTM: Clear and well-formatted changelog entry.

The entry properly documents the change and follows the project's changelog format.

@zzaakiirr zzaakiirr force-pushed the 232-use-image-digest-on-promotion-from-upstream branch from fc4d4a6 to 083ea58 Compare December 16, 2024 08:46
@zzaakiirr zzaakiirr marked this pull request as ready for review December 16, 2024 09:16
@zzaakiirr zzaakiirr linked an issue Dec 16, 2024 that may be closed by this pull request
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fc4d4a6 and 083ea58.

📒 Files selected for processing (6)
  • CHANGELOG.md (1 hunks)
  • lib/command/base.rb (1 hunks)
  • lib/command/deploy_image.rb (2 hunks)
  • lib/command/promote_app_from_upstream.rb (1 hunks)
  • spec/command/deploy_image_spec.rb (1 hunks)
  • spec/command/promote_app_from_upstream_spec.rb (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • lib/command/base.rb
  • CHANGELOG.md
  • spec/command/promote_app_from_upstream_spec.rb
  • lib/command/promote_app_from_upstream.rb
  • spec/command/deploy_image_spec.rb
🔇 Additional comments (2)
lib/command/deploy_image.rb (2)

8-9: LGTM: Command option addition is well-placed

The addition of use_digest_ref_option to the OPTIONS array aligns with the PR's security objectives.


25-30: LGTM: Robust error handling implementation

The error handling for non-existent images is well implemented with a clear, actionable error message that includes the relevant Console URL.

lib/command/deploy_image.rb Outdated Show resolved Hide resolved
@dzirtusss
Copy link
Collaborator

Hi, I guess it is dangerous to switch existing default behaviour all at once.

Overall, it should be:

  1. add new behavior as totally optional
  2. switch some test production apps see if no issues vs previous way (which may take some time to pop up)
  3. deprecate
  4. switch default in new major release

Sure, sometimes can be shortened, but better follow the process, at least don't break. Especially for libs that are used in scripting. I mean some people may be using tags and relying on old way in "unimaginable" ways in their scripts.

Can we please change this PR to be totally optional?

Plus it may be not worth only an command-line option, but a yaml option as well. I mean, personally, I'd better configure this in the yaml as an app default vs updating all the cmd calls.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (6)
spec/dummy/.controlplane/controlplane.yml (1)

136-141: Consider adding documentation comments.

While the configuration is correctly structured, consider adding YAML comments to document:

  • The security implications of using digest references
  • When to enable this option
  • Migration considerations for existing deployments

Example addition:

 dummy-test-use-digest-image-ref-{GLOBAL_IDENTIFIER}:
+    # Enables secure image deployment using SHA256 digest references
+    # Benefits: Prevents tag hijacking and ensures image immutability
+    # Note: Enable this after testing with your CI/CD pipeline
    <<: *common
lib/command/deploy_image.rb (2)

29-33: Enhance error message clarity.

Consider making the error message more specific about the image reference format.

-        raise "Image '#{image}' does not exist in the Docker repository on Control Plane " \
+        raise "Image reference '#{image}' does not exist in the Docker repository on Control Plane " \
               "(see https://console.cpln.io/console/org/#{config.org}/repository/#{config.app}). " \
               "Use `cpflow build-image` first."

35-35: Consider adding debug logging for reference changes.

When switching to digest reference, it would be helpful to log this security enhancement for audit purposes.

-      image = "#{image_details['name']}@#{image_details['digest']}" if config.use_digest_image_ref?
+      if config.use_digest_image_ref?
+        original_ref = image
+        image = "#{image_details['name']}@#{image_details['digest']}"
+        Shell.debug("Enhanced security: Using digest reference instead of tag")
+        Shell.debug("Original: #{original_ref}")
+        Shell.debug("Digest:   #{image}")
+      end
docs/commands.md (1)

130-130: Consider documenting the security benefits of using digest references

The documentation should explain why using digest references is more secure than using tags. This would help users understand the importance of this feature and make informed decisions about using it.

Add a note explaining that digest references provide immutable, cryptographically secure references to exact image content, preventing potential supply chain attacks through tag manipulation.

README.md (2)

319-321: Enhance configuration documentation with security context

The use_digest_image_ref configuration is correctly placed in the production app section, but its documentation could be improved.

Consider expanding the comment to:

-    # Used by the `cpflow deploy-image` and `cpflow promote-app-from-upstream` commands to include Docker image's digest (SHA256 value) in its reference.
+    # Security enhancement: When true, uses cryptographically secure SHA256 digest references instead of mutable tags
+    # for Docker images. This prevents supply chain attacks through tag manipulation and ensures exact image deployment.
+    # Recommended for production environments and any deployment where image integrity is critical.
     use_digest_image_ref: true

319-321: Consider a phased rollout strategy for digest references

The current implementation changes default behavior for promote-app-from-upstream, which could impact existing deployments. Consider implementing a phased approach as suggested in the PR comments:

  1. Keep the current behavior as default
  2. Allow opt-in through configuration
  3. Add deprecation warnings for the old behavior
  4. Change defaults in a major version release

This would provide a smoother transition path while maintaining security benefits.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 083ea58 and 9384ae2.

📒 Files selected for processing (10)
  • CHANGELOG.md (1 hunks)
  • README.md (1 hunks)
  • docs/commands.md (2 hunks)
  • lib/command/base.rb (1 hunks)
  • lib/command/deploy_image.rb (1 hunks)
  • lib/command/promote_app_from_upstream.rb (3 hunks)
  • lib/core/config.rb (1 hunks)
  • spec/command/deploy_image_spec.rb (1 hunks)
  • spec/command/promote_app_from_upstream_spec.rb (2 hunks)
  • spec/dummy/.controlplane/controlplane.yml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • spec/command/deploy_image_spec.rb
  • lib/command/promote_app_from_upstream.rb
  • lib/command/base.rb
  • spec/command/promote_app_from_upstream_spec.rb
  • CHANGELOG.md
🧰 Additional context used
📓 Learnings (1)
lib/command/deploy_image.rb (1)
Learnt from: zzaakiirr
PR: shakacode/control-plane-flow#249
File: lib/command/deploy_image.rb:32-32
Timestamp: 2024-12-16T11:52:41.732Z
Learning: In the `DeployImage` class (`lib/command/deploy_image.rb`), the `image_details` hash returned by `cp.fetch_image_details(image)` always contains a non-empty `digest` key.
🔇 Additional comments (2)
lib/core/config.rb (1)

148-150: LGTM! Well-structured configuration method.

The implementation follows the established pattern of checking both the current configuration and command options, with proper nil-safety using the safe navigation operator.

lib/command/deploy_image.rb (1)

28-35: LGTM! Secure implementation of digest references.

The implementation correctly:

  • Fetches image details
  • Validates image existence
  • Constructs digest reference when configured

docs/commands.md Show resolved Hide resolved
@zzaakiirr
Copy link
Contributor Author

@dzirtusss Hi! I applied your suggestions, can you take another look?

  1. Using digest in Docker image's reference is now optional
  2. This option can also be configured in .controlplane YAML file

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Switch to using digest sha256 value for promotion for security
2 participants