#!/usr/bin/env python3 """ Консольный интерфейс утилиты «iss-ledger» (ИБ 3.0) Управление неизменяемым криптографическим журналом по ГОСТ Р 34.11-2012 («Стрибог-256»). """ import argparse import sys from .ledger import IssLedger117 from .report_fstec import generate_fstec_report __version__ = "1.1.1" def main(): parser = argparse.ArgumentParser( prog="iss-ledger", description="Журнал действий ИИ-агентов с хеш-цепочкой по ГОСТ Р 34.11-2012", ) parser.add_argument( "--version", action="version", version=f"iss-ledger {__version__}", ) parser.add_argument( "--file", "-f", default="audit_fstec117.jsonl", help="Путь к файлу журнала (по умолчанию: audit_fstec117.jsonl)", ) subparsers = parser.add_subparsers(dest="command", help="Команды") # init init_parser = subparsers.add_parser("init", help="Инициализировать новый журнал") # append append_parser = subparsers.add_parser("append", help="Записать событие в журнал") append_parser.add_argument("--agent", required=True, help="Идентификатор агента") append_parser.add_argument("--action", required=True, help="Действие (например: tool_call:bash, tool_call:sql)") append_parser.add_argument("--target", required=True, help="Целевой объект (путь, таблица, хост)") append_parser.add_argument("--verdict", choices=["PERMIT", "BLOCK", "AUDIT"], default="PERMIT", help="Вердикт") append_parser.add_argument("--reason", default="Policy approved", help="Обоснование вердикта или причина отказа") append_parser.add_argument("--payload", default="", help="Параметры/тело запроса (строка или JSON)") # verify verify_parser = subparsers.add_parser("verify", help="Проверить математическую целостность журнала") # report report_parser = subparsers.add_parser("report", help="Сформировать сводку по журналу (рабочий документ, не акт и не заключение)") report_parser.add_argument("--org", default="Организация", help="Наименование организации") report_parser.add_argument("--system", default="Контур ИИ и Агентных систем", help="Наименование системы") report_parser.add_argument("--category", default="не указана", help="Категория значимости объекта — со слов организации") report_parser.add_argument("--out", "-o", help="Сохранить отчет в файл (по умолчанию: вывод в stdout)") args = parser.parse_args() if not args.command: parser.print_help() sys.exit(1) ledger = IssLedger117(args.file) if args.command == "init": print(f"[+] Журнал инициализирован: {ledger.filepath}") elif args.command == "append": entry = ledger.append( agent_id=args.agent, action=args.action, target=args.target, verdict=args.verdict, reason=args.reason, payload=args.payload, ) print(f"[+] Запись #{entry['index']} добавлена:") print(f" Вердикт: {entry['verdict']}") print(f" Хеш блока: {entry['entry_hash']}") elif args.command == "verify": is_valid, count, msg = ledger.verify() if is_valid: print(f"[OK] {msg}") stats = ledger.get_stats() print(f" Всего событий: {stats['total_records']} (PERMIT: {stats['permits']}, BLOCK: {stats['blocks']})") print(f" Хеш среза: {stats['latest_hash']}") sys.exit(0) else: print(f"[FAIL] {msg}") sys.exit(2) elif args.command == "report": report_text = generate_fstec_report( ledger=ledger, organization=args.org, system_name=args.system, category_kii=args.category, ) if args.out: with open(args.out, "w", encoding="utf-8") as f: f.write(report_text) print(f"[+] Сводка по журналу сохранена в: {args.out}") else: print(report_text) if __name__ == "__main__": main()