Skip to content

Add rollback restoration for failed deployments#794

Merged
Bryan-Roe merged 1 commit intomainfrom
codex/add-rollback-support-for-automation
Jul 29, 2025
Merged

Add rollback restoration for failed deployments#794
Bryan-Roe merged 1 commit intomainfrom
codex/add-rollback-support-for-automation

Conversation

@Bryan-Roe
Copy link
Collaborator

@Bryan-Roe Bryan-Roe commented Jul 27, 2025

Summary

  • track the most recent backup in DeploymentAutomator
  • add _restore_backup helper to copy backup contents back into the workspace
  • record backup name in the deployment plan
  • perform automatic restoration inside _rollback_deployment

Testing

  • pytest test_direct_ai.py::test_ai_processing -s (fails: async framework plugin missing)

https://chatgpt.com/codex/tasks/task_e_6886a75b21f08322b293e242277abf2c

Summary by Sourcery

Enable automated backup tracking and restore failed deployments by recording backups and applying them during rollback.

New Features:

  • Track latest backup name and record backup_name in deployment plans
  • Add _restore_backup helper to restore the workspace from a specified backup
  • Automatically restore the last backup during rollback if available

Copilot AI review requested due to automatic review settings July 27, 2025 22:49
@sourcery-ai
Copy link

sourcery-ai bot commented Jul 27, 2025

Reviewer's Guide

This PR enhances the DeploymentAutomator to support automatic rollback by tracking and restoring from the most recent backup when a deployment fails.

Sequence diagram for deployment with automatic rollback restoration

sequenceDiagram
    participant User
    participant DeploymentAutomator
    User->>DeploymentAutomator: deploy(environment, mode)
    DeploymentAutomator->>DeploymentAutomator: _create_backup()
    DeploymentAutomator->>DeploymentAutomator: last_backup = backup_name
    DeploymentAutomator->>DeploymentAutomator: deployment_plan["backup_name"] = last_backup
    alt Deployment fails
        DeploymentAutomator->>DeploymentAutomator: _rollback_deployment(deployment_plan)
        alt last_backup exists
            DeploymentAutomator->>DeploymentAutomator: deployment_plan["rollback_backup"] = last_backup
            DeploymentAutomator->>DeploymentAutomator: _restore_backup(last_backup)
        else No backup available
            DeploymentAutomator->>DeploymentAutomator: print("No backup available for rollback")
        end
    end
Loading

File-Level Changes

Change Details Files
Track and record the most recent backup
  • Introduce last_backup attribute in initializer
  • Set last_backup when creating a backup
  • Attach backup_name to deployment_plan after backup
02-ai-workspace/scripts/deployment_automator.py
Add _restore_backup helper to restore workspace state
  • Load and validate manifest from backup directory
  • Remove existing files/directories before restoring
  • Copy files and directories back into workspace
  • Log restoration status and handle missing backups/manifests
02-ai-workspace/scripts/deployment_automator.py
Integrate automatic restoration into rollback logic
  • Check last_backup inside _rollback_deployment
  • Record rollback_backup in deployment_plan
  • Call _restore_backup for automatic restoration
  • Fallback to manual intervention message when no backup exists
02-ai-workspace/scripts/deployment_automator.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements automatic backup restoration for failed deployments by tracking the most recent backup and adding restoration capabilities to the rollback process.

  • Tracks the most recent backup in the DeploymentAutomator class instance
  • Adds a _restore_backup helper method to restore workspace from backups
  • Records the backup name in deployment plans and performs automatic restoration during rollbacks

self.deployment_dir = self.workspace_root / "09-deployment"
self.config_dir = self.workspace_root / "10-config"
self.backup_dir = self.workspace_root / "backups"
self.last_backup: Optional[str] = None
Copy link

Copilot AI Jul 27, 2025

Choose a reason for hiding this comment

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

The last_backup attribute lacks documentation. Consider adding a docstring or inline comment explaining its purpose and when it gets updated.

Suggested change
self.last_backup: Optional[str] = None
self.last_backup: Optional[str] = None # Stores the name of the most recent backup created during deployment. Updated by the `_create_backup` method.

