feat(init): add preview_changes method to show read-only schema init diff

Adds preview_changes method to utils/neo4j-schema-init.py. Performs
read-only queries against the live database to compare current state
against the v2.3.0 schema spec. Reports expected constraints, indexes,
and sample nodes/relationships by team.
This commit is contained in:
2026-05-20 07:34:05 -04:00
parent 812473ad97
commit 3e68764368
3 changed files with 312 additions and 48 deletions

View File

@@ -123,21 +123,65 @@ EXPECTED_INDEX_SAMPLES = [
]
def _mask_password(pw):
"""Mask a password for display: keep first and last char, hide the middle."""
if not pw:
return "(empty)"
if len(pw) <= 2:
return "*" * len(pw)
return f"{pw[0]}{'*' * (len(pw) - 2)}{pw[-1]} ({len(pw)} chars)"
def get_credentials(args):
uri = args.uri or os.environ.get("NEO4J_URI")
if not uri:
uri = input("Neo4j URI [bolt://localhost:7687]: ").strip() or "bolt://localhost:7687"
"""
Collect Neo4j credentials by prompting for each value sequentially.
user = args.user or os.environ.get("NEO4J_USER")
if not user:
user = input("Neo4j username [neo4j]: ").strip() or "neo4j"
For each of URI, username, password: show the current default (from CLI
arg, env var, or built-in fallback) in brackets; user hits Enter to
accept or types a new value to override. Password prompt uses getpass
so it isn't echoed and doesn't land in shell history.
password = os.environ.get("NEO4J_PASSWORD")
Finally, print a summary (password masked) and ask for final confirmation.
If the user declines, exit cleanly without touching the database.
"""
print()
print("" * 60)
print(" Neo4j Connection")
print("" * 60)
# URI
uri_default = args.uri or os.environ.get("NEO4J_URI") or "bolt://localhost:7687"
uri = input(f" Neo4j URI [{uri_default}]: ").strip() or uri_default
# Username
user_default = args.user or os.environ.get("NEO4J_USER") or "neo4j"
user = input(f" Neo4j username [{user_default}]: ").strip() or user_default
# Password (always via getpass, never echoed)
env_password = os.environ.get("NEO4J_PASSWORD")
if env_password:
prompt = " Neo4j password [from $NEO4J_PASSWORD, Enter to accept]: "
else:
prompt = " Neo4j password: "
password = getpass.getpass(prompt) or env_password or ""
if not password:
password = getpass.getpass("Neo4j password: ")
if not password:
print("ERROR: Password is required")
sys.exit(1)
print("ERROR: Password is required")
sys.exit(1)
# Summary + confirm
print()
print("" * 60)
print(" Connection summary")
print("" * 60)
print(f" URI: {uri}")
print(f" User: {user}")
print(f" Password: {_mask_password(password)}")
print("" * 60)
print(" Validation is read-only — no graph data will be modified.")
confirm = input("Proceed with these credentials? [Y/n]: ").strip().lower()
if confirm and confirm not in ("y", "yes"):
print("Cancelled by user.")
sys.exit(0)
return uri, user, password