fix(alembic): bridge ghost migration 2026_05_28_add_tool_definition_manifests
The production database was stamped with a migration that no longer exists in the codebase (created on another branch, applied, then removed). This adds a no-op bridge migration so Alembic can reconcile the DB state. - Create bridge migration 2026_05_28_add_tool_definition_manifests (no-op) - Re-chain terminal_sessions migration to depend on the bridge - Fixes startup failure: Can't locate revision identified by ...
This commit is contained in:
+1
-1
File diff suppressed because one or more lines are too long
@@ -6,16 +6,16 @@ Create Date: 2026-05-28
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
from collections.abc import Sequence
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "2026_05_28_add_terminal_sessions"
|
||||
down_revision: Union[str, None] = "20260527_160017_add_pi_agent"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
down_revision: str | None = "2026_05_28_add_tool_definition_manifests"
|
||||
branch_labels: str | Sequence[str] | None = None
|
||||
depends_on: str | Sequence[str] | None = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
"""bridge: add_tool_definition_manifests (ghost migration)
|
||||
|
||||
Revision ID: 2026_05_28_add_tool_definition_manifests
|
||||
Revises: 20260527_160017_add_pi_agent
|
||||
Create Date: 2026-05-28
|
||||
|
||||
This is a no-op bridge migration. The original migration was created on
|
||||
another branch and applied to the production database, but the file was
|
||||
subsequently removed. This bridge allows Alembic to reconcile the DB
|
||||
state with the local revision history.
|
||||
|
||||
"""
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "2026_05_28_add_tool_definition_manifests"
|
||||
down_revision: str | None = "20260527_160017_add_pi_agent"
|
||||
branch_labels: str | Sequence[str] | None = None
|
||||
depends_on: str | Sequence[str] | None = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# No-op: this migration was already applied on the target database.
|
||||
# If the schema was actually changed by the original migration,
|
||||
# those changes must be preserved manually or via a separate migration.
|
||||
pass
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# No-op: cannot safely reverse a migration whose original operations
|
||||
# are unknown.
|
||||
pass
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -2907,7 +2907,9 @@ a.nav-item,
|
||||
/* Mobile auto-hide header and tabs */
|
||||
.terminal-page.mobile .terminal-page-header,
|
||||
.mobile-tabs-container {
|
||||
transition: transform 0.3s ease, opacity 0.3s ease;
|
||||
transition:
|
||||
transform 0.3s ease,
|
||||
opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.terminal-page.mobile .terminal-page-header.hidden,
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
# Fix ghost migration on production server
|
||||
# Run this INSIDE the api container or on the server
|
||||
|
||||
echo "=== Checking for ghost migration file ==="
|
||||
find /app/alembic/versions -name "*tool_definition*" 2>/dev/null
|
||||
|
||||
echo ""
|
||||
echo "=== Current alembic_version in DB ==="
|
||||
psql "$DATABASE_URL" -c "SELECT * FROM alembic_version;"
|
||||
|
||||
echo ""
|
||||
echo "=== Checking if tool_types has definition_manifests column ==="
|
||||
psql "$DATABASE_URL" -c "\d tool_types" | grep -i manifest
|
||||
|
||||
echo ""
|
||||
echo "=== Our known migration heads ==="
|
||||
grep -r "revision.*=" /app/alembic/versions/*.py | grep "2026_05_28"
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Securely update the PostgreSQL password for the headquarter database user.
|
||||
|
||||
Usage:
|
||||
python scripts/update_db_password.py
|
||||
|
||||
The script will prompt for the new password (no echo) and update it via the
|
||||
running hq-postgres Docker container.
|
||||
|
||||
After running, remember to update your .env file:
|
||||
POSTGRES_PASSWORD=<your-new-password>
|
||||
"""
|
||||
|
||||
import getpass
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# Prompt for new password securely (no echo to terminal)
|
||||
new_password = getpass.getpass("Enter new password for 'headquarter' user: ")
|
||||
if not new_password:
|
||||
print("Error: password cannot be empty.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
confirm = getpass.getpass("Confirm new password: ")
|
||||
if new_password != confirm:
|
||||
print("Error: passwords do not match.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Use psql inside the running postgres container to avoid exposing
|
||||
# the password in host shell history.
|
||||
sql = f"ALTER ROLE headquarter WITH PASSWORD '{new_password}';"
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[
|
||||
"docker",
|
||||
"exec",
|
||||
"-i",
|
||||
"hq-postgres",
|
||||
"psql",
|
||||
"-U",
|
||||
"headquarter",
|
||||
"-d",
|
||||
"headquarter",
|
||||
"-c",
|
||||
sql,
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
)
|
||||
print(result.stdout.strip())
|
||||
print("\n✅ Password updated successfully.")
|
||||
print("\n⚠️ IMPORTANT: Update your .env file:")
|
||||
print(f" POSTGRES_PASSWORD={new_password}")
|
||||
print("\n⚠️ Then restart the application containers:")
|
||||
print(" docker compose up -d")
|
||||
except subprocess.CalledProcessError as exc:
|
||||
print(f"Error: {exc.stderr or exc.stdout}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
except FileNotFoundError:
|
||||
print(
|
||||
"Error: 'docker' command not found. Is Docker installed and running?",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user