Copilot uses AI. Check for mistakes.
src = backup_path / rel_path
dest = self.workspace_root / rel_path

if dest.exists():
Copy link

Copilot AI Jul 27, 2025

Choose a reason for hiding this comment

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

The restoration process removes existing files/directories without validation. This could lead to unintended data loss if the backup contains malicious paths or if there's a path traversal vulnerability. Consider validating that rel_path doesn't contain directory traversal sequences like '../'.

Copilot uses AI. Check for mistakes.
Comment on lines +554 to +556
if src.is_file():
shutil.copy2(src, dest)
else:
Copy link

Copilot AI Jul 27, 2025

Choose a reason for hiding this comment

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

The code attempts to copy files without ensuring the parent directories exist. If the destination directory structure doesn't exist, shutil.copy2 will fail. Consider using dest.parent.mkdir(parents=True, exist_ok=True) before copying.

Suggested change
if src.is_file():
shutil.copy2(src, dest)
else:
if src.is_file():
dest.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(src, dest)
else:
dest.parent.mkdir(parents=True, exist_ok=True)

Copilot uses AI. Check for mistakes.
Comment on lines +571 to +573
if self.last_backup:
deployment_plan["rollback_backup"] = self.last_backup
self._restore_backup(self.last_backup)
Copy link

Copilot AI Jul 27, 2025

Choose a reason for hiding this comment

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

The rollback logic uses self.last_backup but also checks for deployment_plan.get('backup_name') would be more reliable since it's explicitly tied to the current deployment. Consider using the backup name from the deployment plan instead of the instance variable.

Suggested change
if self.last_backup:
deployment_plan["rollback_backup"] = self.last_backup
self._restore_backup(self.last_backup)
backup_name = deployment_plan.get("backup_name")
if backup_name:
deployment_plan["rollback_backup"] = backup_name
self._restore_backup(backup_name)

Copilot uses AI. Check for mistakes.
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @Bryan-Roe - I've reviewed your changes - here's some feedback:

  • Use the backup_name stored in the deployment_plan to drive the restore in _rollback_deployment rather than relying on a transient self.last_backup attribute, so rollbacks remain consistent even if the automator instance is recreated.
  • Wrap the file operations in _restore_backup with try/except and emit errors or abort on failure to avoid partial restores leaving the workspace in an inconsistent state.
  • After setting deployment_plan["rollback_backup"], call _save_deployment_record to persist the rollback backup choice in the deployment history.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Use the backup_name stored in the deployment_plan to drive the restore in _rollback_deployment rather than relying on a transient self.last_backup attribute, so rollbacks remain consistent even if the automator instance is recreated.
- Wrap the file operations in _restore_backup with try/except and emit errors or abort on failure to avoid partial restores leaving the workspace in an inconsistent state.
- After setting deployment_plan["rollback_backup"], call _save_deployment_record to persist the rollback backup choice in the deployment history.

## Individual Comments

### Comment 1
<location> `02-ai-workspace/scripts/deployment_automator.py:528` </location>
<code_context>
+    def _restore_backup(self, backup_name: str):
</code_context>

<issue_to_address>
Restoration logic may overwrite files and directories without confirmation.

Unconditionally deleting files or directories risks data loss. Please add a prompt, skip option, or backup for overwritten files, or at minimum log replacements.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +528 to +537
def _restore_backup(self, backup_name: str):
"""Restore workspace from a specific backup."""
backup_path = self.backup_dir / backup_name
if not backup_path.exists():
print(f"Backup not found: {backup_name}")
return

manifest_file = backup_path / "manifest.json"
if not manifest_file.exists():
print("Backup manifest missing, cannot restore")
Copy link

Choose a reason for hiding this comment

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

suggestion (bug_risk): Restoration logic may overwrite files and directories without confirmation.

Unconditionally deleting files or directories risks data loss. Please add a prompt, skip option, or backup for overwritten files, or at minimum log replacements.

@Bryan-Roe Bryan-Roe merged commit bdd6f4f into main Jul 29, 2025
7 of 11 checks passed
@Bryan-Roe Bryan-Roe deleted the codex/add-rollback-support-for-automation branch July 29, 2025 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants