-
Notifications
You must be signed in to change notification settings - Fork 227
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
Disallow creating or updating scheduler if invalid #2214
base: master
Are you sure you want to change the base?
Conversation
…or updating current scheduler.
…s if visual run under action does not return an error.
📝 WalkthroughWalkthroughThe changes made to the Changes
Assessment against linked issues
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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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.
Actionable comments posted: 5
Outside diff range and nitpick comments (2)
app/controllers/schedulers_controller.rb (2)
29-30
: Correct error message formatting to avoid unintended newlinesThe error message string spans multiple lines without proper concatenation, which can include unintended newline characters in the displayed message. To ensure the error message is formatted correctly, combine the string into a single line or use string concatenation.
Apply this diff to fix the formatting:
- flash[:error] = "Scheduler create failed. Action file does not exist or is - not readable at #{action_path}." + flash[:error] = "Scheduler create failed. Action file does not exist or is " \ + "not readable at #{action_path}."
109-110
: Correct error message formatting to avoid unintended newlinesSimilar to the issue in the
create
method, the error message here spans multiple lines without proper concatenation. To ensure the message is displayed correctly, combine the string into a single line or use string concatenation.Apply this diff to fix the formatting:
- flash[:error] = "Scheduler update failed. Action file does not exist or is - not readable at #{action_path}." + flash[:error] = "Scheduler update failed. Action file does not exist or is " \ + "not readable at #{action_path}."
Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Files selected for processing (1)
- app/controllers/schedulers_controller.rb (3 hunks)
Additional comments not posted (2)
app/controllers/schedulers_controller.rb (2)
35-44
: Robust error handling added to ensure scheduler validityThe addition of error handling in the
create
method ensures that if thetest_run_visual_scheduler
fails, the created scheduler is destroyed, and an appropriate error message is displayed. This enhances the reliability of the scheduler creation process.
106-113
: Refactor repeated file existence checks into a private methodAs mentioned earlier, the file existence and readability check here is duplicated from the
create
method. Extracting this logic into a private method will reduce duplication and improve code maintainability.
@@ -23,9 +23,25 @@ def new; end | |||
action_auth_level :create, :instructor | |||
def create | |||
@scheduler = @course.scheduler.new(scheduler_params) | |||
# Check if the action file exists and is readable | |||
action_path = Rails.root.join(scheduler_params[:action]).to_path |
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.
Can you also check that the action is within the assessment directory? See Archive.in_dir?
which for example is used in handout.rb
.
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.
Hi! Do you mean the course directory? From what I can tell schedulers are for courses, not specific assessments.
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.
Functionally this works pretty nicely! But I think there should be some refactoring of the code so that it's a bit more maintainable.
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.
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.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (1)
app/controllers/schedulers_controller.rb (1)
Line range hint
26-182
: Consider architectural improvements for better maintainabilityThe current implementation could benefit from the following architectural improvements:
- Extract scheduler validation and execution logic into a service class to improve separation of concerns
- Move allowed paths configuration to a central configuration file
- Implement a more robust error handling strategy with custom exceptions
Example service class structure:
class SchedulerService def initialize(course) @course = course end def validate_and_run(scheduler) validate_path(scheduler.action) validate_file(scheduler.action) run_visual_test(scheduler) end private def validate_path(action_path) # Path validation logic end def validate_file(action_path) # File validation logic end def run_visual_test(scheduler) # Visual test logic end end
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (1)
app/controllers/schedulers_controller.rb
(3 hunks)
🧰 Additional context used
📓 Learnings (1)
app/controllers/schedulers_controller.rb (1)
Learnt from: jhs-panda
PR: autolab/Autolab#2214
File: app/controllers/schedulers_controller.rb:131-141
Timestamp: 2024-11-13T17:02:19.398Z
Learning: The error detection logic in the `run_visual_scheduler` method in `app/controllers/schedulers_controller.rb` has changed, and string matching is no longer used.
🔇 Additional comments (1)
app/controllers/schedulers_controller.rb (1)
57-59
:
Add error handling to visual_run action
The action should handle potential exceptions from execute_action
and provide appropriate feedback to users.
def visual_run
@scheduler = Scheduler.find(params[:scheduler_id])
- @log = execute_action(@scheduler)
+ begin
+ @log = execute_action(@scheduler)
+ rescue StandardError => e
+ @log = "Error executing scheduler: #{e.message}"
+ flash[:error] = "Visual test failed"
+ end
render partial: "visual_test"
end
Likely invalid or redundant comment.
action_path = Rails.root.join(scheduler_params[:action]).to_path | ||
# Check if the action file exists, is readable, and compiles | ||
if validate_compile_action_file(action_path) | ||
if @scheduler.save | ||
# Ensure visual run is successful | ||
if run_visual_scheduler(@scheduler) | ||
flash[:success] = "Scheduler created and executed successfully!" | ||
redirect_to(course_schedulers_path(@course)) and return | ||
else | ||
@scheduler.destroy | ||
flash[:error] = "Scheduler creation failed during execution." | ||
end | ||
else | ||
flash[:error] = "Scheduler create failed. Please check all fields." | ||
end | ||
end | ||
redirect_to(new_course_scheduler_path(@course)) |
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.
Add path validation to prevent directory traversal
The current implementation using Rails.root.join
with user input could be vulnerable to path traversal attacks. Consider adding validation to ensure the action file is within the allowed course directory.
def create
@scheduler = @course.scheduler.new(scheduler_params)
+ course_dir = Rails.root.join('courses', @course.name).to_path
action_path = Rails.root.join(scheduler_params[:action]).to_path
+
+ unless action_path.start_with?(course_dir)
+ flash[:error] = "Action file must be within the course directory"
+ redirect_to(new_course_scheduler_path(@course)) and return
+ end
# Check if the action file exists, is readable, and compiles
if validate_compile_action_file(action_path)
Committable suggestion skipped: line range outside the PR's diff.
action_path = Rails.root.join(scheduler_params[:action]).to_path | ||
# Check if the action file exists, is readable, and compiles | ||
if validate_compile_action_file(action_path) | ||
previous_state = @scheduler.attributes | ||
if @scheduler.update(scheduler_params) | ||
# Ensure visual run is successful | ||
if run_visual_scheduler(@scheduler) | ||
flash[:success] = "Scheduler updated and executed successfully!" | ||
redirect_to(course_schedulers_path(@course)) and return | ||
else | ||
@scheduler.update(previous_state) # If error, revert to previous state. | ||
flash[:error] = "Scheduler update failed during execution. Reverted to previous state." | ||
end | ||
else | ||
flash[:error] = "Scheduler update failed! Please check your fields." | ||
end | ||
end | ||
redirect_to(edit_course_scheduler_path(@course, @scheduler)) |
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.
🛠️ Refactor suggestion
Use database transaction for atomic updates
The current implementation manually manages state rollback. Using a database transaction would ensure atomic updates and proper rollback of all changes.
def update
@scheduler = Scheduler.find_by(id: params[:id])
- action_path = Rails.root.join(scheduler_params[:action]).to_path
- # Check if the action file exists, is readable, and compiles
- if validate_compile_action_file(action_path)
- previous_state = @scheduler.attributes
- if @scheduler.update(scheduler_params)
- # Ensure visual run is successful
- if run_visual_scheduler(@scheduler)
- flash[:success] = "Scheduler updated and executed successfully!"
- redirect_to(course_schedulers_path(@course)) and return
- else
- @scheduler.update(previous_state) # If error, revert to previous state.
- flash[:error] = "Scheduler update failed during execution. Reverted to previous state."
- end
+ ActiveRecord::Base.transaction do
+ action_path = Rails.root.join(scheduler_params[:action]).to_path
+
+ if validate_compile_action_file(action_path)
+ if @scheduler.update(scheduler_params)
+ unless run_visual_scheduler(@scheduler)
+ raise ActiveRecord::Rollback, "Visual run failed"
+ end
+ flash[:success] = "Scheduler updated and executed successfully!"
+ redirect_to(course_schedulers_path(@course)) and return
+ end
end
- end
+ raise ActiveRecord::Rollback
+ end
+ flash[:error] ||= "Scheduler update failed"
redirect_to(edit_course_scheduler_path(@course, @scheduler))
end
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
action_path = Rails.root.join(scheduler_params[:action]).to_path | |
# Check if the action file exists, is readable, and compiles | |
if validate_compile_action_file(action_path) | |
previous_state = @scheduler.attributes | |
if @scheduler.update(scheduler_params) | |
# Ensure visual run is successful | |
if run_visual_scheduler(@scheduler) | |
flash[:success] = "Scheduler updated and executed successfully!" | |
redirect_to(course_schedulers_path(@course)) and return | |
else | |
@scheduler.update(previous_state) # If error, revert to previous state. | |
flash[:error] = "Scheduler update failed during execution. Reverted to previous state." | |
end | |
else | |
flash[:error] = "Scheduler update failed! Please check your fields." | |
end | |
end | |
redirect_to(edit_course_scheduler_path(@course, @scheduler)) | |
def update | |
@scheduler = Scheduler.find_by(id: params[:id]) | |
ActiveRecord::Base.transaction do | |
action_path = Rails.root.join(scheduler_params[:action]).to_path | |
if validate_compile_action_file(action_path) | |
if @scheduler.update(scheduler_params) | |
unless run_visual_scheduler(@scheduler) | |
raise ActiveRecord::Rollback, "Visual run failed" | |
end | |
flash[:success] = "Scheduler updated and executed successfully!" | |
redirect_to(course_schedulers_path(@course)) and return | |
end | |
end | |
raise ActiveRecord::Rollback | |
end | |
flash[:error] ||= "Scheduler update failed" | |
redirect_to(edit_course_scheduler_path(@course, @scheduler)) | |
end |
Description
When creating or updating a scheduler, tests visual run to ensure action can be loaded and works.
If visual run test works, allow scheduler creation/update.
If visual run test doesn't work on creation, delete created scheduler.
If visual run test doesn't work on update, reinstate previous scheduler prior to update attempt.
Motivation and Context
Resolves #2187
How Has This Been Tested?
Before:
Allows creation as long as inputs to Scheduler Creation filled. However, when running scheduler, gets many errors.
After:
Notes error if action does not exist or is not readable:
Notes error if action exists and is readable but cannot execute properly:
If update is not successful, notes error and reverts to previous state:
For successful actions that load properly, work when run:
Types of changes
Checklist:
overcommit --install && overcommit --sign
to use pre-commit hook for lintingOther issues / help required