Objetivo
Section titled “Objetivo”Implementar el primer executor real del pipeline agentic: ReadonlyExecutor. Ejecuta comandos readonly (ls, cat, curl, docker ps, systemctl status, etc.) a través de subprocess.run con shell=False, validación estricta de argumentos y registro completo en audit trail.
Filosofía
Section titled “Filosofía”28.1 → planner DAG + permisos + governance28.2 → readonly executor (comandos seguros, shell=False) ← ESTAMOS AQUÍ28.3 → rollback engine28.4 → tool contracts28.5 → sandbox write simulation28.6 → rollback automatizado28.7 → approval execution gates28.8 → write execution controladaArchivos nuevos (7)
Section titled “Archivos nuevos (7)”runtime/agentic/readonly_registry.py
Section titled “runtime/agentic/readonly_registry.py”Catálogo declarativo de comandos readonly permitidos:
SAFE_READONLY_COMMANDS: dict[str, ReadonlyCommandSpec]— 27 comandos concategory,risk,local_only,requires_args_validationFORBIDDEN_READONLY_COMMANDS: set[str]— 20+ comandos prohibidosFORBIDDEN_READONLY_PATTERNS: set[str]— patrones bloqueados (systemctl restart,docker stop, etc.)DANGEROUS_OPERATORS,DANGEROUS_REDIRECTS,DANGEROUS_TOKENS— tokens bloqueados en readonlyFIND_ALLOWED_PATHS—/opt/ai-lab,/tmp,/var/log,/home/albertDOCKER_ALLOWED_SUBCOMMANDS— solops,stats,inspect,logsRFC1918_PATTERNS— solo IPs locales para curlExecutionCapabilityenum:READONLY,SANDBOX_WRITE,SYSTEM_WRITE
runtime/agentic/safe_runner.py
Section titled “runtime/agentic/safe_runner.py”Wrapper subprocess.run con shell=False:
validate_command()— validación pre-ejecución: shlex parsing, forbidden tokens, redirects, operators, args específicos por comandorun_safe()— ejecuta el comando validado, captura stdout/stderr, calcula hashes SHA-256 truncados a 16 charsSafeRunnerResult— dataclass concommand,exit_code,stdout,stderr,duration_ms,blocked,blocked_reason,stdout_hash,stderr_hash
Validaciones específicas:
- curl: no
-o/-O/--output, target solo RFC1918 - find: path explícito requerido, solo en
FIND_ALLOWED_PATHS - journalctl: no
-f/--follow,--linesmax 500 - docker: solo
ps/stats/inspect/logs, noexec/cp/compose/etc. - systemctl: solo
status/is-active/is-enabled, norestart/stop/start/etc.
runtime/agentic/execution_context.py
Section titled “runtime/agentic/execution_context.py”Contexto de ejecución para el runtime agentic:
ExecutionModeenum:SIMULATION,READONLY,SANDBOX_WRITE,AUTONOMOUSCURRENT_EXECUTION_MODE = ExecutionMode.READONLYDryRunReasonenum:FEATURE_FLAG,GOVERNANCE_BLOCK,RISK_BLOCK,READONLY_PHASERuntimeExecutionContextdataclass:execution_id,mode,phase,dry_run,dry_run_reason
runtime/agentic/readonly_policies.py
Section titled “runtime/agentic/readonly_policies.py”Políticas de governance pre-ejecución:
check_governance()— verifica intentos prohibidos (restart_service,install_package) vs comandos validadosassess_risk()— clasifica riesgo por intent/tool/targetcheck_scope()— verifica targets contra scopes permitidos
runtime/agentic/execution_audit.py
Section titled “runtime/agentic/execution_audit.py”Audit trail en JSONL:
write_execution_audit()— escribe entrada enruntime/state/execution_audit.jsonlbuild_audit_entry()— construye entrada conexecution_mode,dry_run,dry_run_reason, action, resultread_execution_audit()— lee últimas N entradasget_audit_stats()— estadísticas: total, blocked, success, failed
runtime/agentic/readonly_executor.py
Section titled “runtime/agentic/readonly_executor.py”RealReadonlyExecutor — el executor real:
- Feature flags:
ENABLE_EXECUTOR=False,DRY_RUN=Truepor defecto execute()— itera acciones del plan, aplica governance, ejecutarun_safe(), escribe audit trail- Si
DRY_RUN=True→SimulationExecutor.execute_with_context()condry_run_reason - Si
ENABLE_EXECUTOR=TrueyDRY_RUN=False→ ejecución real con shell=False
runtime/agentic/rollback_placeholder.py
Section titled “runtime/agentic/rollback_placeholder.py”Stub para FASE 28.3:
RollbackPlaceholder.rollback()→ siempresuccess=Falseconreason="rollback_not_implemented_before_FASE_28.3"
Archivos modificados (6)
Section titled “Archivos modificados (6)”runtime/agentic/executor.py
Section titled “runtime/agentic/executor.py”SimulationExecutor.execute_with_context()— nuevo método estático que simula ejecución registrandodry_run_reasonyexecution_mode
runtime/agentic/workflow_state.py
Section titled “runtime/agentic/workflow_state.py”WorkflowState.EXECUTINGañadido- Transiciones:
READY_FOR_EXECUTION → EXECUTING,SIMULATING → EXECUTING,EXECUTING → DONE/FAILED
runtime/agentic/permissions.py
Section titled “runtime/agentic/permissions.py”_CURRENT_PHASEactualizado de"28.1"a"28.2"
runtime/agentic/__init__.py
Section titled “runtime/agentic/__init__.py”- Docstring actualizado a FASE 28.2
runtime/gateway/openai_gateway.py
Section titled “runtime/gateway/openai_gateway.py”- Import de
RealReadonlyExecutor,RuntimeExecutionContext,ExecutionMode,DryRunReason - Pipeline agentic (L1433-1502) modificado:
- Si
AI_LAB_ENABLE_PLANNER=TrueyAI_LAB_PLANNER_DRY_RUN=False→RealReadonlyExecutor.execute() - Si no →
SimulationExecutor.execute_with_context()condry_run_reason - Audit event incluye
execution_mode,dry_run,dry_run_reason
- Si
runtime/llm/router_api.py
Section titled “runtime/llm/router_api.py”- 3 endpoints GET nuevos:
GET /agentic/executions— últimos N entries del audit trailGET /agentic/executions/stats— estadísticas de ejecuciónGET /agentic/state— estado actual del executor
runtime/telemetry/prometheus_metrics.py
Section titled “runtime/telemetry/prometheus_metrics.py”- 6 métricas nuevas:
ailab_executor_commands_total— comandos por resultado/riesgoailab_executor_blocked_total— bloqueos por razónailab_executor_governance_blocks_total— governance blocks por intentailab_executor_dry_run_total— dry-runs por razónailab_executor_duration_ms— duración por modoailab_executor_validation_failures_total— fallos de validación por razón
tests/test_executor_28_2.py: 84 tests, 168+ assertions.
| Sección | Tests | Cubre |
|---|---|---|
| SafeRunner Validation | 24 | allowed/forbidden commands, patterns, operators, redirects, curl/find/journalctl/docker/systemctl |
| SafeRunner Execution | 7 | run, block, hash, to_dict, timeout, shlex fail |
| ReadonlyRegistry | 8 | catalog, spec fields, forbidden overlap, patterns, RFC1918 |
| ExecutionContext | 8 | mode enum, dry_run reasons, default context, is_executable, to_dict |
| ReadonlyPolicies | 10 | governance restart/install/run, risk levels, scope check |
| ExecutionAudit | 6 | build entry, write+read, empty, stats, timestamp, phase |
| ReadonlyExecutor | 4 | flags, simulation fallback, empty plan, timeline |
| RollbackPlaceholder | 2 | not_implemented, to_dict |
| WorkflowState | 6 | EXECUTING exists, transitions |
| PermissionsPhase282 | 5 | scope allowed, classification |
| PlannerCompatibility | 5 | plan creation, action fields, timeline transitions |
Métricas
Section titled “Métricas”ailab_executor_commands_total{result="success|blocked|failed", risk="low|medium|high"}ailab_executor_blocked_total{reason="forbidden_pattern|command_not_found|etc"}ailab_executor_governance_blocks_total{intent="restart_service|install_package"}ailab_executor_dry_run_total{reason="feature_flag|readonly_phase|governance_block|risk_block"}ailab_executor_duration_ms{mode="readonly|simulating"}ailab_executor_validation_failures_total{reason="shlex_error|empty_command|etc"}CP-28.2-READONLY-EXECUTOR-STABLE