Initial SQL-only 1C adapter baseline
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
DEFAULT_POLICY = ROOT / "plugins" / "1c" / "connector" / "policies" / "read-only-query.yaml"
|
||||
|
||||
|
||||
def load_policy(path: Path) -> dict:
|
||||
with path.open("r", encoding="utf-8") as handle:
|
||||
data = yaml.safe_load(handle)
|
||||
if not isinstance(data, dict):
|
||||
raise ValueError(f"{path} must contain a YAML mapping")
|
||||
return data
|
||||
|
||||
|
||||
def validate_query(query: str, policy: dict) -> list[str]:
|
||||
errors = []
|
||||
normalized = query.strip()
|
||||
if not normalized:
|
||||
return ["query is empty"]
|
||||
if not re.match(r"(?is)^\s*(ВЫБРАТЬ|SELECT)\b", normalized):
|
||||
errors.append("only SELECT/ВЫБРАТЬ queries are allowed")
|
||||
for pattern in policy.get("deny_patterns") or []:
|
||||
if re.search(pattern, normalized):
|
||||
errors.append(f"query matches denied pattern: {pattern}")
|
||||
return errors
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Validate a read-only 1C query request.")
|
||||
parser.add_argument("--query")
|
||||
parser.add_argument("--request-json", type=Path)
|
||||
parser.add_argument("--policy", type=Path, default=DEFAULT_POLICY)
|
||||
parser.add_argument("--json", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.request_json:
|
||||
request = json.loads(args.request_json.read_text(encoding="utf-8"))
|
||||
query = request.get("query") or ""
|
||||
else:
|
||||
query = args.query or ""
|
||||
|
||||
policy = load_policy(args.policy)
|
||||
errors = validate_query(query, policy)
|
||||
result = {
|
||||
"allowed": not errors,
|
||||
"errors": errors,
|
||||
"limits": policy.get("limits") or {},
|
||||
}
|
||||
if args.json:
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
elif errors:
|
||||
print("Query is denied:", file=sys.stderr)
|
||||
for error in errors:
|
||||
print(f"- {error}", file=sys.stderr)
|
||||
else:
|
||||
print("Query is allowed.")
|
||||
return 0 if not errors else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user