@trac3r/oh-my-god 2.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +188 -0
- package/INSTALL-VERIFICATION-INDEX.md +51 -0
- package/LICENSE +21 -0
- package/OMG-setup.sh +2549 -0
- package/QUICK-REFERENCE.md +58 -0
- package/README.md +207 -0
- package/agents/__init__.py +1 -0
- package/agents/__pycache__/model_roles.cpython-313.pyc +0 -0
- package/agents/_model_roles.yaml +26 -0
- package/agents/designer.md +67 -0
- package/agents/explore.md +60 -0
- package/agents/model_roles.py +196 -0
- package/agents/omg-api-builder.md +23 -0
- package/agents/omg-architect-mode.md +41 -0
- package/agents/omg-architect.md +13 -0
- package/agents/omg-backend-engineer.md +41 -0
- package/agents/omg-critic.md +16 -0
- package/agents/omg-database-engineer.md +41 -0
- package/agents/omg-escalation-router.md +17 -0
- package/agents/omg-executor.md +12 -0
- package/agents/omg-frontend-designer.md +41 -0
- package/agents/omg-implement-mode.md +49 -0
- package/agents/omg-infra-engineer.md +41 -0
- package/agents/omg-qa-tester.md +16 -0
- package/agents/omg-research-mode.md +41 -0
- package/agents/omg-security-auditor.md +41 -0
- package/agents/omg-testing-engineer.md +41 -0
- package/agents/plan.md +80 -0
- package/agents/quick_task.md +64 -0
- package/agents/reviewer.md +83 -0
- package/agents/task.md +71 -0
- package/bin/omg +41 -0
- package/commands/OMG:ai-commit.md +113 -0
- package/commands/OMG:api-twin.md +22 -0
- package/commands/OMG:arch.md +313 -0
- package/commands/OMG:browser.md +29 -0
- package/commands/OMG:ccg.md +22 -0
- package/commands/OMG:compat.md +57 -0
- package/commands/OMG:cost.md +181 -0
- package/commands/OMG:crazy.md +125 -0
- package/commands/OMG:create-agent.md +183 -0
- package/commands/OMG:deep-plan.md +18 -0
- package/commands/OMG:deps.md +248 -0
- package/commands/OMG:diagnose-plugins.md +33 -0
- package/commands/OMG:doctor.md +37 -0
- package/commands/OMG:domain-init.md +11 -0
- package/commands/OMG:escalate.md +52 -0
- package/commands/OMG:forge.md +103 -0
- package/commands/OMG:health-check.md +48 -0
- package/commands/OMG:init.md +134 -0
- package/commands/OMG:issue.md +56 -0
- package/commands/OMG:mode.md +44 -0
- package/commands/OMG:playwright.md +17 -0
- package/commands/OMG:preflight.md +26 -0
- package/commands/OMG:preset.md +49 -0
- package/commands/OMG:profile-review.md +58 -0
- package/commands/OMG:project-init.md +11 -0
- package/commands/OMG:ralph-start.md +43 -0
- package/commands/OMG:ralph-stop.md +23 -0
- package/commands/OMG:security-check.md +28 -0
- package/commands/OMG:session-branch.md +101 -0
- package/commands/OMG:session-fork.md +57 -0
- package/commands/OMG:session-merge.md +138 -0
- package/commands/OMG:setup.md +82 -0
- package/commands/OMG:ship.md +18 -0
- package/commands/OMG:stats.md +225 -0
- package/commands/OMG:teams.md +54 -0
- package/commands/OMG:theme.md +44 -0
- package/commands/OMG:validate.md +59 -0
- package/commands/__init__.py +1 -0
- package/docs/command-surface.md +55 -0
- package/docs/install/claude-code.md +53 -0
- package/docs/install/codex.md +45 -0
- package/docs/install/gemini.md +43 -0
- package/docs/install/github-action.md +81 -0
- package/docs/install/github-app-required-checks.md +107 -0
- package/docs/install/github-app.md +161 -0
- package/docs/install/kimi.md +43 -0
- package/docs/install/opencode.md +38 -0
- package/docs/proof.md +182 -0
- package/hooks/__init__.py +0 -0
- package/hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- package/hooks/__pycache__/_agent_registry.cpython-313.pyc +0 -0
- package/hooks/__pycache__/_analytics.cpython-313.pyc +0 -0
- package/hooks/__pycache__/_budget.cpython-313.pyc +0 -0
- package/hooks/__pycache__/_common.cpython-313.pyc +0 -0
- package/hooks/__pycache__/_compression_optimizer.cpython-313.pyc +0 -0
- package/hooks/__pycache__/_cost_ledger.cpython-313.pyc +0 -0
- package/hooks/__pycache__/_learnings.cpython-313.pyc +0 -0
- package/hooks/__pycache__/_memory.cpython-313.pyc +0 -0
- package/hooks/__pycache__/_post_write.cpython-313.pyc +0 -0
- package/hooks/__pycache__/_protected_context.cpython-313.pyc +0 -0
- package/hooks/__pycache__/_token_counter.cpython-313.pyc +0 -0
- package/hooks/__pycache__/branch_manager.cpython-313.pyc +0 -0
- package/hooks/__pycache__/budget_governor.cpython-313.pyc +0 -0
- package/hooks/__pycache__/circuit-breaker.cpython-313.pyc +0 -0
- package/hooks/__pycache__/compression_feedback.cpython-313.pyc +0 -0
- package/hooks/__pycache__/config-guard.cpython-313.pyc +0 -0
- package/hooks/__pycache__/context_pressure.cpython-313.pyc +0 -0
- package/hooks/__pycache__/credential_store.cpython-313.pyc +0 -0
- package/hooks/__pycache__/fetch-rate-limits.cpython-313.pyc +0 -0
- package/hooks/__pycache__/firewall.cpython-313.pyc +0 -0
- package/hooks/__pycache__/hashline-formatter-bridge.cpython-313.pyc +0 -0
- package/hooks/__pycache__/hashline-injector.cpython-313.pyc +0 -0
- package/hooks/__pycache__/hashline-validator.cpython-313.pyc +0 -0
- package/hooks/__pycache__/idle-detector.cpython-313.pyc +0 -0
- package/hooks/__pycache__/instructions-loaded.cpython-313.pyc +0 -0
- package/hooks/__pycache__/intentgate-keyword-detector.cpython-313.pyc +0 -0
- package/hooks/__pycache__/magic-keyword-router.cpython-313.pyc +0 -0
- package/hooks/__pycache__/policy_engine.cpython-313.pyc +0 -0
- package/hooks/__pycache__/post-tool-failure.cpython-313.pyc +0 -0
- package/hooks/__pycache__/post-write.cpython-313.pyc +0 -0
- package/hooks/__pycache__/post_write.cpython-313.pyc +0 -0
- package/hooks/__pycache__/pre-compact.cpython-313.pyc +0 -0
- package/hooks/__pycache__/pre-tool-inject.cpython-313.pyc +0 -0
- package/hooks/__pycache__/prompt-enhancer.cpython-313.pyc +0 -0
- package/hooks/__pycache__/quality-runner.cpython-313.pyc +0 -0
- package/hooks/__pycache__/query.cpython-313.pyc +0 -0
- package/hooks/__pycache__/secret-guard.cpython-313.pyc +0 -0
- package/hooks/__pycache__/secret_audit.cpython-313.pyc +0 -0
- package/hooks/__pycache__/security_validators.cpython-313.pyc +0 -0
- package/hooks/__pycache__/session-end-capture.cpython-313.pyc +0 -0
- package/hooks/__pycache__/session-start.cpython-313.pyc +0 -0
- package/hooks/__pycache__/setup_wizard.cpython-313.pyc +0 -0
- package/hooks/__pycache__/shadow_manager.cpython-313.pyc +0 -0
- package/hooks/__pycache__/state_migration.cpython-313.pyc +0 -0
- package/hooks/__pycache__/stop-gate.cpython-313.pyc +0 -0
- package/hooks/__pycache__/stop_dispatcher.cpython-313.pyc +0 -0
- package/hooks/__pycache__/tdd-gate.cpython-313.pyc +0 -0
- package/hooks/__pycache__/terms-guard.cpython-313.pyc +0 -0
- package/hooks/__pycache__/test-validator.cpython-313.pyc +0 -0
- package/hooks/__pycache__/test_generator_hook.cpython-313.pyc +0 -0
- package/hooks/__pycache__/todo-state-tracker.cpython-313.pyc +0 -0
- package/hooks/__pycache__/tool-ledger.cpython-313.pyc +0 -0
- package/hooks/__pycache__/trust_review.cpython-313.pyc +0 -0
- package/hooks/__pycache__/user-prompt-submit.cpython-313.pyc +0 -0
- package/hooks/_agent_registry.py +481 -0
- package/hooks/_analytics.py +291 -0
- package/hooks/_budget.py +31 -0
- package/hooks/_common.py +761 -0
- package/hooks/_compression_optimizer.py +119 -0
- package/hooks/_cost_ledger.py +176 -0
- package/hooks/_learnings.py +126 -0
- package/hooks/_memory.py +103 -0
- package/hooks/_post_write.py +46 -0
- package/hooks/_protected_context.py +150 -0
- package/hooks/_token_counter.py +221 -0
- package/hooks/branch_manager.py +255 -0
- package/hooks/budget_governor.py +326 -0
- package/hooks/circuit-breaker.py +270 -0
- package/hooks/compression_feedback.py +254 -0
- package/hooks/config-guard.py +193 -0
- package/hooks/context_pressure.py +119 -0
- package/hooks/credential_store.py +970 -0
- package/hooks/fetch-rate-limits.py +212 -0
- package/hooks/firewall.py +323 -0
- package/hooks/hashline-formatter-bridge.py +224 -0
- package/hooks/hashline-injector.py +273 -0
- package/hooks/hashline-validator.py +216 -0
- package/hooks/idle-detector.py +97 -0
- package/hooks/instructions-loaded.py +26 -0
- package/hooks/intentgate-keyword-detector.py +200 -0
- package/hooks/magic-keyword-router.py +195 -0
- package/hooks/policy_engine.py +767 -0
- package/hooks/post-tool-failure.py +19 -0
- package/hooks/post-write.py +233 -0
- package/hooks/pre-compact.py +470 -0
- package/hooks/pre-tool-inject.py +98 -0
- package/hooks/prompt-enhancer.py +879 -0
- package/hooks/quality-runner.py +191 -0
- package/hooks/query.py +512 -0
- package/hooks/secret-guard.py +120 -0
- package/hooks/secret_audit.py +144 -0
- package/hooks/security_validators.py +93 -0
- package/hooks/session-end-capture.py +505 -0
- package/hooks/session-start.py +261 -0
- package/hooks/setup_wizard.py +1101 -0
- package/hooks/shadow_manager.py +476 -0
- package/hooks/state_migration.py +228 -0
- package/hooks/stop-gate.py +7 -0
- package/hooks/stop_dispatcher.py +1259 -0
- package/hooks/tdd-gate.py +10 -0
- package/hooks/terms-guard.py +98 -0
- package/hooks/test-validator.py +462 -0
- package/hooks/test_generator_hook.py +123 -0
- package/hooks/todo-state-tracker.py +114 -0
- package/hooks/tool-ledger.py +165 -0
- package/hooks/trust_review.py +662 -0
- package/hooks/user-prompt-submit.py +12 -0
- package/hud/omg-hud.mjs +1571 -0
- package/lab/__init__.py +1 -0
- package/lab/__pycache__/__init__.cpython-313.pyc +0 -0
- package/lab/__pycache__/axolotl_adapter.cpython-313.pyc +0 -0
- package/lab/__pycache__/forge_runner.cpython-313.pyc +0 -0
- package/lab/__pycache__/gazebo_adapter.cpython-313.pyc +0 -0
- package/lab/__pycache__/isaac_gym_adapter.cpython-313.pyc +0 -0
- package/lab/__pycache__/mock_isaac_env.cpython-313.pyc +0 -0
- package/lab/__pycache__/pipeline.cpython-313.pyc +0 -0
- package/lab/__pycache__/policies.cpython-313.pyc +0 -0
- package/lab/__pycache__/pybullet_adapter.cpython-313.pyc +0 -0
- package/lab/axolotl_adapter.py +531 -0
- package/lab/forge_runner.py +103 -0
- package/lab/gazebo_adapter.py +168 -0
- package/lab/isaac_gym_adapter.py +190 -0
- package/lab/mock_isaac_env.py +47 -0
- package/lab/pipeline.py +712 -0
- package/lab/policies.py +52 -0
- package/lab/pybullet_adapter.py +192 -0
- package/package.json +61 -0
- package/plugins/README.md +78 -0
- package/plugins/__init__.py +1 -0
- package/plugins/__pycache__/__init__.cpython-313.pyc +0 -0
- package/plugins/advanced/commands/OMG-code-review.md +114 -0
- package/plugins/advanced/commands/OMG-deep-plan.md +266 -0
- package/plugins/advanced/commands/OMG-handoff.md +115 -0
- package/plugins/advanced/commands/OMG-learn.md +110 -0
- package/plugins/advanced/commands/OMG-maintainer.md +31 -0
- package/plugins/advanced/commands/OMG-ralph-start.md +43 -0
- package/plugins/advanced/commands/OMG-ralph-stop.md +23 -0
- package/plugins/advanced/commands/OMG-security-review.md +16 -0
- package/plugins/advanced/commands/OMG-sequential-thinking.md +20 -0
- package/plugins/advanced/commands/OMG-ship.md +46 -0
- package/plugins/advanced/commands/OMG:code-review.md +114 -0
- package/plugins/advanced/commands/OMG:deep-plan.md +266 -0
- package/plugins/advanced/commands/OMG:handoff.md +115 -0
- package/plugins/advanced/commands/OMG:learn.md +110 -0
- package/plugins/advanced/commands/OMG:maintainer.md +31 -0
- package/plugins/advanced/commands/OMG:ralph-start.md +43 -0
- package/plugins/advanced/commands/OMG:ralph-stop.md +23 -0
- package/plugins/advanced/commands/OMG:security-review.md +16 -0
- package/plugins/advanced/commands/OMG:sequential-thinking.md +20 -0
- package/plugins/advanced/commands/OMG:ship.md +46 -0
- package/plugins/advanced/plugin.json +104 -0
- package/plugins/core/plugin.json +204 -0
- package/plugins/dephealth/__init__.py +0 -0
- package/plugins/dephealth/__pycache__/__init__.cpython-313.pyc +0 -0
- package/plugins/dephealth/__pycache__/cve_scanner.cpython-313.pyc +0 -0
- package/plugins/dephealth/__pycache__/license_checker.cpython-313.pyc +0 -0
- package/plugins/dephealth/__pycache__/manifest_detector.cpython-313.pyc +0 -0
- package/plugins/dephealth/__pycache__/vuln_analyzer.cpython-313.pyc +0 -0
- package/plugins/dephealth/cve_scanner.py +279 -0
- package/plugins/dephealth/license_checker.py +135 -0
- package/plugins/dephealth/manifest_detector.py +423 -0
- package/plugins/dephealth/vuln_analyzer.py +176 -0
- package/plugins/testgen/__init__.py +0 -0
- package/plugins/testgen/__pycache__/__init__.cpython-313.pyc +0 -0
- package/plugins/testgen/__pycache__/codamosa_engine.cpython-313.pyc +0 -0
- package/plugins/testgen/__pycache__/edge_case_synthesizer.cpython-313.pyc +0 -0
- package/plugins/testgen/__pycache__/framework_detector.cpython-313.pyc +0 -0
- package/plugins/testgen/__pycache__/skeleton_generator.cpython-313.pyc +0 -0
- package/plugins/testgen/codamosa_engine.py +402 -0
- package/plugins/testgen/edge_case_synthesizer.py +184 -0
- package/plugins/testgen/framework_detector.py +271 -0
- package/plugins/testgen/skeleton_generator.py +219 -0
- package/plugins/viz/__init__.py +0 -0
- package/plugins/viz/__pycache__/__init__.cpython-313.pyc +0 -0
- package/plugins/viz/__pycache__/ast_parser.cpython-313.pyc +0 -0
- package/plugins/viz/__pycache__/diagram_generator.cpython-313.pyc +0 -0
- package/plugins/viz/__pycache__/graph_builder.cpython-313.pyc +0 -0
- package/plugins/viz/__pycache__/native_parsers.cpython-313.pyc +0 -0
- package/plugins/viz/__pycache__/regex_parser.cpython-313.pyc +0 -0
- package/plugins/viz/ast_parser.py +139 -0
- package/plugins/viz/diagram_generator.py +192 -0
- package/plugins/viz/graph_builder.py +444 -0
- package/plugins/viz/native_parsers.py +259 -0
- package/plugins/viz/regex_parser.py +112 -0
- package/pyproject.toml +143 -0
- package/registry/__init__.py +1 -0
- package/registry/__pycache__/__init__.cpython-313.pyc +0 -0
- package/registry/__pycache__/approval_artifact.cpython-313.pyc +0 -0
- package/registry/__pycache__/verify_artifact.cpython-313.pyc +0 -0
- package/registry/approval_artifact.py +236 -0
- package/registry/bundles/algorithms.yaml +45 -0
- package/registry/bundles/api-twin.yaml +48 -0
- package/registry/bundles/ast-pack.yaml +80 -0
- package/registry/bundles/claim-judge.yaml +49 -0
- package/registry/bundles/control-plane.yaml +192 -0
- package/registry/bundles/data-lineage.yaml +47 -0
- package/registry/bundles/delta-classifier.yaml +47 -0
- package/registry/bundles/eval-gate.yaml +47 -0
- package/registry/bundles/hash-edit.yaml +73 -0
- package/registry/bundles/health.yaml +45 -0
- package/registry/bundles/hook-governor.yaml +101 -0
- package/registry/bundles/incident-replay.yaml +47 -0
- package/registry/bundles/lsp-pack.yaml +80 -0
- package/registry/bundles/mcp-fabric.yaml +53 -0
- package/registry/bundles/plan-council.yaml +56 -0
- package/registry/bundles/preflight.yaml +48 -0
- package/registry/bundles/proof-gate.yaml +49 -0
- package/registry/bundles/remote-supervisor.yaml +49 -0
- package/registry/bundles/robotics.yaml +45 -0
- package/registry/bundles/secure-worktree-pipeline.yaml +69 -0
- package/registry/bundles/security-check.yaml +50 -0
- package/registry/bundles/terminal-lane.yaml +61 -0
- package/registry/bundles/test-intent-lock.yaml +49 -0
- package/registry/bundles/tracebank.yaml +47 -0
- package/registry/bundles/vision.yaml +45 -0
- package/registry/omg-capability.schema.json +378 -0
- package/registry/policy-packs/airgapped.lock.json +11 -0
- package/registry/policy-packs/airgapped.signature.json +10 -0
- package/registry/policy-packs/airgapped.yaml +16 -0
- package/registry/policy-packs/fintech.lock.json +11 -0
- package/registry/policy-packs/fintech.signature.json +10 -0
- package/registry/policy-packs/fintech.yaml +15 -0
- package/registry/policy-packs/locked-prod.lock.json +11 -0
- package/registry/policy-packs/locked-prod.signature.json +10 -0
- package/registry/policy-packs/locked-prod.yaml +18 -0
- package/registry/trusted_signers.json +44 -0
- package/registry/verify_artifact.py +493 -0
- package/runtime/__init__.py +36 -0
- package/runtime/__pycache__/__init__.cpython-313.pyc +0 -0
- package/runtime/__pycache__/adoption.cpython-313.pyc +0 -0
- package/runtime/__pycache__/agent_selector.cpython-313.pyc +0 -0
- package/runtime/__pycache__/api_twin.cpython-313.pyc +0 -0
- package/runtime/__pycache__/architecture_signal.cpython-313.pyc +0 -0
- package/runtime/__pycache__/artifact_parsers.cpython-313.pyc +0 -0
- package/runtime/__pycache__/asset_loader.cpython-313.pyc +0 -0
- package/runtime/__pycache__/background_verification.cpython-313.pyc +0 -0
- package/runtime/__pycache__/budget_envelopes.cpython-313.pyc +0 -0
- package/runtime/__pycache__/business_workflow.cpython-313.pyc +0 -0
- package/runtime/__pycache__/canonical_surface.cpython-313.pyc +0 -0
- package/runtime/__pycache__/canonical_taxonomy.cpython-313.pyc +0 -0
- package/runtime/__pycache__/claim_judge.cpython-313.pyc +0 -0
- package/runtime/__pycache__/cli_provider.cpython-313.pyc +0 -0
- package/runtime/__pycache__/compat.cpython-313.pyc +0 -0
- package/runtime/__pycache__/complexity_scorer.cpython-313.pyc +0 -0
- package/runtime/__pycache__/compliance_governor.cpython-313.pyc +0 -0
- package/runtime/__pycache__/config_transaction.cpython-313.pyc +0 -0
- package/runtime/__pycache__/context_compiler.cpython-313.pyc +0 -0
- package/runtime/__pycache__/context_engine.cpython-313.pyc +0 -0
- package/runtime/__pycache__/context_limits.cpython-313.pyc +0 -0
- package/runtime/__pycache__/contract_compiler.cpython-313.pyc +0 -0
- package/runtime/__pycache__/custom_agent_loader.cpython-313.pyc +0 -0
- package/runtime/__pycache__/data_lineage.cpython-313.pyc +0 -0
- package/runtime/__pycache__/defense_state.cpython-313.pyc +0 -0
- package/runtime/__pycache__/delta_classifier.cpython-313.pyc +0 -0
- package/runtime/__pycache__/dispatcher.cpython-313.pyc +0 -0
- package/runtime/__pycache__/doc_generator.cpython-313.pyc +0 -0
- package/runtime/__pycache__/domain_packs.cpython-313.pyc +0 -0
- package/runtime/__pycache__/ecosystem.cpython-313.pyc +0 -0
- package/runtime/__pycache__/equalizer.cpython-313.pyc +0 -0
- package/runtime/__pycache__/eval_gate.cpython-313.pyc +0 -0
- package/runtime/__pycache__/evidence_narrator.cpython-313.pyc +0 -0
- package/runtime/__pycache__/evidence_query.cpython-313.pyc +0 -0
- package/runtime/__pycache__/evidence_registry.cpython-313.pyc +0 -0
- package/runtime/__pycache__/evidence_requirements.cpython-313.pyc +0 -0
- package/runtime/__pycache__/exec_kernel.cpython-313.pyc +0 -0
- package/runtime/__pycache__/explainer_formatter.cpython-313.pyc +0 -0
- package/runtime/__pycache__/feature_registry.cpython-313.pyc +0 -0
- package/runtime/__pycache__/forge_agents.cpython-313.pyc +0 -0
- package/runtime/__pycache__/forge_contracts.cpython-313.pyc +0 -0
- package/runtime/__pycache__/forge_domains.cpython-313.pyc +0 -0
- package/runtime/__pycache__/forge_run_id.cpython-313.pyc +0 -0
- package/runtime/__pycache__/github_integration.cpython-313.pyc +0 -0
- package/runtime/__pycache__/github_review_bot.cpython-313.pyc +0 -0
- package/runtime/__pycache__/github_review_contract.cpython-313.pyc +0 -0
- package/runtime/__pycache__/github_review_formatter.cpython-313.pyc +0 -0
- package/runtime/__pycache__/guide_assert.cpython-313.pyc +0 -0
- package/runtime/__pycache__/hook_governor.cpython-313.pyc +0 -0
- package/runtime/__pycache__/host_parity.cpython-313.pyc +0 -0
- package/runtime/__pycache__/incident_replay.cpython-313.pyc +0 -0
- package/runtime/__pycache__/install_planner.cpython-313.pyc +0 -0
- package/runtime/__pycache__/interaction_journal.cpython-313.pyc +0 -0
- package/runtime/__pycache__/issue_surface.cpython-313.pyc +0 -0
- package/runtime/__pycache__/legacy_compat.cpython-313.pyc +0 -0
- package/runtime/__pycache__/mcp_config_writers.cpython-313.pyc +0 -0
- package/runtime/__pycache__/mcp_lifecycle.cpython-313.pyc +0 -0
- package/runtime/__pycache__/mcp_memory_server.cpython-313.pyc +0 -0
- package/runtime/__pycache__/memory_store.cpython-313.pyc +0 -0
- package/runtime/__pycache__/merge_writer.cpython-313.pyc +0 -0
- package/runtime/__pycache__/music_omr_testbed.cpython-313.pyc +0 -0
- package/runtime/__pycache__/mutation_gate.cpython-313.pyc +0 -0
- package/runtime/__pycache__/omc_compat.cpython-313.pyc +0 -0
- package/runtime/__pycache__/omg_browser_cli.cpython-313.pyc +0 -0
- package/runtime/__pycache__/omg_mcp_server.cpython-313.pyc +0 -0
- package/runtime/__pycache__/opus_plan.cpython-313.pyc +0 -0
- package/runtime/__pycache__/playwright_adapter.cpython-313.pyc +0 -0
- package/runtime/__pycache__/playwright_pack.cpython-313.pyc +0 -0
- package/runtime/__pycache__/plugin_diagnostics.cpython-313.pyc +0 -0
- package/runtime/__pycache__/plugin_interop.cpython-313.pyc +0 -0
- package/runtime/__pycache__/policy_pack_loader.cpython-313.pyc +0 -0
- package/runtime/__pycache__/preflight.cpython-313.pyc +0 -0
- package/runtime/__pycache__/profile_io.cpython-313.pyc +0 -0
- package/runtime/__pycache__/prompt_compiler.cpython-313.pyc +0 -0
- package/runtime/__pycache__/proof_chain.cpython-313.pyc +0 -0
- package/runtime/__pycache__/proof_gate.cpython-313.pyc +0 -0
- package/runtime/__pycache__/provider_parity_eval.cpython-313.pyc +0 -0
- package/runtime/__pycache__/release_artifact_audit.cpython-313.pyc +0 -0
- package/runtime/__pycache__/release_run_coordinator.cpython-313.pyc +0 -0
- package/runtime/__pycache__/release_surface_compiler.cpython-313.pyc +0 -0
- package/runtime/__pycache__/release_surface_registry.cpython-313.pyc +0 -0
- package/runtime/__pycache__/release_surfaces.cpython-313.pyc +0 -0
- package/runtime/__pycache__/remote_supervisor.cpython-313.pyc +0 -0
- package/runtime/__pycache__/repro_pack.cpython-313.pyc +0 -0
- package/runtime/__pycache__/rollback_manifest.cpython-313.pyc +0 -0
- package/runtime/__pycache__/router_critics.cpython-313.pyc +0 -0
- package/runtime/__pycache__/router_executor.cpython-313.pyc +0 -0
- package/runtime/__pycache__/router_selector.cpython-313.pyc +0 -0
- package/runtime/__pycache__/runtime_contracts.cpython-313.pyc +0 -0
- package/runtime/__pycache__/runtime_profile.cpython-313.pyc +0 -0
- package/runtime/__pycache__/security_check.cpython-313.pyc +0 -0
- package/runtime/__pycache__/session_health.cpython-313.pyc +0 -0
- package/runtime/__pycache__/skill_evolution.cpython-313.pyc +0 -0
- package/runtime/__pycache__/skill_registry.cpython-313.pyc +0 -0
- package/runtime/__pycache__/subagent_dispatcher.cpython-313.pyc +0 -0
- package/runtime/__pycache__/subscription_tiers.cpython-313.pyc +0 -0
- package/runtime/__pycache__/team_router.cpython-313.pyc +0 -0
- package/runtime/__pycache__/test_intent_lock.cpython-313-pytest-9.0.2.pyc +0 -0
- package/runtime/__pycache__/test_intent_lock.cpython-313.pyc +0 -0
- package/runtime/__pycache__/tmux_session_manager.cpython-313.pyc +0 -0
- package/runtime/__pycache__/tool_fabric.cpython-313.pyc +0 -0
- package/runtime/__pycache__/tool_plan_gate.cpython-313.pyc +0 -0
- package/runtime/__pycache__/tool_relevance.cpython-313.pyc +0 -0
- package/runtime/__pycache__/tracebank.cpython-313.pyc +0 -0
- package/runtime/__pycache__/untrusted_content.cpython-313.pyc +0 -0
- package/runtime/__pycache__/validate.cpython-313.pyc +0 -0
- package/runtime/__pycache__/verdict_schema.cpython-313.pyc +0 -0
- package/runtime/__pycache__/verification_controller.cpython-313.pyc +0 -0
- package/runtime/__pycache__/verification_loop.cpython-313.pyc +0 -0
- package/runtime/__pycache__/vision_artifacts.cpython-313.pyc +0 -0
- package/runtime/__pycache__/vision_cache.cpython-313.pyc +0 -0
- package/runtime/__pycache__/vision_jobs.cpython-313.pyc +0 -0
- package/runtime/__pycache__/worker_watchdog.cpython-313.pyc +0 -0
- package/runtime/adapters/__init__.py +13 -0
- package/runtime/adapters/__pycache__/__init__.cpython-313.pyc +0 -0
- package/runtime/adapters/__pycache__/claude.cpython-313.pyc +0 -0
- package/runtime/adapters/__pycache__/gpt.cpython-313.pyc +0 -0
- package/runtime/adapters/__pycache__/local.cpython-313.pyc +0 -0
- package/runtime/adapters/claude.py +63 -0
- package/runtime/adapters/gpt.py +56 -0
- package/runtime/adapters/local.py +56 -0
- package/runtime/adoption.py +280 -0
- package/runtime/api_twin.py +450 -0
- package/runtime/architecture_signal.py +226 -0
- package/runtime/artifact_parsers.py +161 -0
- package/runtime/asset_loader.py +62 -0
- package/runtime/background_verification.py +178 -0
- package/runtime/budget_envelopes.py +398 -0
- package/runtime/business_workflow.py +234 -0
- package/runtime/canonical_surface.py +53 -0
- package/runtime/canonical_taxonomy.py +27 -0
- package/runtime/claim_judge.py +648 -0
- package/runtime/cli_provider.py +105 -0
- package/runtime/compat.py +2222 -0
- package/runtime/complexity_scorer.py +148 -0
- package/runtime/compliance_governor.py +505 -0
- package/runtime/config_transaction.py +304 -0
- package/runtime/context_compiler.py +131 -0
- package/runtime/context_engine.py +708 -0
- package/runtime/context_limits.py +363 -0
- package/runtime/contract_compiler.py +3664 -0
- package/runtime/custom_agent_loader.py +366 -0
- package/runtime/data_lineage.py +244 -0
- package/runtime/defense_state.py +261 -0
- package/runtime/delta_classifier.py +231 -0
- package/runtime/dispatcher.py +47 -0
- package/runtime/doc_generator.py +319 -0
- package/runtime/domain_packs.py +75 -0
- package/runtime/ecosystem.py +371 -0
- package/runtime/equalizer.py +268 -0
- package/runtime/eval_gate.py +96 -0
- package/runtime/evidence_narrator.py +147 -0
- package/runtime/evidence_query.py +303 -0
- package/runtime/evidence_registry.py +16 -0
- package/runtime/evidence_requirements.py +157 -0
- package/runtime/exec_kernel.py +267 -0
- package/runtime/explainer_formatter.py +82 -0
- package/runtime/feature_registry.py +109 -0
- package/runtime/forge_agents.py +915 -0
- package/runtime/forge_contracts.py +519 -0
- package/runtime/forge_domains.py +68 -0
- package/runtime/forge_run_id.py +86 -0
- package/runtime/guide_assert.py +135 -0
- package/runtime/hook_governor.py +156 -0
- package/runtime/host_parity.py +373 -0
- package/runtime/incident_replay.py +310 -0
- package/runtime/install_planner.py +617 -0
- package/runtime/interaction_journal.py +566 -0
- package/runtime/issue_surface.py +472 -0
- package/runtime/legacy_compat.py +7 -0
- package/runtime/mcp_config_writers.py +360 -0
- package/runtime/mcp_lifecycle.py +175 -0
- package/runtime/mcp_memory_server.py +220 -0
- package/runtime/memory_parsers/__init__.py +0 -0
- package/runtime/memory_parsers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/runtime/memory_parsers/__pycache__/chatgpt_parser.cpython-313.pyc +0 -0
- package/runtime/memory_parsers/__pycache__/claude_import.cpython-313.pyc +0 -0
- package/runtime/memory_parsers/__pycache__/export.cpython-313.pyc +0 -0
- package/runtime/memory_parsers/__pycache__/gemini_import.cpython-313.pyc +0 -0
- package/runtime/memory_parsers/__pycache__/kimi_import.cpython-313.pyc +0 -0
- package/runtime/memory_parsers/chatgpt_parser.py +257 -0
- package/runtime/memory_parsers/claude_import.py +107 -0
- package/runtime/memory_parsers/export.py +97 -0
- package/runtime/memory_parsers/gemini_import.py +91 -0
- package/runtime/memory_parsers/kimi_import.py +91 -0
- package/runtime/memory_store.py +1182 -0
- package/runtime/merge_writer.py +445 -0
- package/runtime/music_omr_testbed.py +336 -0
- package/runtime/mutation_gate.py +320 -0
- package/runtime/omc_compat.py +7 -0
- package/runtime/omg_browser_cli.py +95 -0
- package/runtime/omg_compat_contract_snapshot.json +936 -0
- package/runtime/omg_contract_snapshot.json +936 -0
- package/runtime/omg_mcp_server.py +306 -0
- package/runtime/playwright_adapter.py +39 -0
- package/runtime/playwright_pack.py +253 -0
- package/runtime/plugin_diagnostics.py +308 -0
- package/runtime/plugin_interop.py +1060 -0
- package/runtime/policy_pack_loader.py +147 -0
- package/runtime/preflight.py +135 -0
- package/runtime/profile_io.py +328 -0
- package/runtime/proof_chain.py +472 -0
- package/runtime/proof_gate.py +442 -0
- package/runtime/provider_parity_eval.py +109 -0
- package/runtime/providers/__init__.py +0 -0
- package/runtime/providers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/runtime/providers/__pycache__/codex_provider.cpython-313.pyc +0 -0
- package/runtime/providers/__pycache__/gemini_provider.cpython-313.pyc +0 -0
- package/runtime/providers/__pycache__/kimi_provider.cpython-313.pyc +0 -0
- package/runtime/providers/__pycache__/opencode_provider.cpython-313.pyc +0 -0
- package/runtime/providers/codex_provider.py +129 -0
- package/runtime/providers/gemini_provider.py +143 -0
- package/runtime/providers/kimi_provider.py +167 -0
- package/runtime/providers/opencode_provider.py +99 -0
- package/runtime/release_artifact_audit.py +556 -0
- package/runtime/release_run_coordinator.py +574 -0
- package/runtime/release_surface_compiler.py +643 -0
- package/runtime/release_surface_registry.py +283 -0
- package/runtime/release_surfaces.py +320 -0
- package/runtime/remote_supervisor.py +79 -0
- package/runtime/repro_pack.py +398 -0
- package/runtime/rollback_manifest.py +143 -0
- package/runtime/router_critics.py +229 -0
- package/runtime/router_executor.py +142 -0
- package/runtime/router_selector.py +99 -0
- package/runtime/runtime_contracts.py +292 -0
- package/runtime/runtime_profile.py +133 -0
- package/runtime/security_check.py +1094 -0
- package/runtime/session_health.py +546 -0
- package/runtime/skill_evolution.py +221 -0
- package/runtime/skill_registry.py +53 -0
- package/runtime/subagent_dispatcher.py +604 -0
- package/runtime/subscription_tiers.py +258 -0
- package/runtime/team_router.py +1399 -0
- package/runtime/test_intent_lock.py +543 -0
- package/runtime/tmux_session_manager.py +172 -0
- package/runtime/tool_fabric.py +570 -0
- package/runtime/tool_plan_gate.py +460 -0
- package/runtime/tracebank.py +125 -0
- package/runtime/untrusted_content.py +360 -0
- package/runtime/validate.py +293 -0
- package/runtime/verdict_schema.py +198 -0
- package/runtime/verification_controller.py +235 -0
- package/runtime/verification_loop.py +73 -0
- package/runtime/vision_artifacts.py +31 -0
- package/runtime/vision_cache.py +38 -0
- package/runtime/vision_jobs.py +92 -0
- package/runtime/worker_watchdog.py +526 -0
- package/scripts/__pycache__/audit-published-artifact.cpython-313.pyc +0 -0
- package/scripts/__pycache__/check-doc-parity.cpython-313.pyc +0 -0
- package/scripts/__pycache__/check-omg-standalone-clean.cpython-313.pyc +0 -0
- package/scripts/__pycache__/github_review_helpers.cpython-313.pyc +0 -0
- package/scripts/__pycache__/omg.cpython-313.pyc +0 -0
- package/scripts/__pycache__/prepare-release-proof-fixtures.cpython-313.pyc +0 -0
- package/scripts/__pycache__/sync-release-identity.cpython-313.pyc +0 -0
- package/scripts/__pycache__/validate-release-identity.cpython-313.pyc +0 -0
- package/scripts/audit-published-artifact.py +59 -0
- package/scripts/check-omg-compat-contract-snapshot.py +137 -0
- package/scripts/check-omg-contract-snapshot.py +12 -0
- package/scripts/check-omg-public-ready.py +273 -0
- package/scripts/check-omg-standalone-clean.py +133 -0
- package/scripts/emit_host_parity.py +72 -0
- package/scripts/legacy_to_omg_migrate.py +29 -0
- package/scripts/migrate-legacy.py +464 -0
- package/scripts/omc_to_omg_migrate.py +12 -0
- package/scripts/omg.py +2962 -0
- package/scripts/pre-release-check.sh +38 -0
- package/scripts/prepare-release-proof-fixtures.py +602 -0
- package/scripts/print-canonical-version.py +80 -0
- package/scripts/settings-merge.py +289 -0
- package/scripts/sync-release-identity.py +481 -0
- package/scripts/validate-release-identity.py +632 -0
- package/scripts/verify-no-omc.sh +5 -0
- package/scripts/verify-standalone.sh +35 -0
- package/settings.json +751 -0
- package/tools/__init__.py +2 -0
- package/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- package/tools/__pycache__/browser_consent.cpython-313.pyc +0 -0
- package/tools/__pycache__/browser_stealth.cpython-313.pyc +0 -0
- package/tools/__pycache__/browser_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/changelog_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/commit_splitter.cpython-313.pyc +0 -0
- package/tools/__pycache__/config_discovery.cpython-313.pyc +0 -0
- package/tools/__pycache__/config_merger.cpython-313.pyc +0 -0
- package/tools/__pycache__/dashboard_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/git_inspector.cpython-313.pyc +0 -0
- package/tools/__pycache__/lsp_client.cpython-313.pyc +0 -0
- package/tools/__pycache__/lsp_operations.cpython-313.pyc +0 -0
- package/tools/__pycache__/pr_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/python_repl.cpython-313.pyc +0 -0
- package/tools/__pycache__/python_sandbox.cpython-313.pyc +0 -0
- package/tools/__pycache__/session_snapshot.cpython-313.pyc +0 -0
- package/tools/__pycache__/ssh_manager.cpython-313.pyc +0 -0
- package/tools/__pycache__/theme_engine.cpython-313.pyc +0 -0
- package/tools/__pycache__/theme_selector.cpython-313.pyc +0 -0
- package/tools/__pycache__/web_search.cpython-313.pyc +0 -0
- package/tools/browser_consent.py +289 -0
- package/tools/browser_stealth.py +481 -0
- package/tools/browser_tool.py +448 -0
- package/tools/changelog_generator.py +347 -0
- package/tools/commit_splitter.py +749 -0
- package/tools/config_discovery.py +151 -0
- package/tools/config_merger.py +449 -0
- package/tools/dashboard_generator.py +300 -0
- package/tools/git_inspector.py +298 -0
- package/tools/lsp_client.py +275 -0
- package/tools/lsp_discovery.py +231 -0
- package/tools/lsp_operations.py +392 -0
- package/tools/pr_generator.py +404 -0
- package/tools/python_repl.py +712 -0
- package/tools/python_sandbox.py +768 -0
- package/tools/search_providers/__init__.py +77 -0
- package/tools/search_providers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/tools/search_providers/__pycache__/brave.cpython-313.pyc +0 -0
- package/tools/search_providers/__pycache__/exa.cpython-313.pyc +0 -0
- package/tools/search_providers/__pycache__/jina.cpython-313.pyc +0 -0
- package/tools/search_providers/__pycache__/perplexity.cpython-313.pyc +0 -0
- package/tools/search_providers/__pycache__/synthetic.cpython-313.pyc +0 -0
- package/tools/search_providers/brave.py +115 -0
- package/tools/search_providers/exa.py +116 -0
- package/tools/search_providers/jina.py +104 -0
- package/tools/search_providers/perplexity.py +139 -0
- package/tools/search_providers/synthetic.py +74 -0
- package/tools/session_snapshot.py +851 -0
- package/tools/ssh_manager.py +912 -0
- package/tools/theme_engine.py +296 -0
- package/tools/theme_selector.py +137 -0
- package/tools/web_search.py +675 -0
|
@@ -0,0 +1,768 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Security Sandbox for OMG Python REPL (REPL-only).
|
|
3
|
+
|
|
4
|
+
Provides a restricted execution environment that blocks dangerous operations:
|
|
5
|
+
- Dangerous imports (subprocess, socket, ctypes, etc.)
|
|
6
|
+
- File write access
|
|
7
|
+
- Network operations
|
|
8
|
+
- Sandbox escape patterns (__class__.__mro__, __subclasses__, etc.)
|
|
9
|
+
- Dangerous builtins (__import__, eval, exec, compile, etc.)
|
|
10
|
+
|
|
11
|
+
Feature flag: OMG_REPL_SANDBOX_ENABLED (default: False)
|
|
12
|
+
|
|
13
|
+
This module is the concrete REPL-only sandbox implementation. Broader sandbox
|
|
14
|
+
policy is mediated by hook-level controls in hooks/firewall.py and
|
|
15
|
+
hooks/secret-guard.py.
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
from tools.python_sandbox import execute_sandboxed, is_safe_code, create_sandbox
|
|
19
|
+
|
|
20
|
+
result = execute_sandboxed("print('hello')")
|
|
21
|
+
# => {"stdout": "hello\\n", "stderr": "", "result": None, "error": None, "blocked": False}
|
|
22
|
+
|
|
23
|
+
safe = is_safe_code("import subprocess")
|
|
24
|
+
# => False
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import ast
|
|
28
|
+
import contextlib
|
|
29
|
+
import io
|
|
30
|
+
import json
|
|
31
|
+
import os
|
|
32
|
+
import subprocess
|
|
33
|
+
import sys
|
|
34
|
+
import time
|
|
35
|
+
import traceback
|
|
36
|
+
from typing import Any, Dict, List, Optional, Set
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# --- Lazy imports for hooks/_common.py ---
|
|
40
|
+
|
|
41
|
+
_get_feature_flag = None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _ensure_imports():
|
|
45
|
+
"""Lazy import feature flag from hooks/_common.py."""
|
|
46
|
+
global _get_feature_flag
|
|
47
|
+
if _get_feature_flag is not None:
|
|
48
|
+
return
|
|
49
|
+
repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
50
|
+
if repo_root not in sys.path:
|
|
51
|
+
sys.path.insert(0, repo_root)
|
|
52
|
+
try:
|
|
53
|
+
from hooks._common import get_feature_flag as _gff
|
|
54
|
+
_get_feature_flag = _gff
|
|
55
|
+
except ImportError:
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _is_sandbox_enabled() -> bool:
|
|
60
|
+
"""Check if sandbox feature is enabled."""
|
|
61
|
+
# Fast path: check env var directly
|
|
62
|
+
env_val = os.environ.get("OMG_REPL_SANDBOX_ENABLED", "").lower()
|
|
63
|
+
if env_val in ("0", "false", "no"):
|
|
64
|
+
return False
|
|
65
|
+
if env_val in ("1", "true", "yes"):
|
|
66
|
+
return True
|
|
67
|
+
# Fallback to hooks/_common.get_feature_flag
|
|
68
|
+
_ensure_imports()
|
|
69
|
+
if _get_feature_flag is not None:
|
|
70
|
+
return _get_feature_flag("REPL_SANDBOX", default=False)
|
|
71
|
+
return False
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# --- Blocked imports configuration ---
|
|
75
|
+
|
|
76
|
+
_DEFAULT_BLOCKED_IMPORTS: frozenset[str] = frozenset({
|
|
77
|
+
"subprocess",
|
|
78
|
+
"socket",
|
|
79
|
+
"ctypes",
|
|
80
|
+
"importlib",
|
|
81
|
+
"pickle",
|
|
82
|
+
"marshal",
|
|
83
|
+
"shelve",
|
|
84
|
+
"multiprocessing",
|
|
85
|
+
"threading",
|
|
86
|
+
"pty",
|
|
87
|
+
"shutil",
|
|
88
|
+
"signal",
|
|
89
|
+
"resource",
|
|
90
|
+
"code",
|
|
91
|
+
"codeop",
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _get_blocked_imports() -> Set[str]:
|
|
96
|
+
"""Get the set of blocked import names, configurable via env var."""
|
|
97
|
+
env_val = os.environ.get("OMG_SANDBOX_BLOCKED_IMPORTS", "").strip()
|
|
98
|
+
if env_val:
|
|
99
|
+
custom = frozenset(name.strip() for name in env_val.split(",") if name.strip())
|
|
100
|
+
return set(_DEFAULT_BLOCKED_IMPORTS | custom)
|
|
101
|
+
return set(_DEFAULT_BLOCKED_IMPORTS)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# --- Blocked builtins ---
|
|
105
|
+
|
|
106
|
+
_DANGEROUS_BUILTINS: frozenset[str] = frozenset({
|
|
107
|
+
"__import__",
|
|
108
|
+
"eval",
|
|
109
|
+
"exec",
|
|
110
|
+
"compile",
|
|
111
|
+
"globals",
|
|
112
|
+
"locals",
|
|
113
|
+
"vars",
|
|
114
|
+
"dir",
|
|
115
|
+
"getattr",
|
|
116
|
+
"setattr",
|
|
117
|
+
"delattr",
|
|
118
|
+
"hasattr",
|
|
119
|
+
"breakpoint",
|
|
120
|
+
"exit",
|
|
121
|
+
"quit",
|
|
122
|
+
"help",
|
|
123
|
+
"input",
|
|
124
|
+
"memoryview",
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# --- Sandbox escape patterns ---
|
|
129
|
+
|
|
130
|
+
_ESCAPE_PATTERNS: List[str] = [
|
|
131
|
+
"__class__",
|
|
132
|
+
"__mro__",
|
|
133
|
+
"__subclasses__",
|
|
134
|
+
"__bases__",
|
|
135
|
+
"__builtins__",
|
|
136
|
+
"__globals__",
|
|
137
|
+
"__code__",
|
|
138
|
+
"__func__",
|
|
139
|
+
"__self__",
|
|
140
|
+
"__dict__",
|
|
141
|
+
"__init_subclass__",
|
|
142
|
+
"__set_name__",
|
|
143
|
+
"__class_getitem__",
|
|
144
|
+
"os.system",
|
|
145
|
+
"os.popen",
|
|
146
|
+
"os.exec",
|
|
147
|
+
"os.spawn",
|
|
148
|
+
"os.fork",
|
|
149
|
+
"sys.modules",
|
|
150
|
+
"sys._getframe",
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# --- AST-based static analysis ---
|
|
155
|
+
|
|
156
|
+
class _SafetyChecker(ast.NodeVisitor):
|
|
157
|
+
"""AST visitor that checks for dangerous code patterns."""
|
|
158
|
+
|
|
159
|
+
def __init__(self, blocked_imports: Set[str]):
|
|
160
|
+
self.blocked_imports = blocked_imports
|
|
161
|
+
self.violations: List[str] = []
|
|
162
|
+
|
|
163
|
+
def visit_Import(self, node: ast.Import) -> None:
|
|
164
|
+
for alias in node.names:
|
|
165
|
+
module_name = alias.name.split(".")[0]
|
|
166
|
+
if module_name in self.blocked_imports:
|
|
167
|
+
self.violations.append(
|
|
168
|
+
f"Blocked import: '{alias.name}'"
|
|
169
|
+
)
|
|
170
|
+
self.generic_visit(node)
|
|
171
|
+
|
|
172
|
+
def visit_ImportFrom(self, node: ast.ImportFrom) -> None:
|
|
173
|
+
if node.module:
|
|
174
|
+
module_name = node.module.split(".")[0]
|
|
175
|
+
if module_name in self.blocked_imports:
|
|
176
|
+
self.violations.append(
|
|
177
|
+
f"Blocked import: 'from {node.module}'"
|
|
178
|
+
)
|
|
179
|
+
self.generic_visit(node)
|
|
180
|
+
|
|
181
|
+
def visit_Call(self, node: ast.Call) -> None:
|
|
182
|
+
# Check for __import__() calls
|
|
183
|
+
if isinstance(node.func, ast.Name):
|
|
184
|
+
if node.func.id == "__import__":
|
|
185
|
+
self.violations.append("Blocked: __import__() call")
|
|
186
|
+
elif node.func.id in ("eval", "exec", "compile"):
|
|
187
|
+
self.violations.append(
|
|
188
|
+
f"Blocked: {node.func.id}() call"
|
|
189
|
+
)
|
|
190
|
+
# Check for os.system(), os.popen() etc
|
|
191
|
+
if isinstance(node.func, ast.Attribute):
|
|
192
|
+
if isinstance(node.func.value, ast.Name):
|
|
193
|
+
full_name = f"{node.func.value.id}.{node.func.attr}"
|
|
194
|
+
if full_name in ("os.system", "os.popen", "os.execvp",
|
|
195
|
+
"os.execv", "os.execve", "os.spawnl",
|
|
196
|
+
"os.spawnle", "os.fork"):
|
|
197
|
+
self.violations.append(f"Blocked: {full_name}() call")
|
|
198
|
+
self.generic_visit(node)
|
|
199
|
+
|
|
200
|
+
def visit_Attribute(self, node: ast.Attribute) -> None:
|
|
201
|
+
# Check for sandbox escape attributes
|
|
202
|
+
if node.attr in ("__class__", "__mro__", "__subclasses__",
|
|
203
|
+
"__bases__", "__builtins__", "__globals__",
|
|
204
|
+
"__code__", "__func__", "__self__",
|
|
205
|
+
"__init_subclass__", "__set_name__",
|
|
206
|
+
"__class_getitem__"):
|
|
207
|
+
self.violations.append(
|
|
208
|
+
f"Blocked: access to '{node.attr}' (sandbox escape)"
|
|
209
|
+
)
|
|
210
|
+
self.generic_visit(node)
|
|
211
|
+
|
|
212
|
+
def visit_Name(self, node: ast.Name) -> None:
|
|
213
|
+
# Block direct access to dangerous names
|
|
214
|
+
if node.id == "__builtins__":
|
|
215
|
+
self.violations.append("Blocked: access to '__builtins__'")
|
|
216
|
+
self.generic_visit(node)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def is_safe_code(code: str) -> bool:
|
|
220
|
+
"""Static analysis check: return True if code appears safe to execute.
|
|
221
|
+
|
|
222
|
+
Parses the code into an AST and checks for:
|
|
223
|
+
- Import statements with blocked modules
|
|
224
|
+
- Call nodes invoking dangerous functions
|
|
225
|
+
- Attribute access to sandbox escape dunder methods
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
code: Python source code to check
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
True if code passes static analysis, False if dangerous patterns found
|
|
232
|
+
"""
|
|
233
|
+
try:
|
|
234
|
+
tree = ast.parse(code)
|
|
235
|
+
except SyntaxError:
|
|
236
|
+
# Let the actual execution report the syntax error
|
|
237
|
+
return True
|
|
238
|
+
|
|
239
|
+
blocked_imports = _get_blocked_imports()
|
|
240
|
+
checker = _SafetyChecker(blocked_imports)
|
|
241
|
+
checker.visit(tree)
|
|
242
|
+
return len(checker.violations) == 0
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def get_code_violations(code: str) -> List[str]:
|
|
246
|
+
"""Return list of safety violations found in code.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
code: Python source code to check
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
List of violation description strings (empty if safe)
|
|
253
|
+
"""
|
|
254
|
+
try:
|
|
255
|
+
tree = ast.parse(code)
|
|
256
|
+
except SyntaxError:
|
|
257
|
+
return []
|
|
258
|
+
|
|
259
|
+
blocked_imports = _get_blocked_imports()
|
|
260
|
+
checker = _SafetyChecker(blocked_imports)
|
|
261
|
+
checker.visit(tree)
|
|
262
|
+
return checker.violations
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
# --- String-level escape detection ---
|
|
266
|
+
|
|
267
|
+
def _check_string_escapes(code: str) -> Optional[str]:
|
|
268
|
+
"""Check for sandbox escape patterns in raw code string.
|
|
269
|
+
|
|
270
|
+
This catches patterns that might not appear in the AST
|
|
271
|
+
(e.g., constructed via string manipulation).
|
|
272
|
+
|
|
273
|
+
Args:
|
|
274
|
+
code: Raw source code string
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
Violation description if found, None if clean
|
|
278
|
+
"""
|
|
279
|
+
for pattern in _ESCAPE_PATTERNS:
|
|
280
|
+
if pattern in code:
|
|
281
|
+
return f"Blocked: suspicious pattern '{pattern}' detected"
|
|
282
|
+
return None
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
# --- Restricted open() ---
|
|
286
|
+
|
|
287
|
+
_ALLOWED_READ_MODES: frozenset[str] = frozenset({
|
|
288
|
+
"r", "rb", "rt",
|
|
289
|
+
"", # default mode is 'r'
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def _restricted_open(name, mode="r", *args, **kwargs):
|
|
294
|
+
"""Restricted open() that only allows read-mode file access.
|
|
295
|
+
|
|
296
|
+
Args:
|
|
297
|
+
name: File path to open
|
|
298
|
+
mode: File open mode (only read modes allowed)
|
|
299
|
+
*args: Passed through to builtin open
|
|
300
|
+
**kwargs: Passed through to builtin open
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
File object (read-only)
|
|
304
|
+
|
|
305
|
+
Raises:
|
|
306
|
+
PermissionError: If write/append mode is attempted
|
|
307
|
+
"""
|
|
308
|
+
# Normalize mode string
|
|
309
|
+
clean_mode = mode.strip().lower()
|
|
310
|
+
if clean_mode not in _ALLOWED_READ_MODES:
|
|
311
|
+
raise PermissionError(
|
|
312
|
+
f"Sandbox: write access denied (mode='{mode}'). "
|
|
313
|
+
f"Only read modes are allowed: {sorted(_ALLOWED_READ_MODES - {''})}"
|
|
314
|
+
)
|
|
315
|
+
return open(name, mode, *args, **kwargs)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
# --- Restricted __import__ ---
|
|
319
|
+
|
|
320
|
+
def _make_restricted_import(blocked_imports: Set[str]):
|
|
321
|
+
"""Create a restricted __import__ function that blocks dangerous modules.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
blocked_imports: Set of module names to block
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
A replacement __import__ function
|
|
328
|
+
"""
|
|
329
|
+
_real_import = __builtins__.__import__ if hasattr(__builtins__, "__import__") else __import__
|
|
330
|
+
|
|
331
|
+
def _restricted_import(name, *args, **kwargs):
|
|
332
|
+
top_level = name.split(".")[0]
|
|
333
|
+
if top_level in blocked_imports:
|
|
334
|
+
raise ImportError(
|
|
335
|
+
f"Sandbox: import of '{name}' is blocked. "
|
|
336
|
+
f"Module '{top_level}' is on the restricted list."
|
|
337
|
+
)
|
|
338
|
+
return _real_import(name, *args, **kwargs)
|
|
339
|
+
|
|
340
|
+
return _restricted_import
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
# --- Safe builtins construction ---
|
|
344
|
+
|
|
345
|
+
def _build_safe_builtins(blocked_imports: Set[str]) -> Dict[str, Any]:
|
|
346
|
+
"""Build a restricted __builtins__ dict for sandbox execution.
|
|
347
|
+
|
|
348
|
+
Removes dangerous builtins and replaces open/__import__ with
|
|
349
|
+
restricted versions.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
blocked_imports: Set of module names to block in __import__
|
|
353
|
+
|
|
354
|
+
Returns:
|
|
355
|
+
Dict of safe builtin names to their values
|
|
356
|
+
"""
|
|
357
|
+
# Start from a copy of real builtins
|
|
358
|
+
if isinstance(__builtins__, dict):
|
|
359
|
+
safe = dict(__builtins__)
|
|
360
|
+
else:
|
|
361
|
+
safe = {k: getattr(__builtins__, k) for k in dir(__builtins__)
|
|
362
|
+
if not k.startswith("_") or k == "__name__"}
|
|
363
|
+
# Include common dunders that are needed
|
|
364
|
+
for attr in ("__build_class__", "__name__", "__spec__"):
|
|
365
|
+
if hasattr(__builtins__, attr):
|
|
366
|
+
safe[attr] = getattr(__builtins__, attr)
|
|
367
|
+
|
|
368
|
+
# Remove dangerous builtins
|
|
369
|
+
for name in _DANGEROUS_BUILTINS:
|
|
370
|
+
safe.pop(name, None)
|
|
371
|
+
|
|
372
|
+
# Replace open with restricted version
|
|
373
|
+
safe["open"] = _restricted_open
|
|
374
|
+
|
|
375
|
+
# Replace __import__ with restricted version
|
|
376
|
+
safe["__import__"] = _make_restricted_import(blocked_imports)
|
|
377
|
+
|
|
378
|
+
# Ensure print is available
|
|
379
|
+
safe["print"] = print
|
|
380
|
+
|
|
381
|
+
return safe
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
# --- SandboxedExecutor ---
|
|
385
|
+
|
|
386
|
+
class SandboxedExecutor:
|
|
387
|
+
"""Restricted Python execution environment.
|
|
388
|
+
|
|
389
|
+
Creates an isolated namespace with restricted builtins that
|
|
390
|
+
prevents dangerous operations like system calls, network access,
|
|
391
|
+
and file writes.
|
|
392
|
+
|
|
393
|
+
Usage:
|
|
394
|
+
sandbox = SandboxedExecutor()
|
|
395
|
+
result = sandbox.execute("print('hello')")
|
|
396
|
+
"""
|
|
397
|
+
|
|
398
|
+
def __init__(
|
|
399
|
+
self,
|
|
400
|
+
namespace: Optional[Dict[str, Any]] = None,
|
|
401
|
+
blocked_imports: Optional[Set[str]] = None,
|
|
402
|
+
extra_blocked_builtins: Optional[Set[str]] = None,
|
|
403
|
+
):
|
|
404
|
+
"""Initialize the sandboxed executor.
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
namespace: Optional existing namespace to sandbox (will be modified)
|
|
408
|
+
blocked_imports: Override the default blocked imports set
|
|
409
|
+
extra_blocked_builtins: Additional builtins to block beyond defaults
|
|
410
|
+
"""
|
|
411
|
+
self._blocked_imports = blocked_imports or _get_blocked_imports()
|
|
412
|
+
|
|
413
|
+
# Build safe builtins
|
|
414
|
+
self._safe_builtins = _build_safe_builtins(self._blocked_imports)
|
|
415
|
+
|
|
416
|
+
# Remove extra builtins if requested
|
|
417
|
+
if extra_blocked_builtins:
|
|
418
|
+
for name in extra_blocked_builtins:
|
|
419
|
+
self._safe_builtins.pop(name, None)
|
|
420
|
+
|
|
421
|
+
# Initialize or adopt namespace
|
|
422
|
+
if namespace is not None:
|
|
423
|
+
self._namespace = namespace
|
|
424
|
+
self._namespace["__builtins__"] = self._safe_builtins
|
|
425
|
+
else:
|
|
426
|
+
self._namespace = {"__builtins__": self._safe_builtins}
|
|
427
|
+
|
|
428
|
+
@property
|
|
429
|
+
def namespace(self) -> Dict[str, Any]:
|
|
430
|
+
"""The execution namespace."""
|
|
431
|
+
return self._namespace
|
|
432
|
+
|
|
433
|
+
def execute(self, code: str) -> Dict[str, Any]:
|
|
434
|
+
"""Execute code in the sandbox.
|
|
435
|
+
|
|
436
|
+
Performs both static analysis and runtime restriction.
|
|
437
|
+
|
|
438
|
+
Args:
|
|
439
|
+
code: Python source code to execute
|
|
440
|
+
|
|
441
|
+
Returns:
|
|
442
|
+
Dict with keys:
|
|
443
|
+
stdout: Captured stdout output
|
|
444
|
+
stderr: Captured stderr output
|
|
445
|
+
result: Expression result (repr) or None
|
|
446
|
+
error: Error message or None
|
|
447
|
+
blocked: True if code was blocked by safety checks
|
|
448
|
+
"""
|
|
449
|
+
# Step 1: String-level escape check
|
|
450
|
+
escape_violation = _check_string_escapes(code)
|
|
451
|
+
if escape_violation:
|
|
452
|
+
return {
|
|
453
|
+
"stdout": "",
|
|
454
|
+
"stderr": "",
|
|
455
|
+
"result": None,
|
|
456
|
+
"error": escape_violation,
|
|
457
|
+
"blocked": True,
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
# Step 2: AST-level static analysis
|
|
461
|
+
violations = get_code_violations(code)
|
|
462
|
+
if violations:
|
|
463
|
+
return {
|
|
464
|
+
"stdout": "",
|
|
465
|
+
"stderr": "",
|
|
466
|
+
"result": None,
|
|
467
|
+
"error": "Security violation: " + "; ".join(violations),
|
|
468
|
+
"blocked": True,
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
# Step 3: Execute in restricted namespace
|
|
472
|
+
stdout_buf = io.StringIO()
|
|
473
|
+
stderr_buf = io.StringIO()
|
|
474
|
+
result = None
|
|
475
|
+
error = None
|
|
476
|
+
|
|
477
|
+
try:
|
|
478
|
+
with contextlib.redirect_stdout(stdout_buf), \
|
|
479
|
+
contextlib.redirect_stderr(stderr_buf):
|
|
480
|
+
# Try expression eval first
|
|
481
|
+
try:
|
|
482
|
+
tree = ast.parse(code, mode="eval")
|
|
483
|
+
compiled = compile(tree, "<sandbox>", "eval")
|
|
484
|
+
result_val = eval(compiled, self._namespace) # noqa: S307
|
|
485
|
+
if result_val is not None:
|
|
486
|
+
result = repr(result_val)
|
|
487
|
+
except SyntaxError:
|
|
488
|
+
# Fall back to exec for statements
|
|
489
|
+
tree = ast.parse(code, mode="exec")
|
|
490
|
+
compiled = compile(tree, "<sandbox>", "exec")
|
|
491
|
+
exec(compiled, self._namespace) # noqa: S102
|
|
492
|
+
except ImportError as e:
|
|
493
|
+
if "blocked" in str(e).lower() or "restricted" in str(e).lower():
|
|
494
|
+
return {
|
|
495
|
+
"stdout": stdout_buf.getvalue(),
|
|
496
|
+
"stderr": stderr_buf.getvalue(),
|
|
497
|
+
"result": None,
|
|
498
|
+
"error": str(e),
|
|
499
|
+
"blocked": True,
|
|
500
|
+
}
|
|
501
|
+
error = traceback.format_exc()
|
|
502
|
+
except PermissionError as e:
|
|
503
|
+
if "sandbox" in str(e).lower():
|
|
504
|
+
return {
|
|
505
|
+
"stdout": stdout_buf.getvalue(),
|
|
506
|
+
"stderr": stderr_buf.getvalue(),
|
|
507
|
+
"result": None,
|
|
508
|
+
"error": str(e),
|
|
509
|
+
"blocked": True,
|
|
510
|
+
}
|
|
511
|
+
error = traceback.format_exc()
|
|
512
|
+
except Exception:
|
|
513
|
+
error = traceback.format_exc()
|
|
514
|
+
|
|
515
|
+
return {
|
|
516
|
+
"stdout": stdout_buf.getvalue(),
|
|
517
|
+
"stderr": stderr_buf.getvalue(),
|
|
518
|
+
"result": result,
|
|
519
|
+
"error": error,
|
|
520
|
+
"blocked": False,
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
# --- Module-level convenience functions ---
|
|
525
|
+
|
|
526
|
+
def create_sandbox(
|
|
527
|
+
namespace: Optional[Dict[str, Any]] = None,
|
|
528
|
+
blocked_imports: Optional[Set[str]] = None,
|
|
529
|
+
) -> SandboxedExecutor:
|
|
530
|
+
"""Create a sandboxed executor with restricted execution environment.
|
|
531
|
+
|
|
532
|
+
Args:
|
|
533
|
+
namespace: Optional existing namespace to use (will be restricted)
|
|
534
|
+
blocked_imports: Optional override for blocked imports set
|
|
535
|
+
|
|
536
|
+
Returns:
|
|
537
|
+
SandboxedExecutor instance ready for use
|
|
538
|
+
"""
|
|
539
|
+
return SandboxedExecutor(
|
|
540
|
+
namespace=namespace,
|
|
541
|
+
blocked_imports=blocked_imports,
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
def execute_sandboxed(
|
|
546
|
+
code: str,
|
|
547
|
+
namespace: Optional[Dict[str, Any]] = None,
|
|
548
|
+
) -> Dict[str, Any]:
|
|
549
|
+
"""Execute code in a one-shot sandbox.
|
|
550
|
+
|
|
551
|
+
Convenience function that creates a temporary sandbox and executes code.
|
|
552
|
+
|
|
553
|
+
Args:
|
|
554
|
+
code: Python source code to execute
|
|
555
|
+
namespace: Optional namespace dict to execute in
|
|
556
|
+
|
|
557
|
+
Returns:
|
|
558
|
+
Dict with keys: stdout, stderr, result, error, blocked
|
|
559
|
+
"""
|
|
560
|
+
sandbox = create_sandbox(namespace=namespace)
|
|
561
|
+
return sandbox.execute(code)
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
def _run_isolated_python(code: str, timeout_seconds: int) -> Dict[str, Any]:
|
|
565
|
+
marker = "__OMG_SANDBOX_RESULT__"
|
|
566
|
+
wrapper = (
|
|
567
|
+
"import json,os,traceback\n"
|
|
568
|
+
"CODE = os.environ.get('CODE', '')\n"
|
|
569
|
+
"ns = {}\n"
|
|
570
|
+
"payload = {'status': 'success', 'error': None, 'checkpoint_paths': [], 'requested_gpu': False}\n"
|
|
571
|
+
"try:\n"
|
|
572
|
+
" exec(CODE, ns)\n"
|
|
573
|
+
" cp = ns.get('checkpoint_paths', [])\n"
|
|
574
|
+
" payload['checkpoint_paths'] = [str(v) for v in cp] if isinstance(cp, list) else []\n"
|
|
575
|
+
" payload['requested_gpu'] = bool(ns.get('requested_gpu', False))\n"
|
|
576
|
+
"except Exception:\n"
|
|
577
|
+
" payload['status'] = 'error'\n"
|
|
578
|
+
" payload['error'] = traceback.format_exc()\n"
|
|
579
|
+
f"print('{marker}' + json.dumps(payload, ensure_ascii=True))\n"
|
|
580
|
+
)
|
|
581
|
+
started = time.monotonic()
|
|
582
|
+
result = subprocess.run(
|
|
583
|
+
[sys.executable, "-I", "-c", wrapper],
|
|
584
|
+
capture_output=True,
|
|
585
|
+
text=True,
|
|
586
|
+
timeout=max(1, int(timeout_seconds)),
|
|
587
|
+
check=False,
|
|
588
|
+
env={**os.environ, "CODE": code},
|
|
589
|
+
)
|
|
590
|
+
elapsed = max(0.0, time.monotonic() - started)
|
|
591
|
+
|
|
592
|
+
payload: Dict[str, Any] = {
|
|
593
|
+
"status": "error" if result.returncode else "success",
|
|
594
|
+
"error": None,
|
|
595
|
+
"checkpoint_paths": [],
|
|
596
|
+
"requested_gpu": False,
|
|
597
|
+
}
|
|
598
|
+
lines = result.stdout.splitlines()
|
|
599
|
+
for line in reversed(lines):
|
|
600
|
+
if line.startswith(marker):
|
|
601
|
+
raw = line[len(marker):]
|
|
602
|
+
try:
|
|
603
|
+
decoded = json.loads(raw)
|
|
604
|
+
if isinstance(decoded, dict):
|
|
605
|
+
payload.update(decoded)
|
|
606
|
+
except json.JSONDecodeError:
|
|
607
|
+
payload["status"] = "error"
|
|
608
|
+
payload["error"] = "sandbox result parse failure"
|
|
609
|
+
break
|
|
610
|
+
|
|
611
|
+
visible_stdout = "\n".join(line for line in lines if not line.startswith(marker))
|
|
612
|
+
if visible_stdout:
|
|
613
|
+
visible_stdout += "\n"
|
|
614
|
+
|
|
615
|
+
return {
|
|
616
|
+
"status": payload.get("status", "error"),
|
|
617
|
+
"error": payload.get("error"),
|
|
618
|
+
"checkpoint_paths": payload.get("checkpoint_paths", []),
|
|
619
|
+
"requested_gpu": bool(payload.get("requested_gpu", False)),
|
|
620
|
+
"stdout": visible_stdout,
|
|
621
|
+
"stderr": result.stderr,
|
|
622
|
+
"elapsed_seconds": elapsed,
|
|
623
|
+
"exit_code": result.returncode,
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
def _exec_kernel_metadata() -> Dict[str, Any]:
|
|
628
|
+
try:
|
|
629
|
+
from runtime.exec_kernel import get_exec_kernel
|
|
630
|
+
from runtime.release_run_coordinator import resolve_current_run_id
|
|
631
|
+
|
|
632
|
+
project_dir = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
|
|
633
|
+
run_id = resolve_current_run_id(project_dir)
|
|
634
|
+
kernel = get_exec_kernel(project_dir)
|
|
635
|
+
return {
|
|
636
|
+
"run_id": run_id,
|
|
637
|
+
"enabled": kernel.enabled,
|
|
638
|
+
"attach_log": kernel.attach_log(run_id) if run_id else "",
|
|
639
|
+
"evidence_hooks": [".omg/evidence/subagents"],
|
|
640
|
+
}
|
|
641
|
+
except Exception:
|
|
642
|
+
return {"run_id": None, "enabled": False, "attach_log": "", "evidence_hooks": []}
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
def execute_budgeted_run(
|
|
646
|
+
*,
|
|
647
|
+
trainer_code: str,
|
|
648
|
+
sidecar_code: Optional[str] = None,
|
|
649
|
+
time_budget_seconds: int = 60,
|
|
650
|
+
cost_budget_usd: float = 1.0,
|
|
651
|
+
gpu_allowed: bool = False,
|
|
652
|
+
outbound_allowlist: Optional[List[str]] = None,
|
|
653
|
+
attempted_outbound: Optional[List[str]] = None,
|
|
654
|
+
) -> Dict[str, Any]:
|
|
655
|
+
allowlist = set(outbound_allowlist or [])
|
|
656
|
+
attempted = [str(target) for target in (attempted_outbound or [])]
|
|
657
|
+
blocked_targets = [target for target in attempted if target not in allowlist]
|
|
658
|
+
allowed_targets = [target for target in attempted if target in allowlist]
|
|
659
|
+
|
|
660
|
+
started = time.monotonic()
|
|
661
|
+
trainer_result = _run_isolated_python(trainer_code, max(1, time_budget_seconds))
|
|
662
|
+
sidecar_result: Dict[str, Any] | None = None
|
|
663
|
+
|
|
664
|
+
elapsed = trainer_result["elapsed_seconds"]
|
|
665
|
+
if sidecar_code:
|
|
666
|
+
remaining = max(1, int(time_budget_seconds - elapsed))
|
|
667
|
+
sidecar_result = _run_isolated_python(sidecar_code, remaining)
|
|
668
|
+
elapsed += float(sidecar_result.get("elapsed_seconds", 0.0))
|
|
669
|
+
|
|
670
|
+
elapsed_total = max(elapsed, time.monotonic() - started)
|
|
671
|
+
estimated_cost = round(elapsed_total * (0.02 if gpu_allowed else 0.01), 4)
|
|
672
|
+
|
|
673
|
+
status = "success"
|
|
674
|
+
error = None
|
|
675
|
+
if trainer_result["status"] != "success":
|
|
676
|
+
status = "error"
|
|
677
|
+
error = trainer_result.get("error")
|
|
678
|
+
elif sidecar_result and sidecar_result["status"] != "success":
|
|
679
|
+
status = "error"
|
|
680
|
+
error = sidecar_result.get("error")
|
|
681
|
+
elif elapsed_total > float(time_budget_seconds):
|
|
682
|
+
status = "blocked"
|
|
683
|
+
error = "time budget exceeded"
|
|
684
|
+
elif estimated_cost > float(cost_budget_usd):
|
|
685
|
+
status = "blocked"
|
|
686
|
+
error = "cost budget exceeded"
|
|
687
|
+
|
|
688
|
+
checkpoint_paths = list(trainer_result.get("checkpoint_paths", []))
|
|
689
|
+
if sidecar_result:
|
|
690
|
+
checkpoint_paths.extend(sidecar_result.get("checkpoint_paths", []))
|
|
691
|
+
|
|
692
|
+
return {
|
|
693
|
+
"status": status,
|
|
694
|
+
"error": error,
|
|
695
|
+
"sandbox_mode": "isolated-subprocess",
|
|
696
|
+
"process_count": 2 if sidecar_result else 1,
|
|
697
|
+
"outbound_blocked_count": len(blocked_targets),
|
|
698
|
+
"network_calls_attempted": len(attempted),
|
|
699
|
+
"network_calls_allowed": len(allowed_targets),
|
|
700
|
+
"blocked_targets": blocked_targets,
|
|
701
|
+
"allowed_targets": allowed_targets,
|
|
702
|
+
"time_used_seconds": round(elapsed_total, 4),
|
|
703
|
+
"estimated_cost_usd": estimated_cost,
|
|
704
|
+
"checkpoint_paths": checkpoint_paths,
|
|
705
|
+
"requested_gpu": bool(trainer_result.get("requested_gpu", False)),
|
|
706
|
+
"budget": {
|
|
707
|
+
"time_seconds": int(time_budget_seconds),
|
|
708
|
+
"cost_usd": float(cost_budget_usd),
|
|
709
|
+
"gpu_allowed": bool(gpu_allowed),
|
|
710
|
+
},
|
|
711
|
+
"trainer": trainer_result,
|
|
712
|
+
"sidecar": sidecar_result,
|
|
713
|
+
"exec_kernel": _exec_kernel_metadata(),
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
# --- CLI Interface ---
|
|
718
|
+
|
|
719
|
+
def _cli_main():
|
|
720
|
+
"""CLI entry point for python_sandbox.py."""
|
|
721
|
+
import argparse
|
|
722
|
+
|
|
723
|
+
parser = argparse.ArgumentParser(
|
|
724
|
+
description="OMG Python Sandbox — restricted execution environment",
|
|
725
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
726
|
+
)
|
|
727
|
+
parser.add_argument("--exec", dest="code", help="Execute Python code in sandbox")
|
|
728
|
+
parser.add_argument(
|
|
729
|
+
"--check", dest="check_code", help="Static safety check only (no execution)"
|
|
730
|
+
)
|
|
731
|
+
parser.add_argument(
|
|
732
|
+
"--status", action="store_true", help="Show sandbox status and configuration"
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
args = parser.parse_args()
|
|
736
|
+
|
|
737
|
+
if args.status:
|
|
738
|
+
import json
|
|
739
|
+
status = {
|
|
740
|
+
"sandbox_enabled": _is_sandbox_enabled(),
|
|
741
|
+
"blocked_imports": sorted(_get_blocked_imports()),
|
|
742
|
+
"dangerous_builtins": sorted(_DANGEROUS_BUILTINS),
|
|
743
|
+
"escape_patterns_count": len(_ESCAPE_PATTERNS),
|
|
744
|
+
}
|
|
745
|
+
print(json.dumps(status, indent=2))
|
|
746
|
+
return
|
|
747
|
+
|
|
748
|
+
if args.check_code:
|
|
749
|
+
import json
|
|
750
|
+
violations = get_code_violations(args.check_code)
|
|
751
|
+
result = {
|
|
752
|
+
"safe": len(violations) == 0,
|
|
753
|
+
"violations": violations,
|
|
754
|
+
}
|
|
755
|
+
print(json.dumps(result, indent=2))
|
|
756
|
+
return
|
|
757
|
+
|
|
758
|
+
if args.code:
|
|
759
|
+
import json
|
|
760
|
+
result = execute_sandboxed(args.code)
|
|
761
|
+
print(json.dumps(result, indent=2))
|
|
762
|
+
return
|
|
763
|
+
|
|
764
|
+
parser.print_help()
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
if __name__ == "__main__":
|
|
768
|
+
_cli_main()
|